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: 474 474 100.0 %
Date: 2019-04-18 Functions: 20 29 69.0 %

          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           9 :   BytecodeArrayBuilderTest() = default;
      28          18 :   ~BytecodeArrayBuilderTest() override = default;
      29             : };
      30             : 
      31             : using ToBooleanMode = BytecodeArrayBuilder::ToBooleanMode;
      32             : 
      33       15419 : TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) {
      34             :   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           1 :                               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, static_cast<int>(AllocationType::kYoung));
     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, 8)
     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             :     BytecodeLoopHeader loop_header;
     284             :     BytecodeLabel after_jump1, after_jump2, after_jump3, after_jump4,
     285             :         after_jump5, after_jump6, after_jump7, after_jump8, after_jump9,
     286             :         after_jump10, after_loop;
     287           1 :     builder.JumpIfNull(&after_loop)
     288           1 :         .Bind(&loop_header)
     289           1 :         .Jump(&after_jump1)
     290           1 :         .Bind(&after_jump1)
     291           1 :         .JumpIfNull(&after_jump2)
     292           1 :         .Bind(&after_jump2)
     293           1 :         .JumpIfNotNull(&after_jump3)
     294           1 :         .Bind(&after_jump3)
     295           1 :         .JumpIfUndefined(&after_jump4)
     296           1 :         .Bind(&after_jump4)
     297           1 :         .JumpIfNotUndefined(&after_jump5)
     298           1 :         .Bind(&after_jump5)
     299           1 :         .JumpIfJSReceiver(&after_jump6)
     300           1 :         .Bind(&after_jump6)
     301           1 :         .JumpIfTrue(ToBooleanMode::kConvertToBoolean, &after_jump7)
     302           1 :         .Bind(&after_jump7)
     303           1 :         .JumpIfTrue(ToBooleanMode::kAlreadyBoolean, &after_jump8)
     304           1 :         .Bind(&after_jump8)
     305           1 :         .JumpIfFalse(ToBooleanMode::kConvertToBoolean, &after_jump9)
     306           1 :         .Bind(&after_jump9)
     307           1 :         .JumpIfFalse(ToBooleanMode::kAlreadyBoolean, &after_jump10)
     308           1 :         .Bind(&after_jump10)
     309           1 :         .JumpLoop(&loop_header, 0)
     310           1 :         .Bind(&after_loop);
     311             :   }
     312             : 
     313          21 :   BytecodeLabel end[10];
     314             :   {
     315             :     // Longer jumps with constant operands
     316             :     BytecodeLabel after_jump;
     317           1 :     builder.JumpIfNull(&after_jump)
     318           1 :         .Jump(&end[0])
     319           1 :         .Bind(&after_jump)
     320           1 :         .JumpIfTrue(ToBooleanMode::kConvertToBoolean, &end[1])
     321           1 :         .JumpIfTrue(ToBooleanMode::kAlreadyBoolean, &end[2])
     322           1 :         .JumpIfFalse(ToBooleanMode::kConvertToBoolean, &end[3])
     323           1 :         .JumpIfFalse(ToBooleanMode::kAlreadyBoolean, &end[4])
     324           1 :         .JumpIfNull(&end[5])
     325           1 :         .JumpIfNotNull(&end[6])
     326           1 :         .JumpIfUndefined(&end[7])
     327           1 :         .JumpIfNotUndefined(&end[8])
     328           1 :         .LoadLiteral(ast_factory.prototype_string())
     329           1 :         .JumpIfJSReceiver(&end[9]);
     330             :   }
     331             : 
     332             :   // Emit Smi table switch bytecode.
     333           1 :   BytecodeJumpTable* jump_table = builder.AllocateJumpTable(1, 0);
     334           1 :   builder.SwitchOnSmiNoFeedback(jump_table).Bind(jump_table, 0);
     335             : 
     336             :   // Emit set pending message bytecode.
     337           1 :   builder.SetPendingMessage();
     338             : 
     339             :   // Emit stack check bytecode.
     340           1 :   builder.StackCheck(0);
     341             : 
     342             :   // Emit throw and re-throw in it's own basic block so that the rest of the
     343             :   // code isn't omitted due to being dead.
     344             :   BytecodeLabel after_throw, after_rethrow;
     345           1 :   builder.JumpIfNull(&after_throw).Throw().Bind(&after_throw);
     346           1 :   builder.JumpIfNull(&after_rethrow).ReThrow().Bind(&after_rethrow);
     347             : 
     348           1 :   builder.ForInEnumerate(reg)
     349           1 :       .ForInPrepare(triple, 1)
     350           1 :       .ForInContinue(reg, reg)
     351           1 :       .ForInNext(reg, reg, pair, 1)
     352           1 :       .ForInStep(reg);
     353             : 
     354             :   // Wide constant pool loads
     355         513 :   for (int i = 0; i < 256; i++) {
     356             :     // Emit junk in constant pool to force wide constant pool index.
     357         256 :     builder.LoadLiteral(2.5321 + i);
     358             :   }
     359           1 :   builder.LoadLiteral(Smi::FromInt(20000000));
     360           1 :   const AstRawString* wide_name = ast_factory.GetOneByteString("var_wide_name");
     361             : 
     362             :   builder.StoreDataPropertyInLiteral(reg, reg,
     363           1 :                                      DataPropertyInLiteralFlag::kNoFlags, 0);
     364             : 
     365             :   // Emit wide context operations.
     366           1 :   builder.LoadContextSlot(reg, 1024, 0, BytecodeArrayBuilder::kMutableSlot)
     367           1 :       .StoreContextSlot(reg, 1024, 0);
     368             : 
     369             :   // Emit wide load / store lookup slots.
     370           1 :   builder.LoadLookupSlot(wide_name, TypeofMode::NOT_INSIDE_TYPEOF)
     371           1 :       .LoadLookupSlot(wide_name, TypeofMode::INSIDE_TYPEOF)
     372             :       .StoreLookupSlot(wide_name, LanguageMode::kSloppy,
     373           1 :                        LookupHoistingMode::kNormal)
     374             :       .StoreLookupSlot(wide_name, LanguageMode::kSloppy,
     375           1 :                        LookupHoistingMode::kLegacySloppy)
     376             :       .StoreLookupSlot(wide_name, LanguageMode::kStrict,
     377           1 :                        LookupHoistingMode::kNormal);
     378             : 
     379             :   // CreateClosureWide
     380           1 :   builder.CreateClosure(1000, 321, static_cast<int>(AllocationType::kYoung));
     381             : 
     382             :   // Emit wide variant of literal creation operations.
     383             :   builder
     384           1 :       .CreateRegExpLiteral(ast_factory.GetOneByteString("wide_literal"), 0, 0)
     385           1 :       .CreateArrayLiteral(0, 0, 0)
     386           1 :       .CreateEmptyArrayLiteral(0)
     387           1 :       .CreateArrayFromIterable()
     388           1 :       .CreateObjectLiteral(0, 0, 0)
     389           1 :       .CreateEmptyObjectLiteral()
     390           1 :       .CloneObject(reg, 0, 0);
     391             : 
     392             :   // Emit load and store operations for module variables.
     393           1 :   builder.LoadModuleVariable(-1, 42)
     394           1 :       .LoadModuleVariable(0, 42)
     395           1 :       .LoadModuleVariable(1, 42)
     396           1 :       .StoreModuleVariable(-1, 42)
     397           1 :       .StoreModuleVariable(0, 42)
     398           1 :       .StoreModuleVariable(1, 42);
     399             : 
     400             :   // Emit generator operations.
     401             :   {
     402             :     // We have to skip over suspend because it returns and marks the remaining
     403             :     // bytecode dead.
     404             :     BytecodeLabel after_suspend;
     405           1 :     builder.JumpIfTrue(ToBooleanMode::kAlreadyBoolean, &after_suspend)
     406           1 :         .SuspendGenerator(reg, reg_list, 0)
     407           1 :         .Bind(&after_suspend)
     408           1 :         .ResumeGenerator(reg, reg_list);
     409             :   }
     410           1 :   BytecodeJumpTable* gen_jump_table = builder.AllocateJumpTable(1, 0);
     411           1 :   builder.SwitchOnGeneratorState(reg, gen_jump_table).Bind(gen_jump_table, 0);
     412             : 
     413             :   // Intrinsics handled by the interpreter.
     414           1 :   builder.CallRuntime(Runtime::kInlineIsArray, reg_list);
     415             : 
     416             :   // Emit debugger bytecode.
     417           1 :   builder.Debugger();
     418             : 
     419             :   // Emit abort bytecode.
     420             :   BytecodeLabel after_abort;
     421           1 :   builder.JumpIfNull(&after_abort)
     422           1 :       .Abort(AbortReason::kOperandIsASmi)
     423           1 :       .Bind(&after_abort);
     424             : 
     425             :   // Insert dummy ops to force longer jumps.
     426         513 :   for (int i = 0; i < 256; i++) {
     427         256 :     builder.Debugger();
     428             :   }
     429             : 
     430             :   // Emit block counter increments.
     431           1 :   builder.IncBlockCounter(0);
     432             : 
     433             :   // Bind labels for long jumps at the very end.
     434          21 :   for (size_t i = 0; i < arraysize(end); i++) {
     435          10 :     builder.Bind(&end[i]);
     436             :   }
     437             : 
     438             :   // Return must be the last instruction.
     439           1 :   builder.Return();
     440             : 
     441             :   // Generate BytecodeArray.
     442           1 :   scope.SetScriptScopeInfo(factory->NewScopeInfo(1));
     443           1 :   ast_factory.Internalize(isolate());
     444           1 :   Handle<BytecodeArray> the_array = builder.ToBytecodeArray(isolate());
     445           2 :   CHECK_EQ(the_array->frame_size(),
     446             :            builder.total_register_count() * kSystemPointerSize);
     447             : 
     448             :   // Build scorecard of bytecodes encountered in the BytecodeArray.
     449           1 :   std::vector<int> scorecard(Bytecodes::ToByte(Bytecode::kLast) + 1);
     450             : 
     451             :   Bytecode final_bytecode = Bytecode::kLdaZero;
     452             :   int i = 0;
     453         939 :   while (i < the_array->length()) {
     454             :     uint8_t code = the_array->get(i);
     455         938 :     scorecard[code] += 1;
     456             :     final_bytecode = Bytecodes::FromByte(code);
     457             :     OperandScale operand_scale = OperandScale::kSingle;
     458             :     int prefix_offset = 0;
     459         469 :     if (Bytecodes::IsPrefixScalingBytecode(final_bytecode)) {
     460          16 :       operand_scale = Bytecodes::PrefixBytecodeToOperandScale(final_bytecode);
     461             :       prefix_offset = 1;
     462          16 :       code = the_array->get(i + 1);
     463          32 :       scorecard[code] += 1;
     464             :       final_bytecode = Bytecodes::FromByte(code);
     465             :     }
     466         469 :     i += prefix_offset + Bytecodes::Size(final_bytecode, operand_scale);
     467             :   }
     468             : 
     469             :   // Insert entry for illegal bytecode as this is never willingly emitted.
     470           1 :   scorecard[Bytecodes::ToByte(Bytecode::kIllegal)] = 1;
     471             : 
     472             :   // Bytecode for CollectTypeProfile is only emitted when
     473             :   // Type Information for DevTools is turned on.
     474           1 :   scorecard[Bytecodes::ToByte(Bytecode::kCollectTypeProfile)] = 1;
     475             : 
     476             :   // Check return occurs at the end and only once in the BytecodeArray.
     477           1 :   CHECK_EQ(final_bytecode, Bytecode::kReturn);
     478           2 :   CHECK_EQ(scorecard[Bytecodes::ToByte(final_bytecode)], 1);
     479             : 
     480             : #define CHECK_BYTECODE_PRESENT(Name, ...)                                \
     481             :   /* Check Bytecode is marked in scorecard, unless it's a debug break */ \
     482             :   if (!Bytecodes::IsDebugBreak(Bytecode::k##Name)) {                     \
     483             :     EXPECT_GE(scorecard[Bytecodes::ToByte(Bytecode::k##Name)], 1);       \
     484             :   }
     485         350 :   BYTECODE_LIST(CHECK_BYTECODE_PRESENT)
     486             : #undef CHECK_BYTECODE_PRESENT
     487           1 : }
     488             : 
     489             : 
     490       15419 : TEST_F(BytecodeArrayBuilderTest, FrameSizesLookGood) {
     491          11 :   for (int locals = 0; locals < 5; locals++) {
     492          35 :     for (int temps = 0; temps < 3; temps++) {
     493          30 :       BytecodeArrayBuilder builder(zone(), 1, locals);
     494             :       BytecodeRegisterAllocator* allocator(builder.register_allocator());
     495          75 :       for (int i = 0; i < locals; i++) {
     496          30 :         builder.LoadLiteral(Smi::zero());
     497          30 :         builder.StoreAccumulatorInRegister(Register(i));
     498             :       }
     499          45 :       for (int i = 0; i < temps; i++) {
     500          15 :         Register temp = allocator->NewRegister();
     501          15 :         builder.LoadLiteral(Smi::zero());
     502          15 :         builder.StoreAccumulatorInRegister(temp);
     503             :         // Ensure temporaries are used so not optimized away by the
     504             :         // register optimizer.
     505          15 :         builder.ToName(temp);
     506             :       }
     507          15 :       builder.Return();
     508             : 
     509          15 :       Handle<BytecodeArray> the_array = builder.ToBytecodeArray(isolate());
     510          15 :       int total_registers = locals + temps;
     511          30 :       CHECK_EQ(the_array->frame_size(), total_registers * kSystemPointerSize);
     512             :     }
     513             :   }
     514           1 : }
     515             : 
     516             : 
     517       15419 : TEST_F(BytecodeArrayBuilderTest, RegisterValues) {
     518             :   int index = 1;
     519             : 
     520             :   Register the_register(index);
     521             :   CHECK_EQ(the_register.index(), index);
     522             : 
     523             :   int actual_operand = the_register.ToOperand();
     524             :   int actual_index = Register::FromOperand(actual_operand).index();
     525             :   CHECK_EQ(actual_index, index);
     526           1 : }
     527             : 
     528             : 
     529       15419 : TEST_F(BytecodeArrayBuilderTest, Parameters) {
     530           2 :   BytecodeArrayBuilder builder(zone(), 10, 0);
     531             : 
     532           1 :   Register receiver(builder.Receiver());
     533           1 :   Register param8(builder.Parameter(8));
     534           1 :   CHECK_EQ(param8.index() - receiver.index(), 9);
     535           1 : }
     536             : 
     537             : 
     538       15419 : TEST_F(BytecodeArrayBuilderTest, Constants) {
     539           2 :   BytecodeArrayBuilder builder(zone(), 1, 0);
     540             :   AstValueFactory ast_factory(zone(), isolate()->ast_string_constants(),
     541           1 :                               HashSeed(isolate()));
     542             : 
     543             :   double heap_num_1 = 3.14;
     544             :   double heap_num_2 = 5.2;
     545             :   double nan = std::numeric_limits<double>::quiet_NaN();
     546           1 :   const AstRawString* string = ast_factory.GetOneByteString("foo");
     547           1 :   const AstRawString* string_copy = ast_factory.GetOneByteString("foo");
     548             : 
     549           1 :   builder.LoadLiteral(heap_num_1)
     550           1 :       .LoadLiteral(heap_num_2)
     551           1 :       .LoadLiteral(string)
     552           1 :       .LoadLiteral(heap_num_1)
     553           1 :       .LoadLiteral(heap_num_1)
     554           1 :       .LoadLiteral(nan)
     555           1 :       .LoadLiteral(string_copy)
     556           1 :       .LoadLiteral(heap_num_2)
     557           1 :       .LoadLiteral(nan)
     558           1 :       .Return();
     559             : 
     560           1 :   ast_factory.Internalize(isolate());
     561           1 :   Handle<BytecodeArray> array = builder.ToBytecodeArray(isolate());
     562             :   // Should only have one entry for each identical constant.
     563           2 :   EXPECT_EQ(4, array->constant_pool()->length());
     564           1 : }
     565             : 
     566       15419 : TEST_F(BytecodeArrayBuilderTest, ForwardJumps) {
     567             :   static const int kFarJumpDistance = 256 + 20;
     568             : 
     569           2 :   BytecodeArrayBuilder builder(zone(), 1, 1);
     570             : 
     571             :   Register reg(0);
     572             :   BytecodeLabel far0, far1, far2, far3, far4;
     573             :   BytecodeLabel near0, near1, near2, near3, near4;
     574             :   BytecodeLabel after_jump_near0, after_jump_far0;
     575             : 
     576           1 :   builder.JumpIfNull(&after_jump_near0)
     577           1 :       .Jump(&near0)
     578           1 :       .Bind(&after_jump_near0)
     579           1 :       .CompareOperation(Token::Value::EQ, reg, 1)
     580           1 :       .JumpIfTrue(ToBooleanMode::kAlreadyBoolean, &near1)
     581           1 :       .CompareOperation(Token::Value::EQ, reg, 2)
     582           1 :       .JumpIfFalse(ToBooleanMode::kAlreadyBoolean, &near2)
     583           1 :       .BinaryOperation(Token::Value::ADD, reg, 1)
     584           1 :       .JumpIfTrue(ToBooleanMode::kConvertToBoolean, &near3)
     585           1 :       .BinaryOperation(Token::Value::ADD, reg, 2)
     586           1 :       .JumpIfFalse(ToBooleanMode::kConvertToBoolean, &near4)
     587           1 :       .Bind(&near0)
     588           1 :       .Bind(&near1)
     589           1 :       .Bind(&near2)
     590           1 :       .Bind(&near3)
     591           1 :       .Bind(&near4)
     592           1 :       .JumpIfNull(&after_jump_far0)
     593           1 :       .Jump(&far0)
     594           1 :       .Bind(&after_jump_far0)
     595           1 :       .CompareOperation(Token::Value::EQ, reg, 3)
     596           1 :       .JumpIfTrue(ToBooleanMode::kAlreadyBoolean, &far1)
     597           1 :       .CompareOperation(Token::Value::EQ, reg, 4)
     598           1 :       .JumpIfFalse(ToBooleanMode::kAlreadyBoolean, &far2)
     599           1 :       .BinaryOperation(Token::Value::ADD, reg, 3)
     600           1 :       .JumpIfTrue(ToBooleanMode::kConvertToBoolean, &far3)
     601           1 :       .BinaryOperation(Token::Value::ADD, reg, 4)
     602           1 :       .JumpIfFalse(ToBooleanMode::kConvertToBoolean, &far4);
     603         509 :   for (int i = 0; i < kFarJumpDistance - 22; i++) {
     604         254 :     builder.Debugger();
     605             :   }
     606           1 :   builder.Bind(&far0).Bind(&far1).Bind(&far2).Bind(&far3).Bind(&far4);
     607           1 :   builder.Return();
     608             : 
     609           1 :   Handle<BytecodeArray> array = builder.ToBytecodeArray(isolate());
     610             :   DCHECK_EQ(array->length(), 48 + kFarJumpDistance - 22 + 1);
     611             : 
     612           1 :   BytecodeArrayIterator iterator(array);
     613             : 
     614             :   // Ignore JumpIfNull operation.
     615           1 :   iterator.Advance();
     616             : 
     617           1 :   CHECK_EQ(iterator.current_bytecode(), Bytecode::kJump);
     618           1 :   CHECK_EQ(iterator.GetUnsignedImmediateOperand(0), 22);
     619           1 :   iterator.Advance();
     620             : 
     621             :   // Ignore compare operation.
     622           1 :   iterator.Advance();
     623             : 
     624           1 :   CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpIfTrue);
     625           1 :   CHECK_EQ(iterator.GetUnsignedImmediateOperand(0), 17);
     626           1 :   iterator.Advance();
     627             : 
     628             :   // Ignore compare operation.
     629           1 :   iterator.Advance();
     630             : 
     631           1 :   CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpIfFalse);
     632           1 :   CHECK_EQ(iterator.GetUnsignedImmediateOperand(0), 12);
     633           1 :   iterator.Advance();
     634             : 
     635             :   // Ignore add operation.
     636           1 :   iterator.Advance();
     637             : 
     638           1 :   CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpIfToBooleanTrue);
     639           1 :   CHECK_EQ(iterator.GetUnsignedImmediateOperand(0), 7);
     640           1 :   iterator.Advance();
     641             : 
     642             :   // Ignore add operation.
     643           1 :   iterator.Advance();
     644             : 
     645           1 :   CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpIfToBooleanFalse);
     646           1 :   CHECK_EQ(iterator.GetUnsignedImmediateOperand(0), 2);
     647           1 :   iterator.Advance();
     648             : 
     649             :   // Ignore JumpIfNull operation.
     650           1 :   iterator.Advance();
     651             : 
     652           1 :   CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpConstant);
     653           2 :   CHECK_EQ(iterator.GetConstantForIndexOperand(0),
     654             :            Smi::FromInt(kFarJumpDistance));
     655           1 :   iterator.Advance();
     656             : 
     657             :   // Ignore compare operation.
     658           1 :   iterator.Advance();
     659             : 
     660           1 :   CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpIfTrueConstant);
     661           2 :   CHECK_EQ(iterator.GetConstantForIndexOperand(0),
     662             :            Smi::FromInt(kFarJumpDistance - 5));
     663           1 :   iterator.Advance();
     664             : 
     665             :   // Ignore compare operation.
     666           1 :   iterator.Advance();
     667             : 
     668           1 :   CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpIfFalseConstant);
     669           2 :   CHECK_EQ(iterator.GetConstantForIndexOperand(0),
     670             :            Smi::FromInt(kFarJumpDistance - 10));
     671           1 :   iterator.Advance();
     672             : 
     673             :   // Ignore add operation.
     674           1 :   iterator.Advance();
     675             : 
     676           1 :   CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpIfToBooleanTrueConstant);
     677           2 :   CHECK_EQ(iterator.GetConstantForIndexOperand(0),
     678             :            Smi::FromInt(kFarJumpDistance - 15));
     679           1 :   iterator.Advance();
     680             : 
     681             :   // Ignore add operation.
     682           1 :   iterator.Advance();
     683             : 
     684           1 :   CHECK_EQ(iterator.current_bytecode(),
     685             :            Bytecode::kJumpIfToBooleanFalseConstant);
     686           2 :   CHECK_EQ(iterator.GetConstantForIndexOperand(0),
     687             :            Smi::FromInt(kFarJumpDistance - 20));
     688           1 :   iterator.Advance();
     689           1 : }
     690             : 
     691             : 
     692       15419 : TEST_F(BytecodeArrayBuilderTest, BackwardJumps) {
     693           2 :   BytecodeArrayBuilder builder(zone(), 1, 1);
     694             : 
     695             :   Register reg(0);
     696             : 
     697             :   BytecodeLabel end;
     698           1 :   builder.JumpIfNull(&end);
     699             : 
     700             :   BytecodeLabel after_loop;
     701             :   // Conditional jump to force the code after the JumpLoop to be live.
     702             :   // Technically this jump is illegal because it's jumping into the middle of
     703             :   // the subsequent loops, but that's ok for this unit test.
     704             :   BytecodeLoopHeader loop_header;
     705           1 :   builder.JumpIfNull(&after_loop)
     706           1 :       .Bind(&loop_header)
     707           1 :       .JumpLoop(&loop_header, 0)
     708           1 :       .Bind(&after_loop);
     709          85 :   for (int i = 0; i < 42; i++) {
     710             :     BytecodeLabel after_loop;
     711             :     // Conditional jump to force the code after the JumpLoop to be live.
     712          42 :     builder.JumpIfNull(&after_loop).JumpLoop(&loop_header, 0).Bind(&after_loop);
     713             :   }
     714             : 
     715             :   // Add padding to force wide backwards jumps.
     716         513 :   for (int i = 0; i < 256; i++) {
     717         256 :     builder.Debugger();
     718             :   }
     719             : 
     720           1 :   builder.JumpLoop(&loop_header, 0);
     721           1 :   builder.Bind(&end);
     722           1 :   builder.Return();
     723             : 
     724           1 :   Handle<BytecodeArray> array = builder.ToBytecodeArray(isolate());
     725           1 :   BytecodeArrayIterator iterator(array);
     726             :   // Ignore the JumpIfNull to the end
     727           1 :   iterator.Advance();
     728             :   // Ignore the JumpIfNull to after the first JumpLoop
     729           1 :   iterator.Advance();
     730           1 :   CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpLoop);
     731           1 :   CHECK_EQ(iterator.GetUnsignedImmediateOperand(0), 0);
     732           1 :   iterator.Advance();
     733          85 :   for (unsigned i = 0; i < 42; i++) {
     734             :     // Ignore the JumpIfNull to after the JumpLoop
     735          42 :     iterator.Advance();
     736             : 
     737          42 :     CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpLoop);
     738          42 :     CHECK_EQ(iterator.current_operand_scale(), OperandScale::kSingle);
     739             :     // offset of 5 (because kJumpLoop takes two immediate operands and
     740             :     // JumpIfNull takes 1)
     741          42 :     CHECK_EQ(iterator.GetUnsignedImmediateOperand(0), i * 5 + 5);
     742          42 :     iterator.Advance();
     743             :   }
     744             :   // Check padding to force wide backwards jumps.
     745         513 :   for (int i = 0; i < 256; i++) {
     746         256 :     CHECK_EQ(iterator.current_bytecode(), Bytecode::kDebugger);
     747         256 :     iterator.Advance();
     748             :   }
     749           1 :   CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpLoop);
     750           1 :   CHECK_EQ(iterator.current_operand_scale(), OperandScale::kDouble);
     751           1 :   CHECK_EQ(iterator.GetUnsignedImmediateOperand(0), 42 * 5 + 256 + 4);
     752           1 :   iterator.Advance();
     753           1 :   CHECK_EQ(iterator.current_bytecode(), Bytecode::kReturn);
     754           1 :   iterator.Advance();
     755           1 :   CHECK(iterator.done());
     756           1 : }
     757             : 
     758       15419 : TEST_F(BytecodeArrayBuilderTest, SmallSwitch) {
     759           2 :   BytecodeArrayBuilder builder(zone(), 1, 1);
     760             : 
     761             :   // Small jump table that fits into the single-size constant pool
     762             :   int small_jump_table_size = 5;
     763             :   int small_jump_table_base = -2;
     764             :   BytecodeJumpTable* small_jump_table =
     765           1 :       builder.AllocateJumpTable(small_jump_table_size, small_jump_table_base);
     766             : 
     767           1 :   builder.LoadLiteral(Smi::FromInt(7)).SwitchOnSmiNoFeedback(small_jump_table);
     768          11 :   for (int i = 0; i < small_jump_table_size; i++) {
     769           5 :     builder.Bind(small_jump_table, small_jump_table_base + i).Debugger();
     770             :   }
     771           1 :   builder.Return();
     772             : 
     773           1 :   Handle<BytecodeArray> array = builder.ToBytecodeArray(isolate());
     774           1 :   BytecodeArrayIterator iterator(array);
     775             : 
     776           1 :   CHECK_EQ(iterator.current_bytecode(), Bytecode::kLdaSmi);
     777           1 :   iterator.Advance();
     778             : 
     779           1 :   CHECK_EQ(iterator.current_bytecode(), Bytecode::kSwitchOnSmiNoFeedback);
     780           1 :   CHECK_EQ(iterator.current_operand_scale(), OperandScale::kSingle);
     781             :   {
     782             :     int i = 0;
     783             :     int switch_end =
     784           1 :         iterator.current_offset() + iterator.current_bytecode_size();
     785             : 
     786           6 :     for (const auto& entry : iterator.GetJumpTableTargetOffsets()) {
     787           5 :       CHECK_EQ(entry.case_value, small_jump_table_base + i);
     788           5 :       CHECK_EQ(entry.target_offset, switch_end + i);
     789             : 
     790           5 :       i++;
     791             :     }
     792           1 :     CHECK_EQ(i, small_jump_table_size);
     793             :   }
     794           1 :   iterator.Advance();
     795             : 
     796          11 :   for (int i = 0; i < small_jump_table_size; i++) {
     797           5 :     CHECK_EQ(iterator.current_bytecode(), Bytecode::kDebugger);
     798           5 :     iterator.Advance();
     799             :   }
     800             : 
     801           1 :   CHECK_EQ(iterator.current_bytecode(), Bytecode::kReturn);
     802           1 :   iterator.Advance();
     803           1 :   CHECK(iterator.done());
     804           1 : }
     805             : 
     806       15419 : TEST_F(BytecodeArrayBuilderTest, WideSwitch) {
     807           2 :   BytecodeArrayBuilder builder(zone(), 1, 1);
     808             : 
     809             :   // Large jump table that requires a wide Switch bytecode.
     810             :   int large_jump_table_size = 256;
     811             :   int large_jump_table_base = -10;
     812             :   BytecodeJumpTable* large_jump_table =
     813           1 :       builder.AllocateJumpTable(large_jump_table_size, large_jump_table_base);
     814             : 
     815           1 :   builder.LoadLiteral(Smi::FromInt(7)).SwitchOnSmiNoFeedback(large_jump_table);
     816         513 :   for (int i = 0; i < large_jump_table_size; i++) {
     817         256 :     builder.Bind(large_jump_table, large_jump_table_base + i).Debugger();
     818             :   }
     819           1 :   builder.Return();
     820             : 
     821           1 :   Handle<BytecodeArray> array = builder.ToBytecodeArray(isolate());
     822           1 :   BytecodeArrayIterator iterator(array);
     823             : 
     824           1 :   CHECK_EQ(iterator.current_bytecode(), Bytecode::kLdaSmi);
     825           1 :   iterator.Advance();
     826             : 
     827           1 :   CHECK_EQ(iterator.current_bytecode(), Bytecode::kSwitchOnSmiNoFeedback);
     828           1 :   CHECK_EQ(iterator.current_operand_scale(), OperandScale::kDouble);
     829             :   {
     830             :     int i = 0;
     831             :     int switch_end =
     832           1 :         iterator.current_offset() + iterator.current_bytecode_size();
     833             : 
     834         257 :     for (const auto& entry : iterator.GetJumpTableTargetOffsets()) {
     835         256 :       CHECK_EQ(entry.case_value, large_jump_table_base + i);
     836         256 :       CHECK_EQ(entry.target_offset, switch_end + i);
     837             : 
     838         256 :       i++;
     839             :     }
     840           1 :     CHECK_EQ(i, large_jump_table_size);
     841             :   }
     842           1 :   iterator.Advance();
     843             : 
     844         513 :   for (int i = 0; i < large_jump_table_size; i++) {
     845         256 :     CHECK_EQ(iterator.current_bytecode(), Bytecode::kDebugger);
     846         256 :     iterator.Advance();
     847             :   }
     848             : 
     849           1 :   CHECK_EQ(iterator.current_bytecode(), Bytecode::kReturn);
     850           1 :   iterator.Advance();
     851           1 :   CHECK(iterator.done());
     852           1 : }
     853             : 
     854             : }  // namespace interpreter
     855             : }  // namespace internal
     856        9249 : }  // namespace v8

Generated by: LCOV version 1.10