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 <utility>
6
7 #include "src/compiler/pipeline.h"
8 #include "src/execution.h"
9 #include "src/handles.h"
10 #include "src/interpreter/bytecode-array-builder.h"
11 #include "src/interpreter/interpreter.h"
12 #include "src/parsing/parser.h"
13 #include "test/cctest/cctest.h"
14
15 namespace v8 {
16 namespace internal {
17 namespace compiler {
18
19
20 static const char kFunctionName[] = "f";
21
22 static const Token::Value kCompareOperators[] = {
23 Token::Value::EQ, Token::Value::NE, Token::Value::EQ_STRICT,
24 Token::Value::NE_STRICT, Token::Value::LT, Token::Value::LTE,
25 Token::Value::GT, Token::Value::GTE};
26
27 static const int SMI_MAX = (1 << 30) - 1;
28 static const int SMI_MIN = -(1 << 30);
29
CallFunction(Isolate * isolate,Handle<JSFunction> function)30 static MaybeHandle<Object> CallFunction(Isolate* isolate,
31 Handle<JSFunction> function) {
32 return Execution::Call(isolate, function,
33 isolate->factory()->undefined_value(), 0, nullptr);
34 }
35
36
37 template <class... A>
CallFunction(Isolate * isolate,Handle<JSFunction> function,A...args)38 static MaybeHandle<Object> CallFunction(Isolate* isolate,
39 Handle<JSFunction> function,
40 A... args) {
41 Handle<Object> argv[] = {args...};
42 return Execution::Call(isolate, function,
43 isolate->factory()->undefined_value(), sizeof...(args),
44 argv);
45 }
46
47
48 template <class... A>
49 class BytecodeGraphCallable {
50 public:
BytecodeGraphCallable(Isolate * isolate,Handle<JSFunction> function)51 BytecodeGraphCallable(Isolate* isolate, Handle<JSFunction> function)
52 : isolate_(isolate), function_(function) {}
~BytecodeGraphCallable()53 virtual ~BytecodeGraphCallable() {}
54
operator ()(A...args)55 MaybeHandle<Object> operator()(A... args) {
56 return CallFunction(isolate_, function_, args...);
57 }
58
59 private:
60 Isolate* isolate_;
61 Handle<JSFunction> function_;
62 };
63
64
65 class BytecodeGraphTester {
66 public:
BytecodeGraphTester(Isolate * isolate,Zone * zone,const char * script,const char * filter=kFunctionName)67 BytecodeGraphTester(Isolate* isolate, Zone* zone, const char* script,
68 const char* filter = kFunctionName)
69 : isolate_(isolate), zone_(zone), script_(script) {
70 i::FLAG_ignition = true;
71 i::FLAG_always_opt = false;
72 i::FLAG_allow_natives_syntax = true;
73 i::FLAG_ignition_fallback_on_eval_and_catch = false;
74 // Set ignition filter flag via SetFlagsFromString to avoid double-free
75 // (or potential leak with StrDup() based on ownership confusion).
76 ScopedVector<char> ignition_filter(64);
77 SNPrintF(ignition_filter, "--ignition-filter=%s", filter);
78 FlagList::SetFlagsFromString(ignition_filter.start(),
79 ignition_filter.length());
80 // Ensure handler table is generated.
81 isolate->interpreter()->Initialize();
82 }
~BytecodeGraphTester()83 virtual ~BytecodeGraphTester() {}
84
85 template <class... A>
GetCallable(const char * functionName=kFunctionName)86 BytecodeGraphCallable<A...> GetCallable(
87 const char* functionName = kFunctionName) {
88 return BytecodeGraphCallable<A...>(isolate_, GetFunction(functionName));
89 }
90
CheckThrowsReturnMessage()91 Local<Message> CheckThrowsReturnMessage() {
92 TryCatch try_catch(reinterpret_cast<v8::Isolate*>(isolate_));
93 auto callable = GetCallable<>();
94 MaybeHandle<Object> no_result = callable();
95 CHECK(isolate_->has_pending_exception());
96 CHECK(try_catch.HasCaught());
97 CHECK(no_result.is_null());
98 isolate_->OptionalRescheduleException(true);
99 CHECK(!try_catch.Message().IsEmpty());
100 return try_catch.Message();
101 }
102
NewObject(const char * script)103 static Handle<Object> NewObject(const char* script) {
104 return v8::Utils::OpenHandle(*CompileRun(script));
105 }
106
107 private:
108 Isolate* isolate_;
109 Zone* zone_;
110 const char* script_;
111
GetFunction(const char * functionName)112 Handle<JSFunction> GetFunction(const char* functionName) {
113 CompileRun(script_);
114 Local<Function> api_function = Local<Function>::Cast(
115 CcTest::global()
116 ->Get(CcTest::isolate()->GetCurrentContext(), v8_str(functionName))
117 .ToLocalChecked());
118 Handle<JSFunction> function =
119 Handle<JSFunction>::cast(v8::Utils::OpenHandle(*api_function));
120 CHECK(function->shared()->HasBytecodeArray());
121
122 ParseInfo parse_info(zone_, function);
123
124 CompilationInfo compilation_info(&parse_info);
125 compilation_info.SetOptimizing(BailoutId::None(), Handle<Code>());
126 compilation_info.MarkAsDeoptimizationEnabled();
127 // TODO(mythria): Remove this step once parse_info is not needed.
128 CHECK(Compiler::ParseAndAnalyze(&parse_info));
129 compiler::Pipeline pipeline(&compilation_info);
130 Handle<Code> code = pipeline.GenerateCode();
131 function->ReplaceCode(*code);
132
133 return function;
134 }
135
136 DISALLOW_COPY_AND_ASSIGN(BytecodeGraphTester);
137 };
138
139
140 #define SPACE()
141
142 #define REPEAT_2(SEP, ...) __VA_ARGS__ SEP() __VA_ARGS__
143 #define REPEAT_4(SEP, ...) \
144 REPEAT_2(SEP, __VA_ARGS__) SEP() REPEAT_2(SEP, __VA_ARGS__)
145 #define REPEAT_8(SEP, ...) \
146 REPEAT_4(SEP, __VA_ARGS__) SEP() REPEAT_4(SEP, __VA_ARGS__)
147 #define REPEAT_16(SEP, ...) \
148 REPEAT_8(SEP, __VA_ARGS__) SEP() REPEAT_8(SEP, __VA_ARGS__)
149 #define REPEAT_32(SEP, ...) \
150 REPEAT_16(SEP, __VA_ARGS__) SEP() REPEAT_16(SEP, __VA_ARGS__)
151 #define REPEAT_64(SEP, ...) \
152 REPEAT_32(SEP, __VA_ARGS__) SEP() REPEAT_32(SEP, __VA_ARGS__)
153 #define REPEAT_128(SEP, ...) \
154 REPEAT_64(SEP, __VA_ARGS__) SEP() REPEAT_64(SEP, __VA_ARGS__)
155 #define REPEAT_256(SEP, ...) \
156 REPEAT_128(SEP, __VA_ARGS__) SEP() REPEAT_128(SEP, __VA_ARGS__)
157
158 #define REPEAT_127(SEP, ...) \
159 REPEAT_64(SEP, __VA_ARGS__) \
160 SEP() \
161 REPEAT_32(SEP, __VA_ARGS__) \
162 SEP() \
163 REPEAT_16(SEP, __VA_ARGS__) \
164 SEP() \
165 REPEAT_8(SEP, __VA_ARGS__) \
166 SEP() \
167 REPEAT_4(SEP, __VA_ARGS__) SEP() REPEAT_2(SEP, __VA_ARGS__) SEP() __VA_ARGS__
168
169
170 template <int N, typename T = Handle<Object>>
171 struct ExpectedSnippet {
172 const char* code_snippet;
173 T return_value_and_parameters[N + 1];
174
return_valuev8::internal::compiler::ExpectedSnippet175 inline T return_value() const { return return_value_and_parameters[0]; }
176
parameterv8::internal::compiler::ExpectedSnippet177 inline T parameter(int i) const {
178 CHECK_GE(i, 0);
179 CHECK_LT(i, N);
180 return return_value_and_parameters[1 + i];
181 }
182 };
183
184
TEST(BytecodeGraphBuilderReturnStatements)185 TEST(BytecodeGraphBuilderReturnStatements) {
186 HandleAndZoneScope scope;
187 Isolate* isolate = scope.main_isolate();
188 Zone* zone = scope.main_zone();
189 Factory* factory = isolate->factory();
190
191 ExpectedSnippet<0> snippets[] = {
192 {"return;", {factory->undefined_value()}},
193 {"return null;", {factory->null_value()}},
194 {"return true;", {factory->true_value()}},
195 {"return false;", {factory->false_value()}},
196 {"return 0;", {factory->NewNumberFromInt(0)}},
197 {"return +1;", {factory->NewNumberFromInt(1)}},
198 {"return -1;", {factory->NewNumberFromInt(-1)}},
199 {"return +127;", {factory->NewNumberFromInt(127)}},
200 {"return -128;", {factory->NewNumberFromInt(-128)}},
201 {"return 0.001;", {factory->NewNumber(0.001)}},
202 {"return 3.7e-60;", {factory->NewNumber(3.7e-60)}},
203 {"return -3.7e60;", {factory->NewNumber(-3.7e60)}},
204 {"return '';", {factory->NewStringFromStaticChars("")}},
205 {"return 'catfood';", {factory->NewStringFromStaticChars("catfood")}},
206 {"return NaN;", {factory->nan_value()}}};
207
208 size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]);
209 for (size_t i = 0; i < num_snippets; i++) {
210 ScopedVector<char> script(1024);
211 SNPrintF(script, "function %s() { %s }\n%s();", kFunctionName,
212 snippets[i].code_snippet, kFunctionName);
213
214 BytecodeGraphTester tester(isolate, zone, script.start());
215 auto callable = tester.GetCallable<>();
216 Handle<Object> return_value = callable().ToHandleChecked();
217 CHECK(return_value->SameValue(*snippets[i].return_value()));
218 }
219 }
220
221
TEST(BytecodeGraphBuilderPrimitiveExpressions)222 TEST(BytecodeGraphBuilderPrimitiveExpressions) {
223 HandleAndZoneScope scope;
224 Isolate* isolate = scope.main_isolate();
225 Zone* zone = scope.main_zone();
226 Factory* factory = isolate->factory();
227
228 ExpectedSnippet<0> snippets[] = {
229 {"return 1 + 1;", {factory->NewNumberFromInt(2)}},
230 {"return 20 - 30;", {factory->NewNumberFromInt(-10)}},
231 {"return 4 * 100;", {factory->NewNumberFromInt(400)}},
232 {"return 100 / 5;", {factory->NewNumberFromInt(20)}},
233 {"return 25 % 7;", {factory->NewNumberFromInt(4)}},
234 };
235
236 size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]);
237 for (size_t i = 0; i < num_snippets; i++) {
238 ScopedVector<char> script(1024);
239 SNPrintF(script, "function %s() { %s }\n%s();", kFunctionName,
240 snippets[i].code_snippet, kFunctionName);
241
242 BytecodeGraphTester tester(isolate, zone, script.start());
243 auto callable = tester.GetCallable<>();
244 Handle<Object> return_value = callable().ToHandleChecked();
245 CHECK(return_value->SameValue(*snippets[i].return_value()));
246 }
247 }
248
249
TEST(BytecodeGraphBuilderTwoParameterTests)250 TEST(BytecodeGraphBuilderTwoParameterTests) {
251 HandleAndZoneScope scope;
252 Isolate* isolate = scope.main_isolate();
253 Zone* zone = scope.main_zone();
254 Factory* factory = isolate->factory();
255
256 ExpectedSnippet<2> snippets[] = {
257 // Integers
258 {"return p1 + p2;",
259 {factory->NewNumberFromInt(-70), factory->NewNumberFromInt(3),
260 factory->NewNumberFromInt(-73)}},
261 {"return p1 + p2 + 3;",
262 {factory->NewNumberFromInt(1139044), factory->NewNumberFromInt(300),
263 factory->NewNumberFromInt(1138741)}},
264 {"return p1 - p2;",
265 {factory->NewNumberFromInt(1100), factory->NewNumberFromInt(1000),
266 factory->NewNumberFromInt(-100)}},
267 {"return p1 * p2;",
268 {factory->NewNumberFromInt(-100000), factory->NewNumberFromInt(1000),
269 factory->NewNumberFromInt(-100)}},
270 {"return p1 / p2;",
271 {factory->NewNumberFromInt(-10), factory->NewNumberFromInt(1000),
272 factory->NewNumberFromInt(-100)}},
273 {"return p1 % p2;",
274 {factory->NewNumberFromInt(5), factory->NewNumberFromInt(373),
275 factory->NewNumberFromInt(16)}},
276 // Doubles
277 {"return p1 + p2;",
278 {factory->NewHeapNumber(9.999), factory->NewHeapNumber(3.333),
279 factory->NewHeapNumber(6.666)}},
280 {"return p1 - p2;",
281 {factory->NewHeapNumber(-3.333), factory->NewHeapNumber(3.333),
282 factory->NewHeapNumber(6.666)}},
283 {"return p1 * p2;",
284 {factory->NewHeapNumber(3.333 * 6.666), factory->NewHeapNumber(3.333),
285 factory->NewHeapNumber(6.666)}},
286 {"return p1 / p2;",
287 {factory->NewHeapNumber(2.25), factory->NewHeapNumber(9),
288 factory->NewHeapNumber(4)}},
289 // Strings
290 {"return p1 + p2;",
291 {factory->NewStringFromStaticChars("abcdef"),
292 factory->NewStringFromStaticChars("abc"),
293 factory->NewStringFromStaticChars("def")}}};
294
295 size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]);
296 for (size_t i = 0; i < num_snippets; i++) {
297 ScopedVector<char> script(1024);
298 SNPrintF(script, "function %s(p1, p2) { %s }\n%s(0, 0);", kFunctionName,
299 snippets[i].code_snippet, kFunctionName);
300
301 BytecodeGraphTester tester(isolate, zone, script.start());
302 auto callable = tester.GetCallable<Handle<Object>, Handle<Object>>();
303 Handle<Object> return_value =
304 callable(snippets[i].parameter(0), snippets[i].parameter(1))
305 .ToHandleChecked();
306 CHECK(return_value->SameValue(*snippets[i].return_value()));
307 }
308 }
309
310
TEST(BytecodeGraphBuilderNamedLoad)311 TEST(BytecodeGraphBuilderNamedLoad) {
312 HandleAndZoneScope scope;
313 Isolate* isolate = scope.main_isolate();
314 Zone* zone = scope.main_zone();
315 Factory* factory = isolate->factory();
316
317 ExpectedSnippet<1> snippets[] = {
318 {"return p1.val;",
319 {factory->NewNumberFromInt(10),
320 BytecodeGraphTester::NewObject("({val : 10})")}},
321 {"return p1[\"name\"];",
322 {factory->NewStringFromStaticChars("abc"),
323 BytecodeGraphTester::NewObject("({name : 'abc'})")}},
324 {"'use strict'; return p1.val;",
325 {factory->NewNumberFromInt(10),
326 BytecodeGraphTester::NewObject("({val : 10 })")}},
327 {"'use strict'; return p1[\"val\"];",
328 {factory->NewNumberFromInt(10),
329 BytecodeGraphTester::NewObject("({val : 10, name : 'abc'})")}},
330 {"var b;\n" REPEAT_127(SPACE, " b = p1.name; ") " return p1.name;\n",
331 {factory->NewStringFromStaticChars("abc"),
332 BytecodeGraphTester::NewObject("({name : 'abc'})")}},
333 {"'use strict'; var b;\n"
334 REPEAT_127(SPACE, " b = p1.name; ")
335 "return p1.name;\n",
336 {factory->NewStringFromStaticChars("abc"),
337 BytecodeGraphTester::NewObject("({ name : 'abc'})")}},
338 };
339
340 size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]);
341 for (size_t i = 0; i < num_snippets; i++) {
342 ScopedVector<char> script(2048);
343 SNPrintF(script, "function %s(p1) { %s };\n%s(0);", kFunctionName,
344 snippets[i].code_snippet, kFunctionName);
345
346 BytecodeGraphTester tester(isolate, zone, script.start());
347 auto callable = tester.GetCallable<Handle<Object>>();
348 Handle<Object> return_value =
349 callable(snippets[i].parameter(0)).ToHandleChecked();
350 CHECK(return_value->SameValue(*snippets[i].return_value()));
351 }
352 }
353
354
TEST(BytecodeGraphBuilderKeyedLoad)355 TEST(BytecodeGraphBuilderKeyedLoad) {
356 HandleAndZoneScope scope;
357 Isolate* isolate = scope.main_isolate();
358 Zone* zone = scope.main_zone();
359 Factory* factory = isolate->factory();
360
361 ExpectedSnippet<2> snippets[] = {
362 {"return p1[p2];",
363 {factory->NewNumberFromInt(10),
364 BytecodeGraphTester::NewObject("({val : 10})"),
365 factory->NewStringFromStaticChars("val")}},
366 {"return p1[100];",
367 {factory->NewStringFromStaticChars("abc"),
368 BytecodeGraphTester::NewObject("({100 : 'abc'})"),
369 factory->NewNumberFromInt(0)}},
370 {"var b = 100; return p1[b];",
371 {factory->NewStringFromStaticChars("abc"),
372 BytecodeGraphTester::NewObject("({100 : 'abc'})"),
373 factory->NewNumberFromInt(0)}},
374 {"'use strict'; return p1[p2];",
375 {factory->NewNumberFromInt(10),
376 BytecodeGraphTester::NewObject("({val : 10 })"),
377 factory->NewStringFromStaticChars("val")}},
378 {"'use strict'; return p1[100];",
379 {factory->NewNumberFromInt(10),
380 BytecodeGraphTester::NewObject("({100 : 10})"),
381 factory->NewNumberFromInt(0)}},
382 {"'use strict'; var b = p2; return p1[b];",
383 {factory->NewStringFromStaticChars("abc"),
384 BytecodeGraphTester::NewObject("({100 : 'abc'})"),
385 factory->NewNumberFromInt(100)}},
386 {"var b;\n" REPEAT_127(SPACE, " b = p1[p2]; ") " return p1[p2];\n",
387 {factory->NewStringFromStaticChars("abc"),
388 BytecodeGraphTester::NewObject("({100 : 'abc'})"),
389 factory->NewNumberFromInt(100)}},
390 {"'use strict'; var b;\n" REPEAT_127(SPACE,
391 " b = p1[p2]; ") "return p1[p2];\n",
392 {factory->NewStringFromStaticChars("abc"),
393 BytecodeGraphTester::NewObject("({ 100 : 'abc'})"),
394 factory->NewNumberFromInt(100)}},
395 };
396
397 size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]);
398 for (size_t i = 0; i < num_snippets; i++) {
399 ScopedVector<char> script(2048);
400 SNPrintF(script, "function %s(p1, p2) { %s };\n%s(0);", kFunctionName,
401 snippets[i].code_snippet, kFunctionName);
402
403 BytecodeGraphTester tester(isolate, zone, script.start());
404 auto callable = tester.GetCallable<Handle<Object>, Handle<Object>>();
405 Handle<Object> return_value =
406 callable(snippets[i].parameter(0), snippets[i].parameter(1))
407 .ToHandleChecked();
408 CHECK(return_value->SameValue(*snippets[i].return_value()));
409 }
410 }
411
412
TEST(BytecodeGraphBuilderNamedStore)413 TEST(BytecodeGraphBuilderNamedStore) {
414 HandleAndZoneScope scope;
415 Isolate* isolate = scope.main_isolate();
416 Zone* zone = scope.main_zone();
417 Factory* factory = isolate->factory();
418
419 ExpectedSnippet<1> snippets[] = {
420 {"return p1.val = 20;",
421 {factory->NewNumberFromInt(20),
422 BytecodeGraphTester::NewObject("({val : 10})")}},
423 {"p1.type = 'int'; return p1.type;",
424 {factory->NewStringFromStaticChars("int"),
425 BytecodeGraphTester::NewObject("({val : 10})")}},
426 {"p1.name = 'def'; return p1[\"name\"];",
427 {factory->NewStringFromStaticChars("def"),
428 BytecodeGraphTester::NewObject("({name : 'abc'})")}},
429 {"'use strict'; p1.val = 20; return p1.val;",
430 {factory->NewNumberFromInt(20),
431 BytecodeGraphTester::NewObject("({val : 10 })")}},
432 {"'use strict'; return p1.type = 'int';",
433 {factory->NewStringFromStaticChars("int"),
434 BytecodeGraphTester::NewObject("({val : 10})")}},
435 {"'use strict'; p1.val = 20; return p1[\"val\"];",
436 {factory->NewNumberFromInt(20),
437 BytecodeGraphTester::NewObject("({val : 10, name : 'abc'})")}},
438 {"var b = 'abc';\n" REPEAT_127(
439 SPACE, " p1.name = b; ") " p1.name = 'def'; return p1.name;\n",
440 {factory->NewStringFromStaticChars("def"),
441 BytecodeGraphTester::NewObject("({name : 'abc'})")}},
442 {"'use strict'; var b = 'def';\n" REPEAT_127(
443 SPACE, " p1.name = 'abc'; ") "p1.name = b; return p1.name;\n",
444 {factory->NewStringFromStaticChars("def"),
445 BytecodeGraphTester::NewObject("({ name : 'abc'})")}},
446 };
447
448 size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]);
449 for (size_t i = 0; i < num_snippets; i++) {
450 ScopedVector<char> script(3072);
451 SNPrintF(script, "function %s(p1) { %s };\n%s({});", kFunctionName,
452 snippets[i].code_snippet, kFunctionName);
453
454 BytecodeGraphTester tester(isolate, zone, script.start());
455 auto callable = tester.GetCallable<Handle<Object>>();
456 Handle<Object> return_value =
457 callable(snippets[i].parameter(0)).ToHandleChecked();
458 CHECK(return_value->SameValue(*snippets[i].return_value()));
459 }
460 }
461
462
TEST(BytecodeGraphBuilderKeyedStore)463 TEST(BytecodeGraphBuilderKeyedStore) {
464 HandleAndZoneScope scope;
465 Isolate* isolate = scope.main_isolate();
466 Zone* zone = scope.main_zone();
467 Factory* factory = isolate->factory();
468
469 ExpectedSnippet<2> snippets[] = {
470 {"p1[p2] = 20; return p1[p2];",
471 {factory->NewNumberFromInt(20),
472 BytecodeGraphTester::NewObject("({val : 10})"),
473 factory->NewStringFromStaticChars("val")}},
474 {"return p1[100] = 'def';",
475 {factory->NewStringFromStaticChars("def"),
476 BytecodeGraphTester::NewObject("({100 : 'abc'})"),
477 factory->NewNumberFromInt(0)}},
478 {"var b = 100; p1[b] = 'def'; return p1[b];",
479 {factory->NewStringFromStaticChars("def"),
480 BytecodeGraphTester::NewObject("({100 : 'abc'})"),
481 factory->NewNumberFromInt(0)}},
482 {"'use strict'; p1[p2] = 20; return p1[p2];",
483 {factory->NewNumberFromInt(20),
484 BytecodeGraphTester::NewObject("({val : 10 })"),
485 factory->NewStringFromStaticChars("val")}},
486 {"'use strict'; return p1[100] = 20;",
487 {factory->NewNumberFromInt(20),
488 BytecodeGraphTester::NewObject("({100 : 10})"),
489 factory->NewNumberFromInt(0)}},
490 {"'use strict'; var b = p2; p1[b] = 'def'; return p1[b];",
491 {factory->NewStringFromStaticChars("def"),
492 BytecodeGraphTester::NewObject("({100 : 'abc'})"),
493 factory->NewNumberFromInt(100)}},
494 {"var b;\n" REPEAT_127(
495 SPACE, " b = p1[p2]; ") " p1[p2] = 'def'; return p1[p2];\n",
496 {factory->NewStringFromStaticChars("def"),
497 BytecodeGraphTester::NewObject("({100 : 'abc'})"),
498 factory->NewNumberFromInt(100)}},
499 {"'use strict'; var b;\n" REPEAT_127(
500 SPACE, " b = p1[p2]; ") " p1[p2] = 'def'; return p1[p2];\n",
501 {factory->NewStringFromStaticChars("def"),
502 BytecodeGraphTester::NewObject("({ 100 : 'abc'})"),
503 factory->NewNumberFromInt(100)}},
504 };
505
506 size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]);
507 for (size_t i = 0; i < num_snippets; i++) {
508 ScopedVector<char> script(2048);
509 SNPrintF(script, "function %s(p1, p2) { %s };\n%s({});", kFunctionName,
510 snippets[i].code_snippet, kFunctionName);
511
512 BytecodeGraphTester tester(isolate, zone, script.start());
513 auto callable = tester.GetCallable<Handle<Object>>();
514 Handle<Object> return_value =
515 callable(snippets[i].parameter(0)).ToHandleChecked();
516 CHECK(return_value->SameValue(*snippets[i].return_value()));
517 }
518 }
519
520
TEST(BytecodeGraphBuilderPropertyCall)521 TEST(BytecodeGraphBuilderPropertyCall) {
522 HandleAndZoneScope scope;
523 Isolate* isolate = scope.main_isolate();
524 Zone* zone = scope.main_zone();
525 Factory* factory = isolate->factory();
526
527 ExpectedSnippet<1> snippets[] = {
528 {"return p1.func();",
529 {factory->NewNumberFromInt(25),
530 BytecodeGraphTester::NewObject("({func() { return 25; }})")}},
531 {"return p1.func('abc');",
532 {factory->NewStringFromStaticChars("abc"),
533 BytecodeGraphTester::NewObject("({func(a) { return a; }})")}},
534 {"return p1.func(1, 2, 3, 4, 5, 6, 7, 8);",
535 {factory->NewNumberFromInt(36),
536 BytecodeGraphTester::NewObject(
537 "({func(a, b, c, d, e, f, g, h) {\n"
538 " return a + b + c + d + e + f + g + h;}})")}},
539 };
540
541 size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]);
542 for (size_t i = 0; i < num_snippets; i++) {
543 ScopedVector<char> script(2048);
544 SNPrintF(script, "function %s(p1) { %s };\n%s({func() {}});", kFunctionName,
545 snippets[i].code_snippet, kFunctionName);
546
547 BytecodeGraphTester tester(isolate, zone, script.start());
548 auto callable = tester.GetCallable<Handle<Object>>();
549 Handle<Object> return_value =
550 callable(snippets[i].parameter(0)).ToHandleChecked();
551 CHECK(return_value->SameValue(*snippets[i].return_value()));
552 }
553 }
554
555
TEST(BytecodeGraphBuilderCallNew)556 TEST(BytecodeGraphBuilderCallNew) {
557 HandleAndZoneScope scope;
558 Isolate* isolate = scope.main_isolate();
559 Zone* zone = scope.main_zone();
560 Factory* factory = isolate->factory();
561
562 ExpectedSnippet<0> snippets[] = {
563 {"function counter() { this.count = 20; }\n"
564 "function f() {\n"
565 " var c = new counter();\n"
566 " return c.count;\n"
567 "}; f()",
568 {factory->NewNumberFromInt(20)}},
569 {"function counter(arg0) { this.count = 17; this.x = arg0; }\n"
570 "function f() {\n"
571 " var c = new counter(6);\n"
572 " return c.count + c.x;\n"
573 "}; f()",
574 {factory->NewNumberFromInt(23)}},
575 {"function counter(arg0, arg1) {\n"
576 " this.count = 17; this.x = arg0; this.y = arg1;\n"
577 "}\n"
578 "function f() {\n"
579 " var c = new counter(3, 5);\n"
580 " return c.count + c.x + c.y;\n"
581 "}; f()",
582 {factory->NewNumberFromInt(25)}},
583 };
584
585 size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]);
586 for (size_t i = 0; i < num_snippets; i++) {
587 BytecodeGraphTester tester(isolate, zone, snippets[i].code_snippet);
588 auto callable = tester.GetCallable<>();
589 Handle<Object> return_value = callable().ToHandleChecked();
590 CHECK(return_value->SameValue(*snippets[i].return_value()));
591 }
592 }
593
594
TEST(BytecodeGraphBuilderCreateClosure)595 TEST(BytecodeGraphBuilderCreateClosure) {
596 HandleAndZoneScope scope;
597 Isolate* isolate = scope.main_isolate();
598 Zone* zone = scope.main_zone();
599 Factory* factory = isolate->factory();
600
601 ExpectedSnippet<0> snippets[] = {
602 {"function f() {\n"
603 " function counter() { this.count = 20; }\n"
604 " var c = new counter();\n"
605 " return c.count;\n"
606 "}; f()",
607 {factory->NewNumberFromInt(20)}},
608 {"function f() {\n"
609 " function counter(arg0) { this.count = 17; this.x = arg0; }\n"
610 " var c = new counter(6);\n"
611 " return c.count + c.x;\n"
612 "}; f()",
613 {factory->NewNumberFromInt(23)}},
614 {"function f() {\n"
615 " function counter(arg0, arg1) {\n"
616 " this.count = 17; this.x = arg0; this.y = arg1;\n"
617 " }\n"
618 " var c = new counter(3, 5);\n"
619 " return c.count + c.x + c.y;\n"
620 "}; f()",
621 {factory->NewNumberFromInt(25)}},
622 };
623
624 size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]);
625 for (size_t i = 0; i < num_snippets; i++) {
626 BytecodeGraphTester tester(isolate, zone, snippets[i].code_snippet);
627 auto callable = tester.GetCallable<>();
628 Handle<Object> return_value = callable().ToHandleChecked();
629 CHECK(return_value->SameValue(*snippets[i].return_value()));
630 }
631 }
632
633
TEST(BytecodeGraphBuilderCallRuntime)634 TEST(BytecodeGraphBuilderCallRuntime) {
635 HandleAndZoneScope scope;
636 Isolate* isolate = scope.main_isolate();
637 Zone* zone = scope.main_zone();
638 Factory* factory = isolate->factory();
639
640 ExpectedSnippet<1> snippets[] = {
641 {"function f(arg0) { return %MaxSmi(); }\nf()",
642 {factory->NewNumberFromInt(Smi::kMaxValue), factory->undefined_value()}},
643 {"function f(arg0) { return %IsArray(arg0) }\nf(undefined)",
644 {factory->true_value(), BytecodeGraphTester::NewObject("[1, 2, 3]")}},
645 {"function f(arg0) { return %Add(arg0, 2) }\nf(1)",
646 {factory->NewNumberFromInt(5), factory->NewNumberFromInt(3)}},
647 {"function f(arg0) { return %spread_arguments(arg0).length }\nf([])",
648 {factory->NewNumberFromInt(3),
649 BytecodeGraphTester::NewObject("[1, 2, 3]")}},
650 };
651
652 size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]);
653 for (size_t i = 0; i < num_snippets; i++) {
654 BytecodeGraphTester tester(isolate, zone, snippets[i].code_snippet);
655 auto callable = tester.GetCallable<Handle<Object>>();
656 Handle<Object> return_value =
657 callable(snippets[i].parameter(0)).ToHandleChecked();
658 CHECK(return_value->SameValue(*snippets[i].return_value()));
659 }
660 }
661
662
TEST(BytecodeGraphBuilderGlobals)663 TEST(BytecodeGraphBuilderGlobals) {
664 HandleAndZoneScope scope;
665 Isolate* isolate = scope.main_isolate();
666 Zone* zone = scope.main_zone();
667 Factory* factory = isolate->factory();
668
669 ExpectedSnippet<0> snippets[] = {
670 {"var global = 321;\n function f() { return global; };\n f();",
671 {factory->NewNumberFromInt(321)}},
672 {"var global = 321;\n"
673 "function f() { global = 123; return global };\n f();",
674 {factory->NewNumberFromInt(123)}},
675 {"var global = function() { return 'abc'};\n"
676 "function f() { return global(); };\n f();",
677 {factory->NewStringFromStaticChars("abc")}},
678 {"var global = 456;\n"
679 "function f() { 'use strict'; return global; };\n f();",
680 {factory->NewNumberFromInt(456)}},
681 {"var global = 987;\n"
682 "function f() { 'use strict'; global = 789; return global };\n f();",
683 {factory->NewNumberFromInt(789)}},
684 {"var global = function() { return 'xyz'};\n"
685 "function f() { 'use strict'; return global(); };\n f();",
686 {factory->NewStringFromStaticChars("xyz")}},
687 {"var global = 'abc'; var global_obj = {val:123};\n"
688 "function f() {\n" REPEAT_127(
689 SPACE, " var b = global_obj.name;\n") "return global; };\n f();\n",
690 {factory->NewStringFromStaticChars("abc")}},
691 {"var global = 'abc'; var global_obj = {val:123};\n"
692 "function f() { 'use strict';\n" REPEAT_127(
693 SPACE, " var b = global_obj.name;\n") "global = 'xyz'; return "
694 "global };\n f();\n",
695 {factory->NewStringFromStaticChars("xyz")}},
696 {"function f() { return typeof(undeclared_var); }\n; f();\n",
697 {factory->NewStringFromStaticChars("undefined")}},
698 {"var defined_var = 10; function f() { return typeof(defined_var); }\n; "
699 "f();\n",
700 {factory->NewStringFromStaticChars("number")}},
701 };
702
703 size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]);
704 for (size_t i = 0; i < num_snippets; i++) {
705 BytecodeGraphTester tester(isolate, zone, snippets[i].code_snippet);
706 auto callable = tester.GetCallable<>();
707 Handle<Object> return_value = callable().ToHandleChecked();
708 CHECK(return_value->SameValue(*snippets[i].return_value()));
709 }
710 }
711
712
TEST(BytecodeGraphBuilderToObject)713 TEST(BytecodeGraphBuilderToObject) {
714 // TODO(mythria): tests for ToObject. Needs ForIn.
715 }
716
717
TEST(BytecodeGraphBuilderToName)718 TEST(BytecodeGraphBuilderToName) {
719 HandleAndZoneScope scope;
720 Isolate* isolate = scope.main_isolate();
721 Zone* zone = scope.main_zone();
722 Factory* factory = isolate->factory();
723
724 ExpectedSnippet<0> snippets[] = {
725 {"var a = 'val'; var obj = {[a] : 10}; return obj.val;",
726 {factory->NewNumberFromInt(10)}},
727 {"var a = 20; var obj = {[a] : 10}; return obj['20'];",
728 {factory->NewNumberFromInt(10)}},
729 {"var a = 20; var obj = {[a] : 10}; return obj[20];",
730 {factory->NewNumberFromInt(10)}},
731 {"var a = {val:23}; var obj = {[a] : 10}; return obj[a];",
732 {factory->NewNumberFromInt(10)}},
733 {"var a = {val:23}; var obj = {[a] : 10}; return obj['[object Object]'];",
734 {factory->NewNumberFromInt(10)}},
735 {"var a = {toString : function() { return 'x'}};\n"
736 "var obj = {[a] : 10};\n"
737 "return obj.x;",
738 {factory->NewNumberFromInt(10)}},
739 {"var a = {valueOf : function() { return 'x'}};\n"
740 "var obj = {[a] : 10};\n"
741 "return obj.x;",
742 {factory->undefined_value()}},
743 {"var a = {[Symbol.toPrimitive] : function() { return 'x'}};\n"
744 "var obj = {[a] : 10};\n"
745 "return obj.x;",
746 {factory->NewNumberFromInt(10)}},
747 };
748
749 size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]);
750 for (size_t i = 0; i < num_snippets; i++) {
751 ScopedVector<char> script(1024);
752 SNPrintF(script, "function %s() { %s }\n%s({});", kFunctionName,
753 snippets[i].code_snippet, kFunctionName);
754
755 BytecodeGraphTester tester(isolate, zone, script.start());
756 auto callable = tester.GetCallable<>();
757 Handle<Object> return_value = callable().ToHandleChecked();
758 CHECK(return_value->SameValue(*snippets[i].return_value()));
759 }
760 }
761
762
TEST(BytecodeGraphBuilderLogicalNot)763 TEST(BytecodeGraphBuilderLogicalNot) {
764 HandleAndZoneScope scope;
765 Isolate* isolate = scope.main_isolate();
766 Zone* zone = scope.main_zone();
767 Factory* factory = isolate->factory();
768
769 ExpectedSnippet<1> snippets[] = {
770 {"return !p1;",
771 {factory->false_value(),
772 BytecodeGraphTester::NewObject("({val : 10})")}},
773 {"return !p1;", {factory->true_value(), factory->NewNumberFromInt(0)}},
774 {"return !p1;", {factory->true_value(), factory->undefined_value()}},
775 {"return !p1;", {factory->false_value(), factory->NewNumberFromInt(10)}},
776 {"return !p1;", {factory->false_value(), factory->true_value()}},
777 {"return !p1;",
778 {factory->false_value(), factory->NewStringFromStaticChars("abc")}},
779 };
780
781 size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]);
782 for (size_t i = 0; i < num_snippets; i++) {
783 ScopedVector<char> script(1024);
784 SNPrintF(script, "function %s(p1) { %s }\n%s({});", kFunctionName,
785 snippets[i].code_snippet, kFunctionName);
786
787 BytecodeGraphTester tester(isolate, zone, script.start());
788 auto callable = tester.GetCallable<Handle<Object>>();
789 Handle<Object> return_value =
790 callable(snippets[i].parameter(0)).ToHandleChecked();
791 CHECK(return_value->SameValue(*snippets[i].return_value()));
792 }
793 }
794
795
TEST(BytecodeGraphBuilderTypeOf)796 TEST(BytecodeGraphBuilderTypeOf) {
797 HandleAndZoneScope scope;
798 Isolate* isolate = scope.main_isolate();
799 Zone* zone = scope.main_zone();
800 Factory* factory = isolate->factory();
801
802 ExpectedSnippet<1> snippets[] = {
803 {"return typeof p1;",
804 {factory->NewStringFromStaticChars("object"),
805 BytecodeGraphTester::NewObject("({val : 10})")}},
806 {"return typeof p1;",
807 {factory->NewStringFromStaticChars("undefined"),
808 factory->undefined_value()}},
809 {"return typeof p1;",
810 {factory->NewStringFromStaticChars("number"),
811 factory->NewNumberFromInt(10)}},
812 {"return typeof p1;",
813 {factory->NewStringFromStaticChars("boolean"), factory->true_value()}},
814 {"return typeof p1;",
815 {factory->NewStringFromStaticChars("string"),
816 factory->NewStringFromStaticChars("abc")}},
817 };
818
819 size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]);
820 for (size_t i = 0; i < num_snippets; i++) {
821 ScopedVector<char> script(1024);
822 SNPrintF(script, "function %s(p1) { %s }\n%s({});", kFunctionName,
823 snippets[i].code_snippet, kFunctionName);
824
825 BytecodeGraphTester tester(isolate, zone, script.start());
826 auto callable = tester.GetCallable<Handle<Object>>();
827 Handle<Object> return_value =
828 callable(snippets[i].parameter(0)).ToHandleChecked();
829 CHECK(return_value->SameValue(*snippets[i].return_value()));
830 }
831 }
832
833
TEST(BytecodeGraphBuilderCountOperation)834 TEST(BytecodeGraphBuilderCountOperation) {
835 HandleAndZoneScope scope;
836 Isolate* isolate = scope.main_isolate();
837 Zone* zone = scope.main_zone();
838 Factory* factory = isolate->factory();
839
840 ExpectedSnippet<1> snippets[] = {
841 {"return ++p1;",
842 {factory->NewNumberFromInt(11), factory->NewNumberFromInt(10)}},
843 {"return p1++;",
844 {factory->NewNumberFromInt(10), factory->NewNumberFromInt(10)}},
845 {"return p1++ + 10;",
846 {factory->NewHeapNumber(15.23), factory->NewHeapNumber(5.23)}},
847 {"return 20 + ++p1;",
848 {factory->NewHeapNumber(27.23), factory->NewHeapNumber(6.23)}},
849 {"return --p1;",
850 {factory->NewHeapNumber(9.8), factory->NewHeapNumber(10.8)}},
851 {"return p1--;",
852 {factory->NewHeapNumber(10.8), factory->NewHeapNumber(10.8)}},
853 {"return p1-- + 10;",
854 {factory->NewNumberFromInt(20), factory->NewNumberFromInt(10)}},
855 {"return 20 + --p1;",
856 {factory->NewNumberFromInt(29), factory->NewNumberFromInt(10)}},
857 {"return p1.val--;",
858 {factory->NewNumberFromInt(10),
859 BytecodeGraphTester::NewObject("({val : 10})")}},
860 {"return ++p1['val'];",
861 {factory->NewNumberFromInt(11),
862 BytecodeGraphTester::NewObject("({val : 10})")}},
863 {"return ++p1[1];",
864 {factory->NewNumberFromInt(11),
865 BytecodeGraphTester::NewObject("({1 : 10})")}},
866 {" function inner() { return p1 } return --p1;",
867 {factory->NewNumberFromInt(9), factory->NewNumberFromInt(10)}},
868 {" function inner() { return p1 } return p1--;",
869 {factory->NewNumberFromInt(10), factory->NewNumberFromInt(10)}},
870 {"return ++p1;",
871 {factory->nan_value(), factory->NewStringFromStaticChars("String")}},
872 };
873
874 size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]);
875 for (size_t i = 0; i < num_snippets; i++) {
876 ScopedVector<char> script(1024);
877 SNPrintF(script, "function %s(p1) { %s }\n%s({});", kFunctionName,
878 snippets[i].code_snippet, kFunctionName);
879
880 BytecodeGraphTester tester(isolate, zone, script.start());
881 auto callable = tester.GetCallable<Handle<Object>>();
882 Handle<Object> return_value =
883 callable(snippets[i].parameter(0)).ToHandleChecked();
884 CHECK(return_value->SameValue(*snippets[i].return_value()));
885 }
886 }
887
888
TEST(BytecodeGraphBuilderDelete)889 TEST(BytecodeGraphBuilderDelete) {
890 HandleAndZoneScope scope;
891 Isolate* isolate = scope.main_isolate();
892 Zone* zone = scope.main_zone();
893 Factory* factory = isolate->factory();
894
895 ExpectedSnippet<1> snippets[] = {
896 {"return delete p1.val;",
897 {factory->true_value(), BytecodeGraphTester::NewObject("({val : 10})")}},
898 {"delete p1.val; return p1.val;",
899 {factory->undefined_value(),
900 BytecodeGraphTester::NewObject("({val : 10})")}},
901 {"delete p1.name; return p1.val;",
902 {factory->NewNumberFromInt(10),
903 BytecodeGraphTester::NewObject("({val : 10, name:'abc'})")}},
904 {"'use strict'; return delete p1.val;",
905 {factory->true_value(), BytecodeGraphTester::NewObject("({val : 10})")}},
906 {"'use strict'; delete p1.val; return p1.val;",
907 {factory->undefined_value(),
908 BytecodeGraphTester::NewObject("({val : 10})")}},
909 {"'use strict'; delete p1.name; return p1.val;",
910 {factory->NewNumberFromInt(10),
911 BytecodeGraphTester::NewObject("({val : 10, name:'abc'})")}},
912 };
913
914 size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]);
915 for (size_t i = 0; i < num_snippets; i++) {
916 ScopedVector<char> script(1024);
917 SNPrintF(script, "function %s(p1) { %s }\n%s({});", kFunctionName,
918 snippets[i].code_snippet, kFunctionName);
919
920 BytecodeGraphTester tester(isolate, zone, script.start());
921 auto callable = tester.GetCallable<Handle<Object>>();
922 Handle<Object> return_value =
923 callable(snippets[i].parameter(0)).ToHandleChecked();
924 CHECK(return_value->SameValue(*snippets[i].return_value()));
925 }
926 }
927
928
TEST(BytecodeGraphBuilderDeleteGlobal)929 TEST(BytecodeGraphBuilderDeleteGlobal) {
930 HandleAndZoneScope scope;
931 Isolate* isolate = scope.main_isolate();
932 Zone* zone = scope.main_zone();
933 Factory* factory = isolate->factory();
934
935 ExpectedSnippet<0> snippets[] = {
936 {"var obj = {val : 10, type : 'int'};"
937 "function f() {return delete obj;};",
938 {factory->false_value()}},
939 {"function f() {return delete this;};", {factory->true_value()}},
940 {"var obj = {val : 10, type : 'int'};"
941 "function f() {return delete obj.val;};",
942 {factory->true_value()}},
943 {"var obj = {val : 10, type : 'int'};"
944 "function f() {'use strict'; return delete obj.val;};",
945 {factory->true_value()}},
946 {"var obj = {val : 10, type : 'int'};"
947 "function f() {delete obj.val; return obj.val;};",
948 {factory->undefined_value()}},
949 {"var obj = {val : 10, type : 'int'};"
950 "function f() {'use strict'; delete obj.val; return obj.val;};",
951 {factory->undefined_value()}},
952 {"var obj = {1 : 10, 2 : 20};"
953 "function f() { return delete obj[1]; };",
954 {factory->true_value()}},
955 {"var obj = {1 : 10, 2 : 20};"
956 "function f() { 'use strict'; return delete obj[1];};",
957 {factory->true_value()}},
958 {"obj = {1 : 10, 2 : 20};"
959 "function f() { delete obj[1]; return obj[2];};",
960 {factory->NewNumberFromInt(20)}},
961 {"function f() {"
962 " var obj = {1 : 10, 2 : 20};"
963 " function inner() { return obj[1]; };"
964 " return delete obj[1];"
965 "}",
966 {factory->true_value()}},
967 };
968
969 size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]);
970 for (size_t i = 0; i < num_snippets; i++) {
971 ScopedVector<char> script(1024);
972 SNPrintF(script, "%s %s({});", snippets[i].code_snippet, kFunctionName);
973
974 BytecodeGraphTester tester(isolate, zone, script.start());
975 auto callable = tester.GetCallable<>();
976 Handle<Object> return_value = callable().ToHandleChecked();
977 CHECK(return_value->SameValue(*snippets[i].return_value()));
978 }
979 }
980
981
TEST(BytecodeGraphBuilderDeleteLookupSlot)982 TEST(BytecodeGraphBuilderDeleteLookupSlot) {
983 HandleAndZoneScope scope;
984 Isolate* isolate = scope.main_isolate();
985 Zone* zone = scope.main_zone();
986 Factory* factory = isolate->factory();
987
988 // TODO(mythria): Add more tests when we have support for LdaLookupSlot.
989 const char* function_prologue = "var f;"
990 "var x = 1;"
991 "y = 10;"
992 "var obj = {val:10};"
993 "var z = 30;"
994 "function f1() {"
995 " var z = 20;"
996 " eval(\"function t() {";
997 const char* function_epilogue = " }; f = t; t();\");"
998 "}"
999 "f1();";
1000
1001 ExpectedSnippet<0> snippets[] = {
1002 {"return delete y;", {factory->true_value()}},
1003 {"return delete z;", {factory->false_value()}},
1004 };
1005
1006 size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]);
1007 for (size_t i = 0; i < num_snippets; i++) {
1008 ScopedVector<char> script(1024);
1009 SNPrintF(script, "%s %s %s", function_prologue, snippets[i].code_snippet,
1010 function_epilogue);
1011
1012 BytecodeGraphTester tester(isolate, zone, script.start(), "t");
1013 auto callable = tester.GetCallable<>();
1014 Handle<Object> return_value = callable().ToHandleChecked();
1015 CHECK(return_value->SameValue(*snippets[i].return_value()));
1016 }
1017 }
1018
1019
TEST(BytecodeGraphBuilderLookupSlot)1020 TEST(BytecodeGraphBuilderLookupSlot) {
1021 HandleAndZoneScope scope;
1022 Isolate* isolate = scope.main_isolate();
1023 Zone* zone = scope.main_zone();
1024 Factory* factory = isolate->factory();
1025
1026 const char* function_prologue = "var f;"
1027 "var x = 12;"
1028 "y = 10;"
1029 "var obj = {val:3.1414};"
1030 "var z = 30;"
1031 "function f1() {"
1032 " var z = 20;"
1033 " eval(\"function t() {";
1034 const char* function_epilogue = " }; f = t; t();\");"
1035 "}"
1036 "f1();";
1037
1038 ExpectedSnippet<0> snippets[] = {
1039 {"return x;", {factory->NewNumber(12)}},
1040 {"return obj.val;", {factory->NewNumber(3.1414)}},
1041 {"return typeof x;", {factory->NewStringFromStaticChars("number")}},
1042 {"return typeof dummy;",
1043 {factory->NewStringFromStaticChars("undefined")}},
1044 {"x = 23; return x;", {factory->NewNumber(23)}},
1045 {"'use strict'; obj.val = 23.456; return obj.val;",
1046 {factory->NewNumber(23.456)}}};
1047
1048 size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]);
1049 for (size_t i = 0; i < num_snippets; i++) {
1050 ScopedVector<char> script(1024);
1051 SNPrintF(script, "%s %s %s", function_prologue, snippets[i].code_snippet,
1052 function_epilogue);
1053
1054 BytecodeGraphTester tester(isolate, zone, script.start(), "t");
1055 auto callable = tester.GetCallable<>();
1056 Handle<Object> return_value = callable().ToHandleChecked();
1057 CHECK(return_value->SameValue(*snippets[i].return_value()));
1058 }
1059 }
1060
1061
TEST(BytecodeGraphBuilderLookupSlotWide)1062 TEST(BytecodeGraphBuilderLookupSlotWide) {
1063 HandleAndZoneScope scope;
1064 Isolate* isolate = scope.main_isolate();
1065 Zone* zone = scope.main_zone();
1066 Factory* factory = isolate->factory();
1067
1068 const char* function_prologue =
1069 "var f;"
1070 "var x = 12;"
1071 "y = 10;"
1072 "var obj = {val:3.1414};"
1073 "var z = 30;"
1074 "function f1() {"
1075 " var z = 20;"
1076 " eval(\"function t() {";
1077 const char* function_epilogue =
1078 " }; f = t; t();\");"
1079 "}"
1080 "f1();";
1081
1082 ExpectedSnippet<0> snippets[] = {
1083 {"var y = 2.3;" REPEAT_256(SPACE, "y = 2.3;") "return x;",
1084 {factory->NewNumber(12)}},
1085 {"var y = 2.3;" REPEAT_256(SPACE, "y = 2.3;") "return typeof x;",
1086 {factory->NewStringFromStaticChars("number")}},
1087 {"var y = 2.3;" REPEAT_256(SPACE, "y = 2.3;") "return x = 23;",
1088 {factory->NewNumber(23)}},
1089 {"'use strict';" REPEAT_256(SPACE, "y = 2.3;") "return obj.val = 23.456;",
1090 {factory->NewNumber(23.456)}}};
1091
1092 size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]);
1093 for (size_t i = 0; i < num_snippets; i++) {
1094 ScopedVector<char> script(3072);
1095 SNPrintF(script, "%s %s %s", function_prologue, snippets[i].code_snippet,
1096 function_epilogue);
1097
1098 BytecodeGraphTester tester(isolate, zone, script.start(), "t");
1099 auto callable = tester.GetCallable<>();
1100 Handle<Object> return_value = callable().ToHandleChecked();
1101 CHECK(return_value->SameValue(*snippets[i].return_value()));
1102 }
1103 }
1104
1105
TEST(BytecodeGraphBuilderCallLookupSlot)1106 TEST(BytecodeGraphBuilderCallLookupSlot) {
1107 HandleAndZoneScope scope;
1108 Isolate* isolate = scope.main_isolate();
1109 Zone* zone = scope.main_zone();
1110
1111 ExpectedSnippet<0> snippets[] = {
1112 {"g = function(){ return 2 }; eval(''); return g();",
1113 {handle(Smi::FromInt(2), isolate)}},
1114 {"g = function(){ return 2 }; eval('g = function() {return 3}');\n"
1115 "return g();",
1116 {handle(Smi::FromInt(3), isolate)}},
1117 {"g = { x: function(){ return this.y }, y: 20 };\n"
1118 "eval('g = { x: g.x, y: 30 }');\n"
1119 "return g.x();",
1120 {handle(Smi::FromInt(30), isolate)}},
1121 };
1122
1123 size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]);
1124 for (size_t i = 0; i < num_snippets; i++) {
1125 ScopedVector<char> script(1024);
1126 SNPrintF(script, "function %s() { %s }\n%s();", kFunctionName,
1127 snippets[i].code_snippet, kFunctionName);
1128 BytecodeGraphTester tester(isolate, zone, script.start());
1129 auto callable = tester.GetCallable<>();
1130 Handle<Object> return_value = callable().ToHandleChecked();
1131 CHECK(return_value->SameValue(*snippets[i].return_value()));
1132 }
1133 }
1134
1135
TEST(BytecodeGraphBuilderEval)1136 TEST(BytecodeGraphBuilderEval) {
1137 HandleAndZoneScope scope;
1138 Isolate* isolate = scope.main_isolate();
1139 Zone* zone = scope.main_zone();
1140 Factory* factory = isolate->factory();
1141
1142 ExpectedSnippet<0> snippets[] = {
1143 {"return eval('1;');", {handle(Smi::FromInt(1), isolate)}},
1144 {"return eval('100 * 20;');", {handle(Smi::FromInt(2000), isolate)}},
1145 {"var x = 10; return eval('x + 20;');",
1146 {handle(Smi::FromInt(30), isolate)}},
1147 {"var x = 10; eval('x = 33;'); return x;",
1148 {handle(Smi::FromInt(33), isolate)}},
1149 {"'use strict'; var x = 20; var z = 0;\n"
1150 "eval('var x = 33; z = x;'); return x + z;",
1151 {handle(Smi::FromInt(53), isolate)}},
1152 {"eval('var x = 33;'); eval('var y = x + 20'); return x + y;",
1153 {handle(Smi::FromInt(86), isolate)}},
1154 {"var x = 1; eval('for(i = 0; i < 10; i++) x = x + 1;'); return x",
1155 {handle(Smi::FromInt(11), isolate)}},
1156 {"var x = 10; eval('var x = 20;'); return x;",
1157 {handle(Smi::FromInt(20), isolate)}},
1158 {"var x = 1; eval('\"use strict\"; var x = 2;'); return x;",
1159 {handle(Smi::FromInt(1), isolate)}},
1160 {"'use strict'; var x = 1; eval('var x = 2;'); return x;",
1161 {handle(Smi::FromInt(1), isolate)}},
1162 {"var x = 10; eval('x + 20;'); return typeof x;",
1163 {factory->NewStringFromStaticChars("number")}},
1164 {"eval('var y = 10;'); return typeof unallocated;",
1165 {factory->NewStringFromStaticChars("undefined")}},
1166 {"'use strict'; eval('var y = 10;'); return typeof unallocated;",
1167 {factory->NewStringFromStaticChars("undefined")}},
1168 {"eval('var x = 10;'); return typeof x;",
1169 {factory->NewStringFromStaticChars("number")}},
1170 {"var x = {}; eval('var x = 10;'); return typeof x;",
1171 {factory->NewStringFromStaticChars("number")}},
1172 {"'use strict'; var x = {}; eval('var x = 10;'); return typeof x;",
1173 {factory->NewStringFromStaticChars("object")}},
1174 };
1175
1176 size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]);
1177 for (size_t i = 0; i < num_snippets; i++) {
1178 ScopedVector<char> script(1024);
1179 SNPrintF(script, "function %s() { %s }\n%s();", kFunctionName,
1180 snippets[i].code_snippet, kFunctionName);
1181 BytecodeGraphTester tester(isolate, zone, script.start());
1182 auto callable = tester.GetCallable<>();
1183 Handle<Object> return_value = callable().ToHandleChecked();
1184 CHECK(return_value->SameValue(*snippets[i].return_value()));
1185 }
1186 }
1187
1188
TEST(BytecodeGraphBuilderEvalParams)1189 TEST(BytecodeGraphBuilderEvalParams) {
1190 HandleAndZoneScope scope;
1191 Isolate* isolate = scope.main_isolate();
1192 Zone* zone = scope.main_zone();
1193
1194 ExpectedSnippet<1> snippets[] = {
1195 {"var x = 10; return eval('x + p1;');",
1196 {handle(Smi::FromInt(30), isolate), handle(Smi::FromInt(20), isolate)}},
1197 {"var x = 10; eval('p1 = x;'); return p1;",
1198 {handle(Smi::FromInt(10), isolate), handle(Smi::FromInt(20), isolate)}},
1199 {"var a = 10;"
1200 "function inner() { return eval('a + p1;');}"
1201 "return inner();",
1202 {handle(Smi::FromInt(30), isolate), handle(Smi::FromInt(20), isolate)}},
1203 };
1204
1205 size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]);
1206 for (size_t i = 0; i < num_snippets; i++) {
1207 ScopedVector<char> script(1024);
1208 SNPrintF(script, "function %s(p1) { %s }\n%s(0);", kFunctionName,
1209 snippets[i].code_snippet, kFunctionName);
1210 BytecodeGraphTester tester(isolate, zone, script.start());
1211 auto callable = tester.GetCallable<Handle<Object>>();
1212 Handle<Object> return_value =
1213 callable(snippets[i].parameter(0)).ToHandleChecked();
1214 CHECK(return_value->SameValue(*snippets[i].return_value()));
1215 }
1216 }
1217
1218
TEST(BytecodeGraphBuilderEvalGlobal)1219 TEST(BytecodeGraphBuilderEvalGlobal) {
1220 HandleAndZoneScope scope;
1221 Isolate* isolate = scope.main_isolate();
1222 Zone* zone = scope.main_zone();
1223 Factory* factory = isolate->factory();
1224
1225 ExpectedSnippet<0> snippets[] = {
1226 {"function add_global() { eval('function f() { z = 33; }; f()'); };"
1227 "function f() { add_global(); return z; }; f();",
1228 {handle(Smi::FromInt(33), isolate)}},
1229 {"function add_global() {\n"
1230 " eval('\"use strict\"; function f() { y = 33; };"
1231 " try { f() } catch(e) {}');\n"
1232 "}\n"
1233 "function f() { add_global(); return typeof y; } f();",
1234 {factory->NewStringFromStaticChars("undefined")}},
1235 };
1236
1237 size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]);
1238 for (size_t i = 0; i < num_snippets; i++) {
1239 BytecodeGraphTester tester(isolate, zone, snippets[i].code_snippet);
1240 auto callable = tester.GetCallable<>();
1241 Handle<Object> return_value = callable().ToHandleChecked();
1242 CHECK(return_value->SameValue(*snippets[i].return_value()));
1243 }
1244 }
1245
1246
get_compare_result(Token::Value opcode,Handle<Object> lhs_value,Handle<Object> rhs_value)1247 bool get_compare_result(Token::Value opcode, Handle<Object> lhs_value,
1248 Handle<Object> rhs_value) {
1249 switch (opcode) {
1250 case Token::Value::EQ:
1251 return Object::Equals(lhs_value, rhs_value).FromJust();
1252 case Token::Value::NE:
1253 return !Object::Equals(lhs_value, rhs_value).FromJust();
1254 case Token::Value::EQ_STRICT:
1255 return lhs_value->StrictEquals(*rhs_value);
1256 case Token::Value::NE_STRICT:
1257 return !lhs_value->StrictEquals(*rhs_value);
1258 case Token::Value::LT:
1259 return Object::LessThan(lhs_value, rhs_value).FromJust();
1260 case Token::Value::LTE:
1261 return Object::LessThanOrEqual(lhs_value, rhs_value).FromJust();
1262 case Token::Value::GT:
1263 return Object::GreaterThan(lhs_value, rhs_value).FromJust();
1264 case Token::Value::GTE:
1265 return Object::GreaterThanOrEqual(lhs_value, rhs_value).FromJust();
1266 default:
1267 UNREACHABLE();
1268 return false;
1269 }
1270 }
1271
1272
get_code_snippet(Token::Value opcode)1273 const char* get_code_snippet(Token::Value opcode) {
1274 switch (opcode) {
1275 case Token::Value::EQ:
1276 return "return p1 == p2;";
1277 case Token::Value::NE:
1278 return "return p1 != p2;";
1279 case Token::Value::EQ_STRICT:
1280 return "return p1 === p2;";
1281 case Token::Value::NE_STRICT:
1282 return "return p1 !== p2;";
1283 case Token::Value::LT:
1284 return "return p1 < p2;";
1285 case Token::Value::LTE:
1286 return "return p1 <= p2;";
1287 case Token::Value::GT:
1288 return "return p1 > p2;";
1289 case Token::Value::GTE:
1290 return "return p1 >= p2;";
1291 default:
1292 UNREACHABLE();
1293 return "";
1294 }
1295 }
1296
1297
TEST(BytecodeGraphBuilderCompare)1298 TEST(BytecodeGraphBuilderCompare) {
1299 HandleAndZoneScope scope;
1300 Isolate* isolate = scope.main_isolate();
1301 Zone* zone = scope.main_zone();
1302 Factory* factory = isolate->factory();
1303 Handle<Object> lhs_values[] = {
1304 factory->NewNumberFromInt(10), factory->NewHeapNumber(3.45),
1305 factory->NewStringFromStaticChars("abc"),
1306 factory->NewNumberFromInt(SMI_MAX), factory->NewNumberFromInt(SMI_MIN)};
1307 Handle<Object> rhs_values[] = {factory->NewNumberFromInt(10),
1308 factory->NewStringFromStaticChars("10"),
1309 factory->NewNumberFromInt(20),
1310 factory->NewStringFromStaticChars("abc"),
1311 factory->NewHeapNumber(3.45),
1312 factory->NewNumberFromInt(SMI_MAX),
1313 factory->NewNumberFromInt(SMI_MIN)};
1314
1315 for (size_t i = 0; i < arraysize(kCompareOperators); i++) {
1316 ScopedVector<char> script(1024);
1317 SNPrintF(script, "function %s(p1, p2) { %s }\n%s({}, {});", kFunctionName,
1318 get_code_snippet(kCompareOperators[i]), kFunctionName);
1319
1320 BytecodeGraphTester tester(isolate, zone, script.start());
1321 auto callable = tester.GetCallable<Handle<Object>, Handle<Object>>();
1322 for (size_t j = 0; j < arraysize(lhs_values); j++) {
1323 for (size_t k = 0; k < arraysize(rhs_values); k++) {
1324 Handle<Object> return_value =
1325 callable(lhs_values[j], rhs_values[k]).ToHandleChecked();
1326 bool result = get_compare_result(kCompareOperators[i], lhs_values[j],
1327 rhs_values[k]);
1328 CHECK(return_value->SameValue(*factory->ToBoolean(result)));
1329 }
1330 }
1331 }
1332 }
1333
1334
TEST(BytecodeGraphBuilderTestIn)1335 TEST(BytecodeGraphBuilderTestIn) {
1336 HandleAndZoneScope scope;
1337 Isolate* isolate = scope.main_isolate();
1338 Zone* zone = scope.main_zone();
1339 Factory* factory = isolate->factory();
1340
1341 ExpectedSnippet<2> snippets[] = {
1342 {"return p2 in p1;",
1343 {factory->true_value(), BytecodeGraphTester::NewObject("({val : 10})"),
1344 factory->NewStringFromStaticChars("val")}},
1345 {"return p2 in p1;",
1346 {factory->true_value(), BytecodeGraphTester::NewObject("[]"),
1347 factory->NewStringFromStaticChars("length")}},
1348 {"return p2 in p1;",
1349 {factory->true_value(), BytecodeGraphTester::NewObject("[]"),
1350 factory->NewStringFromStaticChars("toString")}},
1351 {"return p2 in p1;",
1352 {factory->true_value(), BytecodeGraphTester::NewObject("({val : 10})"),
1353 factory->NewStringFromStaticChars("toString")}},
1354 {"return p2 in p1;",
1355 {factory->false_value(), BytecodeGraphTester::NewObject("({val : 10})"),
1356 factory->NewStringFromStaticChars("abc")}},
1357 {"return p2 in p1;",
1358 {factory->false_value(), BytecodeGraphTester::NewObject("({val : 10})"),
1359 factory->NewNumberFromInt(10)}},
1360 {"return p2 in p1;",
1361 {factory->true_value(), BytecodeGraphTester::NewObject("({10 : 'val'})"),
1362 factory->NewNumberFromInt(10)}},
1363 {"return p2 in p1;",
1364 {factory->false_value(),
1365 BytecodeGraphTester::NewObject("({10 : 'val'})"),
1366 factory->NewNumberFromInt(1)}},
1367 };
1368
1369 size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]);
1370 for (size_t i = 0; i < num_snippets; i++) {
1371 ScopedVector<char> script(1024);
1372 SNPrintF(script, "function %s(p1, p2) { %s }\n%s({}, {});", kFunctionName,
1373 snippets[i].code_snippet, kFunctionName);
1374
1375 BytecodeGraphTester tester(isolate, zone, script.start());
1376 auto callable = tester.GetCallable<Handle<Object>, Handle<Object>>();
1377 Handle<Object> return_value =
1378 callable(snippets[i].parameter(0), snippets[i].parameter(1))
1379 .ToHandleChecked();
1380 CHECK(return_value->SameValue(*snippets[i].return_value()));
1381 }
1382 }
1383
1384
TEST(BytecodeGraphBuilderTestInstanceOf)1385 TEST(BytecodeGraphBuilderTestInstanceOf) {
1386 HandleAndZoneScope scope;
1387 Isolate* isolate = scope.main_isolate();
1388 Zone* zone = scope.main_zone();
1389 Factory* factory = isolate->factory();
1390
1391 ExpectedSnippet<1> snippets[] = {
1392 {"return p1 instanceof Object;",
1393 {factory->true_value(), BytecodeGraphTester::NewObject("({val : 10})")}},
1394 {"return p1 instanceof String;",
1395 {factory->false_value(), factory->NewStringFromStaticChars("string")}},
1396 {"var cons = function() {};"
1397 "var obj = new cons();"
1398 "return obj instanceof cons;",
1399 {factory->true_value(), factory->undefined_value()}},
1400 };
1401
1402 size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]);
1403 for (size_t i = 0; i < num_snippets; i++) {
1404 ScopedVector<char> script(1024);
1405 SNPrintF(script, "function %s(p1) { %s }\n%s({});", kFunctionName,
1406 snippets[i].code_snippet, kFunctionName);
1407
1408 BytecodeGraphTester tester(isolate, zone, script.start());
1409 auto callable = tester.GetCallable<Handle<Object>>();
1410 Handle<Object> return_value =
1411 callable(snippets[i].parameter(0)).ToHandleChecked();
1412 CHECK(return_value->SameValue(*snippets[i].return_value()));
1413 }
1414 }
1415
1416
TEST(BytecodeGraphBuilderThrow)1417 TEST(BytecodeGraphBuilderThrow) {
1418 HandleAndZoneScope scope;
1419 Isolate* isolate = scope.main_isolate();
1420 Zone* zone = scope.main_zone();
1421
1422 // TODO(mythria): Add more tests when real try-catch and deoptimization
1423 // information are supported.
1424 ExpectedSnippet<0, const char*> snippets[] = {
1425 {"throw undefined;", {"Uncaught undefined"}},
1426 {"throw 1;", {"Uncaught 1"}},
1427 {"throw 'Error';", {"Uncaught Error"}},
1428 {"throw 'Error1'; throw 'Error2'", {"Uncaught Error1"}},
1429 // TODO(mythria): Enable these tests when JumpIfTrue is supported.
1430 // {"var a = true; if (a) { throw 'Error'; }", {"Error"}},
1431 };
1432
1433 size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]);
1434 for (size_t i = 0; i < num_snippets; i++) {
1435 ScopedVector<char> script(1024);
1436 SNPrintF(script, "function %s() { %s }\n%s();", kFunctionName,
1437 snippets[i].code_snippet, kFunctionName);
1438 BytecodeGraphTester tester(isolate, zone, script.start());
1439 v8::Local<v8::String> message = tester.CheckThrowsReturnMessage()->Get();
1440 v8::Local<v8::String> expected_string = v8_str(snippets[i].return_value());
1441 CHECK(
1442 message->Equals(CcTest::isolate()->GetCurrentContext(), expected_string)
1443 .FromJust());
1444 }
1445 }
1446
1447
TEST(BytecodeGraphBuilderContext)1448 TEST(BytecodeGraphBuilderContext) {
1449 HandleAndZoneScope scope;
1450 Isolate* isolate = scope.main_isolate();
1451 Zone* zone = scope.main_zone();
1452 Factory* factory = isolate->factory();
1453
1454 ExpectedSnippet<0> snippets[] = {
1455 {"var x = 'outer';"
1456 "function f() {"
1457 " 'use strict';"
1458 " {"
1459 " let x = 'inner';"
1460 " (function() {x});"
1461 " }"
1462 "return(x);"
1463 "}"
1464 "f();",
1465 {factory->NewStringFromStaticChars("outer")}},
1466 {"var x = 'outer';"
1467 "function f() {"
1468 " 'use strict';"
1469 " {"
1470 " let x = 'inner ';"
1471 " var innerFunc = function() {return x};"
1472 " }"
1473 "return(innerFunc() + x);"
1474 "}"
1475 "f();",
1476 {factory->NewStringFromStaticChars("inner outer")}},
1477 {"var x = 'outer';"
1478 "function f() {"
1479 " 'use strict';"
1480 " {"
1481 " let x = 'inner ';"
1482 " var innerFunc = function() {return x;};"
1483 " {"
1484 " let x = 'innermost ';"
1485 " var innerMostFunc = function() {return x + innerFunc();};"
1486 " }"
1487 " x = 'inner_changed ';"
1488 " }"
1489 " return(innerMostFunc() + x);"
1490 "}"
1491 "f();",
1492 {factory->NewStringFromStaticChars("innermost inner_changed outer")}},
1493 };
1494
1495 size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]);
1496 for (size_t i = 0; i < num_snippets; i++) {
1497 ScopedVector<char> script(1024);
1498 SNPrintF(script, "%s", snippets[i].code_snippet);
1499
1500 BytecodeGraphTester tester(isolate, zone, script.start(), "f");
1501 auto callable = tester.GetCallable<>("f");
1502 Handle<Object> return_value = callable().ToHandleChecked();
1503 CHECK(return_value->SameValue(*snippets[i].return_value()));
1504 }
1505 }
1506
1507
TEST(BytecodeGraphBuilderLoadContext)1508 TEST(BytecodeGraphBuilderLoadContext) {
1509 HandleAndZoneScope scope;
1510 Isolate* isolate = scope.main_isolate();
1511 Zone* zone = scope.main_zone();
1512 Factory* factory = isolate->factory();
1513
1514 ExpectedSnippet<1> snippets[] = {
1515 {"function Outer() {"
1516 " var outerVar = 2;"
1517 " function Inner(innerArg) {"
1518 " this.innerFunc = function () {"
1519 " return outerVar * innerArg;"
1520 " };"
1521 " };"
1522 " this.getInnerFunc = function GetInner() {"
1523 " return new Inner(3).innerFunc;"
1524 " }"
1525 "}"
1526 "var f = new Outer().getInnerFunc();"
1527 "f();",
1528 {factory->NewNumberFromInt(6), factory->undefined_value()}},
1529 {"function Outer() {"
1530 " var outerVar = 2;"
1531 " function Inner(innerArg) {"
1532 " this.innerFunc = function () {"
1533 " outerVar = innerArg; return outerVar;"
1534 " };"
1535 " };"
1536 " this.getInnerFunc = function GetInner() {"
1537 " return new Inner(10).innerFunc;"
1538 " }"
1539 "}"
1540 "var f = new Outer().getInnerFunc();"
1541 "f();",
1542 {factory->NewNumberFromInt(10), factory->undefined_value()}},
1543 {"function testOuter(outerArg) {"
1544 " this.testinnerFunc = function testInner(innerArg) {"
1545 " return innerArg + outerArg;"
1546 " }"
1547 "}"
1548 "var f = new testOuter(10).testinnerFunc;"
1549 "f(0);",
1550 {factory->NewNumberFromInt(14), factory->NewNumberFromInt(4)}},
1551 {"function testOuter(outerArg) {"
1552 " var outerVar = outerArg * 2;"
1553 " this.testinnerFunc = function testInner(innerArg) {"
1554 " outerVar = outerVar + innerArg; return outerVar;"
1555 " }"
1556 "}"
1557 "var f = new testOuter(10).testinnerFunc;"
1558 "f(0);",
1559 {factory->NewNumberFromInt(24), factory->NewNumberFromInt(4)}}};
1560
1561 size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]);
1562 for (size_t i = 0; i < num_snippets; i++) {
1563 ScopedVector<char> script(1024);
1564 SNPrintF(script, "%s", snippets[i].code_snippet);
1565
1566 BytecodeGraphTester tester(isolate, zone, script.start(), "*");
1567 auto callable = tester.GetCallable<Handle<Object>>("f");
1568 Handle<Object> return_value =
1569 callable(snippets[i].parameter(0)).ToHandleChecked();
1570 CHECK(return_value->SameValue(*snippets[i].return_value()));
1571 }
1572 }
1573
1574
TEST(BytecodeGraphBuilderCreateArgumentsNoParameters)1575 TEST(BytecodeGraphBuilderCreateArgumentsNoParameters) {
1576 HandleAndZoneScope scope;
1577 Isolate* isolate = scope.main_isolate();
1578 Zone* zone = scope.main_zone();
1579 Factory* factory = isolate->factory();
1580
1581 ExpectedSnippet<0> snippets[] = {
1582 {"function f() {return arguments[0];}", {factory->undefined_value()}},
1583 {"function f(a) {return arguments[0];}", {factory->undefined_value()}},
1584 {"function f() {'use strict'; return arguments[0];}",
1585 {factory->undefined_value()}},
1586 {"function f(a) {'use strict'; return arguments[0];}",
1587 {factory->undefined_value()}},
1588 };
1589
1590 size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]);
1591 for (size_t i = 0; i < num_snippets; i++) {
1592 ScopedVector<char> script(1024);
1593 SNPrintF(script, "%s\n%s();", snippets[i].code_snippet, kFunctionName);
1594
1595 BytecodeGraphTester tester(isolate, zone, script.start());
1596 auto callable = tester.GetCallable<>();
1597 Handle<Object> return_value = callable().ToHandleChecked();
1598 CHECK(return_value->SameValue(*snippets[i].return_value()));
1599 }
1600 }
1601
1602
TEST(BytecodeGraphBuilderCreateArguments)1603 TEST(BytecodeGraphBuilderCreateArguments) {
1604 HandleAndZoneScope scope;
1605 Isolate* isolate = scope.main_isolate();
1606 Zone* zone = scope.main_zone();
1607 Factory* factory = isolate->factory();
1608
1609 ExpectedSnippet<3> snippets[] = {
1610 {"function f(a, b, c) {return arguments[0];}",
1611 {factory->NewNumberFromInt(1), factory->NewNumberFromInt(1),
1612 factory->NewNumberFromInt(2), factory->NewNumberFromInt(3)}},
1613 {"function f(a, b, c) {return arguments[3];}",
1614 {factory->undefined_value(), factory->NewNumberFromInt(1),
1615 factory->NewNumberFromInt(2), factory->NewNumberFromInt(3)}},
1616 {"function f(a, b, c) { b = c; return arguments[1];}",
1617 {factory->NewNumberFromInt(3), factory->NewNumberFromInt(1),
1618 factory->NewNumberFromInt(2), factory->NewNumberFromInt(3)}},
1619 {"function f(a, b, c) {'use strict'; return arguments[0];}",
1620 {factory->NewNumberFromInt(1), factory->NewNumberFromInt(1),
1621 factory->NewNumberFromInt(2), factory->NewNumberFromInt(3)}},
1622 {"function f(a, b, c) {'use strict'; return arguments[3];}",
1623 {factory->undefined_value(), factory->NewNumberFromInt(1),
1624 factory->NewNumberFromInt(2), factory->NewNumberFromInt(3)}},
1625 {"function f(a, b, c) {'use strict'; b = c; return arguments[1];}",
1626 {factory->NewNumberFromInt(2), factory->NewNumberFromInt(1),
1627 factory->NewNumberFromInt(2), factory->NewNumberFromInt(3)}},
1628 {"function inline_func(a, b) { return arguments[0] }"
1629 "function f(a, b, c) {return inline_func(b, c) + arguments[0];}",
1630 {factory->NewNumberFromInt(3), factory->NewNumberFromInt(1),
1631 factory->NewNumberFromInt(2), factory->NewNumberFromInt(30)}},
1632 };
1633
1634 size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]);
1635 for (size_t i = 0; i < num_snippets; i++) {
1636 ScopedVector<char> script(1024);
1637 SNPrintF(script, "%s\n%s();", snippets[i].code_snippet, kFunctionName);
1638
1639 BytecodeGraphTester tester(isolate, zone, script.start());
1640 auto callable =
1641 tester.GetCallable<Handle<Object>, Handle<Object>, Handle<Object>>();
1642 Handle<Object> return_value =
1643 callable(snippets[i].parameter(0), snippets[i].parameter(1),
1644 snippets[i].parameter(2))
1645 .ToHandleChecked();
1646 CHECK(return_value->SameValue(*snippets[i].return_value()));
1647 }
1648 }
1649
1650
TEST(BytecodeGraphBuilderRegExpLiterals)1651 TEST(BytecodeGraphBuilderRegExpLiterals) {
1652 HandleAndZoneScope scope;
1653 Isolate* isolate = scope.main_isolate();
1654 Zone* zone = scope.main_zone();
1655 Factory* factory = isolate->factory();
1656
1657 ExpectedSnippet<0> snippets[] = {
1658 {"return /abd/.exec('cccabbdd');", {factory->null_value()}},
1659 {"return /ab+d/.exec('cccabbdd')[0];",
1660 {factory->NewStringFromStaticChars("abbd")}},
1661 {"var a = 3.1414;"
1662 REPEAT_256(SPACE, "a = 3.1414;")
1663 "return /ab+d/.exec('cccabbdd')[0];",
1664 {factory->NewStringFromStaticChars("abbd")}},
1665 {"return /ab+d/.exec('cccabbdd')[1];", {factory->undefined_value()}},
1666 {"return /AbC/i.exec('ssaBC')[0];",
1667 {factory->NewStringFromStaticChars("aBC")}},
1668 {"return 'ssaBC'.match(/AbC/i)[0];",
1669 {factory->NewStringFromStaticChars("aBC")}},
1670 {"return 'ssaBCtAbC'.match(/(AbC)/gi)[1];",
1671 {factory->NewStringFromStaticChars("AbC")}},
1672 };
1673
1674 size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]);
1675 for (size_t i = 0; i < num_snippets; i++) {
1676 ScopedVector<char> script(4096);
1677 SNPrintF(script, "function %s() { %s }\n%s();", kFunctionName,
1678 snippets[i].code_snippet, kFunctionName);
1679
1680 BytecodeGraphTester tester(isolate, zone, script.start());
1681 auto callable = tester.GetCallable<>();
1682 Handle<Object> return_value = callable().ToHandleChecked();
1683 CHECK(return_value->SameValue(*snippets[i].return_value()));
1684 }
1685 }
1686
1687
TEST(BytecodeGraphBuilderArrayLiterals)1688 TEST(BytecodeGraphBuilderArrayLiterals) {
1689 HandleAndZoneScope scope;
1690 Isolate* isolate = scope.main_isolate();
1691 Zone* zone = scope.main_zone();
1692 Factory* factory = isolate->factory();
1693
1694 ExpectedSnippet<0> snippets[] = {
1695 {"return [][0];", {factory->undefined_value()}},
1696 {"return [1, 3, 2][1];", {factory->NewNumberFromInt(3)}},
1697 {"var a;" REPEAT_256(SPACE, "a = 9.87;") "return [1, 3, 2][1];",
1698 {factory->NewNumberFromInt(3)}},
1699 {"return ['a', 'b', 'c'][2];", {factory->NewStringFromStaticChars("c")}},
1700 {"var a = 100; return [a, a++, a + 2, a + 3][2];",
1701 {factory->NewNumberFromInt(103)}},
1702 {"var a = 100; return [a, ++a, a + 2, a + 3][1];",
1703 {factory->NewNumberFromInt(101)}},
1704 {"var a = 9.2;"
1705 REPEAT_256(SPACE, "a = 9.34;")
1706 "return [a, ++a, a + 2, a + 3][2];",
1707 {factory->NewHeapNumber(12.34)}},
1708 {"return [[1, 2, 3], ['a', 'b', 'c']][1][0];",
1709 {factory->NewStringFromStaticChars("a")}},
1710 {"var t = 't'; return [[t, t + 'est'], [1 + t]][0][1];",
1711 {factory->NewStringFromStaticChars("test")}},
1712 {"var t = 't'; return [[t, t + 'est'], [1 + t]][1][0];",
1713 {factory->NewStringFromStaticChars("1t")}}};
1714
1715 size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]);
1716 for (size_t i = 0; i < num_snippets; i++) {
1717 ScopedVector<char> script(4096);
1718 SNPrintF(script, "function %s() { %s }\n%s();", kFunctionName,
1719 snippets[i].code_snippet, kFunctionName);
1720
1721 BytecodeGraphTester tester(isolate, zone, script.start());
1722 auto callable = tester.GetCallable<>();
1723 Handle<Object> return_value = callable().ToHandleChecked();
1724 CHECK(return_value->SameValue(*snippets[i].return_value()));
1725 }
1726 }
1727
1728
TEST(BytecodeGraphBuilderObjectLiterals)1729 TEST(BytecodeGraphBuilderObjectLiterals) {
1730 HandleAndZoneScope scope;
1731 Isolate* isolate = scope.main_isolate();
1732 Zone* zone = scope.main_zone();
1733 Factory* factory = isolate->factory();
1734
1735 ExpectedSnippet<0> snippets[] = {
1736 {"return { }.name;", {factory->undefined_value()}},
1737 {"return { name: 'string', val: 9.2 }.name;",
1738 {factory->NewStringFromStaticChars("string")}},
1739 {"var a;\n"
1740 REPEAT_256(SPACE, "a = 1.23;\n")
1741 "return { name: 'string', val: 9.2 }.name;",
1742 {factory->NewStringFromStaticChars("string")}},
1743 {"return { name: 'string', val: 9.2 }['name'];",
1744 {factory->NewStringFromStaticChars("string")}},
1745 {"var a = 15; return { name: 'string', val: a }.val;",
1746 {factory->NewNumberFromInt(15)}},
1747 {"var a;"
1748 REPEAT_256(SPACE, "a = 1.23;")
1749 "return { name: 'string', val: a }.val;",
1750 {factory->NewHeapNumber(1.23)}},
1751 {"var a = 15; var b = 'val'; return { name: 'string', val: a }[b];",
1752 {factory->NewNumberFromInt(15)}},
1753 {"var a = 5; return { val: a, val: a + 1 }.val;",
1754 {factory->NewNumberFromInt(6)}},
1755 {"return { func: function() { return 'test' } }.func();",
1756 {factory->NewStringFromStaticChars("test")}},
1757 {"return { func(a) { return a + 'st'; } }.func('te');",
1758 {factory->NewStringFromStaticChars("test")}},
1759 {"return { get a() { return 22; } }.a;", {factory->NewNumberFromInt(22)}},
1760 {"var a = { get b() { return this.x + 't'; },\n"
1761 " set b(val) { this.x = val + 's' } };\n"
1762 "a.b = 'te';\n"
1763 "return a.b;",
1764 {factory->NewStringFromStaticChars("test")}},
1765 {"var a = 123; return { 1: a }[1];", {factory->NewNumberFromInt(123)}},
1766 {"return Object.getPrototypeOf({ __proto__: null });",
1767 {factory->null_value()}},
1768 {"var a = 'test'; return { [a]: 1 }.test;",
1769 {factory->NewNumberFromInt(1)}},
1770 {"var a = 'test'; return { b: a, [a]: a + 'ing' }['test']",
1771 {factory->NewStringFromStaticChars("testing")}},
1772 {"var a = 'proto_str';\n"
1773 "var b = { [a]: 1, __proto__: { var : a } };\n"
1774 "return Object.getPrototypeOf(b).var",
1775 {factory->NewStringFromStaticChars("proto_str")}},
1776 {"var n = 'name';\n"
1777 "return { [n]: 'val', get a() { return 987 } }['a'];",
1778 {factory->NewNumberFromInt(987)}},
1779 };
1780
1781 size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]);
1782 for (size_t i = 0; i < num_snippets; i++) {
1783 ScopedVector<char> script(4096);
1784 SNPrintF(script, "function %s() { %s }\n%s();", kFunctionName,
1785 snippets[i].code_snippet, kFunctionName);
1786 BytecodeGraphTester tester(isolate, zone, script.start());
1787 auto callable = tester.GetCallable<>();
1788 Handle<Object> return_value = callable().ToHandleChecked();
1789 CHECK(return_value->SameValue(*snippets[i].return_value()));
1790 }
1791 }
1792
1793
TEST(BytecodeGraphBuilderIf)1794 TEST(BytecodeGraphBuilderIf) {
1795 HandleAndZoneScope scope;
1796 Isolate* isolate = scope.main_isolate();
1797 Zone* zone = scope.main_zone();
1798 Factory* factory = isolate->factory();
1799
1800 ExpectedSnippet<1> snippets[] = {
1801 {"if (p1 > 1) return 1;\n"
1802 "return -1;",
1803 {factory->NewNumberFromInt(1), factory->NewNumberFromInt(2)}},
1804 {"if (p1 > 1) return 1;\n"
1805 "return -1;",
1806 {factory->NewNumberFromInt(-1), factory->NewNumberFromInt(1)}},
1807 {"if (p1 > 1) { return 1; } else { return -1; }",
1808 {factory->NewNumberFromInt(1), factory->NewNumberFromInt(2)}},
1809 {"if (p1 > 1) { return 1; } else { return -1; }",
1810 {factory->NewNumberFromInt(-1), factory->NewNumberFromInt(1)}},
1811 {"if (p1 > 50) {\n"
1812 " return 1;\n"
1813 "} else if (p1 < 10) {\n"
1814 " return 10;\n"
1815 "} else {\n"
1816 " return -10;\n"
1817 "}",
1818 {factory->NewNumberFromInt(1), factory->NewNumberFromInt(51)}},
1819 {"if (p1 > 50) {\n"
1820 " return 1;\n"
1821 "} else if (p1 < 10) {\n"
1822 " return 10;\n"
1823 "} else {\n"
1824 " return 100;\n"
1825 "}",
1826 {factory->NewNumberFromInt(10), factory->NewNumberFromInt(9)}},
1827 {"if (p1 > 50) {\n"
1828 " return 1;\n"
1829 "} else if (p1 < 10) {\n"
1830 " return 10;\n"
1831 "} else {\n"
1832 " return 100;\n"
1833 "}",
1834 {factory->NewNumberFromInt(100), factory->NewNumberFromInt(10)}},
1835 {"if (p1 >= 0) {\n"
1836 " if (p1 > 10) { return 2; } else { return 1; }\n"
1837 "} else {\n"
1838 " if (p1 < -10) { return -2; } else { return -1; }\n"
1839 "}",
1840 {factory->NewNumberFromInt(2), factory->NewNumberFromInt(100)}},
1841 {"if (p1 >= 0) {\n"
1842 " if (p1 > 10) { return 2; } else { return 1; }\n"
1843 "} else {\n"
1844 " if (p1 < -10) { return -2; } else { return -1; }\n"
1845 "}",
1846 {factory->NewNumberFromInt(1), factory->NewNumberFromInt(10)}},
1847 {"if (p1 >= 0) {\n"
1848 " if (p1 > 10) { return 2; } else { return 1; }\n"
1849 "} else {\n"
1850 " if (p1 < -10) { return -2; } else { return -1; }\n"
1851 "}",
1852 {factory->NewNumberFromInt(-2), factory->NewNumberFromInt(-11)}},
1853 {"if (p1 >= 0) {\n"
1854 " if (p1 > 10) { return 2; } else { return 1; }\n"
1855 "} else {\n"
1856 " if (p1 < -10) { return -2; } else { return -1; }\n"
1857 "}",
1858 {factory->NewNumberFromInt(-1), factory->NewNumberFromInt(-10)}},
1859 };
1860
1861 size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]);
1862 for (size_t i = 0; i < num_snippets; i++) {
1863 ScopedVector<char> script(2048);
1864 SNPrintF(script, "function %s(p1) { %s };\n%s(0);", kFunctionName,
1865 snippets[i].code_snippet, kFunctionName);
1866
1867 BytecodeGraphTester tester(isolate, zone, script.start());
1868 auto callable = tester.GetCallable<Handle<Object>>();
1869 Handle<Object> return_value =
1870 callable(snippets[i].parameter(0)).ToHandleChecked();
1871 CHECK(return_value->SameValue(*snippets[i].return_value()));
1872 }
1873 }
1874
1875
TEST(BytecodeGraphBuilderConditionalOperator)1876 TEST(BytecodeGraphBuilderConditionalOperator) {
1877 HandleAndZoneScope scope;
1878 Isolate* isolate = scope.main_isolate();
1879 Zone* zone = scope.main_zone();
1880 Factory* factory = isolate->factory();
1881
1882 ExpectedSnippet<1> snippets[] = {
1883 {"return (p1 > 1) ? 1 : -1;",
1884 {factory->NewNumberFromInt(1), factory->NewNumberFromInt(2)}},
1885 {"return (p1 > 1) ? 1 : -1;",
1886 {factory->NewNumberFromInt(-1), factory->NewNumberFromInt(0)}},
1887 {"return (p1 > 50) ? 1 : ((p1 < 10) ? 10 : -10);",
1888 {factory->NewNumberFromInt(10), factory->NewNumberFromInt(2)}},
1889 {"return (p1 > 50) ? 1 : ((p1 < 10) ? 10 : -10);",
1890 {factory->NewNumberFromInt(-10), factory->NewNumberFromInt(20)}},
1891 };
1892
1893 size_t num_snippets = sizeof(snippets) / sizeof(snippets[0]);
1894 for (size_t i = 0; i < num_snippets; i++) {
1895 ScopedVector<char> script(2048);
1896 SNPrintF(script, "function %s(p1) { %s };\n%s(0);", kFunctionName,
1897 snippets[i].code_snippet, kFunctionName);
1898
1899 BytecodeGraphTester tester(isolate, zone, script.start());
1900 auto callable = tester.GetCallable<Handle<Object>>();
1901 Handle<Object> return_value =
1902 callable(snippets[i].parameter(0)).ToHandleChecked();
1903 CHECK(return_value->SameValue(*snippets[i].return_value()));
1904 }
1905 }
1906
1907
TEST(BytecodeGraphBuilderSwitch)1908 TEST(BytecodeGraphBuilderSwitch) {
1909 HandleAndZoneScope scope;
1910 Isolate* isolate = scope.main_isolate();
1911 Zone* zone = scope.main_zone();
1912 Factory* factory = isolate->factory();
1913
1914 const char* switch_code =
1915 "switch (p1) {\n"
1916 " case 1: return 0;\n"
1917 " case 2: return 1;\n"
1918 " case 3:\n"
1919 " case 4: return 2;\n"
1920 " case 9: break;\n"
1921 " default: return 3;\n"
1922 "}\n"
1923 "return 9;";
1924
1925 ExpectedSnippet<1> snippets[] = {
1926 {switch_code,
1927 {factory->NewNumberFromInt(0), factory->NewNumberFromInt(1)}},
1928 {switch_code,
1929 {factory->NewNumberFromInt(1), factory->NewNumberFromInt(2)}},
1930 {switch_code,
1931 {factory->NewNumberFromInt(2), factory->NewNumberFromInt(3)}},
1932 {switch_code,
1933 {factory->NewNumberFromInt(2), factory->NewNumberFromInt(4)}},
1934 {switch_code,
1935 {factory->NewNumberFromInt(9), factory->NewNumberFromInt(9)}},
1936 {switch_code,
1937 {factory->NewNumberFromInt(3), factory->NewNumberFromInt(5)}},
1938 {switch_code,
1939 {factory->NewNumberFromInt(3), factory->NewNumberFromInt(6)}},
1940 };
1941
1942 for (size_t i = 0; i < arraysize(snippets); i++) {
1943 ScopedVector<char> script(2048);
1944 SNPrintF(script, "function %s(p1) { %s };\n%s(0);", kFunctionName,
1945 snippets[i].code_snippet, kFunctionName);
1946
1947 BytecodeGraphTester tester(isolate, zone, script.start());
1948 auto callable = tester.GetCallable<Handle<Object>>();
1949 Handle<Object> return_value =
1950 callable(snippets[i].parameter(0)).ToHandleChecked();
1951 CHECK(return_value->SameValue(*snippets[i].return_value()));
1952 }
1953 }
1954
1955
TEST(BytecodeGraphBuilderNestedSwitch)1956 TEST(BytecodeGraphBuilderNestedSwitch) {
1957 HandleAndZoneScope scope;
1958 Isolate* isolate = scope.main_isolate();
1959 Zone* zone = scope.main_zone();
1960 Factory* factory = isolate->factory();
1961
1962 const char* switch_code =
1963 "switch (p1) {\n"
1964 " case 0: {"
1965 " switch (p2) { case 0: return 0; case 1: return 1; case 2: break; }\n"
1966 " return -1;"
1967 " }\n"
1968 " case 1: {"
1969 " switch (p2) { case 0: return 2; case 1: return 3; }\n"
1970 " }\n"
1971 " case 2: break;"
1972 " }\n"
1973 "return -2;";
1974
1975 ExpectedSnippet<2> snippets[] = {
1976 {switch_code,
1977 {factory->NewNumberFromInt(0), factory->NewNumberFromInt(0),
1978 factory->NewNumberFromInt(0)}},
1979 {switch_code,
1980 {factory->NewNumberFromInt(1), factory->NewNumberFromInt(0),
1981 factory->NewNumberFromInt(1)}},
1982 {switch_code,
1983 {factory->NewNumberFromInt(-1), factory->NewNumberFromInt(0),
1984 factory->NewNumberFromInt(2)}},
1985 {switch_code,
1986 {factory->NewNumberFromInt(-1), factory->NewNumberFromInt(0),
1987 factory->NewNumberFromInt(3)}},
1988 {switch_code,
1989 {factory->NewNumberFromInt(2), factory->NewNumberFromInt(1),
1990 factory->NewNumberFromInt(0)}},
1991 {switch_code,
1992 {factory->NewNumberFromInt(3), factory->NewNumberFromInt(1),
1993 factory->NewNumberFromInt(1)}},
1994 {switch_code,
1995 {factory->NewNumberFromInt(-2), factory->NewNumberFromInt(1),
1996 factory->NewNumberFromInt(2)}},
1997 {switch_code,
1998 {factory->NewNumberFromInt(-2), factory->NewNumberFromInt(2),
1999 factory->NewNumberFromInt(0)}},
2000 };
2001
2002 for (size_t i = 0; i < arraysize(snippets); i++) {
2003 ScopedVector<char> script(2048);
2004 SNPrintF(script, "function %s(p1, p2) { %s };\n%s(0, 0);", kFunctionName,
2005 snippets[i].code_snippet, kFunctionName);
2006
2007 BytecodeGraphTester tester(isolate, zone, script.start());
2008 auto callable = tester.GetCallable<Handle<Object>, Handle<Object>>();
2009 Handle<Object> return_value =
2010 callable(snippets[i].parameter(0), snippets[i].parameter(1))
2011 .ToHandleChecked();
2012 CHECK(return_value->SameValue(*snippets[i].return_value()));
2013 }
2014 }
2015
2016
TEST(BytecodeGraphBuilderBreakableBlocks)2017 TEST(BytecodeGraphBuilderBreakableBlocks) {
2018 HandleAndZoneScope scope;
2019 Isolate* isolate = scope.main_isolate();
2020 Zone* zone = scope.main_zone();
2021 Factory* factory = isolate->factory();
2022
2023 ExpectedSnippet<0> snippets[] = {
2024 {"var x = 0;\n"
2025 "my_heart: {\n"
2026 " x = x + 1;\n"
2027 " break my_heart;\n"
2028 " x = x + 2;\n"
2029 "}\n"
2030 "return x;\n",
2031 {factory->NewNumberFromInt(1)}},
2032 {"var sum = 0;\n"
2033 "outta_here: {\n"
2034 " for (var x = 0; x < 10; ++x) {\n"
2035 " for (var y = 0; y < 3; ++y) {\n"
2036 " ++sum;\n"
2037 " if (x + y == 12) { break outta_here; }\n"
2038 " }\n"
2039 " }\n"
2040 "}\n"
2041 "return sum;",
2042 {factory->NewNumber(30)}},
2043 };
2044
2045 for (size_t i = 0; i < arraysize(snippets); i++) {
2046 ScopedVector<char> script(1024);
2047 SNPrintF(script, "function %s() { %s }\n%s();", kFunctionName,
2048 snippets[i].code_snippet, kFunctionName);
2049
2050 BytecodeGraphTester tester(isolate, zone, script.start());
2051 auto callable = tester.GetCallable<>();
2052 Handle<Object> return_value = callable().ToHandleChecked();
2053 CHECK(return_value->SameValue(*snippets[i].return_value()));
2054 }
2055 }
2056
2057
TEST(BytecodeGraphBuilderWhile)2058 TEST(BytecodeGraphBuilderWhile) {
2059 HandleAndZoneScope scope;
2060 Isolate* isolate = scope.main_isolate();
2061 Zone* zone = scope.main_zone();
2062 Factory* factory = isolate->factory();
2063
2064 ExpectedSnippet<0> snippets[] = {
2065 {"var x = 1; while (x < 1) { x *= 100; } return x;",
2066 {factory->NewNumberFromInt(1)}},
2067 {"var x = 1, y = 0; while (x < 7) { y += x * x; x += 1; } return y;",
2068 {factory->NewNumberFromInt(91)}},
2069 {"var x = 1; while (true) { x += 1; if (x == 10) break; } return x;",
2070 {factory->NewNumberFromInt(10)}},
2071 {"var x = 1; while (false) { x += 1; } return x;",
2072 {factory->NewNumberFromInt(1)}},
2073 {"var x = 0;\n"
2074 "while (true) {\n"
2075 " while (x < 10) {\n"
2076 " x = x * x + 1;\n"
2077 " }"
2078 " x += 1;\n"
2079 " break;\n"
2080 "}\n"
2081 "return x;",
2082 {factory->NewNumberFromInt(27)}},
2083 {"var x = 1, y = 0;\n"
2084 "while (x < 7) {\n"
2085 " x += 1;\n"
2086 " if (x == 2) continue;\n"
2087 " if (x == 3) continue;\n"
2088 " y += x * x;\n"
2089 " if (x == 4) break;\n"
2090 "}\n"
2091 "return y;",
2092 {factory->NewNumberFromInt(16)}}};
2093
2094 for (size_t i = 0; i < arraysize(snippets); i++) {
2095 ScopedVector<char> script(1024);
2096 SNPrintF(script, "function %s() { %s }\n%s();", kFunctionName,
2097 snippets[i].code_snippet, kFunctionName);
2098
2099 BytecodeGraphTester tester(isolate, zone, script.start());
2100 auto callable = tester.GetCallable<>();
2101 Handle<Object> return_value = callable().ToHandleChecked();
2102 CHECK(return_value->SameValue(*snippets[i].return_value()));
2103 }
2104 }
2105
2106
TEST(BytecodeGraphBuilderDo)2107 TEST(BytecodeGraphBuilderDo) {
2108 HandleAndZoneScope scope;
2109 Isolate* isolate = scope.main_isolate();
2110 Zone* zone = scope.main_zone();
2111 Factory* factory = isolate->factory();
2112
2113 ExpectedSnippet<0> snippets[] = {
2114 {"var x = 1; do { x *= 100; } while (x < 100); return x;",
2115 {factory->NewNumberFromInt(100)}},
2116 {"var x = 1; do { x = x * x + 1; } while (x < 7) return x;",
2117 {factory->NewNumberFromInt(26)}},
2118 {"var x = 1; do { x += 1; } while (false); return x;",
2119 {factory->NewNumberFromInt(2)}},
2120 {"var x = 1, y = 0;\n"
2121 "do {\n"
2122 " x += 1;\n"
2123 " if (x == 2) continue;\n"
2124 " if (x == 3) continue;\n"
2125 " y += x * x;\n"
2126 " if (x == 4) break;\n"
2127 "} while (x < 7);\n"
2128 "return y;",
2129 {factory->NewNumberFromInt(16)}}};
2130
2131 for (size_t i = 0; i < arraysize(snippets); i++) {
2132 ScopedVector<char> script(1024);
2133 SNPrintF(script, "function %s() { %s }\n%s();", kFunctionName,
2134 snippets[i].code_snippet, kFunctionName);
2135
2136 BytecodeGraphTester tester(isolate, zone, script.start());
2137 auto callable = tester.GetCallable<>();
2138 Handle<Object> return_value = callable().ToHandleChecked();
2139 CHECK(return_value->SameValue(*snippets[i].return_value()));
2140 }
2141 }
2142
2143
TEST(BytecodeGraphBuilderFor)2144 TEST(BytecodeGraphBuilderFor) {
2145 HandleAndZoneScope scope;
2146 Isolate* isolate = scope.main_isolate();
2147 Zone* zone = scope.main_zone();
2148 Factory* factory = isolate->factory();
2149
2150 ExpectedSnippet<0> snippets[] = {
2151 {"for (var x = 0;; x = 2 * x + 1) { if (x > 10) return x; }",
2152 {factory->NewNumberFromInt(15)}},
2153 {"for (var x = 0; true; x = 2 * x + 1) { if (x > 100) return x; }",
2154 {factory->NewNumberFromInt(127)}},
2155 {"for (var x = 0; false; x = 2 * x + 1) { if (x > 100) return x; } "
2156 "return 0;",
2157 {factory->NewNumberFromInt(0)}},
2158 {"for (var x = 0; x < 200; x = 2 * x + 1) { x = x; } return x;",
2159 {factory->NewNumberFromInt(255)}},
2160 {"for (var x = 0; x < 200; x = 2 * x + 1) {} return x;",
2161 {factory->NewNumberFromInt(255)}},
2162 {"var sum = 0;\n"
2163 "for (var x = 0; x < 200; x += 1) {\n"
2164 " if (x % 2) continue;\n"
2165 " if (sum > 10) break;\n"
2166 " sum += x;\n"
2167 "}\n"
2168 "return sum;",
2169 {factory->NewNumberFromInt(12)}},
2170 {"var sum = 0;\n"
2171 "for (var w = 0; w < 2; w++) {\n"
2172 " for (var x = 0; x < 200; x += 1) {\n"
2173 " if (x % 2) continue;\n"
2174 " if (x > 4) break;\n"
2175 " sum += x + w;\n"
2176 " }\n"
2177 "}\n"
2178 "return sum;",
2179 {factory->NewNumberFromInt(15)}},
2180 {"var sum = 0;\n"
2181 "for (var w = 0; w < 2; w++) {\n"
2182 " if (w == 1) break;\n"
2183 " for (var x = 0; x < 200; x += 1) {\n"
2184 " if (x % 2) continue;\n"
2185 " if (x > 4) break;\n"
2186 " sum += x + w;\n"
2187 " }\n"
2188 "}\n"
2189 "return sum;",
2190 {factory->NewNumberFromInt(6)}},
2191 {"var sum = 0;\n"
2192 "for (var w = 0; w < 3; w++) {\n"
2193 " if (w == 1) continue;\n"
2194 " for (var x = 0; x < 200; x += 1) {\n"
2195 " if (x % 2) continue;\n"
2196 " if (x > 4) break;\n"
2197 " sum += x + w;\n"
2198 " }\n"
2199 "}\n"
2200 "return sum;",
2201 {factory->NewNumberFromInt(18)}},
2202 {"var sum = 0;\n"
2203 "for (var x = 1; x < 10; x += 2) {\n"
2204 " for (var y = x; y < x + 2; y++) {\n"
2205 " sum += y * y;\n"
2206 " }\n"
2207 "}\n"
2208 "return sum;",
2209 {factory->NewNumberFromInt(385)}},
2210 };
2211
2212 for (size_t i = 0; i < arraysize(snippets); i++) {
2213 ScopedVector<char> script(1024);
2214 SNPrintF(script, "function %s() { %s }\n%s();", kFunctionName,
2215 snippets[i].code_snippet, kFunctionName);
2216
2217 BytecodeGraphTester tester(isolate, zone, script.start());
2218 auto callable = tester.GetCallable<>();
2219 Handle<Object> return_value = callable().ToHandleChecked();
2220 CHECK(return_value->SameValue(*snippets[i].return_value()));
2221 }
2222 }
2223
2224
TEST(BytecodeGraphBuilderForIn)2225 TEST(BytecodeGraphBuilderForIn) {
2226 HandleAndZoneScope scope;
2227 Isolate* isolate = scope.main_isolate();
2228 Zone* zone = scope.main_zone();
2229 Factory* factory = isolate->factory();
2230 ExpectedSnippet<0> snippets[] = {
2231 {"var sum = 0;\n"
2232 "var empty = null;\n"
2233 "for (var x in empty) { sum++; }\n"
2234 "return sum;",
2235 {factory->NewNumberFromInt(0)}},
2236 {"var sum = 100;\n"
2237 "var empty = 1;\n"
2238 "for (var x in empty) { sum++; }\n"
2239 "return sum;",
2240 {factory->NewNumberFromInt(100)}},
2241 {"for (var x in [ 10, 20, 30 ]) {}\n"
2242 "return 2;",
2243 {factory->NewNumberFromInt(2)}},
2244 {"var last = 0;\n"
2245 "for (var x in [ 10, 20, 30 ]) {\n"
2246 " last = x;\n"
2247 "}\n"
2248 "return +last;",
2249 {factory->NewNumberFromInt(2)}},
2250 {"var first = -1;\n"
2251 "for (var x in [ 10, 20, 30 ]) {\n"
2252 " first = +x;\n"
2253 " if (first > 0) break;\n"
2254 "}\n"
2255 "return first;",
2256 {factory->NewNumberFromInt(1)}},
2257 {"var first = -1;\n"
2258 "for (var x in [ 10, 20, 30 ]) {\n"
2259 " if (first >= 0) continue;\n"
2260 " first = x;\n"
2261 "}\n"
2262 "return +first;",
2263 {factory->NewNumberFromInt(0)}},
2264 {"var sum = 0;\n"
2265 "for (var x in [ 10, 20, 30 ]) {\n"
2266 " for (var y in [ 11, 22, 33, 44, 55, 66, 77 ]) {\n"
2267 " sum += 1;\n"
2268 " }\n"
2269 "}\n"
2270 "return sum;",
2271 {factory->NewNumberFromInt(21)}},
2272 {"var sum = 0;\n"
2273 "for (var x in [ 10, 20, 30 ]) {\n"
2274 " for (var y in [ 11, 22, 33, 44, 55, 66, 77 ]) {\n"
2275 " if (sum == 7) break;\n"
2276 " if (sum == 6) continue;\n"
2277 " sum += 1;\n"
2278 " }\n"
2279 "}\n"
2280 "return sum;",
2281 {factory->NewNumberFromInt(6)}},
2282 };
2283
2284 for (size_t i = 0; i < arraysize(snippets); i++) {
2285 ScopedVector<char> script(1024);
2286 SNPrintF(script, "function %s() { %s }\n%s();", kFunctionName,
2287 snippets[i].code_snippet, kFunctionName);
2288
2289 BytecodeGraphTester tester(isolate, zone, script.start());
2290 auto callable = tester.GetCallable<>();
2291 Handle<Object> return_value = callable().ToHandleChecked();
2292 CHECK(return_value->SameValue(*snippets[i].return_value()));
2293 }
2294 }
2295
2296
TEST(JumpWithConstantsAndWideConstants)2297 TEST(JumpWithConstantsAndWideConstants) {
2298 HandleAndZoneScope scope;
2299 auto isolate = scope.main_isolate();
2300 const int kStep = 19;
2301 int start = 7;
2302 for (int constants = start; constants < 256 + 3 * kStep; constants += kStep) {
2303 std::stringstream filler_os;
2304 // Generate a string that consumes constant pool entries and
2305 // spread out branch distances in script below.
2306 for (int i = 0; i < constants; i++) {
2307 filler_os << "var x_ = 'x_" << i << "';\n";
2308 }
2309 std::string filler(filler_os.str());
2310
2311 std::stringstream script_os;
2312 script_os << "function " << kFunctionName << "(a) {\n";
2313 script_os << " " << filler;
2314 script_os << " for (var i = a; i < 2; i++) {\n";
2315 script_os << " " << filler;
2316 script_os << " if (i == 0) { " << filler << "i = 10; continue; }\n";
2317 script_os << " else if (i == a) { " << filler << "i = 12; break; }\n";
2318 script_os << " else { " << filler << " }\n";
2319 script_os << " }\n";
2320 script_os << " return i;\n";
2321 script_os << "}\n";
2322 script_os << kFunctionName << "(0);\n";
2323 std::string script(script_os.str());
2324 auto factory = isolate->factory();
2325 auto zone = scope.main_zone();
2326 for (int a = 0; a < 3; a++) {
2327 BytecodeGraphTester tester(isolate, zone, script.c_str());
2328 auto callable = tester.GetCallable<Handle<Object>>();
2329 Handle<Object> return_val =
2330 callable(factory->NewNumberFromInt(a)).ToHandleChecked();
2331 static const int results[] = {11, 12, 2};
2332 CHECK_EQ(Handle<Smi>::cast(return_val)->value(), results[a]);
2333 }
2334 }
2335 }
2336
2337 } // namespace compiler
2338 } // namespace internal
2339 } // namespace v8
2340