LCOV - code coverage report
Current view: top level - test/unittests/interpreter - bytecode-array-builder-unittest.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 512 512 100.0 %
Date: 2019-02-19 Functions: 24 37 64.9 %

          Line data    Source code
       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 <limits>
       6             : 
       7             : #include "src/v8.h"
       8             : 
       9             : #include "src/ast/scopes.h"
      10             : #include "src/hash-seed-inl.h"
      11             : #include "src/interpreter/bytecode-array-builder.h"
      12             : #include "src/interpreter/bytecode-array-iterator.h"
      13             : #include "src/interpreter/bytecode-jump-table.h"
      14             : #include "src/interpreter/bytecode-label.h"
      15             : #include "src/interpreter/bytecode-register-allocator.h"
      16             : #include "src/objects-inl.h"
      17             : #include "src/objects/smi.h"
      18             : #include "test/unittests/interpreter/bytecode-utils.h"
      19             : #include "test/unittests/test-utils.h"
      20             : 
      21             : namespace v8 {
      22             : namespace internal {
      23             : namespace interpreter {
      24             : 
      25             : class BytecodeArrayBuilderTest : public TestWithIsolateAndZone {
      26             :  public:
      27          11 :   BytecodeArrayBuilderTest() = default;
      28          11 :   ~BytecodeArrayBuilderTest() override = default;
      29             : };
      30             : 
      31             : using ToBooleanMode = BytecodeArrayBuilder::ToBooleanMode;
      32             : 
      33       15189 : TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) {
      34           1 :   FeedbackVectorSpec feedback_spec(zone());
      35           2 :   BytecodeArrayBuilder builder(zone(), 1, 131, &feedback_spec);
      36             :   Factory* factory = isolate()->factory();
      37             :   AstValueFactory ast_factory(zone(), isolate()->ast_string_constants(),
      38           2 :                               HashSeed(isolate()));
      39           1 :   DeclarationScope scope(zone(), &ast_factory);
      40             : 
      41           1 :   CHECK_EQ(builder.locals_count(), 131);
      42           1 :   CHECK_EQ(builder.fixed_register_count(), 131);
      43             : 
      44             :   Register reg(0);
      45             :   Register other(reg.index() + 1);
      46             :   Register wide(128);
      47             :   RegisterList empty;
      48           1 :   RegisterList single = BytecodeUtils::NewRegisterList(0, 1);
      49           1 :   RegisterList pair = BytecodeUtils::NewRegisterList(0, 2);
      50           1 :   RegisterList triple = BytecodeUtils::NewRegisterList(0, 3);
      51           1 :   RegisterList reg_list = BytecodeUtils::NewRegisterList(0, 10);
      52             : 
      53             :   // Emit argument creation operations.
      54           1 :   builder.CreateArguments(CreateArgumentsType::kMappedArguments)
      55           1 :       .CreateArguments(CreateArgumentsType::kUnmappedArguments)
      56           1 :       .CreateArguments(CreateArgumentsType::kRestParameter);
      57             : 
      58             :   // Emit constant loads.
      59           1 :   builder.LoadLiteral(Smi::zero())
      60           1 :       .StoreAccumulatorInRegister(reg)
      61           1 :       .LoadLiteral(Smi::FromInt(8))
      62             :       .CompareOperation(Token::Value::EQ, reg,
      63           1 :                         1)  // Prevent peephole optimization
      64             :                             // LdaSmi, Star -> LdrSmi.
      65           1 :       .StoreAccumulatorInRegister(reg)
      66           1 :       .LoadLiteral(Smi::FromInt(10000000))
      67           1 :       .StoreAccumulatorInRegister(reg)
      68           2 :       .LoadLiteral(ast_factory.GetOneByteString("A constant"))
      69           1 :       .StoreAccumulatorInRegister(reg)
      70           1 :       .LoadUndefined()
      71           1 :       .StoreAccumulatorInRegister(reg)
      72           1 :       .LoadNull()
      73           1 :       .StoreAccumulatorInRegister(reg)
      74           1 :       .LoadTheHole()
      75           1 :       .StoreAccumulatorInRegister(reg)
      76           1 :       .LoadTrue()
      77           1 :       .StoreAccumulatorInRegister(reg)
      78           1 :       .LoadFalse()
      79           1 :       .StoreAccumulatorInRegister(wide);
      80             : 
      81             :   // Emit Ldar and Star taking care to foil the register optimizer.
      82           1 :   builder.StackCheck(0)
      83           1 :       .LoadAccumulatorWithRegister(other)
      84           1 :       .BinaryOperation(Token::ADD, reg, 1)
      85           1 :       .StoreAccumulatorInRegister(reg)
      86           1 :       .LoadNull();
      87             : 
      88             :   // Emit register-register transfer.
      89           1 :   builder.MoveRegister(reg, other);
      90           1 :   builder.MoveRegister(reg, wide);
      91             : 
      92             :   FeedbackSlot load_global_slot =
      93             :       feedback_spec.AddLoadGlobalICSlot(NOT_INSIDE_TYPEOF);
      94             :   FeedbackSlot load_global_typeof_slot =
      95             :       feedback_spec.AddLoadGlobalICSlot(INSIDE_TYPEOF);
      96             :   FeedbackSlot sloppy_store_global_slot =
      97             :       feedback_spec.AddStoreGlobalICSlot(LanguageMode::kSloppy);
      98             :   FeedbackSlot load_slot = feedback_spec.AddLoadICSlot();
      99             :   FeedbackSlot keyed_load_slot = feedback_spec.AddKeyedLoadICSlot();
     100             :   FeedbackSlot sloppy_store_slot =
     101             :       feedback_spec.AddStoreICSlot(LanguageMode::kSloppy);
     102             :   FeedbackSlot strict_store_slot =
     103             :       feedback_spec.AddStoreICSlot(LanguageMode::kStrict);
     104             :   FeedbackSlot sloppy_keyed_store_slot =
     105             :       feedback_spec.AddKeyedStoreICSlot(LanguageMode::kSloppy);
     106             :   FeedbackSlot strict_keyed_store_slot =
     107             :       feedback_spec.AddKeyedStoreICSlot(LanguageMode::kStrict);
     108             :   FeedbackSlot store_own_slot = feedback_spec.AddStoreOwnICSlot();
     109             :   FeedbackSlot store_array_element_slot =
     110             :       feedback_spec.AddStoreInArrayLiteralICSlot();
     111             : 
     112             :   // Emit global load / store operations.
     113           1 :   const AstRawString* name = ast_factory.GetOneByteString("var_name");
     114             :   builder
     115           1 :       .LoadGlobal(name, load_global_slot.ToInt(), TypeofMode::NOT_INSIDE_TYPEOF)
     116             :       .LoadGlobal(name, load_global_typeof_slot.ToInt(),
     117           1 :                   TypeofMode::INSIDE_TYPEOF)
     118           1 :       .StoreGlobal(name, sloppy_store_global_slot.ToInt());
     119             : 
     120             :   // Emit context operations.
     121           1 :   builder.PushContext(reg)
     122           1 :       .PopContext(reg)
     123           1 :       .LoadContextSlot(reg, 1, 0, BytecodeArrayBuilder::kMutableSlot)
     124           1 :       .StoreContextSlot(reg, 1, 0)
     125           1 :       .LoadContextSlot(reg, 2, 0, BytecodeArrayBuilder::kImmutableSlot)
     126           1 :       .StoreContextSlot(reg, 3, 0);
     127             : 
     128             :   // Emit context operations which operate on the local context.
     129             :   builder
     130             :       .LoadContextSlot(Register::current_context(), 1, 0,
     131           1 :                        BytecodeArrayBuilder::kMutableSlot)
     132           2 :       .StoreContextSlot(Register::current_context(), 1, 0)
     133             :       .LoadContextSlot(Register::current_context(), 2, 0,
     134           2 :                        BytecodeArrayBuilder::kImmutableSlot)
     135           2 :       .StoreContextSlot(Register::current_context(), 3, 0);
     136             : 
     137             :   // Emit load / store property operations.
     138           1 :   builder.LoadNamedProperty(reg, name, load_slot.ToInt())
     139           1 :       .LoadNamedPropertyNoFeedback(reg, name)
     140           1 :       .LoadKeyedProperty(reg, keyed_load_slot.ToInt())
     141             :       .StoreNamedProperty(reg, name, sloppy_store_slot.ToInt(),
     142           1 :                           LanguageMode::kSloppy)
     143           1 :       .StoreNamedPropertyNoFeedback(reg, name, LanguageMode::kStrict)
     144           1 :       .StoreNamedPropertyNoFeedback(reg, name, LanguageMode::kSloppy)
     145             :       .StoreKeyedProperty(reg, reg, sloppy_keyed_store_slot.ToInt(),
     146           1 :                           LanguageMode::kSloppy)
     147             :       .StoreNamedProperty(reg, name, strict_store_slot.ToInt(),
     148           1 :                           LanguageMode::kStrict)
     149             :       .StoreKeyedProperty(reg, reg, strict_keyed_store_slot.ToInt(),
     150           1 :                           LanguageMode::kStrict)
     151           1 :       .StoreNamedOwnProperty(reg, name, store_own_slot.ToInt())
     152           1 :       .StoreInArrayLiteral(reg, reg, store_array_element_slot.ToInt());
     153             : 
     154             :   // Emit load / store lookup slots.
     155           1 :   builder.LoadLookupSlot(name, TypeofMode::NOT_INSIDE_TYPEOF)
     156           1 :       .LoadLookupSlot(name, TypeofMode::INSIDE_TYPEOF)
     157           1 :       .StoreLookupSlot(name, LanguageMode::kSloppy, LookupHoistingMode::kNormal)
     158             :       .StoreLookupSlot(name, LanguageMode::kSloppy,
     159           1 :                        LookupHoistingMode::kLegacySloppy)
     160             :       .StoreLookupSlot(name, LanguageMode::kStrict,
     161           1 :                        LookupHoistingMode::kNormal);
     162             : 
     163             :   // Emit load / store lookup slots with context fast paths.
     164           1 :   builder.LoadLookupContextSlot(name, TypeofMode::NOT_INSIDE_TYPEOF, 1, 0)
     165           1 :       .LoadLookupContextSlot(name, TypeofMode::INSIDE_TYPEOF, 1, 0);
     166             : 
     167             :   // Emit load / store lookup slots with global fast paths.
     168           1 :   builder.LoadLookupGlobalSlot(name, TypeofMode::NOT_INSIDE_TYPEOF, 1, 0)
     169           1 :       .LoadLookupGlobalSlot(name, TypeofMode::INSIDE_TYPEOF, 1, 0);
     170             : 
     171             :   // Emit closure operations.
     172           1 :   builder.CreateClosure(0, 1, NOT_TENURED);
     173             : 
     174             :   // Emit create context operation.
     175           1 :   builder.CreateBlockContext(&scope);
     176           1 :   builder.CreateCatchContext(reg, &scope);
     177           1 :   builder.CreateFunctionContext(&scope, 1);
     178           1 :   builder.CreateEvalContext(&scope, 1);
     179           1 :   builder.CreateWithContext(reg, &scope);
     180             : 
     181             :   // Emit literal creation operations.
     182           1 :   builder.CreateRegExpLiteral(ast_factory.GetOneByteString("a"), 0, 0);
     183           1 :   builder.CreateArrayLiteral(0, 0, 0);
     184           1 :   builder.CreateObjectLiteral(0, 0, 0);
     185             : 
     186             :   // Emit tagged template operations.
     187           1 :   builder.GetTemplateObject(0, 0);
     188             : 
     189             :   // Call operations.
     190           1 :   builder.CallAnyReceiver(reg, reg_list, 1)
     191           1 :       .CallProperty(reg, reg_list, 1)
     192           1 :       .CallProperty(reg, single, 1)
     193           1 :       .CallProperty(reg, pair, 1)
     194           1 :       .CallProperty(reg, triple, 1)
     195           1 :       .CallUndefinedReceiver(reg, reg_list, 1)
     196           1 :       .CallUndefinedReceiver(reg, empty, 1)
     197           1 :       .CallUndefinedReceiver(reg, single, 1)
     198           1 :       .CallUndefinedReceiver(reg, pair, 1)
     199           1 :       .CallRuntime(Runtime::kIsArray, reg)
     200           1 :       .CallRuntimeForPair(Runtime::kLoadLookupSlotForCall, reg_list, pair)
     201           1 :       .CallJSRuntime(Context::OBJECT_CREATE, reg_list)
     202           1 :       .CallWithSpread(reg, reg_list, 1)
     203           1 :       .CallNoFeedback(reg, reg_list);
     204             : 
     205             :   // Emit binary operator invocations.
     206           1 :   builder.BinaryOperation(Token::Value::ADD, reg, 1)
     207           1 :       .BinaryOperation(Token::Value::SUB, reg, 2)
     208           1 :       .BinaryOperation(Token::Value::MUL, reg, 3)
     209           1 :       .BinaryOperation(Token::Value::DIV, reg, 4)
     210           1 :       .BinaryOperation(Token::Value::MOD, reg, 5)
     211           1 :       .BinaryOperation(Token::Value::EXP, reg, 6);
     212             : 
     213             :   // Emit bitwise operator invocations
     214           1 :   builder.BinaryOperation(Token::Value::BIT_OR, reg, 6)
     215           1 :       .BinaryOperation(Token::Value::BIT_XOR, reg, 7)
     216           1 :       .BinaryOperation(Token::Value::BIT_AND, reg, 8);
     217             : 
     218             :   // Emit shift operator invocations
     219           1 :   builder.BinaryOperation(Token::Value::SHL, reg, 9)
     220           1 :       .BinaryOperation(Token::Value::SAR, reg, 10)
     221           1 :       .BinaryOperation(Token::Value::SHR, reg, 11);
     222             : 
     223             :   // Emit Smi binary operations.
     224           1 :   builder.BinaryOperationSmiLiteral(Token::Value::ADD, Smi::FromInt(42), 2)
     225           1 :       .BinaryOperationSmiLiteral(Token::Value::SUB, Smi::FromInt(42), 2)
     226           1 :       .BinaryOperationSmiLiteral(Token::Value::MUL, Smi::FromInt(42), 2)
     227           1 :       .BinaryOperationSmiLiteral(Token::Value::DIV, Smi::FromInt(42), 2)
     228           1 :       .BinaryOperationSmiLiteral(Token::Value::MOD, Smi::FromInt(42), 2)
     229           1 :       .BinaryOperationSmiLiteral(Token::Value::EXP, Smi::FromInt(42), 2)
     230           1 :       .BinaryOperationSmiLiteral(Token::Value::BIT_OR, Smi::FromInt(42), 2)
     231           1 :       .BinaryOperationSmiLiteral(Token::Value::BIT_XOR, Smi::FromInt(42), 2)
     232           1 :       .BinaryOperationSmiLiteral(Token::Value::BIT_AND, Smi::FromInt(42), 2)
     233           1 :       .BinaryOperationSmiLiteral(Token::Value::SHL, Smi::FromInt(42), 2)
     234           1 :       .BinaryOperationSmiLiteral(Token::Value::SAR, Smi::FromInt(42), 2)
     235           1 :       .BinaryOperationSmiLiteral(Token::Value::SHR, Smi::FromInt(42), 2);
     236             : 
     237             :   // Emit unary and count operator invocations.
     238           1 :   builder.UnaryOperation(Token::Value::INC, 1)
     239           1 :       .UnaryOperation(Token::Value::DEC, 1)
     240           1 :       .UnaryOperation(Token::Value::ADD, 1)
     241           1 :       .UnaryOperation(Token::Value::SUB, 1)
     242           1 :       .UnaryOperation(Token::Value::BIT_NOT, 1);
     243             : 
     244             :   // Emit unary operator invocations.
     245           1 :   builder.LogicalNot(ToBooleanMode::kConvertToBoolean)
     246           1 :       .LogicalNot(ToBooleanMode::kAlreadyBoolean)
     247           1 :       .TypeOf();
     248             : 
     249             :   // Emit delete
     250           1 :   builder.Delete(reg, LanguageMode::kSloppy).Delete(reg, LanguageMode::kStrict);
     251             : 
     252             :   // Emit construct.
     253           1 :   builder.Construct(reg, reg_list, 1).ConstructWithSpread(reg, reg_list, 1);
     254             : 
     255             :   // Emit test operator invocations.
     256           1 :   builder.CompareOperation(Token::Value::EQ, reg, 1)
     257           1 :       .CompareOperation(Token::Value::EQ_STRICT, reg, 2)
     258           1 :       .CompareOperation(Token::Value::LT, reg, 3)
     259           1 :       .CompareOperation(Token::Value::GT, reg, 4)
     260           1 :       .CompareOperation(Token::Value::LTE, reg, 5)
     261           1 :       .CompareOperation(Token::Value::GTE, reg, 6)
     262           1 :       .CompareTypeOf(TestTypeOfFlags::LiteralFlag::kNumber)
     263           1 :       .CompareOperation(Token::Value::INSTANCEOF, reg, 7)
     264           1 :       .CompareOperation(Token::Value::IN, reg)
     265           1 :       .CompareReference(reg)
     266           1 :       .CompareUndetectable()
     267           1 :       .CompareUndefined()
     268           1 :       .CompareNull();
     269             : 
     270             :   // Emit conversion operator invocations.
     271           1 :   builder.ToNumber(1).ToNumeric(1).ToObject(reg).ToName(reg).ToString();
     272             : 
     273             :   // Emit GetSuperConstructor.
     274           1 :   builder.GetSuperConstructor(reg);
     275             : 
     276             :   // Hole checks.
     277           1 :   builder.ThrowReferenceErrorIfHole(name)
     278           1 :       .ThrowSuperAlreadyCalledIfNotHole()
     279           1 :       .ThrowSuperNotCalledIfHole();
     280             : 
     281             :   // Short jumps with Imm8 operands
     282             :   {
     283             :     BytecodeLabel start, after_jump1, after_jump2, after_jump3, after_jump4,
     284             :         after_jump5, after_jump6, after_jump7, after_jump8, after_jump9,
     285             :         after_jump10;
     286           1 :     builder.Bind(&start)
     287           1 :         .Jump(&after_jump1)
     288           1 :         .Bind(&after_jump1)
     289           1 :         .JumpIfNull(&after_jump2)
     290           1 :         .Bind(&after_jump2)
     291           1 :         .JumpIfNotNull(&after_jump3)
     292           1 :         .Bind(&after_jump3)
     293           1 :         .JumpIfUndefined(&after_jump4)
     294           1 :         .Bind(&after_jump4)
     295           1 :         .JumpIfNotUndefined(&after_jump5)
     296           1 :         .Bind(&after_jump5)
     297           1 :         .JumpIfJSReceiver(&after_jump6)
     298           1 :         .Bind(&after_jump6)
     299           1 :         .JumpIfTrue(ToBooleanMode::kConvertToBoolean, &after_jump7)
     300           1 :         .Bind(&after_jump7)
     301           1 :         .JumpIfTrue(ToBooleanMode::kAlreadyBoolean, &after_jump8)
     302           1 :         .Bind(&after_jump8)
     303           1 :         .JumpIfFalse(ToBooleanMode::kConvertToBoolean, &after_jump9)
     304           1 :         .Bind(&after_jump9)
     305           1 :         .JumpIfFalse(ToBooleanMode::kAlreadyBoolean, &after_jump10)
     306           1 :         .Bind(&after_jump10)
     307           1 :         .JumpLoop(&start, 0);
     308             :   }
     309             : 
     310             :   // Longer jumps with constant operands
     311          11 :   BytecodeLabel end[10];
     312             :   {
     313             :     BytecodeLabel after_jump;
     314           1 :     builder.Jump(&end[0])
     315           1 :         .Bind(&after_jump)
     316           1 :         .JumpIfTrue(ToBooleanMode::kConvertToBoolean, &end[1])
     317           1 :         .JumpIfTrue(ToBooleanMode::kAlreadyBoolean, &end[2])
     318           1 :         .JumpIfFalse(ToBooleanMode::kConvertToBoolean, &end[3])
     319           1 :         .JumpIfFalse(ToBooleanMode::kAlreadyBoolean, &end[4])
     320           1 :         .JumpIfNull(&end[5])
     321           1 :         .JumpIfNotNull(&end[6])
     322           1 :         .JumpIfUndefined(&end[7])
     323           1 :         .JumpIfNotUndefined(&end[8])
     324           2 :         .LoadLiteral(ast_factory.prototype_string())
     325           1 :         .JumpIfJSReceiver(&end[9]);
     326             :   }
     327             : 
     328             :   // Emit Smi table switch bytecode.
     329           1 :   BytecodeJumpTable* jump_table = builder.AllocateJumpTable(1, 0);
     330           1 :   builder.SwitchOnSmiNoFeedback(jump_table).Bind(jump_table, 0);
     331             : 
     332             :   // Emit set pending message bytecode.
     333           1 :   builder.SetPendingMessage();
     334             : 
     335             :   // Emit stack check bytecode.
     336           1 :   builder.StackCheck(0);
     337             : 
     338             :   // Emit throw and re-throw in it's own basic block so that the rest of the
     339             :   // code isn't omitted due to being dead.
     340             :   BytecodeLabel after_throw;
     341           1 :   builder.Throw().Bind(&after_throw);
     342             :   BytecodeLabel after_rethrow;
     343           1 :   builder.ReThrow().Bind(&after_rethrow);
     344             : 
     345           1 :   builder.ForInEnumerate(reg)
     346           1 :       .ForInPrepare(triple, 1)
     347           1 :       .ForInContinue(reg, reg)
     348           1 :       .ForInNext(reg, reg, pair, 1)
     349           1 :       .ForInStep(reg);
     350             : 
     351             :   // Wide constant pool loads
     352         257 :   for (int i = 0; i < 256; i++) {
     353             :     // Emit junk in constant pool to force wide constant pool index.
     354         256 :     builder.LoadLiteral(2.5321 + i);
     355             :   }
     356           1 :   builder.LoadLiteral(Smi::FromInt(20000000));
     357           1 :   const AstRawString* wide_name = ast_factory.GetOneByteString("var_wide_name");
     358             : 
     359             :   builder.StoreDataPropertyInLiteral(reg, reg,
     360           1 :                                      DataPropertyInLiteralFlag::kNoFlags, 0);
     361             : 
     362             :   // Emit wide context operations.
     363           1 :   builder.LoadContextSlot(reg, 1024, 0, BytecodeArrayBuilder::kMutableSlot)
     364           1 :       .StoreContextSlot(reg, 1024, 0);
     365             : 
     366             :   // Emit wide load / store lookup slots.
     367           1 :   builder.LoadLookupSlot(wide_name, TypeofMode::NOT_INSIDE_TYPEOF)
     368           1 :       .LoadLookupSlot(wide_name, TypeofMode::INSIDE_TYPEOF)
     369             :       .StoreLookupSlot(wide_name, LanguageMode::kSloppy,
     370           1 :                        LookupHoistingMode::kNormal)
     371             :       .StoreLookupSlot(wide_name, LanguageMode::kSloppy,
     372           1 :                        LookupHoistingMode::kLegacySloppy)
     373             :       .StoreLookupSlot(wide_name, LanguageMode::kStrict,
     374           1 :                        LookupHoistingMode::kNormal);
     375             : 
     376             :   // CreateClosureWide
     377           1 :   builder.CreateClosure(1000, 321, NOT_TENURED);
     378             : 
     379             :   // Emit wide variant of literal creation operations.
     380             :   builder
     381           1 :       .CreateRegExpLiteral(ast_factory.GetOneByteString("wide_literal"), 0, 0)
     382           1 :       .CreateArrayLiteral(0, 0, 0)
     383           1 :       .CreateEmptyArrayLiteral(0)
     384           1 :       .CreateArrayFromIterable()
     385           1 :       .CreateObjectLiteral(0, 0, 0)
     386           1 :       .CreateEmptyObjectLiteral()
     387           1 :       .CloneObject(reg, 0, 0);
     388             : 
     389             :   // Emit load and store operations for module variables.
     390           1 :   builder.LoadModuleVariable(-1, 42)
     391           1 :       .LoadModuleVariable(0, 42)
     392           1 :       .LoadModuleVariable(1, 42)
     393           1 :       .StoreModuleVariable(-1, 42)
     394           1 :       .StoreModuleVariable(0, 42)
     395           1 :       .StoreModuleVariable(1, 42);
     396             : 
     397             :   // Emit generator operations.
     398             :   {
     399             :     // We have to skip over suspend because it returns and marks the remaining
     400             :     // bytecode dead.
     401             :     BytecodeLabel after_suspend;
     402           1 :     builder.JumpIfTrue(ToBooleanMode::kAlreadyBoolean, &after_suspend)
     403           1 :         .SuspendGenerator(reg, reg_list, 0)
     404           1 :         .Bind(&after_suspend)
     405           1 :         .ResumeGenerator(reg, reg_list);
     406             :   }
     407           1 :   BytecodeJumpTable* gen_jump_table = builder.AllocateJumpTable(1, 0);
     408           1 :   builder.SwitchOnGeneratorState(reg, gen_jump_table).Bind(gen_jump_table, 0);
     409             : 
     410             :   // Intrinsics handled by the interpreter.
     411           1 :   builder.CallRuntime(Runtime::kInlineIsArray, reg_list);
     412             : 
     413             :   // Emit debugger bytecode.
     414           1 :   builder.Debugger();
     415             : 
     416             :   // Emit abort bytecode.
     417             :   {
     418             :     BytecodeLabel after;
     419           1 :     builder.Abort(AbortReason::kOperandIsASmi).Bind(&after);
     420             :   }
     421             : 
     422             :   // Insert dummy ops to force longer jumps.
     423         257 :   for (int i = 0; i < 256; i++) {
     424         256 :     builder.Debugger();
     425             :   }
     426             : 
     427             :   // Emit block counter increments.
     428           1 :   builder.IncBlockCounter(0);
     429             : 
     430             :   // Bind labels for long jumps at the very end.
     431          11 :   for (size_t i = 0; i < arraysize(end); i++) {
     432          10 :     builder.Bind(&end[i]);
     433             :   }
     434             : 
     435             :   // Return must be the last instruction.
     436           1 :   builder.Return();
     437             : 
     438             :   // Generate BytecodeArray.
     439           1 :   scope.SetScriptScopeInfo(factory->NewScopeInfo(1));
     440           1 :   ast_factory.Internalize(isolate());
     441           1 :   Handle<BytecodeArray> the_array = builder.ToBytecodeArray(isolate());
     442           2 :   CHECK_EQ(the_array->frame_size(),
     443             :            builder.total_register_count() * kSystemPointerSize);
     444             : 
     445             :   // Build scorecard of bytecodes encountered in the BytecodeArray.
     446           1 :   std::vector<int> scorecard(Bytecodes::ToByte(Bytecode::kLast) + 1);
     447             : 
     448             :   Bytecode final_bytecode = Bytecode::kLdaZero;
     449             :   int i = 0;
     450         466 :   while (i < the_array->length()) {
     451             :     uint8_t code = the_array->get(i);
     452         928 :     scorecard[code] += 1;
     453             :     final_bytecode = Bytecodes::FromByte(code);
     454             :     OperandScale operand_scale = OperandScale::kSingle;
     455             :     int prefix_offset = 0;
     456         464 :     if (Bytecodes::IsPrefixScalingBytecode(final_bytecode)) {
     457          15 :       operand_scale = Bytecodes::PrefixBytecodeToOperandScale(final_bytecode);
     458             :       prefix_offset = 1;
     459          15 :       code = the_array->get(i + 1);
     460          30 :       scorecard[code] += 1;
     461             :       final_bytecode = Bytecodes::FromByte(code);
     462             :     }
     463         464 :     i += prefix_offset + Bytecodes::Size(final_bytecode, operand_scale);
     464             :   }
     465             : 
     466             :   // Insert entry for illegal bytecode as this is never willingly emitted.
     467           1 :   scorecard[Bytecodes::ToByte(Bytecode::kIllegal)] = 1;
     468             : 
     469             :   // Bytecode for CollectTypeProfile is only emitted when
     470             :   // Type Information for DevTools is turned on.
     471           1 :   scorecard[Bytecodes::ToByte(Bytecode::kCollectTypeProfile)] = 1;
     472             : 
     473             :   // Check return occurs at the end and only once in the BytecodeArray.
     474           1 :   CHECK_EQ(final_bytecode, Bytecode::kReturn);
     475           2 :   CHECK_EQ(scorecard[Bytecodes::ToByte(final_bytecode)], 1);
     476             : 
     477             : #define CHECK_BYTECODE_PRESENT(Name, ...)                                \
     478             :   /* Check Bytecode is marked in scorecard, unless it's a debug break */ \
     479             :   if (!Bytecodes::IsDebugBreak(Bytecode::k##Name)) {                     \
     480             :     EXPECT_GE(scorecard[Bytecodes::ToByte(Bytecode::k##Name)], 1);       \
     481             :   }
     482         180 :   BYTECODE_LIST(CHECK_BYTECODE_PRESENT)
     483             : #undef CHECK_BYTECODE_PRESENT
     484           1 : }
     485             : 
     486             : 
     487       15189 : TEST_F(BytecodeArrayBuilderTest, FrameSizesLookGood) {
     488           6 :   for (int locals = 0; locals < 5; locals++) {
     489          15 :     for (int temps = 0; temps < 3; temps++) {
     490          15 :       BytecodeArrayBuilder builder(zone(), 1, locals);
     491             :       BytecodeRegisterAllocator* allocator(builder.register_allocator());
     492          45 :       for (int i = 0; i < locals; i++) {
     493          30 :         builder.LoadLiteral(Smi::zero());
     494          30 :         builder.StoreAccumulatorInRegister(Register(i));
     495             :       }
     496          15 :       for (int i = 0; i < temps; i++) {
     497          15 :         Register temp = allocator->NewRegister();
     498          15 :         builder.LoadLiteral(Smi::zero());
     499          15 :         builder.StoreAccumulatorInRegister(temp);
     500             :         // Ensure temporaries are used so not optimized away by the
     501             :         // register optimizer.
     502          15 :         builder.ToName(temp);
     503             :       }
     504          15 :       builder.Return();
     505             : 
     506          15 :       Handle<BytecodeArray> the_array = builder.ToBytecodeArray(isolate());
     507          15 :       int total_registers = locals + temps;
     508          30 :       CHECK_EQ(the_array->frame_size(), total_registers * kSystemPointerSize);
     509          15 :     }
     510             :   }
     511           1 : }
     512             : 
     513             : 
     514       15189 : TEST_F(BytecodeArrayBuilderTest, RegisterValues) {
     515             :   int index = 1;
     516             : 
     517             :   Register the_register(index);
     518           1 :   CHECK_EQ(the_register.index(), index);
     519             : 
     520             :   int actual_operand = the_register.ToOperand();
     521             :   int actual_index = Register::FromOperand(actual_operand).index();
     522           1 :   CHECK_EQ(actual_index, index);
     523           1 : }
     524             : 
     525             : 
     526       15189 : TEST_F(BytecodeArrayBuilderTest, Parameters) {
     527           1 :   BytecodeArrayBuilder builder(zone(), 10, 0);
     528             : 
     529           1 :   Register receiver(builder.Receiver());
     530           1 :   Register param8(builder.Parameter(8));
     531           1 :   CHECK_EQ(param8.index() - receiver.index(), 9);
     532           1 : }
     533             : 
     534             : 
     535       15189 : TEST_F(BytecodeArrayBuilderTest, Constants) {
     536           1 :   BytecodeArrayBuilder builder(zone(), 1, 0);
     537             :   AstValueFactory ast_factory(zone(), isolate()->ast_string_constants(),
     538           2 :                               HashSeed(isolate()));
     539             : 
     540             :   double heap_num_1 = 3.14;
     541             :   double heap_num_2 = 5.2;
     542             :   double nan = std::numeric_limits<double>::quiet_NaN();
     543           1 :   const AstRawString* string = ast_factory.GetOneByteString("foo");
     544           1 :   const AstRawString* string_copy = ast_factory.GetOneByteString("foo");
     545             : 
     546           1 :   builder.LoadLiteral(heap_num_1)
     547           1 :       .LoadLiteral(heap_num_2)
     548           1 :       .LoadLiteral(string)
     549           1 :       .LoadLiteral(heap_num_1)
     550           1 :       .LoadLiteral(heap_num_1)
     551           1 :       .LoadLiteral(nan)
     552           1 :       .LoadLiteral(string_copy)
     553           1 :       .LoadLiteral(heap_num_2)
     554           1 :       .LoadLiteral(nan)
     555           1 :       .Return();
     556             : 
     557           1 :   ast_factory.Internalize(isolate());
     558           1 :   Handle<BytecodeArray> array = builder.ToBytecodeArray(isolate());
     559             :   // Should only have one entry for each identical constant.
     560           4 :   EXPECT_EQ(4, array->constant_pool()->length());
     561           1 : }
     562             : 
     563       15189 : TEST_F(BytecodeArrayBuilderTest, ForwardJumps) {
     564             :   static const int kFarJumpDistance = 256 + 20;
     565             : 
     566           1 :   BytecodeArrayBuilder builder(zone(), 1, 1);
     567             : 
     568             :   Register reg(0);
     569             :   BytecodeLabel far0, far1, far2, far3, far4;
     570             :   BytecodeLabel near0, near1, near2, near3, near4;
     571             :   BytecodeLabel after_jump0, after_jump1;
     572             : 
     573           1 :   builder.Jump(&near0)
     574           1 :       .Bind(&after_jump0)
     575           1 :       .CompareOperation(Token::Value::EQ, reg, 1)
     576           1 :       .JumpIfTrue(ToBooleanMode::kAlreadyBoolean, &near1)
     577           1 :       .CompareOperation(Token::Value::EQ, reg, 2)
     578           1 :       .JumpIfFalse(ToBooleanMode::kAlreadyBoolean, &near2)
     579           1 :       .BinaryOperation(Token::Value::ADD, reg, 1)
     580           1 :       .JumpIfTrue(ToBooleanMode::kConvertToBoolean, &near3)
     581           1 :       .BinaryOperation(Token::Value::ADD, reg, 2)
     582           1 :       .JumpIfFalse(ToBooleanMode::kConvertToBoolean, &near4)
     583           1 :       .Bind(&near0)
     584           1 :       .Bind(&near1)
     585           1 :       .Bind(&near2)
     586           1 :       .Bind(&near3)
     587           1 :       .Bind(&near4)
     588           1 :       .Jump(&far0)
     589           1 :       .Bind(&after_jump1)
     590           1 :       .CompareOperation(Token::Value::EQ, reg, 3)
     591           1 :       .JumpIfTrue(ToBooleanMode::kAlreadyBoolean, &far1)
     592           1 :       .CompareOperation(Token::Value::EQ, reg, 4)
     593           1 :       .JumpIfFalse(ToBooleanMode::kAlreadyBoolean, &far2)
     594           1 :       .BinaryOperation(Token::Value::ADD, reg, 3)
     595           1 :       .JumpIfTrue(ToBooleanMode::kConvertToBoolean, &far3)
     596           1 :       .BinaryOperation(Token::Value::ADD, reg, 4)
     597           1 :       .JumpIfFalse(ToBooleanMode::kConvertToBoolean, &far4);
     598         255 :   for (int i = 0; i < kFarJumpDistance - 22; i++) {
     599         254 :     builder.Debugger();
     600             :   }
     601           1 :   builder.Bind(&far0).Bind(&far1).Bind(&far2).Bind(&far3).Bind(&far4);
     602           1 :   builder.Return();
     603             : 
     604           1 :   Handle<BytecodeArray> array = builder.ToBytecodeArray(isolate());
     605             :   DCHECK_EQ(array->length(), 44 + kFarJumpDistance - 22 + 1);
     606             : 
     607           1 :   BytecodeArrayIterator iterator(array);
     608           1 :   CHECK_EQ(iterator.current_bytecode(), Bytecode::kJump);
     609           1 :   CHECK_EQ(iterator.GetUnsignedImmediateOperand(0), 22);
     610           1 :   iterator.Advance();
     611             : 
     612             :   // Ignore compare operation.
     613           1 :   iterator.Advance();
     614             : 
     615           1 :   CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpIfTrue);
     616           1 :   CHECK_EQ(iterator.GetUnsignedImmediateOperand(0), 17);
     617           1 :   iterator.Advance();
     618             : 
     619             :   // Ignore compare operation.
     620           1 :   iterator.Advance();
     621             : 
     622           1 :   CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpIfFalse);
     623           1 :   CHECK_EQ(iterator.GetUnsignedImmediateOperand(0), 12);
     624           1 :   iterator.Advance();
     625             : 
     626             :   // Ignore add operation.
     627           1 :   iterator.Advance();
     628             : 
     629           1 :   CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpIfToBooleanTrue);
     630           1 :   CHECK_EQ(iterator.GetUnsignedImmediateOperand(0), 7);
     631           1 :   iterator.Advance();
     632             : 
     633             :   // Ignore add operation.
     634           1 :   iterator.Advance();
     635             : 
     636           1 :   CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpIfToBooleanFalse);
     637           1 :   CHECK_EQ(iterator.GetUnsignedImmediateOperand(0), 2);
     638           1 :   iterator.Advance();
     639             : 
     640           1 :   CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpConstant);
     641           2 :   CHECK_EQ(iterator.GetConstantForIndexOperand(0),
     642             :            Smi::FromInt(kFarJumpDistance));
     643           1 :   iterator.Advance();
     644             : 
     645             :   // Ignore compare operation.
     646           1 :   iterator.Advance();
     647             : 
     648           1 :   CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpIfTrueConstant);
     649           2 :   CHECK_EQ(iterator.GetConstantForIndexOperand(0),
     650             :            Smi::FromInt(kFarJumpDistance - 5));
     651           1 :   iterator.Advance();
     652             : 
     653             :   // Ignore compare operation.
     654           1 :   iterator.Advance();
     655             : 
     656           1 :   CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpIfFalseConstant);
     657           2 :   CHECK_EQ(iterator.GetConstantForIndexOperand(0),
     658             :            Smi::FromInt(kFarJumpDistance - 10));
     659           1 :   iterator.Advance();
     660             : 
     661             :   // Ignore add operation.
     662           1 :   iterator.Advance();
     663             : 
     664           1 :   CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpIfToBooleanTrueConstant);
     665           2 :   CHECK_EQ(iterator.GetConstantForIndexOperand(0),
     666             :            Smi::FromInt(kFarJumpDistance - 15));
     667           1 :   iterator.Advance();
     668             : 
     669             :   // Ignore add operation.
     670           1 :   iterator.Advance();
     671             : 
     672           1 :   CHECK_EQ(iterator.current_bytecode(),
     673             :            Bytecode::kJumpIfToBooleanFalseConstant);
     674           2 :   CHECK_EQ(iterator.GetConstantForIndexOperand(0),
     675             :            Smi::FromInt(kFarJumpDistance - 20));
     676           1 :   iterator.Advance();
     677           1 : }
     678             : 
     679             : 
     680       15189 : TEST_F(BytecodeArrayBuilderTest, BackwardJumps) {
     681           1 :   BytecodeArrayBuilder builder(zone(), 1, 1);
     682             : 
     683             :   Register reg(0);
     684             : 
     685             :   BytecodeLabel label0;
     686           1 :   builder.Bind(&label0).JumpLoop(&label0, 0);
     687          43 :   for (int i = 0; i < 42; i++) {
     688             :     BytecodeLabel after_jump;
     689          42 :     builder.JumpLoop(&label0, 0).Bind(&after_jump);
     690             :   }
     691             : 
     692             :   // Add padding to force wide backwards jumps.
     693         256 :   for (int i = 0; i < 256; i++) {
     694         256 :     builder.Debugger();
     695             :   }
     696             : 
     697           1 :   builder.JumpLoop(&label0, 0);
     698             :   BytecodeLabel end;
     699           1 :   builder.Bind(&end);
     700           1 :   builder.Return();
     701             : 
     702           1 :   Handle<BytecodeArray> array = builder.ToBytecodeArray(isolate());
     703           1 :   BytecodeArrayIterator iterator(array);
     704           1 :   CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpLoop);
     705           1 :   CHECK_EQ(iterator.GetUnsignedImmediateOperand(0), 0);
     706           1 :   iterator.Advance();
     707          44 :   for (unsigned i = 0; i < 42; i++) {
     708          42 :     CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpLoop);
     709          42 :     CHECK_EQ(iterator.current_operand_scale(), OperandScale::kSingle);
     710             :     // offset of 3 (because kJumpLoop takes two immediate operands)
     711          42 :     CHECK_EQ(iterator.GetUnsignedImmediateOperand(0), i * 3 + 3);
     712          42 :     iterator.Advance();
     713             :   }
     714             :   // Check padding to force wide backwards jumps.
     715         256 :   for (int i = 0; i < 256; i++) {
     716         256 :     CHECK_EQ(iterator.current_bytecode(), Bytecode::kDebugger);
     717         256 :     iterator.Advance();
     718             :   }
     719           1 :   CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpLoop);
     720           1 :   CHECK_EQ(iterator.current_operand_scale(), OperandScale::kDouble);
     721           1 :   CHECK_EQ(iterator.GetUnsignedImmediateOperand(0), 386);
     722           1 :   iterator.Advance();
     723           1 :   CHECK_EQ(iterator.current_bytecode(), Bytecode::kReturn);
     724           1 :   iterator.Advance();
     725           1 :   CHECK(iterator.done());
     726           1 : }
     727             : 
     728       15189 : TEST_F(BytecodeArrayBuilderTest, SmallSwitch) {
     729           1 :   BytecodeArrayBuilder builder(zone(), 1, 1);
     730             : 
     731             :   // Small jump table that fits into the single-size constant pool
     732             :   int small_jump_table_size = 5;
     733             :   int small_jump_table_base = -2;
     734             :   BytecodeJumpTable* small_jump_table =
     735           1 :       builder.AllocateJumpTable(small_jump_table_size, small_jump_table_base);
     736             : 
     737           1 :   builder.LoadLiteral(Smi::FromInt(7)).SwitchOnSmiNoFeedback(small_jump_table);
     738           6 :   for (int i = 0; i < small_jump_table_size; i++) {
     739           5 :     builder.Bind(small_jump_table, small_jump_table_base + i).Debugger();
     740             :   }
     741           1 :   builder.Return();
     742             : 
     743           1 :   Handle<BytecodeArray> array = builder.ToBytecodeArray(isolate());
     744           1 :   BytecodeArrayIterator iterator(array);
     745             : 
     746           1 :   CHECK_EQ(iterator.current_bytecode(), Bytecode::kLdaSmi);
     747           1 :   iterator.Advance();
     748             : 
     749           1 :   CHECK_EQ(iterator.current_bytecode(), Bytecode::kSwitchOnSmiNoFeedback);
     750           1 :   CHECK_EQ(iterator.current_operand_scale(), OperandScale::kSingle);
     751             :   {
     752             :     int i = 0;
     753             :     int switch_end =
     754           1 :         iterator.current_offset() + iterator.current_bytecode_size();
     755             : 
     756           6 :     for (const auto& entry : iterator.GetJumpTableTargetOffsets()) {
     757           5 :       CHECK_EQ(entry.case_value, small_jump_table_base + i);
     758           5 :       CHECK_EQ(entry.target_offset, switch_end + i);
     759             : 
     760           5 :       i++;
     761             :     }
     762           1 :     CHECK_EQ(i, small_jump_table_size);
     763             :   }
     764           1 :   iterator.Advance();
     765             : 
     766           6 :   for (int i = 0; i < small_jump_table_size; i++) {
     767           5 :     CHECK_EQ(iterator.current_bytecode(), Bytecode::kDebugger);
     768           5 :     iterator.Advance();
     769             :   }
     770             : 
     771           1 :   CHECK_EQ(iterator.current_bytecode(), Bytecode::kReturn);
     772           1 :   iterator.Advance();
     773           1 :   CHECK(iterator.done());
     774           1 : }
     775             : 
     776       15189 : TEST_F(BytecodeArrayBuilderTest, WideSwitch) {
     777           1 :   BytecodeArrayBuilder builder(zone(), 1, 1);
     778             : 
     779             :   // Large jump table that requires a wide Switch bytecode.
     780             :   int large_jump_table_size = 256;
     781             :   int large_jump_table_base = -10;
     782             :   BytecodeJumpTable* large_jump_table =
     783           1 :       builder.AllocateJumpTable(large_jump_table_size, large_jump_table_base);
     784             : 
     785           1 :   builder.LoadLiteral(Smi::FromInt(7)).SwitchOnSmiNoFeedback(large_jump_table);
     786         257 :   for (int i = 0; i < large_jump_table_size; i++) {
     787         256 :     builder.Bind(large_jump_table, large_jump_table_base + i).Debugger();
     788             :   }
     789           1 :   builder.Return();
     790             : 
     791           1 :   Handle<BytecodeArray> array = builder.ToBytecodeArray(isolate());
     792           1 :   BytecodeArrayIterator iterator(array);
     793             : 
     794           1 :   CHECK_EQ(iterator.current_bytecode(), Bytecode::kLdaSmi);
     795           1 :   iterator.Advance();
     796             : 
     797           1 :   CHECK_EQ(iterator.current_bytecode(), Bytecode::kSwitchOnSmiNoFeedback);
     798           1 :   CHECK_EQ(iterator.current_operand_scale(), OperandScale::kDouble);
     799             :   {
     800             :     int i = 0;
     801             :     int switch_end =
     802           1 :         iterator.current_offset() + iterator.current_bytecode_size();
     803             : 
     804         257 :     for (const auto& entry : iterator.GetJumpTableTargetOffsets()) {
     805         256 :       CHECK_EQ(entry.case_value, large_jump_table_base + i);
     806         256 :       CHECK_EQ(entry.target_offset, switch_end + i);
     807             : 
     808         256 :       i++;
     809             :     }
     810           1 :     CHECK_EQ(i, large_jump_table_size);
     811             :   }
     812           1 :   iterator.Advance();
     813             : 
     814         257 :   for (int i = 0; i < large_jump_table_size; i++) {
     815         256 :     CHECK_EQ(iterator.current_bytecode(), Bytecode::kDebugger);
     816         256 :     iterator.Advance();
     817             :   }
     818             : 
     819           1 :   CHECK_EQ(iterator.current_bytecode(), Bytecode::kReturn);
     820           1 :   iterator.Advance();
     821           1 :   CHECK(iterator.done());
     822           1 : }
     823             : 
     824       15189 : TEST_F(BytecodeArrayBuilderTest, LabelReuse) {
     825           1 :   BytecodeArrayBuilder builder(zone(), 1, 0);
     826             : 
     827             :   // Labels can only have 1 forward reference, but
     828             :   // can be referred to mulitple times once bound.
     829             :   BytecodeLabel label, after_jump0, after_jump1;
     830             : 
     831           1 :   builder.Jump(&label)
     832           1 :       .Bind(&label)
     833           1 :       .JumpLoop(&label, 0)
     834           1 :       .Bind(&after_jump0)
     835           1 :       .JumpLoop(&label, 0)
     836           1 :       .Bind(&after_jump1)
     837           1 :       .Return();
     838             : 
     839           1 :   Handle<BytecodeArray> array = builder.ToBytecodeArray(isolate());
     840           1 :   BytecodeArrayIterator iterator(array);
     841           1 :   CHECK_EQ(iterator.current_bytecode(), Bytecode::kJump);
     842           1 :   CHECK_EQ(iterator.GetUnsignedImmediateOperand(0), 2);
     843           1 :   iterator.Advance();
     844           1 :   CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpLoop);
     845           1 :   CHECK_EQ(iterator.GetUnsignedImmediateOperand(0), 0);
     846           1 :   iterator.Advance();
     847           1 :   CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpLoop);
     848           1 :   CHECK_EQ(iterator.GetUnsignedImmediateOperand(0), 3);
     849           1 :   iterator.Advance();
     850           1 :   CHECK_EQ(iterator.current_bytecode(), Bytecode::kReturn);
     851           1 :   iterator.Advance();
     852           1 :   CHECK(iterator.done());
     853           1 : }
     854             : 
     855             : 
     856       15189 : TEST_F(BytecodeArrayBuilderTest, LabelAddressReuse) {
     857             :   static const int kRepeats = 3;
     858             : 
     859           1 :   BytecodeArrayBuilder builder(zone(), 1, 0);
     860           4 :   for (int i = 0; i < kRepeats; i++) {
     861             :     BytecodeLabel label, after_jump0, after_jump1;
     862           3 :     builder.Jump(&label)
     863           3 :         .Bind(&label)
     864           3 :         .JumpLoop(&label, 0)
     865           3 :         .Bind(&after_jump0)
     866           3 :         .JumpLoop(&label, 0)
     867           3 :         .Bind(&after_jump1);
     868             :   }
     869           1 :   builder.Return();
     870             : 
     871           1 :   Handle<BytecodeArray> array = builder.ToBytecodeArray(isolate());
     872           1 :   BytecodeArrayIterator iterator(array);
     873           4 :   for (int i = 0; i < kRepeats; i++) {
     874           3 :     CHECK_EQ(iterator.current_bytecode(), Bytecode::kJump);
     875           3 :     CHECK_EQ(iterator.GetUnsignedImmediateOperand(0), 2);
     876           3 :     iterator.Advance();
     877           3 :     CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpLoop);
     878           3 :     CHECK_EQ(iterator.GetUnsignedImmediateOperand(0), 0);
     879           3 :     iterator.Advance();
     880           3 :     CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpLoop);
     881           3 :     CHECK_EQ(iterator.GetUnsignedImmediateOperand(0), 3);
     882           3 :     iterator.Advance();
     883             :   }
     884           1 :   CHECK_EQ(iterator.current_bytecode(), Bytecode::kReturn);
     885           1 :   iterator.Advance();
     886           1 :   CHECK(iterator.done());
     887           1 : }
     888             : 
     889             : }  // namespace interpreter
     890             : }  // namespace internal
     891        9111 : }  // namespace v8

Generated by: LCOV version 1.10