e0668d5b49a244dba7fd1d50bc877b54ea775c5f
[platform/upstream/v8.git] / test / cctest / interpreter / test-bytecode-generator.cc
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 "src/v8.h"
6
7 #include "src/compiler.h"
8 #include "src/interpreter/bytecode-array-iterator.h"
9 #include "src/interpreter/bytecode-generator.h"
10 #include "src/interpreter/interpreter.h"
11 #include "test/cctest/cctest.h"
12
13 namespace v8 {
14 namespace internal {
15 namespace interpreter {
16
17 class BytecodeGeneratorHelper {
18  public:
19   const char* kFunctionName = "f";
20
21   static const int kLastParamIndex =
22       -InterpreterFrameConstants::kLastParamFromRegisterPointer / kPointerSize;
23
24   BytecodeGeneratorHelper() {
25     i::FLAG_vector_stores = true;
26     i::FLAG_ignition = true;
27     i::FLAG_ignition_filter = StrDup(kFunctionName);
28     i::FLAG_always_opt = false;
29     CcTest::i_isolate()->interpreter()->Initialize();
30   }
31
32
33   Factory* factory() { return CcTest::i_isolate()->factory(); }
34
35
36   Handle<BytecodeArray> MakeBytecode(const char* script,
37                                      const char* function_name) {
38     CompileRun(script);
39     Local<Function> function =
40         Local<Function>::Cast(CcTest::global()->Get(v8_str(function_name)));
41     i::Handle<i::JSFunction> js_function = v8::Utils::OpenHandle(*function);
42     return handle(js_function->shared()->bytecode_array(), CcTest::i_isolate());
43   }
44
45
46   Handle<BytecodeArray> MakeBytecodeForFunctionBody(const char* body) {
47     ScopedVector<char> program(1024);
48     SNPrintF(program, "function %s() { %s }\n%s();", kFunctionName, body,
49              kFunctionName);
50     return MakeBytecode(program.start(), kFunctionName);
51   }
52
53   Handle<BytecodeArray> MakeBytecodeForFunction(const char* function) {
54     ScopedVector<char> program(1024);
55     SNPrintF(program, "%s\n%s();", function, kFunctionName);
56     return MakeBytecode(program.start(), kFunctionName);
57   }
58 };
59
60
61 // Helper macros for handcrafting bytecode sequences.
62 #define B(x) static_cast<uint8_t>(Bytecode::k##x)
63 #define U8(x) static_cast<uint8_t>((x) & 0xff)
64 #define R(x) static_cast<uint8_t>(-(x) & 0xff)
65 #define _ static_cast<uint8_t>(0x5a)
66
67
68 // Structure for containing expected bytecode snippets.
69 template<typename T>
70 struct ExpectedSnippet {
71   const char* code_snippet;
72   int frame_size;
73   int parameter_count;
74   int bytecode_length;
75   const uint8_t bytecode[512];
76   int constant_count;
77   T constants[4];
78 };
79
80
81 static void CheckConstant(int expected, Object* actual) {
82   CHECK_EQ(expected, Smi::cast(actual)->value());
83 }
84
85
86 static void CheckConstant(double expected, Object* actual) {
87   CHECK_EQ(expected, HeapNumber::cast(actual)->value());
88 }
89
90
91 static void CheckConstant(const char* expected, Object* actual) {
92   Handle<String> expected_string =
93       CcTest::i_isolate()->factory()->NewStringFromAsciiChecked(expected);
94   CHECK(String::cast(actual)->Equals(*expected_string));
95 }
96
97
98 static void CheckConstant(Handle<Object> expected, Object* actual) {
99   CHECK(actual == *expected || expected->StrictEquals(actual));
100 }
101
102
103 template <typename T>
104 static void CheckBytecodeArrayEqual(struct ExpectedSnippet<T> expected,
105                                     Handle<BytecodeArray> actual,
106                                     bool has_unknown = false) {
107   CHECK_EQ(actual->frame_size(), expected.frame_size);
108   CHECK_EQ(actual->parameter_count(), expected.parameter_count);
109   CHECK_EQ(actual->length(), expected.bytecode_length);
110   if (expected.constant_count == 0) {
111     CHECK_EQ(actual->constant_pool(), CcTest::heap()->empty_fixed_array());
112   } else {
113     CHECK_EQ(actual->constant_pool()->length(), expected.constant_count);
114     for (int i = 0; i < expected.constant_count; i++) {
115       CheckConstant(expected.constants[i], actual->constant_pool()->get(i));
116     }
117   }
118
119   BytecodeArrayIterator iterator(actual);
120   int i = 0;
121   while (!iterator.done()) {
122     int bytecode_index = i++;
123     Bytecode bytecode = iterator.current_bytecode();
124     if (Bytecodes::ToByte(bytecode) != expected.bytecode[bytecode_index]) {
125       std::ostringstream stream;
126       stream << "Check failed: expected bytecode [" << bytecode_index
127              << "] to be " << Bytecodes::ToString(static_cast<Bytecode>(
128                                   expected.bytecode[bytecode_index]))
129              << " but got " << Bytecodes::ToString(bytecode);
130       FATAL(stream.str().c_str());
131     }
132     for (int j = 0; j < Bytecodes::NumberOfOperands(bytecode); ++j, ++i) {
133       uint8_t raw_operand =
134           iterator.GetRawOperand(j, Bytecodes::GetOperandType(bytecode, j));
135       if (has_unknown) {
136         // Check actual bytecode array doesn't have the same byte as the
137         // one we use to specify an unknown byte.
138         CHECK_NE(raw_operand, _);
139         if (expected.bytecode[i] == _) {
140           continue;
141         }
142       }
143       if (raw_operand != expected.bytecode[i]) {
144         std::ostringstream stream;
145         stream << "Check failed: expected operand [" << j << "] for bytecode ["
146                << bytecode_index << "] to be "
147                << static_cast<unsigned int>(expected.bytecode[i]) << " but got "
148                << static_cast<unsigned int>(raw_operand);
149         FATAL(stream.str().c_str());
150       }
151     }
152     iterator.Advance();
153   }
154 }
155
156
157 TEST(PrimitiveReturnStatements) {
158   InitializedHandleScope handle_scope;
159   BytecodeGeneratorHelper helper;
160
161   ExpectedSnippet<int> snippets[] = {
162       {"", 0, 1, 2, {B(LdaUndefined), B(Return)}, 0},
163       {"return;", 0, 1, 2, {B(LdaUndefined), B(Return)}, 0},
164       {"return null;", 0, 1, 2, {B(LdaNull), B(Return)}, 0},
165       {"return true;", 0, 1, 2, {B(LdaTrue), B(Return)}, 0},
166       {"return false;", 0, 1, 2, {B(LdaFalse), B(Return)}, 0},
167       {"return 0;", 0, 1, 2, {B(LdaZero), B(Return)}, 0},
168       {"return +1;", 0, 1, 3, {B(LdaSmi8), U8(1), B(Return)}, 0},
169       {"return -1;", 0, 1, 3, {B(LdaSmi8), U8(-1), B(Return)}, 0},
170       {"return +127;", 0, 1, 3, {B(LdaSmi8), U8(127), B(Return)}, 0},
171       {"return -128;", 0, 1, 3, {B(LdaSmi8), U8(-128), B(Return)}, 0},
172   };
173
174   for (size_t i = 0; i < arraysize(snippets); i++) {
175     Handle<BytecodeArray> bytecode_array =
176         helper.MakeBytecodeForFunctionBody(snippets[i].code_snippet);
177     CheckBytecodeArrayEqual(snippets[i], bytecode_array);
178   }
179 }
180
181
182 TEST(PrimitiveExpressions) {
183   InitializedHandleScope handle_scope;
184   BytecodeGeneratorHelper helper;
185
186   ExpectedSnippet<int> snippets[] = {
187       {"var x = 0; return x;",
188        kPointerSize,
189        1,
190        6,
191        {
192            B(LdaZero),     //
193            B(Star), R(0),  //
194            B(Ldar), R(0),  //
195            B(Return)       //
196        },
197        0
198       },
199       {"var x = 0; return x + 3;",
200        2 * kPointerSize,
201        1,
202        12,
203        {
204            B(LdaZero),         //
205            B(Star), R(0),      //
206            B(Ldar), R(0),      // Easy to spot r1 not really needed here.
207            B(Star), R(1),      // Dead store.
208            B(LdaSmi8), U8(3),  //
209            B(Add), R(1),       //
210            B(Return)           //
211        },
212        0
213      }};
214
215   for (size_t i = 0; i < arraysize(snippets); i++) {
216     Handle<BytecodeArray> bytecode_array =
217         helper.MakeBytecodeForFunctionBody(snippets[i].code_snippet);
218     CheckBytecodeArrayEqual(snippets[i], bytecode_array);
219   }
220 }
221
222
223 TEST(Parameters) {
224   InitializedHandleScope handle_scope;
225   BytecodeGeneratorHelper helper;
226
227   ExpectedSnippet<int> snippets[] = {
228       {"function f() { return this; }",
229        0, 1, 3, {B(Ldar), R(helper.kLastParamIndex), B(Return)}, 0},
230       {"function f(arg1) { return arg1; }",
231        0, 2, 3, {B(Ldar), R(helper.kLastParamIndex), B(Return)}, 0},
232       {"function f(arg1) { return this; }",
233        0, 2, 3, {B(Ldar), R(helper.kLastParamIndex - 1), B(Return)}, 0},
234       {"function f(arg1, arg2, arg3, arg4, arg5, arg6, arg7) { return arg4; }",
235        0, 8, 3, {B(Ldar), R(helper.kLastParamIndex - 3), B(Return)}, 0},
236       {"function f(arg1, arg2, arg3, arg4, arg5, arg6, arg7) { return this; }",
237        0, 8, 3, {B(Ldar), R(helper.kLastParamIndex - 7), B(Return)}, 0}
238   };
239
240   for (size_t i = 0; i < arraysize(snippets); i++) {
241     Handle<BytecodeArray> bytecode_array =
242         helper.MakeBytecodeForFunction(snippets[i].code_snippet);
243     CheckBytecodeArrayEqual(snippets[i], bytecode_array);
244   }
245 }
246
247
248 TEST(IntegerConstants) {
249   InitializedHandleScope handle_scope;
250   BytecodeGeneratorHelper helper;
251
252   ExpectedSnippet<int> snippets[] = {
253     {"return 12345678;",
254      0,
255      1,
256      3,
257      {
258        B(LdaConstant), U8(0),  //
259        B(Return)               //
260      },
261      1,
262      {12345678}},
263     {"var a = 1234; return 5678;",
264      1 * kPointerSize,
265      1,
266      7,
267      {
268        B(LdaConstant), U8(0),  //
269        B(Star), R(0),          //
270        B(LdaConstant), U8(1),  //
271        B(Return)               //
272      },
273      2,
274      {1234, 5678}},
275     {"var a = 1234; return 1234;",
276      1 * kPointerSize,
277      1,
278      7,
279      {
280        B(LdaConstant), U8(0),  //
281        B(Star), R(0),          //
282        B(LdaConstant), U8(0),  //
283        B(Return)               //
284      },
285      1,
286      {1234}}};
287
288   for (size_t i = 0; i < arraysize(snippets); i++) {
289     Handle<BytecodeArray> bytecode_array =
290         helper.MakeBytecodeForFunctionBody(snippets[i].code_snippet);
291     CheckBytecodeArrayEqual(snippets[i], bytecode_array);
292   }
293 }
294
295
296 TEST(HeapNumberConstants) {
297   InitializedHandleScope handle_scope;
298   BytecodeGeneratorHelper helper;
299
300   ExpectedSnippet<double> snippets[] = {
301     {"return 1.2;",
302      0,
303      1,
304      3,
305      {
306        B(LdaConstant), U8(0),  //
307        B(Return)               //
308      },
309      1,
310      {1.2}},
311     {"var a = 1.2; return 2.6;",
312      1 * kPointerSize,
313      1,
314      7,
315      {
316        B(LdaConstant), U8(0),  //
317        B(Star), R(0),          //
318        B(LdaConstant), U8(1),  //
319        B(Return)               //
320      },
321      2,
322      {1.2, 2.6}},
323     {"var a = 3.14; return 3.14;",
324      1 * kPointerSize,
325      1,
326      7,
327      {
328        B(LdaConstant), U8(0),  //
329        B(Star), R(0),          //
330        B(LdaConstant), U8(1),  //
331        B(Return)               //
332      },
333      2,
334      {3.14, 3.14}}};
335   for (size_t i = 0; i < arraysize(snippets); i++) {
336     Handle<BytecodeArray> bytecode_array =
337         helper.MakeBytecodeForFunctionBody(snippets[i].code_snippet);
338     CheckBytecodeArrayEqual(snippets[i], bytecode_array);
339   }
340 }
341
342
343 TEST(StringConstants) {
344   InitializedHandleScope handle_scope;
345   BytecodeGeneratorHelper helper;
346
347   ExpectedSnippet<const char*> snippets[] = {
348       {"return \"This is a string\";",
349        0,
350        1,
351        3,
352        {
353            B(LdaConstant), U8(0),  //
354            B(Return)               //
355        },
356        1,
357        {"This is a string"}},
358       {"var a = \"First string\"; return \"Second string\";",
359        1 * kPointerSize,
360        1,
361        7,
362        {
363            B(LdaConstant), U8(0),  //
364            B(Star), R(0),          //
365            B(LdaConstant), U8(1),  //
366            B(Return)               //
367        },
368        2,
369        {"First string", "Second string"}},
370       {"var a = \"Same string\"; return \"Same string\";",
371        1 * kPointerSize,
372        1,
373        7,
374        {
375            B(LdaConstant), U8(0),  //
376            B(Star), R(0),          //
377            B(LdaConstant), U8(0),  //
378            B(Return)               //
379        },
380        1,
381        {"Same string"}}};
382
383   for (size_t i = 0; i < arraysize(snippets); i++) {
384     Handle<BytecodeArray> bytecode_array =
385         helper.MakeBytecodeForFunctionBody(snippets[i].code_snippet);
386     CheckBytecodeArrayEqual(snippets[i], bytecode_array);
387   }
388 }
389
390
391 TEST(PropertyLoads) {
392   InitializedHandleScope handle_scope;
393   BytecodeGeneratorHelper helper;
394
395   FeedbackVectorSlotKind ic_kinds[] = {i::FeedbackVectorSlotKind::LOAD_IC,
396                                        i::FeedbackVectorSlotKind::LOAD_IC};
397   StaticFeedbackVectorSpec feedback_spec(0, 2, ic_kinds);
398   Handle<i::TypeFeedbackVector> vector =
399       helper.factory()->NewTypeFeedbackVector(&feedback_spec);
400
401   ExpectedSnippet<const char*> snippets[] = {
402       {"function f(a) { return a.name; }\nf({name : \"test\"})",
403        1 * kPointerSize,
404        2,
405        10,
406        {
407            B(Ldar), R(helper.kLastParamIndex),                  //
408            B(Star), R(0),                                       //
409            B(LdaConstant), U8(0),                               //
410            B(LoadIC), R(0), U8(vector->first_ic_slot_index()),  //
411            B(Return)                                            //
412        },
413        1,
414        {"name"}},
415       {"function f(a) { return a[\"key\"]; }\nf({key : \"test\"})",
416        1 * kPointerSize,
417        2,
418        10,
419        {
420            B(Ldar), R(helper.kLastParamIndex),                  //
421            B(Star), R(0),                                       //
422            B(LdaConstant), U8(0),                               //
423            B(LoadIC), R(0), U8(vector->first_ic_slot_index()),  //
424            B(Return)                                            //
425        },
426        1,
427        {"key"}},
428       {"function f(a) { return a[100]; }\nf({100 : \"test\"})",
429        1 * kPointerSize,
430        2,
431        10,
432        {
433            B(Ldar), R(helper.kLastParamIndex),                       //
434            B(Star), R(0),                                            //
435            B(LdaSmi8), U8(100),                                      //
436            B(KeyedLoadIC), R(0), U8(vector->first_ic_slot_index()),  //
437            B(Return)                                                 //
438        },
439        0},
440       {"function f(a, b) { return a[b]; }\nf({arg : \"test\"}, \"arg\")",
441        1 * kPointerSize,
442        3,
443        10,
444        {
445            B(Ldar), R(helper.kLastParamIndex - 1),                   //
446            B(Star), R(0),                                            //
447            B(Ldar), R(helper.kLastParamIndex),                       //
448            B(KeyedLoadIC), R(0), U8(vector->first_ic_slot_index()),  //
449            B(Return)                                                 //
450        },
451        0},
452       {"function f(a) { var b = a.name; return a[-124]; }\n"
453        "f({\"-124\" : \"test\", name : 123 })",
454        2 * kPointerSize,
455        2,
456        21,
457        {
458            B(Ldar), R(helper.kLastParamIndex),                           //
459            B(Star), R(1),                                                //
460            B(LdaConstant), U8(0),                                        //
461            B(LoadIC), R(1), U8(vector->first_ic_slot_index()),           //
462            B(Star), R(0),                                                //
463            B(Ldar), R(helper.kLastParamIndex),                           //
464            B(Star), R(1),                                                //
465            B(LdaSmi8), U8(-124),                                         //
466            B(KeyedLoadIC), R(1), U8(vector->first_ic_slot_index() + 2),  //
467            B(Return)                                                     //
468        },
469        1,
470        {"name"}}};
471   for (size_t i = 0; i < arraysize(snippets); i++) {
472     Handle<BytecodeArray> bytecode_array =
473         helper.MakeBytecode(snippets[i].code_snippet, helper.kFunctionName);
474     CheckBytecodeArrayEqual(snippets[i], bytecode_array);
475   }
476 }
477
478
479 TEST(PropertyStores) {
480   InitializedHandleScope handle_scope;
481   BytecodeGeneratorHelper helper;
482
483   FeedbackVectorSlotKind ic_kinds[] = {i::FeedbackVectorSlotKind::STORE_IC,
484                                        i::FeedbackVectorSlotKind::STORE_IC};
485   StaticFeedbackVectorSpec feedback_spec(0, 2, ic_kinds);
486   Handle<i::TypeFeedbackVector> vector =
487       helper.factory()->NewTypeFeedbackVector(&feedback_spec);
488
489   ExpectedSnippet<const char*> snippets[] = {
490       {"function f(a) { a.name = \"val\"; }\nf({name : \"test\"})",
491        2 * kPointerSize,
492        2,
493        16,
494        {
495            B(Ldar), R(helper.kLastParamIndex),                         //
496            B(Star), R(0),                                              //
497            B(LdaConstant), U8(0),                                      //
498            B(Star), R(1),                                              //
499            B(LdaConstant), U8(1),                                      //
500            B(StoreIC), R(0), R(1), U8(vector->first_ic_slot_index()),  //
501            B(LdaUndefined),                                            //
502            B(Return)                                                   //
503        },
504        2,
505        {"name", "val"}},
506       {"function f(a) { a[\"key\"] = \"val\"; }\nf({key : \"test\"})",
507        2 * kPointerSize,
508        2,
509        16,
510        {
511            B(Ldar), R(helper.kLastParamIndex),                         //
512            B(Star), R(0),                                              //
513            B(LdaConstant), U8(0),                                      //
514            B(Star), R(1),                                              //
515            B(LdaConstant), U8(1),                                      //
516            B(StoreIC), R(0), R(1), U8(vector->first_ic_slot_index()),  //
517            B(LdaUndefined),                                            //
518            B(Return)                                                   //
519        },
520        2,
521        {"key", "val"}},
522       {"function f(a) { a[100] = \"val\"; }\nf({100 : \"test\"})",
523        2 * kPointerSize,
524        2,
525        16,
526        {
527            B(Ldar), R(helper.kLastParamIndex),                              //
528            B(Star), R(0),                                                   //
529            B(LdaSmi8), U8(100),                                             //
530            B(Star), R(1),                                                   //
531            B(LdaConstant), U8(0),                                           //
532            B(KeyedStoreIC), R(0), R(1), U8(vector->first_ic_slot_index()),  //
533            B(LdaUndefined),                                                 //
534            B(Return)                                                        //
535        },
536        1,
537        {"val"}},
538       {"function f(a, b) { a[b] = \"val\"; }\nf({arg : \"test\"}, \"arg\")",
539        2 * kPointerSize,
540        3,
541        16,
542        {
543            B(Ldar), R(helper.kLastParamIndex - 1),                          //
544            B(Star), R(0),                                                   //
545            B(Ldar), R(helper.kLastParamIndex),                              //
546            B(Star), R(1),                                                   //
547            B(LdaConstant), U8(0),                                           //
548            B(KeyedStoreIC), R(0), R(1), U8(vector->first_ic_slot_index()),  //
549            B(LdaUndefined),                                                 //
550            B(Return)                                                        //
551        },
552        1,
553        {"val"}},
554       {"function f(a) { a.name = a[-124]; }\n"
555        "f({\"-124\" : \"test\", name : 123 })",
556        3 * kPointerSize,
557        2,
558        23,
559        {
560            B(Ldar), R(helper.kLastParamIndex),                             //
561            B(Star), R(0),                                                  //
562            B(LdaConstant), U8(0),                                          //
563            B(Star), R(1),                                                  //
564            B(Ldar), R(helper.kLastParamIndex),                             //
565            B(Star), R(2),                                                  //
566            B(LdaSmi8), U8(-124),                                           //
567            B(KeyedLoadIC), R(2), U8(vector->first_ic_slot_index()),        //
568            B(StoreIC), R(0), R(1), U8(vector->first_ic_slot_index() + 2),  //
569            B(LdaUndefined),                                                //
570            B(Return)                                                       //
571        },
572        1,
573        {"name"}}};
574   for (size_t i = 0; i < arraysize(snippets); i++) {
575     Handle<BytecodeArray> bytecode_array =
576         helper.MakeBytecode(snippets[i].code_snippet, helper.kFunctionName);
577     CheckBytecodeArrayEqual(snippets[i], bytecode_array);
578   }
579 }
580
581
582 #define FUNC_ARG "new (function Obj() { this.func = function() { return; }})()"
583
584
585 TEST(PropertyCall) {
586   InitializedHandleScope handle_scope;
587   BytecodeGeneratorHelper helper;  //
588
589   FeedbackVectorSlotKind ic_kinds[] = {i::FeedbackVectorSlotKind::LOAD_IC,
590                                        i::FeedbackVectorSlotKind::LOAD_IC};
591   StaticFeedbackVectorSpec feedback_spec(0, 2, ic_kinds);
592   Handle<i::TypeFeedbackVector> vector =
593       helper.factory()->NewTypeFeedbackVector(&feedback_spec);
594
595   ExpectedSnippet<const char*> snippets[] = {
596       {"function f(a) { return a.func(); }\nf(" FUNC_ARG ")",
597        2 * kPointerSize,
598        2,
599        16,
600        {
601            B(Ldar), R(helper.kLastParamIndex),                      //
602            B(Star), R(1),                                           //
603            B(LdaConstant), U8(0),                                   //
604            B(LoadIC), R(1), U8(vector->first_ic_slot_index() + 2),  //
605            B(Star), R(0),                                           //
606            B(Call), R(0), R(1), U8(0),                              //
607            B(Return)                                                //
608        },
609        1,
610        {"func"}},
611       {"function f(a, b, c) { return a.func(b, c); }\nf(" FUNC_ARG ", 1, 2)",
612        4 * kPointerSize,
613        4,
614        24,
615        {
616            B(Ldar), R(helper.kLastParamIndex - 2),                  //
617            B(Star), R(1),                                           //
618            B(LdaConstant), U8(0),                                   //
619            B(LoadIC), R(1), U8(vector->first_ic_slot_index() + 2),  //
620            B(Star), R(0),                                           //
621            B(Ldar), R(helper.kLastParamIndex - 1),                  //
622            B(Star), R(2),                                           //
623            B(Ldar), R(helper.kLastParamIndex),                      //
624            B(Star), R(3),                                           //
625            B(Call), R(0), R(1), U8(2),                              //
626            B(Return)                                                //
627        },
628        1,
629        {"func"}},
630       {"function f(a, b) { return a.func(b + b, b); }\nf(" FUNC_ARG ", 1)",
631        4 * kPointerSize,
632        3,
633        30,
634        {
635            B(Ldar), R(helper.kLastParamIndex - 1),                  //
636            B(Star), R(1),                                           //
637            B(LdaConstant), U8(0),                                   //
638            B(LoadIC), R(1), U8(vector->first_ic_slot_index() + 2),  //
639            B(Star), R(0),                                           //
640            B(Ldar), R(helper.kLastParamIndex),                      //
641            B(Star), R(2),                                           //
642            B(Ldar), R(helper.kLastParamIndex),                      //
643            B(Add), R(2),                                            //
644            B(Star), R(2),                                           //
645            B(Ldar), R(helper.kLastParamIndex),                      //
646            B(Star), R(3),                                           //
647            B(Call), R(0), R(1), U8(2),                              //
648            B(Return)                                                //
649        },
650        1,
651        {"func"}}};
652   for (size_t i = 0; i < arraysize(snippets); i++) {
653     Handle<BytecodeArray> bytecode_array =
654         helper.MakeBytecode(snippets[i].code_snippet, helper.kFunctionName);
655     CheckBytecodeArrayEqual(snippets[i], bytecode_array);
656   }
657 }
658
659
660 TEST(LoadGlobal) {
661   InitializedHandleScope handle_scope;
662   BytecodeGeneratorHelper helper;
663
664   ExpectedSnippet<const char*> snippets[] = {
665       {"var a = 1;\nfunction f() { return a; }\nf()",
666        0, 1, 3,
667        {
668           B(LdaGlobal), _,
669           B(Return)
670        },
671       },
672       {"function t() { }\nfunction f() { return t; }\nf()",
673        0, 1, 3,
674        {
675           B(LdaGlobal), _,
676           B(Return)
677        },
678       },
679   };
680
681   for (size_t i = 0; i < arraysize(snippets); i++) {
682     Handle<BytecodeArray> bytecode_array =
683         helper.MakeBytecode(snippets[i].code_snippet, "f");
684     CheckBytecodeArrayEqual(snippets[i], bytecode_array, true);
685   }
686 }
687
688
689 TEST(CallGlobal) {
690   InitializedHandleScope handle_scope;
691   BytecodeGeneratorHelper helper;
692
693   ExpectedSnippet<const char*> snippets[] = {
694       {"function t() { }\nfunction f() { return t(); }\nf()",
695        2 * kPointerSize, 1, 12,
696        {
697           B(LdaUndefined),
698           B(Star), R(1),
699           B(LdaGlobal), _,
700           B(Star), R(0),
701           B(Call), R(0), R(1), U8(0),
702           B(Return)
703        },
704       },
705       {"function t(a, b, c) { }\nfunction f() { return t(1, 2, 3); }\nf()",
706        5 * kPointerSize, 1, 24,
707        {
708           B(LdaUndefined),
709           B(Star), R(1),
710           B(LdaGlobal), _,
711           B(Star), R(0),
712           B(LdaSmi8), U8(1),
713           B(Star), R(2),
714           B(LdaSmi8), U8(2),
715           B(Star), R(3),
716           B(LdaSmi8), U8(3),
717           B(Star), R(4),
718           B(Call), R(0), R(1), U8(3),
719           B(Return)
720        },
721       },
722   };
723
724   for (size_t i = 0; i < arraysize(snippets); i++) {
725     Handle<BytecodeArray> bytecode_array =
726         helper.MakeBytecode(snippets[i].code_snippet, "f");
727     CheckBytecodeArrayEqual(snippets[i], bytecode_array, true);
728   }
729 }
730
731
732 TEST(IfConditions) {
733   InitializedHandleScope handle_scope;
734   BytecodeGeneratorHelper helper;
735
736   Handle<Object> unused = helper.factory()->undefined_value();
737
738   ExpectedSnippet<Handle<Object>> snippets[] = {
739       {"function f() { if (0) { return 1; } else { return -1; } } f()",
740        0,
741        1,
742        14,
743        {B(LdaZero),             //
744         B(ToBoolean),           //
745         B(JumpIfFalse), U8(7),  //
746         B(LdaSmi8), U8(1),      //
747         B(Return),              //
748         B(Jump), U8(5),         // TODO(oth): Unreachable jump after return
749         B(LdaSmi8), U8(-1),     //
750         B(Return),              //
751         B(LdaUndefined),        //
752         B(Return)},             //
753        0,
754        {unused, unused, unused, unused}},
755       {"function f() { if ('lucky') { return 1; } else { return -1; } } f();",
756        0,
757        1,
758        15,
759        {B(LdaConstant), U8(0),  //
760         B(ToBoolean),           //
761         B(JumpIfFalse), U8(7),  //
762         B(LdaSmi8), U8(1),      //
763         B(Return),              //
764         B(Jump), U8(5),         // TODO(oth): Unreachable jump after return
765         B(LdaSmi8), U8(-1),     //
766         B(Return),              //
767         B(LdaUndefined),        //
768         B(Return)},             //
769        1,
770        {helper.factory()->NewStringFromStaticChars("lucky"), unused, unused,
771         unused}},
772       {"function f() { if (false) { return 1; } else { return -1; } } f();",
773        0,
774        1,
775        13,
776        {B(LdaFalse),            //
777         B(JumpIfFalse), U8(7),  //
778         B(LdaSmi8), U8(1),      //
779         B(Return),              //
780         B(Jump), U8(5),         // TODO(oth): Unreachable jump after return
781         B(LdaSmi8), U8(-1),     //
782         B(Return),              //
783         B(LdaUndefined),        //
784         B(Return)},             //
785        0,
786        {unused, unused, unused, unused}},
787       {"function f(a) { if (a <= 0) { return 200; } else { return -200; } }"
788        "f(99);",
789        kPointerSize,
790        2,
791        19,
792        {B(Ldar), R(-5),                //
793         B(Star), R(0),                 //
794         B(LdaZero),                    //
795         B(TestLessThanOrEqual), R(0),  //
796         B(JumpIfFalse), U8(7),         //
797         B(LdaConstant), U8(0),         //
798         B(Return),                     //
799         B(Jump), U8(5),         // TODO(oth): Unreachable jump after return
800         B(LdaConstant), U8(1),  //
801         B(Return),              //
802         B(LdaUndefined),        //
803         B(Return)},             //
804        2,
805        {helper.factory()->NewNumberFromInt(200),
806         helper.factory()->NewNumberFromInt(-200), unused, unused}},
807       {"function f(a, b) { if (a in b) { return 200; } }"
808        "f('prop', { prop: 'yes'});",
809        kPointerSize,
810        3,
811        17,
812        {B(Ldar), R(-6),         //
813         B(Star), R(0),          //
814         B(Ldar), R(-5),         //
815         B(TestIn), R(0),        //
816         B(JumpIfFalse), U8(7),  //
817         B(LdaConstant), U8(0),  //
818         B(Return),              //
819         B(Jump), U8(2),         // TODO(oth): Unreachable jump after return
820         B(LdaUndefined),        //
821         B(Return)},             //
822        1,
823        {helper.factory()->NewNumberFromInt(200), unused, unused, unused}},
824       {"function f(z) { var a = 0; var b = 0; if (a === 0.01) { "
825 #define X "b = a; a = b; "
826        X X X X X X X X X X X X X X X X X X X X X X X X
827 #undef X
828        " return 200; } else { return -200; } } f(0.001)",
829        3 * kPointerSize,
830        2,
831        218,
832        {B(LdaZero),                     //
833         B(Star), R(0),                  //
834         B(LdaZero),                     //
835         B(Star), R(1),                  //
836         B(Ldar), R(0),                  //
837         B(Star), R(2),                  //
838         B(LdaConstant), U8(0),          //
839         B(TestEqualStrict), R(2),       //
840         B(JumpIfFalseConstant), U8(2),  //
841 #define X B(Ldar), R(0), B(Star), R(1), B(Ldar), R(1), B(Star), R(0),
842         X X X X X X X X X X X X X X X X X X X X X X X X
843 #undef X
844             B(LdaConstant),
845         U8(1),                  //
846         B(Return),              //
847         B(Jump), U8(5),         // TODO(oth): Unreachable jump after return
848         B(LdaConstant), U8(3),  //
849         B(Return),              //
850         B(LdaUndefined),        //
851         B(Return)},             //
852        4,
853        {helper.factory()->NewHeapNumber(0.01),
854         helper.factory()->NewNumberFromInt(200),
855         helper.factory()->NewNumberFromInt(199),
856         helper.factory()->NewNumberFromInt(-200)}},
857       {"function f(a, b) {\n"
858        "  if (a == b) { return 1; }\n"
859        "  if (a === b) { return 1; }\n"
860        "  if (a < b) { return 1; }\n"
861        "  if (a > b) { return 1; }\n"
862        "  if (a <= b) { return 1; }\n"
863        "  if (a >= b) { return 1; }\n"
864        "  if (a in b) { return 1; }\n"
865        "  if (a instanceof b) { return 1; }\n"
866        "  /* if (a != b) { return 1; } */"   // TODO(oth) Ast visitor yields
867        "  /* if (a !== b) { return 1; } */"  // UNARY NOT, rather than !=/!==.
868        "  return 0;\n"
869        "} f(1, 1);",
870        kPointerSize,
871        3,
872        122,
873        {
874 #define IF_CONDITION_RETURN(condition) \
875   B(Ldar), R(-6),                      \
876   B(Star), R(0),                       \
877   B(Ldar), R(-5),                      \
878   B(condition), R(0),                  \
879   B(JumpIfFalse), U8(7),               \
880   B(LdaSmi8), U8(1),                   \
881   B(Return),                           \
882   B(Jump), U8(2),
883            IF_CONDITION_RETURN(TestEqual)               //
884            IF_CONDITION_RETURN(TestEqualStrict)         //
885            IF_CONDITION_RETURN(TestLessThan)            //
886            IF_CONDITION_RETURN(TestGreaterThan)         //
887            IF_CONDITION_RETURN(TestLessThanOrEqual)     //
888            IF_CONDITION_RETURN(TestGreaterThanOrEqual)  //
889            IF_CONDITION_RETURN(TestIn)                  //
890            IF_CONDITION_RETURN(TestInstanceOf)          //
891 #undef IF_CONDITION_RETURN
892            B(LdaZero),  //
893            B(Return)},  //
894        0,
895        {unused, unused, unused, unused}},
896   };
897
898   for (size_t i = 0; i < arraysize(snippets); i++) {
899     Handle<BytecodeArray> bytecode_array =
900         helper.MakeBytecode(snippets[i].code_snippet, helper.kFunctionName);
901     CheckBytecodeArrayEqual(snippets[i], bytecode_array);
902   }
903 }
904
905
906 }  // namespace interpreter
907 }  // namespace internal
908 }  // namespance v8