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 |