• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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