| OLD | NEW |
| (Empty) |
| 1 // Copyright 2015 the V8 project authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include <iostream> | |
| 6 | |
| 7 #include "src/compiler/bytecode-graph-builder.h" | |
| 8 #include "src/compiler/common-operator.h" | |
| 9 #include "src/compiler/graph-visualizer.h" | |
| 10 #include "src/compiler/instruction.h" | |
| 11 #include "src/compiler/instruction-selector.h" | |
| 12 #include "src/compiler/js-graph.h" | |
| 13 #include "src/compiler/js-operator.h" | |
| 14 #include "src/compiler/linkage.h" | |
| 15 #include "src/interpreter/bytecode-array-builder.h" | |
| 16 #include "src/parser.h" | |
| 17 #include "test/unittests/compiler/compiler-test-utils.h" | |
| 18 #include "test/unittests/compiler/graph-unittest.h" | |
| 19 #include "test/unittests/compiler/node-test-utils.h" | |
| 20 #include "test/unittests/test-utils.h" | |
| 21 | |
| 22 using ::testing::_; | |
| 23 | |
| 24 namespace v8 { | |
| 25 namespace internal { | |
| 26 namespace compiler { | |
| 27 | |
| 28 static const LanguageMode kLanguageModes[] = {LanguageMode::SLOPPY, | |
| 29 LanguageMode::STRICT}; | |
| 30 | |
| 31 Handle<TypeFeedbackVector> NewTypeFeedbackVector(Isolate* isolate, | |
| 32 FeedbackVectorSpec* spec) { | |
| 33 Handle<TypeFeedbackMetadata> vector_metadata = | |
| 34 TypeFeedbackMetadata::New(isolate, spec); | |
| 35 return TypeFeedbackVector::New(isolate, vector_metadata); | |
| 36 } | |
| 37 | |
| 38 | |
| 39 class BytecodeGraphBuilderTest : public TestWithIsolateAndZone { | |
| 40 public: | |
| 41 BytecodeGraphBuilderTest() {} | |
| 42 | |
| 43 Graph* GetCompletedGraph(Handle<BytecodeArray> bytecode_array, | |
| 44 MaybeHandle<TypeFeedbackVector> feedback_vector = | |
| 45 MaybeHandle<TypeFeedbackVector>(), | |
| 46 LanguageMode language_mode = LanguageMode::SLOPPY); | |
| 47 | |
| 48 Matcher<Node*> IsUndefinedConstant(); | |
| 49 Matcher<Node*> IsNullConstant(); | |
| 50 Matcher<Node*> IsTheHoleConstant(); | |
| 51 Matcher<Node*> IsFalseConstant(); | |
| 52 Matcher<Node*> IsTrueConstant(); | |
| 53 Matcher<Node*> IsIntPtrConstant(int value); | |
| 54 Matcher<Node*> IsFeedbackVector(Node* effect, Node* control); | |
| 55 | |
| 56 static Handle<String> GetName(Isolate* isolate, const char* name) { | |
| 57 Handle<String> result = isolate->factory()->NewStringFromAsciiChecked(name); | |
| 58 return isolate->factory()->string_table()->LookupString(isolate, result); | |
| 59 } | |
| 60 | |
| 61 private: | |
| 62 DISALLOW_COPY_AND_ASSIGN(BytecodeGraphBuilderTest); | |
| 63 }; | |
| 64 | |
| 65 | |
| 66 Graph* BytecodeGraphBuilderTest::GetCompletedGraph( | |
| 67 Handle<BytecodeArray> bytecode_array, | |
| 68 MaybeHandle<TypeFeedbackVector> feedback_vector, | |
| 69 LanguageMode language_mode) { | |
| 70 MachineOperatorBuilder* machine = new (zone()) MachineOperatorBuilder( | |
| 71 zone(), kMachPtr, InstructionSelector::SupportedMachineOperatorFlags()); | |
| 72 CommonOperatorBuilder* common = new (zone()) CommonOperatorBuilder(zone()); | |
| 73 JSOperatorBuilder* javascript = new (zone()) JSOperatorBuilder(zone()); | |
| 74 Graph* graph = new (zone()) Graph(zone()); | |
| 75 JSGraph* jsgraph = new (zone()) | |
| 76 JSGraph(isolate(), graph, common, javascript, nullptr, machine); | |
| 77 | |
| 78 Handle<String> name = factory()->NewStringFromStaticChars("test"); | |
| 79 Handle<String> script = factory()->NewStringFromStaticChars("test() {}"); | |
| 80 Handle<SharedFunctionInfo> shared_info = | |
| 81 factory()->NewSharedFunctionInfo(name, MaybeHandle<Code>(), true); | |
| 82 shared_info->set_script(*factory()->NewScript(script)); | |
| 83 if (!feedback_vector.is_null()) { | |
| 84 shared_info->set_feedback_vector(*feedback_vector.ToHandleChecked()); | |
| 85 } | |
| 86 | |
| 87 ParseInfo parse_info(zone(), shared_info); | |
| 88 parse_info.set_language_mode(language_mode); | |
| 89 CompilationInfo info(&parse_info); | |
| 90 info.shared_info()->set_function_data(*bytecode_array); | |
| 91 | |
| 92 BytecodeGraphBuilder graph_builder(zone(), &info, jsgraph); | |
| 93 graph_builder.CreateGraph(); | |
| 94 return graph; | |
| 95 } | |
| 96 | |
| 97 | |
| 98 Matcher<Node*> BytecodeGraphBuilderTest::IsUndefinedConstant() { | |
| 99 return IsHeapConstant(factory()->undefined_value()); | |
| 100 } | |
| 101 | |
| 102 | |
| 103 Matcher<Node*> BytecodeGraphBuilderTest::IsNullConstant() { | |
| 104 return IsHeapConstant(factory()->null_value()); | |
| 105 } | |
| 106 | |
| 107 | |
| 108 Matcher<Node*> BytecodeGraphBuilderTest::IsTheHoleConstant() { | |
| 109 return IsHeapConstant(factory()->the_hole_value()); | |
| 110 } | |
| 111 | |
| 112 | |
| 113 Matcher<Node*> BytecodeGraphBuilderTest::IsFalseConstant() { | |
| 114 return IsHeapConstant(factory()->false_value()); | |
| 115 } | |
| 116 | |
| 117 | |
| 118 Matcher<Node*> BytecodeGraphBuilderTest::IsTrueConstant() { | |
| 119 return IsHeapConstant(factory()->true_value()); | |
| 120 } | |
| 121 | |
| 122 | |
| 123 Matcher<Node*> BytecodeGraphBuilderTest::IsIntPtrConstant(int value) { | |
| 124 if (kPointerSize == 8) { | |
| 125 return IsInt64Constant(value); | |
| 126 } else { | |
| 127 return IsInt32Constant(value); | |
| 128 } | |
| 129 } | |
| 130 | |
| 131 | |
| 132 Matcher<Node*> BytecodeGraphBuilderTest::IsFeedbackVector(Node* effect, | |
| 133 Node* control) { | |
| 134 int offset = SharedFunctionInfo::kFeedbackVectorOffset - kHeapObjectTag; | |
| 135 int offset1 = JSFunction::kSharedFunctionInfoOffset - kHeapObjectTag; | |
| 136 | |
| 137 return IsLoad( | |
| 138 kMachAnyTagged, | |
| 139 IsLoad(kMachAnyTagged, IsParameter(Linkage::kJSCallClosureParamIndex), | |
| 140 IsIntPtrConstant(offset1), effect, control), | |
| 141 IsIntPtrConstant(offset), effect, control); | |
| 142 } | |
| 143 | |
| 144 | |
| 145 TEST_F(BytecodeGraphBuilderTest, ReturnUndefined) { | |
| 146 interpreter::BytecodeArrayBuilder array_builder(isolate(), zone()); | |
| 147 array_builder.set_locals_count(0); | |
| 148 array_builder.set_context_count(0); | |
| 149 array_builder.set_parameter_count(1); | |
| 150 array_builder.LoadUndefined().Return(); | |
| 151 | |
| 152 Graph* graph = GetCompletedGraph(array_builder.ToBytecodeArray()); | |
| 153 Node* end = graph->end(); | |
| 154 EXPECT_EQ(1, end->InputCount()); | |
| 155 Node* ret = end->InputAt(0); | |
| 156 Node* effect = graph->start(); | |
| 157 Node* control = graph->start(); | |
| 158 EXPECT_THAT(ret, IsReturn(IsUndefinedConstant(), effect, control)); | |
| 159 } | |
| 160 | |
| 161 | |
| 162 TEST_F(BytecodeGraphBuilderTest, ReturnNull) { | |
| 163 interpreter::BytecodeArrayBuilder array_builder(isolate(), zone()); | |
| 164 array_builder.set_locals_count(0); | |
| 165 array_builder.set_context_count(0); | |
| 166 array_builder.set_parameter_count(1); | |
| 167 array_builder.LoadNull().Return(); | |
| 168 | |
| 169 Graph* graph = GetCompletedGraph(array_builder.ToBytecodeArray()); | |
| 170 Node* end = graph->end(); | |
| 171 EXPECT_EQ(1, end->InputCount()); | |
| 172 Node* ret = end->InputAt(0); | |
| 173 EXPECT_THAT(ret, IsReturn(IsNullConstant(), graph->start(), graph->start())); | |
| 174 } | |
| 175 | |
| 176 | |
| 177 TEST_F(BytecodeGraphBuilderTest, ReturnTheHole) { | |
| 178 interpreter::BytecodeArrayBuilder array_builder(isolate(), zone()); | |
| 179 array_builder.set_locals_count(0); | |
| 180 array_builder.set_context_count(0); | |
| 181 array_builder.set_parameter_count(1); | |
| 182 array_builder.LoadTheHole().Return(); | |
| 183 | |
| 184 Graph* graph = GetCompletedGraph(array_builder.ToBytecodeArray()); | |
| 185 Node* end = graph->end(); | |
| 186 EXPECT_EQ(1, end->InputCount()); | |
| 187 Node* ret = end->InputAt(0); | |
| 188 Node* effect = graph->start(); | |
| 189 Node* control = graph->start(); | |
| 190 EXPECT_THAT(ret, IsReturn(IsTheHoleConstant(), effect, control)); | |
| 191 } | |
| 192 | |
| 193 | |
| 194 TEST_F(BytecodeGraphBuilderTest, ReturnTrue) { | |
| 195 interpreter::BytecodeArrayBuilder array_builder(isolate(), zone()); | |
| 196 array_builder.set_locals_count(0); | |
| 197 array_builder.set_context_count(0); | |
| 198 array_builder.set_parameter_count(1); | |
| 199 array_builder.LoadTrue().Return(); | |
| 200 | |
| 201 Graph* graph = GetCompletedGraph(array_builder.ToBytecodeArray()); | |
| 202 Node* end = graph->end(); | |
| 203 EXPECT_EQ(1, end->InputCount()); | |
| 204 Node* ret = end->InputAt(0); | |
| 205 Node* effect = graph->start(); | |
| 206 Node* control = graph->start(); | |
| 207 EXPECT_THAT(ret, IsReturn(IsTrueConstant(), effect, control)); | |
| 208 } | |
| 209 | |
| 210 | |
| 211 TEST_F(BytecodeGraphBuilderTest, ReturnFalse) { | |
| 212 interpreter::BytecodeArrayBuilder array_builder(isolate(), zone()); | |
| 213 array_builder.set_locals_count(0); | |
| 214 array_builder.set_context_count(0); | |
| 215 array_builder.set_parameter_count(1); | |
| 216 array_builder.LoadFalse().Return(); | |
| 217 | |
| 218 Graph* graph = GetCompletedGraph(array_builder.ToBytecodeArray()); | |
| 219 Node* end = graph->end(); | |
| 220 EXPECT_EQ(1, end->InputCount()); | |
| 221 Node* ret = end->InputAt(0); | |
| 222 Node* effect = graph->start(); | |
| 223 Node* control = graph->start(); | |
| 224 EXPECT_THAT(ret, IsReturn(IsFalseConstant(), effect, control)); | |
| 225 } | |
| 226 | |
| 227 | |
| 228 TEST_F(BytecodeGraphBuilderTest, ReturnInt8) { | |
| 229 interpreter::BytecodeArrayBuilder array_builder(isolate(), zone()); | |
| 230 static const int kValue = 3; | |
| 231 array_builder.set_locals_count(0); | |
| 232 array_builder.set_context_count(0); | |
| 233 array_builder.set_parameter_count(1); | |
| 234 array_builder.LoadLiteral(Smi::FromInt(kValue)).Return(); | |
| 235 | |
| 236 Graph* graph = GetCompletedGraph(array_builder.ToBytecodeArray()); | |
| 237 Node* end = graph->end(); | |
| 238 EXPECT_EQ(1, end->InputCount()); | |
| 239 Node* ret = end->InputAt(0); | |
| 240 Node* effect = graph->start(); | |
| 241 Node* control = graph->start(); | |
| 242 EXPECT_THAT(ret, IsReturn(IsNumberConstant(kValue), effect, control)); | |
| 243 } | |
| 244 | |
| 245 | |
| 246 TEST_F(BytecodeGraphBuilderTest, ReturnDouble) { | |
| 247 interpreter::BytecodeArrayBuilder array_builder(isolate(), zone()); | |
| 248 const double kValue = 0.123456789; | |
| 249 array_builder.set_locals_count(0); | |
| 250 array_builder.set_context_count(0); | |
| 251 array_builder.set_parameter_count(1); | |
| 252 array_builder.LoadLiteral(factory()->NewHeapNumber(kValue)); | |
| 253 array_builder.Return(); | |
| 254 | |
| 255 Graph* graph = GetCompletedGraph(array_builder.ToBytecodeArray()); | |
| 256 Node* end = graph->end(); | |
| 257 EXPECT_EQ(1, end->InputCount()); | |
| 258 Node* ret = end->InputAt(0); | |
| 259 Node* effect = graph->start(); | |
| 260 Node* control = graph->start(); | |
| 261 EXPECT_THAT(ret, IsReturn(IsNumberConstant(kValue), effect, control)); | |
| 262 } | |
| 263 | |
| 264 | |
| 265 TEST_F(BytecodeGraphBuilderTest, SimpleExpressionWithParameters) { | |
| 266 interpreter::BytecodeArrayBuilder array_builder(isolate(), zone()); | |
| 267 array_builder.set_locals_count(1); | |
| 268 array_builder.set_context_count(0); | |
| 269 array_builder.set_parameter_count(3); | |
| 270 array_builder.LoadAccumulatorWithRegister(array_builder.Parameter(1)) | |
| 271 .BinaryOperation(Token::Value::ADD, array_builder.Parameter(2), | |
| 272 Strength::WEAK) | |
| 273 .StoreAccumulatorInRegister(interpreter::Register(0)) | |
| 274 .Return(); | |
| 275 | |
| 276 Graph* graph = GetCompletedGraph(array_builder.ToBytecodeArray()); | |
| 277 Node* end = graph->end(); | |
| 278 EXPECT_EQ(1, end->InputCount()); | |
| 279 Node* ret = end->InputAt(0); | |
| 280 // NB binary operation is <reg> <op> <acc>. The register represents | |
| 281 // the left-hand side, which is why parameters appear in opposite | |
| 282 // order to construction via the builder. | |
| 283 EXPECT_THAT(ret, IsReturn(IsJSAdd(IsParameter(2), IsParameter(1)), _, _)); | |
| 284 } | |
| 285 | |
| 286 | |
| 287 TEST_F(BytecodeGraphBuilderTest, SimpleExpressionWithRegister) { | |
| 288 interpreter::BytecodeArrayBuilder array_builder(isolate(), zone()); | |
| 289 static const int kLeft = -655371; | |
| 290 static const int kRight = +2000000; | |
| 291 array_builder.set_locals_count(1); | |
| 292 array_builder.set_context_count(0); | |
| 293 array_builder.set_parameter_count(1); | |
| 294 array_builder.LoadLiteral(Smi::FromInt(kLeft)) | |
| 295 .StoreAccumulatorInRegister(interpreter::Register(0)) | |
| 296 .LoadLiteral(Smi::FromInt(kRight)) | |
| 297 .BinaryOperation(Token::Value::ADD, interpreter::Register(0), | |
| 298 Strength::WEAK) | |
| 299 .Return(); | |
| 300 | |
| 301 Graph* graph = GetCompletedGraph(array_builder.ToBytecodeArray()); | |
| 302 Node* end = graph->end(); | |
| 303 EXPECT_EQ(1, end->InputCount()); | |
| 304 Node* ret = end->InputAt(0); | |
| 305 EXPECT_THAT( | |
| 306 ret, IsReturn(IsJSAdd(IsNumberConstant(kLeft), IsNumberConstant(kRight)), | |
| 307 _, _)); | |
| 308 } | |
| 309 | |
| 310 | |
| 311 TEST_F(BytecodeGraphBuilderTest, NamedLoad) { | |
| 312 const bool kWideBytecode[] = {false, true}; | |
| 313 TRACED_FOREACH(LanguageMode, language_mode, kLanguageModes) { | |
| 314 TRACED_FOREACH(bool, wide_bytecode, kWideBytecode) { | |
| 315 FeedbackVectorSpec feedback_spec(zone()); | |
| 316 if (wide_bytecode) { | |
| 317 for (int i = 0; i < 128; i++) { | |
| 318 feedback_spec.AddLoadICSlot(); | |
| 319 } | |
| 320 } | |
| 321 FeedbackVectorSlot slot = feedback_spec.AddLoadICSlot(); | |
| 322 Handle<TypeFeedbackVector> vector = | |
| 323 NewTypeFeedbackVector(isolate(), &feedback_spec); | |
| 324 | |
| 325 interpreter::BytecodeArrayBuilder array_builder(isolate(), zone()); | |
| 326 array_builder.set_locals_count(1); | |
| 327 array_builder.set_context_count(0); | |
| 328 array_builder.set_parameter_count(2); | |
| 329 | |
| 330 Handle<Name> name = GetName(isolate(), "val"); | |
| 331 size_t name_index = array_builder.GetConstantPoolEntry(name); | |
| 332 | |
| 333 array_builder.LoadNamedProperty(array_builder.Parameter(1), name_index, | |
| 334 vector->GetIndex(slot), language_mode) | |
| 335 .Return(); | |
| 336 Graph* graph = GetCompletedGraph(array_builder.ToBytecodeArray(), vector, | |
| 337 language_mode); | |
| 338 | |
| 339 Node* ret = graph->end()->InputAt(0); | |
| 340 Node* start = graph->start(); | |
| 341 | |
| 342 Matcher<Node*> feedback_vector_matcher = IsFeedbackVector(start, start); | |
| 343 Matcher<Node*> load_named_matcher = IsJSLoadNamed( | |
| 344 name, IsParameter(1), feedback_vector_matcher, start, start); | |
| 345 | |
| 346 EXPECT_THAT(ret, IsReturn(load_named_matcher, _, _)); | |
| 347 } | |
| 348 } | |
| 349 } | |
| 350 | |
| 351 | |
| 352 TEST_F(BytecodeGraphBuilderTest, CallProperty0) { | |
| 353 FeedbackVectorSpec feedback_spec(zone()); | |
| 354 FeedbackVectorSlot call_slot = feedback_spec.AddCallICSlot(); | |
| 355 FeedbackVectorSlot load_slot = feedback_spec.AddLoadICSlot(); | |
| 356 Handle<TypeFeedbackVector> vector = | |
| 357 NewTypeFeedbackVector(isolate(), &feedback_spec); | |
| 358 | |
| 359 interpreter::BytecodeArrayBuilder array_builder(isolate(), zone()); | |
| 360 array_builder.set_locals_count(1); | |
| 361 array_builder.set_context_count(0); | |
| 362 array_builder.set_parameter_count(2); | |
| 363 | |
| 364 Handle<Name> func_name = GetName(isolate(), "func"); | |
| 365 size_t func_name_index = array_builder.GetConstantPoolEntry(func_name); | |
| 366 | |
| 367 interpreter::Register reg0 = interpreter::Register(0); | |
| 368 array_builder.LoadNamedProperty(array_builder.Parameter(1), func_name_index, | |
| 369 vector->GetIndex(load_slot), | |
| 370 LanguageMode::SLOPPY) | |
| 371 .StoreAccumulatorInRegister(reg0) | |
| 372 .Call(reg0, array_builder.Parameter(1), 0, vector->GetIndex(call_slot)) | |
| 373 .Return(); | |
| 374 | |
| 375 Graph* graph = GetCompletedGraph(array_builder.ToBytecodeArray(), vector); | |
| 376 Node* ret = graph->end()->InputAt(0); | |
| 377 Node* start = graph->start(); | |
| 378 | |
| 379 Matcher<Node*> feedback_vector_matcher = IsFeedbackVector(start, start); | |
| 380 Matcher<Node*> load_named_matcher = IsJSLoadNamed( | |
| 381 func_name, IsParameter(1), feedback_vector_matcher, start, start); | |
| 382 std::vector<Matcher<Node*>> call_inputs; | |
| 383 call_inputs.push_back(load_named_matcher); | |
| 384 call_inputs.push_back(IsParameter(1)); | |
| 385 Matcher<Node*> call_matcher = | |
| 386 IsJSCallFunction(call_inputs, load_named_matcher, IsIfSuccess(_)); | |
| 387 | |
| 388 EXPECT_THAT(ret, IsReturn(call_matcher, _, _)); | |
| 389 } | |
| 390 | |
| 391 | |
| 392 TEST_F(BytecodeGraphBuilderTest, CallProperty2) { | |
| 393 FeedbackVectorSpec feedback_spec(zone()); | |
| 394 FeedbackVectorSlot call_slot = feedback_spec.AddCallICSlot(); | |
| 395 FeedbackVectorSlot load_slot = feedback_spec.AddLoadICSlot(); | |
| 396 Handle<TypeFeedbackVector> vector = | |
| 397 NewTypeFeedbackVector(isolate(), &feedback_spec); | |
| 398 | |
| 399 interpreter::BytecodeArrayBuilder array_builder(isolate(), zone()); | |
| 400 array_builder.set_locals_count(4); | |
| 401 array_builder.set_context_count(0); | |
| 402 array_builder.set_parameter_count(4); | |
| 403 | |
| 404 Handle<Name> func_name = GetName(isolate(), "func"); | |
| 405 size_t func_name_index = array_builder.GetConstantPoolEntry(func_name); | |
| 406 | |
| 407 interpreter::Register reg0 = interpreter::Register(0); | |
| 408 interpreter::Register reg1 = interpreter::Register(1); | |
| 409 interpreter::Register reg2 = interpreter::Register(2); | |
| 410 interpreter::Register reg3 = interpreter::Register(3); | |
| 411 array_builder.LoadNamedProperty(array_builder.Parameter(1), func_name_index, | |
| 412 vector->GetIndex(load_slot), | |
| 413 LanguageMode::SLOPPY) | |
| 414 .StoreAccumulatorInRegister(reg0) | |
| 415 .LoadAccumulatorWithRegister(array_builder.Parameter(1)) | |
| 416 .StoreAccumulatorInRegister(reg1) | |
| 417 .LoadAccumulatorWithRegister(array_builder.Parameter(2)) | |
| 418 .StoreAccumulatorInRegister(reg2) | |
| 419 .LoadAccumulatorWithRegister(array_builder.Parameter(3)) | |
| 420 .StoreAccumulatorInRegister(reg3) | |
| 421 .Call(reg0, reg1, 2, vector->GetIndex(call_slot)) | |
| 422 .Return(); | |
| 423 | |
| 424 Graph* graph = GetCompletedGraph(array_builder.ToBytecodeArray(), vector); | |
| 425 Node* ret = graph->end()->InputAt(0); | |
| 426 Node* start = graph->start(); | |
| 427 | |
| 428 Matcher<Node*> feedback_vector_matcher = IsFeedbackVector(start, start); | |
| 429 Matcher<Node*> load_named_matcher = IsJSLoadNamed( | |
| 430 func_name, IsParameter(1), feedback_vector_matcher, start, start); | |
| 431 std::vector<Matcher<Node*>> call_inputs; | |
| 432 call_inputs.push_back(load_named_matcher); | |
| 433 call_inputs.push_back(IsParameter(1)); | |
| 434 call_inputs.push_back(IsParameter(2)); | |
| 435 call_inputs.push_back(IsParameter(3)); | |
| 436 Matcher<Node*> call_matcher = | |
| 437 IsJSCallFunction(call_inputs, load_named_matcher, IsIfSuccess(_)); | |
| 438 | |
| 439 EXPECT_THAT(ret, IsReturn(call_matcher, _, _)); | |
| 440 } | |
| 441 | |
| 442 | |
| 443 TEST_F(BytecodeGraphBuilderTest, LoadGlobal) { | |
| 444 const TypeofMode kTypeOfModes[] = {TypeofMode::NOT_INSIDE_TYPEOF, | |
| 445 TypeofMode::INSIDE_TYPEOF}; | |
| 446 const bool kWideBytecode[] = {false, true}; | |
| 447 TRACED_FOREACH(LanguageMode, language_mode, kLanguageModes) { | |
| 448 TRACED_FOREACH(TypeofMode, typeof_mode, kTypeOfModes) { | |
| 449 TRACED_FOREACH(bool, wide_bytecode, kWideBytecode) { | |
| 450 FeedbackVectorSpec feedback_spec(zone()); | |
| 451 if (wide_bytecode) { | |
| 452 for (int i = 0; i < 128; i++) { | |
| 453 feedback_spec.AddLoadICSlot(); | |
| 454 } | |
| 455 } | |
| 456 FeedbackVectorSlot slot = feedback_spec.AddLoadICSlot(); | |
| 457 Handle<TypeFeedbackVector> vector = | |
| 458 NewTypeFeedbackVector(isolate(), &feedback_spec); | |
| 459 | |
| 460 interpreter::BytecodeArrayBuilder array_builder(isolate(), zone()); | |
| 461 array_builder.set_locals_count(0); | |
| 462 array_builder.set_context_count(0); | |
| 463 array_builder.set_parameter_count(1); | |
| 464 | |
| 465 Handle<Name> name = GetName(isolate(), "global"); | |
| 466 size_t name_index = array_builder.GetConstantPoolEntry(name); | |
| 467 | |
| 468 array_builder.LoadGlobal(name_index, vector->GetIndex(slot), | |
| 469 language_mode, typeof_mode) | |
| 470 .Return(); | |
| 471 Graph* graph = GetCompletedGraph(array_builder.ToBytecodeArray(), | |
| 472 vector, language_mode); | |
| 473 | |
| 474 Node* ret = graph->end()->InputAt(0); | |
| 475 Node* start = graph->start(); | |
| 476 | |
| 477 Matcher<Node*> feedback_vector_matcher = IsFeedbackVector(start, start); | |
| 478 Matcher<Node*> load_global_matcher = IsJSLoadGlobal( | |
| 479 name, typeof_mode, feedback_vector_matcher, start, start); | |
| 480 | |
| 481 EXPECT_THAT(ret, IsReturn(load_global_matcher, _, _)); | |
| 482 } | |
| 483 } | |
| 484 } | |
| 485 } | |
| 486 | |
| 487 | |
| 488 TEST_F(BytecodeGraphBuilderTest, StoreGlobal) { | |
| 489 const bool kWideBytecode[] = {false, true}; | |
| 490 TRACED_FOREACH(LanguageMode, language_mode, kLanguageModes) { | |
| 491 TRACED_FOREACH(bool, wide_bytecode, kWideBytecode) { | |
| 492 FeedbackVectorSpec feedback_spec(zone()); | |
| 493 if (wide_bytecode) { | |
| 494 for (int i = 0; i < 128; i++) { | |
| 495 feedback_spec.AddStoreICSlot(); | |
| 496 } | |
| 497 } | |
| 498 FeedbackVectorSlot slot = feedback_spec.AddStoreICSlot(); | |
| 499 Handle<TypeFeedbackVector> vector = | |
| 500 NewTypeFeedbackVector(isolate(), &feedback_spec); | |
| 501 | |
| 502 interpreter::BytecodeArrayBuilder array_builder(isolate(), zone()); | |
| 503 array_builder.set_locals_count(0); | |
| 504 array_builder.set_context_count(0); | |
| 505 array_builder.set_parameter_count(1); | |
| 506 | |
| 507 Handle<Name> name = GetName(isolate(), "global"); | |
| 508 size_t name_index = array_builder.GetConstantPoolEntry(name); | |
| 509 | |
| 510 array_builder.LoadLiteral(Smi::FromInt(321)) | |
| 511 .StoreGlobal(name_index, vector->GetIndex(slot), language_mode) | |
| 512 .Return(); | |
| 513 Graph* graph = GetCompletedGraph(array_builder.ToBytecodeArray(), vector, | |
| 514 language_mode); | |
| 515 | |
| 516 Node* ret = graph->end()->InputAt(0); | |
| 517 Node* start = graph->start(); | |
| 518 | |
| 519 Matcher<Node*> value_matcher = IsNumberConstant(321); | |
| 520 Matcher<Node*> feedback_vector_matcher = IsFeedbackVector(start, start); | |
| 521 Matcher<Node*> store_global_matcher = IsJSStoreGlobal( | |
| 522 name, value_matcher, feedback_vector_matcher, start, start); | |
| 523 | |
| 524 EXPECT_THAT(ret, IsReturn(_, store_global_matcher, _)); | |
| 525 } | |
| 526 } | |
| 527 } | |
| 528 | |
| 529 | |
| 530 TEST_F(BytecodeGraphBuilderTest, LogicalNot) { | |
| 531 interpreter::BytecodeArrayBuilder array_builder(isolate(), zone()); | |
| 532 array_builder.set_locals_count(1); | |
| 533 array_builder.set_context_count(0); | |
| 534 array_builder.set_parameter_count(2); | |
| 535 array_builder.LoadAccumulatorWithRegister(array_builder.Parameter(1)) | |
| 536 .LogicalNot() | |
| 537 .Return(); | |
| 538 | |
| 539 FeedbackVectorSpec feedback_spec(zone()); | |
| 540 Handle<TypeFeedbackVector> vector = | |
| 541 NewTypeFeedbackVector(isolate(), &feedback_spec); | |
| 542 Graph* graph = GetCompletedGraph(array_builder.ToBytecodeArray(), vector); | |
| 543 | |
| 544 Node* ret = graph->end()->InputAt(0); | |
| 545 EXPECT_THAT(ret, IsReturn(IsJSUnaryNot(IsParameter(1)), _, _)); | |
| 546 } | |
| 547 | |
| 548 | |
| 549 TEST_F(BytecodeGraphBuilderTest, TypeOf) { | |
| 550 interpreter::BytecodeArrayBuilder array_builder(isolate(), zone()); | |
| 551 array_builder.set_locals_count(1); | |
| 552 array_builder.set_context_count(0); | |
| 553 array_builder.set_parameter_count(2); | |
| 554 array_builder.LoadAccumulatorWithRegister(array_builder.Parameter(1)) | |
| 555 .TypeOf() | |
| 556 .Return(); | |
| 557 | |
| 558 FeedbackVectorSpec feedback_spec(zone()); | |
| 559 Handle<TypeFeedbackVector> vector = | |
| 560 NewTypeFeedbackVector(isolate(), &feedback_spec); | |
| 561 Graph* graph = GetCompletedGraph(array_builder.ToBytecodeArray(), vector); | |
| 562 | |
| 563 Node* ret = graph->end()->InputAt(0); | |
| 564 EXPECT_THAT(ret, IsReturn(IsJSTypeOf(IsParameter(1)), _, _)); | |
| 565 } | |
| 566 | |
| 567 | |
| 568 TEST_F(BytecodeGraphBuilderTest, Delete) { | |
| 569 TRACED_FOREACH(LanguageMode, language_mode, kLanguageModes) { | |
| 570 interpreter::BytecodeArrayBuilder array_builder(isolate(), zone()); | |
| 571 array_builder.set_locals_count(1); | |
| 572 array_builder.set_context_count(0); | |
| 573 array_builder.set_parameter_count(2); | |
| 574 Handle<Name> name = GetName(isolate(), "val"); | |
| 575 array_builder.LoadLiteral(name) | |
| 576 .Delete(array_builder.Parameter(1), language_mode) | |
| 577 .Return(); | |
| 578 | |
| 579 FeedbackVectorSpec feedback_spec(zone()); | |
| 580 Handle<TypeFeedbackVector> vector = | |
| 581 NewTypeFeedbackVector(isolate(), &feedback_spec); | |
| 582 Graph* graph = GetCompletedGraph(array_builder.ToBytecodeArray(), vector, | |
| 583 language_mode); | |
| 584 | |
| 585 Node* start = graph->start(); | |
| 586 Node* ret = graph->end()->InputAt(0); | |
| 587 | |
| 588 Matcher<Node*> delete_matcher = | |
| 589 IsJSDeleteProperty(IsParameter(1), IsHeapConstant(name), start, start); | |
| 590 EXPECT_THAT(ret, IsReturn(delete_matcher, _, _)); | |
| 591 } | |
| 592 } | |
| 593 | |
| 594 | |
| 595 TEST_F(BytecodeGraphBuilderTest, KeyedLoad) { | |
| 596 const int kValue = 100; | |
| 597 const bool kWideBytecode[] = {false, true}; | |
| 598 TRACED_FOREACH(LanguageMode, language_mode, kLanguageModes) { | |
| 599 TRACED_FOREACH(bool, wide_bytecode, kWideBytecode) { | |
| 600 FeedbackVectorSpec feedback_spec(zone()); | |
| 601 if (wide_bytecode) { | |
| 602 for (int i = 0; i < 128; i++) { | |
| 603 feedback_spec.AddLoadICSlot(); | |
| 604 } | |
| 605 } | |
| 606 FeedbackVectorSlot slot = feedback_spec.AddLoadICSlot(); | |
| 607 Handle<TypeFeedbackVector> vector = | |
| 608 NewTypeFeedbackVector(isolate(), &feedback_spec); | |
| 609 | |
| 610 interpreter::BytecodeArrayBuilder array_builder(isolate(), zone()); | |
| 611 array_builder.set_locals_count(1); | |
| 612 array_builder.set_context_count(0); | |
| 613 array_builder.set_parameter_count(2); | |
| 614 | |
| 615 array_builder.LoadLiteral(Smi::FromInt(kValue)) | |
| 616 .LoadKeyedProperty(array_builder.Parameter(1), vector->GetIndex(slot), | |
| 617 language_mode) | |
| 618 .Return(); | |
| 619 Graph* graph = GetCompletedGraph(array_builder.ToBytecodeArray(), vector, | |
| 620 language_mode); | |
| 621 | |
| 622 Node* ret = graph->end()->InputAt(0); | |
| 623 Node* start = graph->start(); | |
| 624 | |
| 625 Matcher<Node*> feedback_vector_matcher = IsFeedbackVector(start, start); | |
| 626 Matcher<Node*> load_keyed_matcher = | |
| 627 IsJSLoadProperty(IsParameter(1), IsNumberConstant(kValue), | |
| 628 feedback_vector_matcher, start, start); | |
| 629 | |
| 630 EXPECT_THAT(ret, IsReturn(load_keyed_matcher, _, _)); | |
| 631 } | |
| 632 } | |
| 633 } | |
| 634 | |
| 635 | |
| 636 TEST_F(BytecodeGraphBuilderTest, NamedStore) { | |
| 637 const int kValue = 100; | |
| 638 const bool kWideBytecode[] = {false, true}; | |
| 639 TRACED_FOREACH(LanguageMode, language_mode, kLanguageModes) { | |
| 640 TRACED_FOREACH(bool, wide_bytecode, kWideBytecode) { | |
| 641 FeedbackVectorSpec feedback_spec(zone()); | |
| 642 if (wide_bytecode) { | |
| 643 for (int i = 0; i < 128; i++) { | |
| 644 feedback_spec.AddLoadICSlot(); | |
| 645 } | |
| 646 } | |
| 647 FeedbackVectorSlot slot = feedback_spec.AddLoadICSlot(); | |
| 648 Handle<TypeFeedbackVector> vector = | |
| 649 NewTypeFeedbackVector(isolate(), &feedback_spec); | |
| 650 | |
| 651 interpreter::BytecodeArrayBuilder array_builder(isolate(), zone()); | |
| 652 array_builder.set_locals_count(1); | |
| 653 array_builder.set_context_count(0); | |
| 654 array_builder.set_parameter_count(2); | |
| 655 | |
| 656 Handle<Name> name = GetName(isolate(), "val"); | |
| 657 size_t name_index = array_builder.GetConstantPoolEntry(name); | |
| 658 | |
| 659 array_builder.LoadLiteral(Smi::FromInt(kValue)) | |
| 660 .StoreNamedProperty(array_builder.Parameter(1), name_index, | |
| 661 vector->GetIndex(slot), language_mode) | |
| 662 .Return(); | |
| 663 Graph* graph = GetCompletedGraph(array_builder.ToBytecodeArray(), vector, | |
| 664 language_mode); | |
| 665 | |
| 666 Node* ret = graph->end()->InputAt(0); | |
| 667 Node* start = graph->start(); | |
| 668 | |
| 669 Matcher<Node*> feedback_vector_matcher = IsFeedbackVector(start, start); | |
| 670 Matcher<Node*> store_named_matcher = | |
| 671 IsJSStoreNamed(name, IsParameter(1), IsNumberConstant(kValue), | |
| 672 feedback_vector_matcher, start, start); | |
| 673 | |
| 674 EXPECT_THAT(ret, IsReturn(_, store_named_matcher, _)); | |
| 675 } | |
| 676 } | |
| 677 } | |
| 678 | |
| 679 | |
| 680 TEST_F(BytecodeGraphBuilderTest, KeyedStore) { | |
| 681 const int kValue = 100; | |
| 682 const int kKey = 10; | |
| 683 const bool kWideBytecode[] = {false, true}; | |
| 684 TRACED_FOREACH(LanguageMode, language_mode, kLanguageModes) { | |
| 685 TRACED_FOREACH(bool, wide_bytecode, kWideBytecode) { | |
| 686 FeedbackVectorSpec feedback_spec(zone()); | |
| 687 if (wide_bytecode) { | |
| 688 for (int i = 0; i < 128; i++) { | |
| 689 feedback_spec.AddStoreICSlot(); | |
| 690 } | |
| 691 } | |
| 692 FeedbackVectorSlot slot = feedback_spec.AddStoreICSlot(); | |
| 693 Handle<TypeFeedbackVector> vector = | |
| 694 NewTypeFeedbackVector(isolate(), &feedback_spec); | |
| 695 | |
| 696 interpreter::BytecodeArrayBuilder array_builder(isolate(), zone()); | |
| 697 array_builder.set_locals_count(1); | |
| 698 array_builder.set_context_count(0); | |
| 699 array_builder.set_parameter_count(2); | |
| 700 | |
| 701 array_builder.LoadLiteral(Smi::FromInt(kKey)) | |
| 702 .StoreAccumulatorInRegister(interpreter::Register(0)) | |
| 703 .LoadLiteral(Smi::FromInt(kValue)) | |
| 704 .StoreKeyedProperty(array_builder.Parameter(1), | |
| 705 interpreter::Register(0), vector->GetIndex(slot), | |
| 706 language_mode) | |
| 707 .Return(); | |
| 708 Graph* graph = GetCompletedGraph(array_builder.ToBytecodeArray(), vector, | |
| 709 language_mode); | |
| 710 | |
| 711 Node* ret = graph->end()->InputAt(0); | |
| 712 Node* start = graph->start(); | |
| 713 | |
| 714 Matcher<Node*> feedback_vector_matcher = IsFeedbackVector(start, start); | |
| 715 Matcher<Node*> store_keyed_matcher = IsJSStoreProperty( | |
| 716 IsParameter(1), IsNumberConstant(kKey), IsNumberConstant(kValue), | |
| 717 feedback_vector_matcher, start, start); | |
| 718 | |
| 719 EXPECT_THAT(ret, IsReturn(_, store_keyed_matcher, _)); | |
| 720 } | |
| 721 } | |
| 722 } | |
| 723 | |
| 724 | |
| 725 TEST_F(BytecodeGraphBuilderTest, CallRuntime) { | |
| 726 interpreter::BytecodeArrayBuilder array_builder(isolate(), zone()); | |
| 727 array_builder.set_locals_count(2); | |
| 728 array_builder.set_context_count(0); | |
| 729 array_builder.set_parameter_count(3); | |
| 730 | |
| 731 array_builder.LoadAccumulatorWithRegister(array_builder.Parameter(1)) | |
| 732 .StoreAccumulatorInRegister(interpreter::Register(0)) | |
| 733 .LoadAccumulatorWithRegister(array_builder.Parameter(2)) | |
| 734 .StoreAccumulatorInRegister(interpreter::Register(1)) | |
| 735 .CallRuntime(Runtime::kAdd, interpreter::Register(0), 2) | |
| 736 .Return(); | |
| 737 | |
| 738 Graph* graph = GetCompletedGraph(array_builder.ToBytecodeArray()); | |
| 739 Node* start = graph->start(); | |
| 740 Node* ret = graph->end()->InputAt(0); | |
| 741 std::vector<Matcher<Node*>> call_inputs; | |
| 742 call_inputs.push_back(IsParameter(1)); | |
| 743 call_inputs.push_back(IsParameter(2)); | |
| 744 Matcher<Node*> call_js_runtime = IsJSCallRuntime(call_inputs, start, start); | |
| 745 | |
| 746 EXPECT_THAT(ret, IsReturn(call_js_runtime, call_js_runtime, IsIfSuccess(_))); | |
| 747 } | |
| 748 | |
| 749 | |
| 750 TEST_F(BytecodeGraphBuilderTest, CallJSRuntime) { | |
| 751 interpreter::BytecodeArrayBuilder array_builder(isolate(), zone()); | |
| 752 array_builder.set_locals_count(1); | |
| 753 array_builder.set_context_count(1); | |
| 754 array_builder.set_parameter_count(2); | |
| 755 | |
| 756 // function f(arg) { return %spread_arguments(arg0); } | |
| 757 interpreter::Register reg0 = interpreter::Register(0); | |
| 758 array_builder.LoadAccumulatorWithRegister(array_builder.Parameter(1)) | |
| 759 .StoreAccumulatorInRegister(reg0) | |
| 760 .CallJSRuntime(Context::SPREAD_ARGUMENTS_INDEX, reg0, 1) | |
| 761 .Return(); | |
| 762 | |
| 763 Graph* graph = GetCompletedGraph(array_builder.ToBytecodeArray()); | |
| 764 Node* ret = graph->end()->InputAt(0); | |
| 765 Matcher<Node*> load_context = | |
| 766 IsLoadContext(ContextAccess(0, Context::SPREAD_ARGUMENTS_INDEX, true), _); | |
| 767 std::vector<Matcher<Node*>> call_inputs; | |
| 768 call_inputs.push_back(load_context); | |
| 769 call_inputs.push_back(IsParameter(1)); | |
| 770 Matcher<Node*> call_js_function = | |
| 771 IsJSCallFunction(call_inputs, load_context, graph->start()); | |
| 772 | |
| 773 EXPECT_THAT(ret, | |
| 774 IsReturn(call_js_function, call_js_function, IsIfSuccess(_))); | |
| 775 } | |
| 776 | |
| 777 | |
| 778 TEST_F(BytecodeGraphBuilderTest, New) { | |
| 779 interpreter::BytecodeArrayBuilder array_builder(isolate(), zone()); | |
| 780 array_builder.set_locals_count(4); | |
| 781 array_builder.set_context_count(0); | |
| 782 array_builder.set_parameter_count(5); | |
| 783 | |
| 784 array_builder.LoadAccumulatorWithRegister(array_builder.Parameter(1)) | |
| 785 .StoreAccumulatorInRegister(interpreter::Register(0)) | |
| 786 .LoadAccumulatorWithRegister(array_builder.Parameter(2)) | |
| 787 .StoreAccumulatorInRegister(interpreter::Register(1)) | |
| 788 .LoadAccumulatorWithRegister(array_builder.Parameter(3)) | |
| 789 .StoreAccumulatorInRegister(interpreter::Register(2)) | |
| 790 .LoadAccumulatorWithRegister(array_builder.Parameter(4)) | |
| 791 .StoreAccumulatorInRegister(interpreter::Register(3)) | |
| 792 .New(interpreter::Register(0), interpreter::Register(1), 3) | |
| 793 .Return(); | |
| 794 auto bytecode_array = array_builder.ToBytecodeArray(); | |
| 795 Graph* graph = GetCompletedGraph(bytecode_array); | |
| 796 | |
| 797 Node* start = graph->start(); | |
| 798 Node* ret = graph->end()->InputAt(0); | |
| 799 std::vector<Matcher<Node*>> construct_inputs; | |
| 800 construct_inputs.push_back(IsParameter(1)); | |
| 801 construct_inputs.push_back(IsParameter(2)); | |
| 802 construct_inputs.push_back(IsParameter(3)); | |
| 803 construct_inputs.push_back(IsParameter(4)); | |
| 804 construct_inputs.push_back(IsParameter(1)); | |
| 805 Matcher<Node*> call_construct = | |
| 806 IsJSCallConstruct(construct_inputs, start, start); | |
| 807 EXPECT_THAT(ret, IsReturn(call_construct, call_construct, IsIfSuccess(_))); | |
| 808 } | |
| 809 | |
| 810 } // namespace compiler | |
| 811 } // namespace internal | |
| 812 } // namespace v8 | |
| OLD | NEW |