Home | History | Annotate | Download | only in interpreter
      1 // Copyright 2014 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/interpreter/bytecode-array-builder.h"
      8 #include "src/interpreter/bytecode-array-iterator.h"
      9 #include "src/interpreter/bytecode-register-allocator.h"
     10 #include "test/unittests/test-utils.h"
     11 
     12 namespace v8 {
     13 namespace internal {
     14 namespace interpreter {
     15 
     16 class BytecodeArrayBuilderTest : public TestWithIsolateAndZone {
     17  public:
     18   BytecodeArrayBuilderTest() {}
     19   ~BytecodeArrayBuilderTest() override {}
     20 };
     21 
     22 
     23 TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) {
     24   BytecodeArrayBuilder builder(isolate(), zone());
     25 
     26   builder.set_locals_count(200);
     27   builder.set_context_count(1);
     28   builder.set_parameter_count(0);
     29   CHECK_EQ(builder.locals_count(), 200);
     30   CHECK_EQ(builder.context_count(), 1);
     31   CHECK_EQ(builder.fixed_register_count(), 201);
     32 
     33   // Emit constant loads.
     34   builder.LoadLiteral(Smi::FromInt(0))
     35       .LoadLiteral(Smi::FromInt(8))
     36       .LoadLiteral(Smi::FromInt(10000000))
     37       .LoadUndefined()
     38       .LoadNull()
     39       .LoadTheHole()
     40       .LoadTrue()
     41       .LoadFalse();
     42 
     43   // Emit accumulator transfers. Stores followed by loads to the same register
     44   // are not generated. Hence, a dummy instruction in between.
     45   Register reg(0);
     46   builder.LoadAccumulatorWithRegister(reg)
     47       .LoadNull()
     48       .StoreAccumulatorInRegister(reg);
     49 
     50   // Emit register-register transfer.
     51   Register other(1);
     52   builder.MoveRegister(reg, other);
     53 
     54   // Emit register-register exchanges.
     55   Register wide(150);
     56   builder.ExchangeRegisters(reg, wide);
     57   builder.ExchangeRegisters(wide, reg);
     58   Register wider(151);
     59   builder.ExchangeRegisters(wide, wider);
     60 
     61   // Emit global load / store operations.
     62   Factory* factory = isolate()->factory();
     63   Handle<String> name = factory->NewStringFromStaticChars("var_name");
     64   builder.LoadGlobal(name, 1, LanguageMode::SLOPPY,
     65                      TypeofMode::NOT_INSIDE_TYPEOF)
     66       .LoadGlobal(name, 1, LanguageMode::STRICT, TypeofMode::NOT_INSIDE_TYPEOF)
     67       .LoadGlobal(name, 1, LanguageMode::SLOPPY, TypeofMode::INSIDE_TYPEOF)
     68       .LoadGlobal(name, 1, LanguageMode::STRICT, TypeofMode::INSIDE_TYPEOF)
     69       .StoreGlobal(name, 1, LanguageMode::SLOPPY)
     70       .StoreGlobal(name, 1, LanguageMode::STRICT);
     71 
     72   // Emit context operations.
     73   builder.PushContext(reg)
     74       .PopContext(reg)
     75       .LoadContextSlot(reg, 1)
     76       .StoreContextSlot(reg, 1);
     77 
     78   // Emit load / store property operations.
     79   builder.LoadNamedProperty(reg, name, 0, LanguageMode::SLOPPY)
     80       .LoadKeyedProperty(reg, 0, LanguageMode::SLOPPY)
     81       .StoreNamedProperty(reg, name, 0, LanguageMode::SLOPPY)
     82       .StoreKeyedProperty(reg, reg, 0, LanguageMode::SLOPPY)
     83       .LoadNamedProperty(reg, name, 0, LanguageMode::STRICT)
     84       .LoadKeyedProperty(reg, 0, LanguageMode::STRICT)
     85       .StoreNamedProperty(reg, name, 0, LanguageMode::STRICT)
     86       .StoreKeyedProperty(reg, reg, 0, LanguageMode::STRICT);
     87 
     88   // Emit load / store lookup slots.
     89   builder.LoadLookupSlot(name, TypeofMode::NOT_INSIDE_TYPEOF)
     90       .LoadLookupSlot(name, TypeofMode::INSIDE_TYPEOF)
     91       .StoreLookupSlot(name, LanguageMode::SLOPPY)
     92       .StoreLookupSlot(name, LanguageMode::STRICT);
     93 
     94   // Emit closure operations.
     95   Handle<SharedFunctionInfo> shared_info = factory->NewSharedFunctionInfo(
     96       factory->NewStringFromStaticChars("function_a"), MaybeHandle<Code>(),
     97       false);
     98   builder.CreateClosure(shared_info, NOT_TENURED);
     99 
    100   // Emit argument creation operations.
    101   builder.CreateArguments(CreateArgumentsType::kMappedArguments)
    102       .CreateArguments(CreateArgumentsType::kUnmappedArguments);
    103 
    104   // Emit literal creation operations.
    105   builder.CreateRegExpLiteral(factory->NewStringFromStaticChars("a"), 0, 0)
    106       .CreateArrayLiteral(factory->NewFixedArray(1), 0, 0)
    107       .CreateObjectLiteral(factory->NewFixedArray(1), 0, 0);
    108 
    109   // Call operations.
    110   builder.Call(reg, reg, 0, 0)
    111       .Call(reg, reg, 0, 1024)
    112       .CallRuntime(Runtime::kIsArray, reg, 1)
    113       .CallRuntimeForPair(Runtime::kLoadLookupSlot, reg, 1, reg)
    114       .CallJSRuntime(Context::SPREAD_ITERABLE_INDEX, reg, 1);
    115 
    116   // Emit binary operator invocations.
    117   builder.BinaryOperation(Token::Value::ADD, reg, Strength::WEAK)
    118       .BinaryOperation(Token::Value::SUB, reg, Strength::WEAK)
    119       .BinaryOperation(Token::Value::MUL, reg, Strength::WEAK)
    120       .BinaryOperation(Token::Value::DIV, reg, Strength::WEAK)
    121       .BinaryOperation(Token::Value::MOD, reg, Strength::WEAK);
    122 
    123   // Emit bitwise operator invocations
    124   builder.BinaryOperation(Token::Value::BIT_OR, reg, Strength::WEAK)
    125       .BinaryOperation(Token::Value::BIT_XOR, reg, Strength::WEAK)
    126       .BinaryOperation(Token::Value::BIT_AND, reg, Strength::WEAK);
    127 
    128   // Emit shift operator invocations
    129   builder.BinaryOperation(Token::Value::SHL, reg, Strength::WEAK)
    130       .BinaryOperation(Token::Value::SAR, reg, Strength::WEAK)
    131       .BinaryOperation(Token::Value::SHR, reg, Strength::WEAK);
    132 
    133   // Emit count operatior invocations
    134   builder.CountOperation(Token::Value::ADD, Strength::WEAK)
    135       .CountOperation(Token::Value::SUB, Strength::WEAK);
    136 
    137   // Emit unary operator invocations.
    138   builder.LogicalNot().TypeOf();
    139 
    140   // Emit delete
    141   builder.Delete(reg, LanguageMode::SLOPPY)
    142       .Delete(reg, LanguageMode::STRICT)
    143       .DeleteLookupSlot();
    144 
    145   // Emit new.
    146   builder.New(reg, reg, 0);
    147 
    148   // Emit test operator invocations.
    149   builder.CompareOperation(Token::Value::EQ, reg, Strength::WEAK)
    150       .CompareOperation(Token::Value::NE, reg, Strength::WEAK)
    151       .CompareOperation(Token::Value::EQ_STRICT, reg, Strength::WEAK)
    152       .CompareOperation(Token::Value::NE_STRICT, reg, Strength::WEAK)
    153       .CompareOperation(Token::Value::LT, reg, Strength::WEAK)
    154       .CompareOperation(Token::Value::GT, reg, Strength::WEAK)
    155       .CompareOperation(Token::Value::LTE, reg, Strength::WEAK)
    156       .CompareOperation(Token::Value::GTE, reg, Strength::WEAK)
    157       .CompareOperation(Token::Value::INSTANCEOF, reg, Strength::WEAK)
    158       .CompareOperation(Token::Value::IN, reg, Strength::WEAK);
    159 
    160   // Emit cast operator invocations.
    161   builder.CastAccumulatorToNumber()
    162       .CastAccumulatorToJSObject()
    163       .CastAccumulatorToName();
    164 
    165   // Emit control flow. Return must be the last instruction.
    166   BytecodeLabel start;
    167   builder.Bind(&start);
    168   // Short jumps with Imm8 operands
    169   builder.Jump(&start)
    170       .JumpIfNull(&start)
    171       .JumpIfUndefined(&start);
    172   // Perform an operation that returns boolean value to
    173   // generate JumpIfTrue/False
    174   builder.CompareOperation(Token::Value::EQ, reg, Strength::WEAK)
    175       .JumpIfTrue(&start)
    176       .CompareOperation(Token::Value::EQ, reg, Strength::WEAK)
    177       .JumpIfFalse(&start);
    178   // Perform an operation that returns a non-boolean operation to
    179   // generate JumpIfToBooleanTrue/False.
    180   builder.BinaryOperation(Token::Value::ADD, reg, Strength::WEAK)
    181       .JumpIfTrue(&start)
    182       .BinaryOperation(Token::Value::ADD, reg, Strength::WEAK)
    183       .JumpIfFalse(&start);
    184   // Insert dummy ops to force longer jumps
    185   for (int i = 0; i < 128; i++) {
    186     builder.LoadTrue();
    187   }
    188   // Longer jumps requiring Constant operand
    189   builder.Jump(&start)
    190       .JumpIfNull(&start)
    191       .JumpIfUndefined(&start);
    192   // Perform an operation that returns boolean value to
    193   // generate JumpIfTrue/False
    194   builder.CompareOperation(Token::Value::EQ, reg, Strength::WEAK)
    195       .JumpIfTrue(&start)
    196       .CompareOperation(Token::Value::EQ, reg, Strength::WEAK)
    197       .JumpIfFalse(&start);
    198   // Perform an operation that returns a non-boolean operation to
    199   // generate JumpIfToBooleanTrue/False.
    200   builder.BinaryOperation(Token::Value::ADD, reg, Strength::WEAK)
    201       .JumpIfTrue(&start)
    202       .BinaryOperation(Token::Value::ADD, reg, Strength::WEAK)
    203       .JumpIfFalse(&start);
    204 
    205   // Emit throw in it's own basic block so that the rest of the code isn't
    206   // omitted due to being dead.
    207   BytecodeLabel after_throw;
    208   builder.Jump(&after_throw)
    209     .Throw()
    210     .Bind(&after_throw);
    211 
    212   builder.ForInPrepare(reg, reg, reg)
    213       .ForInDone(reg, reg)
    214       .ForInNext(reg, reg, reg, reg)
    215       .ForInStep(reg);
    216 
    217   // Wide constant pool loads
    218   for (int i = 0; i < 256; i++) {
    219     // Emit junk in constant pool to force wide constant pool index.
    220     builder.LoadLiteral(factory->NewNumber(2.5321 + i));
    221   }
    222   builder.LoadLiteral(Smi::FromInt(20000000));
    223   Handle<String> wide_name = factory->NewStringFromStaticChars("var_wide_name");
    224 
    225   // Emit wide global load / store operations.
    226   builder.LoadGlobal(name, 1024, LanguageMode::SLOPPY,
    227                      TypeofMode::NOT_INSIDE_TYPEOF)
    228       .LoadGlobal(wide_name, 1, LanguageMode::STRICT,
    229                   TypeofMode::NOT_INSIDE_TYPEOF)
    230       .LoadGlobal(name, 1024, LanguageMode::SLOPPY, TypeofMode::INSIDE_TYPEOF)
    231       .LoadGlobal(wide_name, 1, LanguageMode::STRICT, TypeofMode::INSIDE_TYPEOF)
    232       .StoreGlobal(name, 1024, LanguageMode::SLOPPY)
    233       .StoreGlobal(wide_name, 1, LanguageMode::STRICT);
    234 
    235   // Emit wide load / store property operations.
    236   builder.LoadNamedProperty(reg, wide_name, 0, LanguageMode::SLOPPY)
    237       .LoadKeyedProperty(reg, 2056, LanguageMode::SLOPPY)
    238       .StoreNamedProperty(reg, wide_name, 0, LanguageMode::SLOPPY)
    239       .StoreKeyedProperty(reg, reg, 2056, LanguageMode::SLOPPY)
    240       .LoadNamedProperty(reg, wide_name, 0, LanguageMode::STRICT)
    241       .LoadKeyedProperty(reg, 2056, LanguageMode::STRICT)
    242       .StoreNamedProperty(reg, wide_name, 0, LanguageMode::STRICT)
    243       .StoreKeyedProperty(reg, reg, 2056, LanguageMode::STRICT);
    244 
    245   // Emit wide context operations.
    246   builder.LoadContextSlot(reg, 1024)
    247       .StoreContextSlot(reg, 1024);
    248 
    249   // Emit wide load / store lookup slots.
    250   builder.LoadLookupSlot(wide_name, TypeofMode::NOT_INSIDE_TYPEOF)
    251       .LoadLookupSlot(wide_name, TypeofMode::INSIDE_TYPEOF)
    252       .StoreLookupSlot(wide_name, LanguageMode::SLOPPY)
    253       .StoreLookupSlot(wide_name, LanguageMode::STRICT);
    254 
    255   // CreateClosureWide
    256   Handle<SharedFunctionInfo> shared_info2 = factory->NewSharedFunctionInfo(
    257       factory->NewStringFromStaticChars("function_b"), MaybeHandle<Code>(),
    258       false);
    259   builder.CreateClosure(shared_info2, NOT_TENURED);
    260 
    261   // Emit wide variant of literal creation operations.
    262   builder.CreateRegExpLiteral(factory->NewStringFromStaticChars("wide_literal"),
    263                               0, 0)
    264       .CreateArrayLiteral(factory->NewFixedArray(2), 0, 0)
    265       .CreateObjectLiteral(factory->NewFixedArray(2), 0, 0);
    266 
    267   // Longer jumps requiring ConstantWide operand
    268   builder.Jump(&start).JumpIfNull(&start).JumpIfUndefined(&start);
    269   // Perform an operation that returns boolean value to
    270   // generate JumpIfTrue/False
    271   builder.CompareOperation(Token::Value::EQ, reg, Strength::WEAK)
    272       .JumpIfTrue(&start)
    273       .CompareOperation(Token::Value::EQ, reg, Strength::WEAK)
    274       .JumpIfFalse(&start);
    275   // Perform an operation that returns a non-boolean operation to
    276   // generate JumpIfToBooleanTrue/False.
    277   builder.BinaryOperation(Token::Value::ADD, reg, Strength::WEAK)
    278       .JumpIfTrue(&start)
    279       .BinaryOperation(Token::Value::ADD, reg, Strength::WEAK)
    280       .JumpIfFalse(&start);
    281 
    282   builder.Return();
    283 
    284   // Generate BytecodeArray.
    285   Handle<BytecodeArray> the_array = builder.ToBytecodeArray();
    286   CHECK_EQ(the_array->frame_size(),
    287            builder.fixed_register_count() * kPointerSize);
    288 
    289   // Build scorecard of bytecodes encountered in the BytecodeArray.
    290   std::vector<int> scorecard(Bytecodes::ToByte(Bytecode::kLast) + 1);
    291   Bytecode final_bytecode = Bytecode::kLdaZero;
    292   int i = 0;
    293   while (i < the_array->length()) {
    294     uint8_t code = the_array->get(i);
    295     scorecard[code] += 1;
    296     final_bytecode = Bytecodes::FromByte(code);
    297     i += Bytecodes::Size(Bytecodes::FromByte(code));
    298   }
    299 
    300   // Check return occurs at the end and only once in the BytecodeArray.
    301   CHECK_EQ(final_bytecode, Bytecode::kReturn);
    302   CHECK_EQ(scorecard[Bytecodes::ToByte(final_bytecode)], 1);
    303 
    304 #define CHECK_BYTECODE_PRESENT(Name, ...)     \
    305   /* Check Bytecode is marked in scorecard */ \
    306   CHECK_GE(scorecard[Bytecodes::ToByte(Bytecode::k##Name)], 1);
    307   BYTECODE_LIST(CHECK_BYTECODE_PRESENT)
    308 #undef CHECK_BYTECODE_PRESENT
    309 }
    310 
    311 
    312 TEST_F(BytecodeArrayBuilderTest, FrameSizesLookGood) {
    313   for (int locals = 0; locals < 5; locals++) {
    314     for (int contexts = 0; contexts < 4; contexts++) {
    315       for (int temps = 0; temps < 3; temps++) {
    316         BytecodeArrayBuilder builder(isolate(), zone());
    317         builder.set_parameter_count(0);
    318         builder.set_locals_count(locals);
    319         builder.set_context_count(contexts);
    320 
    321         BytecodeRegisterAllocator temporaries(&builder);
    322         for (int i = 0; i < temps; i++) {
    323           builder.StoreAccumulatorInRegister(temporaries.NewRegister());
    324         }
    325         builder.Return();
    326 
    327         Handle<BytecodeArray> the_array = builder.ToBytecodeArray();
    328         int total_registers = locals + contexts + temps;
    329         CHECK_EQ(the_array->frame_size(), total_registers * kPointerSize);
    330       }
    331     }
    332   }
    333 }
    334 
    335 
    336 TEST_F(BytecodeArrayBuilderTest, RegisterValues) {
    337   int index = 1;
    338   uint8_t operand = static_cast<uint8_t>(-index);
    339 
    340   Register the_register(index);
    341   CHECK_EQ(the_register.index(), index);
    342 
    343   int actual_operand = the_register.ToOperand();
    344   CHECK_EQ(actual_operand, operand);
    345 
    346   int actual_index = Register::FromOperand(actual_operand).index();
    347   CHECK_EQ(actual_index, index);
    348 }
    349 
    350 
    351 TEST_F(BytecodeArrayBuilderTest, Parameters) {
    352   BytecodeArrayBuilder builder(isolate(), zone());
    353   builder.set_parameter_count(10);
    354   builder.set_locals_count(0);
    355   builder.set_context_count(0);
    356 
    357   Register param0(builder.Parameter(0));
    358   Register param9(builder.Parameter(9));
    359   CHECK_EQ(param9.index() - param0.index(), 9);
    360 }
    361 
    362 
    363 TEST_F(BytecodeArrayBuilderTest, RegisterType) {
    364   BytecodeArrayBuilder builder(isolate(), zone());
    365   builder.set_parameter_count(10);
    366   builder.set_locals_count(3);
    367   builder.set_context_count(0);
    368 
    369   BytecodeRegisterAllocator register_allocator(&builder);
    370   Register temp0 = register_allocator.NewRegister();
    371   Register param0(builder.Parameter(0));
    372   Register param9(builder.Parameter(9));
    373   Register temp1 = register_allocator.NewRegister();
    374   Register reg0(0);
    375   Register reg1(1);
    376   Register reg2(2);
    377   Register temp2 = register_allocator.NewRegister();
    378   CHECK_EQ(builder.RegisterIsParameterOrLocal(temp0), false);
    379   CHECK_EQ(builder.RegisterIsParameterOrLocal(temp1), false);
    380   CHECK_EQ(builder.RegisterIsParameterOrLocal(temp2), false);
    381   CHECK_EQ(builder.RegisterIsParameterOrLocal(param0), true);
    382   CHECK_EQ(builder.RegisterIsParameterOrLocal(param9), true);
    383   CHECK_EQ(builder.RegisterIsParameterOrLocal(reg0), true);
    384   CHECK_EQ(builder.RegisterIsParameterOrLocal(reg1), true);
    385   CHECK_EQ(builder.RegisterIsParameterOrLocal(reg2), true);
    386 }
    387 
    388 
    389 TEST_F(BytecodeArrayBuilderTest, Constants) {
    390   BytecodeArrayBuilder builder(isolate(), zone());
    391   builder.set_parameter_count(0);
    392   builder.set_locals_count(0);
    393   builder.set_context_count(0);
    394 
    395   Factory* factory = isolate()->factory();
    396   Handle<HeapObject> heap_num_1 = factory->NewHeapNumber(3.14);
    397   Handle<HeapObject> heap_num_2 = factory->NewHeapNumber(5.2);
    398   Handle<Object> large_smi(Smi::FromInt(0x12345678), isolate());
    399   Handle<HeapObject> heap_num_2_copy(*heap_num_2);
    400   builder.LoadLiteral(heap_num_1)
    401       .LoadLiteral(heap_num_2)
    402       .LoadLiteral(large_smi)
    403       .LoadLiteral(heap_num_1)
    404       .LoadLiteral(heap_num_1)
    405       .LoadLiteral(heap_num_2_copy);
    406 
    407   Handle<BytecodeArray> array = builder.ToBytecodeArray();
    408   // Should only have one entry for each identical constant.
    409   CHECK_EQ(array->constant_pool()->length(), 3);
    410 }
    411 
    412 
    413 TEST_F(BytecodeArrayBuilderTest, ForwardJumps) {
    414   static const int kFarJumpDistance = 256;
    415 
    416   BytecodeArrayBuilder builder(isolate(), zone());
    417   builder.set_parameter_count(0);
    418   builder.set_locals_count(1);
    419   builder.set_context_count(0);
    420 
    421   Register reg(0);
    422   BytecodeLabel far0, far1, far2, far3, far4;
    423   BytecodeLabel near0, near1, near2, near3, near4;
    424 
    425   builder.Jump(&near0)
    426       .CompareOperation(Token::Value::EQ, reg, Strength::WEAK)
    427       .JumpIfTrue(&near1)
    428       .CompareOperation(Token::Value::EQ, reg, Strength::WEAK)
    429       .JumpIfFalse(&near2)
    430       .BinaryOperation(Token::Value::ADD, reg, Strength::WEAK)
    431       .JumpIfTrue(&near3)
    432       .BinaryOperation(Token::Value::ADD, reg, Strength::WEAK)
    433       .JumpIfFalse(&near4)
    434       .Bind(&near0)
    435       .Bind(&near1)
    436       .Bind(&near2)
    437       .Bind(&near3)
    438       .Bind(&near4)
    439       .Jump(&far0)
    440       .CompareOperation(Token::Value::EQ, reg, Strength::WEAK)
    441       .JumpIfTrue(&far1)
    442       .CompareOperation(Token::Value::EQ, reg, Strength::WEAK)
    443       .JumpIfFalse(&far2)
    444       .BinaryOperation(Token::Value::ADD, reg, Strength::WEAK)
    445       .JumpIfTrue(&far3)
    446       .BinaryOperation(Token::Value::ADD, reg, Strength::WEAK)
    447       .JumpIfFalse(&far4);
    448   for (int i = 0; i < kFarJumpDistance - 18; i++) {
    449     builder.LoadUndefined();
    450   }
    451   builder.Bind(&far0).Bind(&far1).Bind(&far2).Bind(&far3).Bind(&far4);
    452   builder.Return();
    453 
    454   Handle<BytecodeArray> array = builder.ToBytecodeArray();
    455   DCHECK_EQ(array->length(), 36 + kFarJumpDistance - 18 + 1);
    456 
    457   BytecodeArrayIterator iterator(array);
    458   CHECK_EQ(iterator.current_bytecode(), Bytecode::kJump);
    459   CHECK_EQ(iterator.GetImmediateOperand(0), 18);
    460   iterator.Advance();
    461 
    462   // Ignore compare operation.
    463   iterator.Advance();
    464 
    465   CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpIfTrue);
    466   CHECK_EQ(iterator.GetImmediateOperand(0), 14);
    467   iterator.Advance();
    468 
    469   // Ignore compare operation.
    470   iterator.Advance();
    471 
    472   CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpIfFalse);
    473   CHECK_EQ(iterator.GetImmediateOperand(0), 10);
    474   iterator.Advance();
    475 
    476   // Ignore add operation.
    477   iterator.Advance();
    478 
    479   CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpIfToBooleanTrue);
    480   CHECK_EQ(iterator.GetImmediateOperand(0), 6);
    481   iterator.Advance();
    482 
    483   // Ignore add operation.
    484   iterator.Advance();
    485 
    486   CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpIfToBooleanFalse);
    487   CHECK_EQ(iterator.GetImmediateOperand(0), 2);
    488   iterator.Advance();
    489 
    490 
    491   CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpConstant);
    492   CHECK_EQ(*iterator.GetConstantForIndexOperand(0),
    493            Smi::FromInt(kFarJumpDistance));
    494   iterator.Advance();
    495 
    496   // Ignore compare operation.
    497   iterator.Advance();
    498 
    499   CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpIfTrueConstant);
    500   CHECK_EQ(*iterator.GetConstantForIndexOperand(0),
    501            Smi::FromInt(kFarJumpDistance - 4));
    502   iterator.Advance();
    503 
    504   // Ignore compare operation.
    505   iterator.Advance();
    506 
    507   CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpIfFalseConstant);
    508   CHECK_EQ(*iterator.GetConstantForIndexOperand(0),
    509            Smi::FromInt(kFarJumpDistance - 8));
    510   iterator.Advance();
    511 
    512   // Ignore add operation.
    513   iterator.Advance();
    514 
    515   CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpIfToBooleanTrueConstant);
    516   CHECK_EQ(*iterator.GetConstantForIndexOperand(0),
    517            Smi::FromInt(kFarJumpDistance - 12));
    518   iterator.Advance();
    519 
    520   // Ignore add operation.
    521   iterator.Advance();
    522 
    523   CHECK_EQ(iterator.current_bytecode(),
    524            Bytecode::kJumpIfToBooleanFalseConstant);
    525   CHECK_EQ(*iterator.GetConstantForIndexOperand(0),
    526            Smi::FromInt(kFarJumpDistance - 16));
    527   iterator.Advance();
    528 }
    529 
    530 
    531 TEST_F(BytecodeArrayBuilderTest, BackwardJumps) {
    532   BytecodeArrayBuilder builder(isolate(), zone());
    533   builder.set_parameter_count(0);
    534   builder.set_locals_count(1);
    535   builder.set_context_count(0);
    536   Register reg(0);
    537 
    538   BytecodeLabel label0, label1, label2, label3, label4;
    539   builder.Bind(&label0)
    540       .Jump(&label0)
    541       .Bind(&label1)
    542       .CompareOperation(Token::Value::EQ, reg, Strength::WEAK)
    543       .JumpIfTrue(&label1)
    544       .Bind(&label2)
    545       .CompareOperation(Token::Value::EQ, reg, Strength::WEAK)
    546       .JumpIfFalse(&label2)
    547       .Bind(&label3)
    548       .BinaryOperation(Token::Value::ADD, reg, Strength::WEAK)
    549       .JumpIfTrue(&label3)
    550       .Bind(&label4)
    551       .BinaryOperation(Token::Value::ADD, reg, Strength::WEAK)
    552       .JumpIfFalse(&label4);
    553   for (int i = 0; i < 63; i++) {
    554     builder.Jump(&label4);
    555   }
    556   builder.BinaryOperation(Token::Value::ADD, reg, Strength::WEAK)
    557       .JumpIfFalse(&label4);
    558   builder.BinaryOperation(Token::Value::ADD, reg, Strength::WEAK)
    559       .JumpIfTrue(&label3);
    560   builder.CompareOperation(Token::Value::EQ, reg, Strength::WEAK)
    561       .JumpIfFalse(&label2);
    562   builder.CompareOperation(Token::Value::EQ, reg, Strength::WEAK)
    563       .JumpIfTrue(&label1);
    564   builder.Jump(&label0);
    565   builder.Return();
    566 
    567   Handle<BytecodeArray> array = builder.ToBytecodeArray();
    568   BytecodeArrayIterator iterator(array);
    569   CHECK_EQ(iterator.current_bytecode(), Bytecode::kJump);
    570   CHECK_EQ(iterator.GetImmediateOperand(0), 0);
    571   iterator.Advance();
    572   // Ignore compare operation.
    573   iterator.Advance();
    574   CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpIfTrue);
    575   CHECK_EQ(iterator.GetImmediateOperand(0), -2);
    576   iterator.Advance();
    577   // Ignore compare operation.
    578   iterator.Advance();
    579   CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpIfFalse);
    580   CHECK_EQ(iterator.GetImmediateOperand(0), -2);
    581   iterator.Advance();
    582   // Ignore binary operation.
    583   iterator.Advance();
    584   CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpIfToBooleanTrue);
    585   CHECK_EQ(iterator.GetImmediateOperand(0), -2);
    586   iterator.Advance();
    587   // Ignore binary operation.
    588   iterator.Advance();
    589   CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpIfToBooleanFalse);
    590   CHECK_EQ(iterator.GetImmediateOperand(0), -2);
    591   iterator.Advance();
    592   for (int i = 0; i < 63; i++) {
    593     CHECK_EQ(iterator.current_bytecode(), Bytecode::kJump);
    594     CHECK_EQ(iterator.GetImmediateOperand(0), -i * 2 - 4);
    595     iterator.Advance();
    596   }
    597   // Ignore binary operation.
    598   iterator.Advance();
    599   CHECK_EQ(iterator.current_bytecode(),
    600            Bytecode::kJumpIfToBooleanFalseConstant);
    601   CHECK_EQ(Smi::cast(*iterator.GetConstantForIndexOperand(0))->value(), -132);
    602   iterator.Advance();
    603   // Ignore binary operation.
    604   iterator.Advance();
    605   CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpIfToBooleanTrueConstant);
    606   CHECK_EQ(Smi::cast(*iterator.GetConstantForIndexOperand(0))->value(), -140);
    607   iterator.Advance();
    608   // Ignore compare operation.
    609   iterator.Advance();
    610   CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpIfFalseConstant);
    611   CHECK_EQ(Smi::cast(*iterator.GetConstantForIndexOperand(0))->value(), -148);
    612   iterator.Advance();
    613   // Ignore compare operation.
    614   iterator.Advance();
    615   CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpIfTrueConstant);
    616   CHECK_EQ(Smi::cast(*iterator.GetConstantForIndexOperand(0))->value(), -156);
    617   iterator.Advance();
    618   CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpConstant);
    619   CHECK_EQ(Smi::cast(*iterator.GetConstantForIndexOperand(0))->value(), -160);
    620   iterator.Advance();
    621   CHECK_EQ(iterator.current_bytecode(), Bytecode::kReturn);
    622   iterator.Advance();
    623   CHECK(iterator.done());
    624 }
    625 
    626 
    627 TEST_F(BytecodeArrayBuilderTest, LabelReuse) {
    628   BytecodeArrayBuilder builder(isolate(), zone());
    629   builder.set_parameter_count(0);
    630   builder.set_locals_count(0);
    631   builder.set_context_count(0);
    632 
    633   // Labels can only have 1 forward reference, but
    634   // can be referred to mulitple times once bound.
    635   BytecodeLabel label;
    636 
    637   builder.Jump(&label).Bind(&label).Jump(&label).Jump(&label).Return();
    638 
    639   Handle<BytecodeArray> array = builder.ToBytecodeArray();
    640   BytecodeArrayIterator iterator(array);
    641   CHECK_EQ(iterator.current_bytecode(), Bytecode::kJump);
    642   CHECK_EQ(iterator.GetImmediateOperand(0), 2);
    643   iterator.Advance();
    644   CHECK_EQ(iterator.current_bytecode(), Bytecode::kJump);
    645   CHECK_EQ(iterator.GetImmediateOperand(0), 0);
    646   iterator.Advance();
    647   CHECK_EQ(iterator.current_bytecode(), Bytecode::kJump);
    648   CHECK_EQ(iterator.GetImmediateOperand(0), -2);
    649   iterator.Advance();
    650   CHECK_EQ(iterator.current_bytecode(), Bytecode::kReturn);
    651   iterator.Advance();
    652   CHECK(iterator.done());
    653 }
    654 
    655 
    656 TEST_F(BytecodeArrayBuilderTest, LabelAddressReuse) {
    657   static const int kRepeats = 3;
    658 
    659   BytecodeArrayBuilder builder(isolate(), zone());
    660   builder.set_parameter_count(0);
    661   builder.set_locals_count(0);
    662   builder.set_context_count(0);
    663 
    664   for (int i = 0; i < kRepeats; i++) {
    665     BytecodeLabel label;
    666     builder.Jump(&label).Bind(&label).Jump(&label).Jump(&label);
    667   }
    668 
    669   builder.Return();
    670 
    671   Handle<BytecodeArray> array = builder.ToBytecodeArray();
    672   BytecodeArrayIterator iterator(array);
    673   for (int i = 0; i < kRepeats; i++) {
    674     CHECK_EQ(iterator.current_bytecode(), Bytecode::kJump);
    675     CHECK_EQ(iterator.GetImmediateOperand(0), 2);
    676     iterator.Advance();
    677     CHECK_EQ(iterator.current_bytecode(), Bytecode::kJump);
    678     CHECK_EQ(iterator.GetImmediateOperand(0), 0);
    679     iterator.Advance();
    680     CHECK_EQ(iterator.current_bytecode(), Bytecode::kJump);
    681     CHECK_EQ(iterator.GetImmediateOperand(0), -2);
    682     iterator.Advance();
    683   }
    684   CHECK_EQ(iterator.current_bytecode(), Bytecode::kReturn);
    685   iterator.Advance();
    686   CHECK(iterator.done());
    687 }
    688 
    689 
    690 }  // namespace interpreter
    691 }  // namespace internal
    692 }  // namespace v8
    693