LCOV - code coverage report
Current view: top level - src/interpreter - bytecode-array-writer.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 153 165 92.7 %
Date: 2017-04-26 Functions: 14 17 82.4 %

          Line data    Source code
       1             : // Copyright 2015 the V8 project authors. All rights reserved.
       2             : // Use of this source code is governed by a BSD-style license that can be
       3             : // found in the LICENSE file.
       4             : 
       5             : #include "src/interpreter/bytecode-array-writer.h"
       6             : 
       7             : #include "src/api.h"
       8             : #include "src/interpreter/bytecode-label.h"
       9             : #include "src/interpreter/bytecode-node.h"
      10             : #include "src/interpreter/bytecode-register.h"
      11             : #include "src/interpreter/bytecode-source-info.h"
      12             : #include "src/interpreter/constant-array-builder.h"
      13             : #include "src/log.h"
      14             : #include "src/objects-inl.h"
      15             : 
      16             : namespace v8 {
      17             : namespace internal {
      18             : namespace interpreter {
      19             : 
      20             : STATIC_CONST_MEMBER_DEFINITION const size_t
      21             :     BytecodeArrayWriter::kMaxSizeOfPackedBytecode;
      22             : 
      23     2104905 : BytecodeArrayWriter::BytecodeArrayWriter(
      24             :     Zone* zone, ConstantArrayBuilder* constant_array_builder,
      25             :     SourcePositionTableBuilder::RecordingMode source_position_mode)
      26             :     : bytecodes_(zone),
      27             :       unbound_jumps_(0),
      28             :       source_position_table_builder_(zone, source_position_mode),
      29             :       constant_array_builder_(constant_array_builder),
      30             :       last_bytecode_(Bytecode::kIllegal),
      31             :       last_bytecode_offset_(0),
      32             :       last_bytecode_had_source_info_(false),
      33             :       elide_noneffectful_bytecodes_(FLAG_ignition_elide_noneffectful_bytecodes),
      34     4209810 :       exit_seen_in_block_(false) {
      35     2104905 :   bytecodes_.reserve(512);  // Derived via experimentation.
      36     2104911 : }
      37             : 
      38     2103817 : Handle<BytecodeArray> BytecodeArrayWriter::ToBytecodeArray(
      39             :     Isolate* isolate, int register_count, int parameter_count,
      40     2103817 :     Handle<FixedArray> handler_table) {
      41             :   DCHECK_EQ(0, unbound_jumps_);
      42             : 
      43     4207634 :   int bytecode_size = static_cast<int>(bytecodes()->size());
      44     2103817 :   int frame_size = register_count * kPointerSize;
      45             :   Handle<FixedArray> constant_pool =
      46     2103817 :       constant_array_builder()->ToFixedArray(isolate);
      47             :   Handle<BytecodeArray> bytecode_array = isolate->factory()->NewBytecodeArray(
      48             :       bytecode_size, &bytecodes()->front(), frame_size, parameter_count,
      49     2103823 :       constant_pool);
      50     2103825 :   bytecode_array->set_handler_table(*handler_table);
      51             :   Handle<ByteArray> source_position_table =
      52             :       source_position_table_builder()->ToSourcePositionTable(
      53     2103820 :           isolate, Handle<AbstractCode>::cast(bytecode_array));
      54     2103822 :   bytecode_array->set_source_position_table(*source_position_table);
      55     2103825 :   return bytecode_array;
      56             : }
      57             : 
      58   139358676 : void BytecodeArrayWriter::Write(BytecodeNode* node) {
      59             :   DCHECK(!Bytecodes::IsJump(node->bytecode()));
      60             : 
      61   139410838 :   if (exit_seen_in_block_) return;  // Don't emit dead code.
      62             :   UpdateExitSeenInBlock(node->bytecode());
      63   139306486 :   MaybeElideLastBytecode(node->bytecode(), node->source_info().is_valid());
      64             : 
      65    69653348 :   UpdateSourcePositionTable(node);
      66    69653334 :   EmitBytecode(node);
      67             : }
      68             : 
      69     6153842 : void BytecodeArrayWriter::WriteJump(BytecodeNode* node, BytecodeLabel* label) {
      70             :   DCHECK(Bytecodes::IsJump(node->bytecode()));
      71             : 
      72             :   // TODO(rmcilroy): For forward jumps we could also mark the label as dead,
      73             :   // thereby avoiding emitting dead code when we bind the label.
      74     6168918 :   if (exit_seen_in_block_) return;  // Don't emit dead code.
      75             :   UpdateExitSeenInBlock(node->bytecode());
      76     6138764 :   MaybeElideLastBytecode(node->bytecode(), node->source_info().is_valid());
      77             : 
      78     3069382 :   UpdateSourcePositionTable(node);
      79     3069382 :   EmitJump(node, label);
      80             : }
      81             : 
      82     4749872 : void BytecodeArrayWriter::BindLabel(BytecodeLabel* label) {
      83     4749872 :   size_t current_offset = bytecodes()->size();
      84     4749872 :   if (label->is_forward_target()) {
      85             :     // An earlier jump instruction refers to this label. Update it's location.
      86     2877991 :     PatchJump(current_offset, label->offset());
      87             :     // Now treat as if the label will only be back referred to.
      88             :   }
      89             :   label->bind_to(current_offset);
      90             :   InvalidateLastBytecode();
      91     4749872 :   exit_seen_in_block_ = false;  // Starting a new basic block.
      92     4749872 : }
      93             : 
      94           0 : void BytecodeArrayWriter::BindLabel(const BytecodeLabel& target,
      95             :                                     BytecodeLabel* label) {
      96             :   DCHECK(!label->is_bound());
      97             :   DCHECK(target.is_bound());
      98           0 :   if (label->is_forward_target()) {
      99             :     // An earlier jump instruction refers to this label. Update it's location.
     100           0 :     PatchJump(target.offset(), label->offset());
     101             :     // Now treat as if the label will only be back referred to.
     102             :   }
     103             :   label->bind_to(target.offset());
     104             :   InvalidateLastBytecode();
     105             :   // exit_seen_in_block_ was reset when target was bound, so shouldn't be
     106             :   // changed here.
     107           0 : }
     108             : 
     109    72722691 : void BytecodeArrayWriter::UpdateSourcePositionTable(
     110             :     const BytecodeNode* const node) {
     111   145445382 :   int bytecode_offset = static_cast<int>(bytecodes()->size());
     112   100302691 :   const BytecodeSourceInfo& source_info = node->source_info();
     113    72722691 :   if (source_info.is_valid()) {
     114             :     source_position_table_builder()->AddPosition(
     115             :         bytecode_offset, SourcePosition(source_info.source_position()),
     116    55160000 :         source_info.is_statement());
     117             :   }
     118    72722685 : }
     119             : 
     120           0 : void BytecodeArrayWriter::UpdateExitSeenInBlock(Bytecode bytecode) {
     121             :   switch (bytecode) {
     122             :     case Bytecode::kReturn:
     123             :     case Bytecode::kThrow:
     124             :     case Bytecode::kReThrow:
     125             :     case Bytecode::kJump:
     126             :     case Bytecode::kJumpConstant:
     127     3543362 :       exit_seen_in_block_ = true;
     128           0 :       break;
     129             :     default:
     130             :       break;
     131             :   }
     132           0 : }
     133             : 
     134    72722589 : void BytecodeArrayWriter::MaybeElideLastBytecode(Bytecode next_bytecode,
     135             :                                                  bool has_source_info) {
     136   145445274 :   if (!elide_noneffectful_bytecodes_) return;
     137             : 
     138             :   // If the last bytecode loaded the accumulator without any external effect,
     139             :   // and the next bytecode clobbers this load without reading the accumulator,
     140             :   // then the previous bytecode can be elided as it has no effect.
     141   162779939 :   if (Bytecodes::IsAccumulatorLoadWithoutEffects(last_bytecode_) &&
     142    73308631 :       Bytecodes::GetAccumulatorUse(next_bytecode) == AccumulatorUse::kWrite &&
     143      587492 :       (!last_bytecode_had_source_info_ || !has_source_info)) {
     144             :     DCHECK_GT(bytecodes()->size(), last_bytecode_offset_);
     145      584702 :     bytecodes()->resize(last_bytecode_offset_);
     146             :     // If the last bytecode had source info we will transfer the source info
     147             :     // to this bytecode.
     148      584702 :     has_source_info |= last_bytecode_had_source_info_;
     149             :   }
     150    72722648 :   last_bytecode_ = next_bytecode;
     151    72722648 :   last_bytecode_had_source_info_ = has_source_info;
     152   145445296 :   last_bytecode_offset_ = bytecodes()->size();
     153             : }
     154             : 
     155           0 : void BytecodeArrayWriter::InvalidateLastBytecode() {
     156     4749872 :   last_bytecode_ = Bytecode::kIllegal;
     157           0 : }
     158             : 
     159   145445229 : void BytecodeArrayWriter::EmitBytecode(const BytecodeNode* const node) {
     160             :   DCHECK_NE(node->bytecode(), Bytecode::kIllegal);
     161             : 
     162             :   Bytecode bytecode = node->bytecode();
     163             :   OperandScale operand_scale = node->operand_scale();
     164             : 
     165    72722627 :   if (operand_scale != OperandScale::kSingle) {
     166    11174064 :     Bytecode prefix = Bytecodes::OperandScaleToPrefixBytecode(operand_scale);
     167    22348128 :     bytecodes()->push_back(Bytecodes::ToByte(prefix));
     168             :   }
     169   145445229 :   bytecodes()->push_back(Bytecodes::ToByte(bytecode));
     170             : 
     171    72722602 :   const uint32_t* const operands = node->operands();
     172             :   const int operand_count = node->operand_count();
     173             :   const OperandSize* operand_sizes =
     174             :       Bytecodes::GetOperandSizes(bytecode, operand_scale);
     175   176283678 :   for (int i = 0; i < operand_count; ++i) {
     176   103561160 :     switch (operand_sizes[i]) {
     177             :       case OperandSize::kNone:
     178           4 :         UNREACHABLE();
     179             :         break;
     180             :       case OperandSize::kByte:
     181   170139341 :         bytecodes()->push_back(static_cast<uint8_t>(operands[i]));
     182    85069631 :         break;
     183             :       case OperandSize::kShort: {
     184    18296616 :         uint16_t operand = static_cast<uint16_t>(operands[i]);
     185             :         const uint8_t* raw_operand = reinterpret_cast<const uint8_t*>(&operand);
     186    18296616 :         bytecodes()->push_back(raw_operand[0]);
     187    18296616 :         bytecodes()->push_back(raw_operand[1]);
     188             :         break;
     189             :       }
     190             :       case OperandSize::kQuad: {
     191             :         const uint8_t* raw_operand =
     192      194944 :             reinterpret_cast<const uint8_t*>(&operands[i]);
     193      194944 :         bytecodes()->push_back(raw_operand[0]);
     194      194944 :         bytecodes()->push_back(raw_operand[1]);
     195      194944 :         bytecodes()->push_back(raw_operand[2]);
     196      194944 :         bytecodes()->push_back(raw_operand[3]);
     197      194944 :         break;
     198             :       }
     199             :     }
     200             :   }
     201    72722518 : }
     202             : 
     203             : // static
     204       82763 : Bytecode GetJumpWithConstantOperand(Bytecode jump_bytecode) {
     205       82763 :   switch (jump_bytecode) {
     206             :     case Bytecode::kJump:
     207             :       return Bytecode::kJumpConstant;
     208             :     case Bytecode::kJumpIfTrue:
     209       25557 :       return Bytecode::kJumpIfTrueConstant;
     210             :     case Bytecode::kJumpIfFalse:
     211        5479 :       return Bytecode::kJumpIfFalseConstant;
     212             :     case Bytecode::kJumpIfToBooleanTrue:
     213        7382 :       return Bytecode::kJumpIfToBooleanTrueConstant;
     214             :     case Bytecode::kJumpIfToBooleanFalse:
     215        1111 :       return Bytecode::kJumpIfToBooleanFalseConstant;
     216             :     case Bytecode::kJumpIfNotHole:
     217           1 :       return Bytecode::kJumpIfNotHoleConstant;
     218             :     case Bytecode::kJumpIfNull:
     219         208 :       return Bytecode::kJumpIfNullConstant;
     220             :     case Bytecode::kJumpIfNotNull:
     221           1 :       return Bytecode::kJumpIfNotNullConstant;
     222             :     case Bytecode::kJumpIfUndefined:
     223         484 :       return Bytecode::kJumpIfUndefinedConstant;
     224             :     case Bytecode::kJumpIfNotUndefined:
     225          31 :       return Bytecode::kJumpIfNotUndefinedConstant;
     226             :     case Bytecode::kJumpIfJSReceiver:
     227           1 :       return Bytecode::kJumpIfJSReceiverConstant;
     228             :     default:
     229           0 :       UNREACHABLE();
     230             :       return Bytecode::kIllegal;
     231             :   }
     232             : }
     233             : 
     234     2794851 : void BytecodeArrayWriter::PatchJumpWith8BitOperand(size_t jump_location,
     235     2794851 :                                                    int delta) {
     236     2794851 :   Bytecode jump_bytecode = Bytecodes::FromByte(bytecodes()->at(jump_location));
     237             :   DCHECK(Bytecodes::IsForwardJump(jump_bytecode));
     238             :   DCHECK(Bytecodes::IsJumpImmediate(jump_bytecode));
     239             :   DCHECK_EQ(Bytecodes::GetOperandType(jump_bytecode, 0), OperandType::kUImm);
     240             :   DCHECK_GT(delta, 0);
     241     2794851 :   size_t operand_location = jump_location + 1;
     242             :   DCHECK_EQ(bytecodes()->at(operand_location), k8BitJumpPlaceholder);
     243     5589702 :   if (Bytecodes::ScaleForUnsignedOperand(delta) == OperandScale::kSingle) {
     244             :     // The jump fits within the range of an UImm8 operand, so cancel
     245             :     // the reservation and jump directly.
     246     2712095 :     constant_array_builder()->DiscardReservedEntry(OperandSize::kByte);
     247     2712095 :     bytecodes()->at(operand_location) = static_cast<uint8_t>(delta);
     248             :   } else {
     249             :     // The jump does not fit within the range of an UImm8 operand, so
     250             :     // commit reservation putting the offset into the constant pool,
     251             :     // and update the jump instruction and operand.
     252             :     size_t entry = constant_array_builder()->CommitReservedEntry(
     253       82756 :         OperandSize::kByte, Smi::FromInt(delta));
     254             :     DCHECK_EQ(Bytecodes::SizeForUnsignedOperand(static_cast<uint32_t>(entry)),
     255             :               OperandSize::kByte);
     256       82756 :     jump_bytecode = GetJumpWithConstantOperand(jump_bytecode);
     257       82756 :     bytecodes()->at(jump_location) = Bytecodes::ToByte(jump_bytecode);
     258       82756 :     bytecodes()->at(operand_location) = static_cast<uint8_t>(entry);
     259             :   }
     260     2794851 : }
     261             : 
     262       83133 : void BytecodeArrayWriter::PatchJumpWith16BitOperand(size_t jump_location,
     263       83133 :                                                     int delta) {
     264       83133 :   Bytecode jump_bytecode = Bytecodes::FromByte(bytecodes()->at(jump_location));
     265             :   DCHECK(Bytecodes::IsForwardJump(jump_bytecode));
     266             :   DCHECK(Bytecodes::IsJumpImmediate(jump_bytecode));
     267             :   DCHECK_EQ(Bytecodes::GetOperandType(jump_bytecode, 0), OperandType::kUImm);
     268             :   DCHECK_GT(delta, 0);
     269       83133 :   size_t operand_location = jump_location + 1;
     270             :   uint8_t operand_bytes[2];
     271      166266 :   if (Bytecodes::ScaleForUnsignedOperand(delta) <= OperandScale::kDouble) {
     272             :     // The jump fits within the range of an Imm16 operand, so cancel
     273             :     // the reservation and jump directly.
     274       83126 :     constant_array_builder()->DiscardReservedEntry(OperandSize::kShort);
     275       83126 :     WriteUnalignedUInt16(operand_bytes, static_cast<uint16_t>(delta));
     276             :   } else {
     277             :     // The jump does not fit within the range of an Imm16 operand, so
     278             :     // commit reservation putting the offset into the constant pool,
     279             :     // and update the jump instruction and operand.
     280             :     size_t entry = constant_array_builder()->CommitReservedEntry(
     281           7 :         OperandSize::kShort, Smi::FromInt(delta));
     282           7 :     jump_bytecode = GetJumpWithConstantOperand(jump_bytecode);
     283           7 :     bytecodes()->at(jump_location) = Bytecodes::ToByte(jump_bytecode);
     284           7 :     WriteUnalignedUInt16(operand_bytes, static_cast<uint16_t>(entry));
     285             :   }
     286             :   DCHECK(bytecodes()->at(operand_location) == k8BitJumpPlaceholder &&
     287             :          bytecodes()->at(operand_location + 1) == k8BitJumpPlaceholder);
     288      166266 :   bytecodes()->at(operand_location++) = operand_bytes[0];
     289       83133 :   bytecodes()->at(operand_location) = operand_bytes[1];
     290       83133 : }
     291             : 
     292           7 : void BytecodeArrayWriter::PatchJumpWith32BitOperand(size_t jump_location,
     293           7 :                                                     int delta) {
     294             :   DCHECK(Bytecodes::IsJumpImmediate(
     295             :       Bytecodes::FromByte(bytecodes()->at(jump_location))));
     296           7 :   constant_array_builder()->DiscardReservedEntry(OperandSize::kQuad);
     297             :   uint8_t operand_bytes[4];
     298           7 :   WriteUnalignedUInt32(operand_bytes, static_cast<uint32_t>(delta));
     299           7 :   size_t operand_location = jump_location + 1;
     300             :   DCHECK(bytecodes()->at(operand_location) == k8BitJumpPlaceholder &&
     301             :          bytecodes()->at(operand_location + 1) == k8BitJumpPlaceholder &&
     302             :          bytecodes()->at(operand_location + 2) == k8BitJumpPlaceholder &&
     303             :          bytecodes()->at(operand_location + 3) == k8BitJumpPlaceholder);
     304          14 :   bytecodes()->at(operand_location++) = operand_bytes[0];
     305          14 :   bytecodes()->at(operand_location++) = operand_bytes[1];
     306          14 :   bytecodes()->at(operand_location++) = operand_bytes[2];
     307           7 :   bytecodes()->at(operand_location) = operand_bytes[3];
     308           7 : }
     309             : 
     310     2877991 : void BytecodeArrayWriter::PatchJump(size_t jump_target, size_t jump_location) {
     311     2877991 :   Bytecode jump_bytecode = Bytecodes::FromByte(bytecodes()->at(jump_location));
     312     2877991 :   int delta = static_cast<int>(jump_target - jump_location);
     313             :   int prefix_offset = 0;
     314             :   OperandScale operand_scale = OperandScale::kSingle;
     315     2877991 :   if (Bytecodes::IsPrefixScalingBytecode(jump_bytecode)) {
     316             :     // If a prefix scaling bytecode is emitted the target offset is one
     317             :     // less than the case of no prefix scaling bytecode.
     318       83140 :     delta -= 1;
     319             :     prefix_offset = 1;
     320       83140 :     operand_scale = Bytecodes::PrefixBytecodeToOperandScale(jump_bytecode);
     321             :     jump_bytecode =
     322       83140 :         Bytecodes::FromByte(bytecodes()->at(jump_location + prefix_offset));
     323             :   }
     324             : 
     325             :   DCHECK(Bytecodes::IsJump(jump_bytecode));
     326     2877991 :   switch (operand_scale) {
     327             :     case OperandScale::kSingle:
     328     2794851 :       PatchJumpWith8BitOperand(jump_location, delta);
     329     2794851 :       break;
     330             :     case OperandScale::kDouble:
     331       83133 :       PatchJumpWith16BitOperand(jump_location + prefix_offset, delta);
     332       83133 :       break;
     333             :     case OperandScale::kQuadruple:
     334           7 :       PatchJumpWith32BitOperand(jump_location + prefix_offset, delta);
     335           7 :       break;
     336             :     default:
     337           0 :       UNREACHABLE();
     338             :   }
     339     2877991 :   unbound_jumps_--;
     340     2877991 : }
     341             : 
     342     9208146 : void BytecodeArrayWriter::EmitJump(BytecodeNode* node, BytecodeLabel* label) {
     343             :   DCHECK(Bytecodes::IsJump(node->bytecode()));
     344             :   DCHECK_EQ(0u, node->operand(0));
     345             : 
     346     3069382 :   size_t current_offset = bytecodes()->size();
     347             : 
     348     3069382 :   if (label->is_bound()) {
     349      191393 :     CHECK_GE(current_offset, label->offset());
     350      191393 :     CHECK_LE(current_offset, static_cast<size_t>(kMaxUInt32));
     351             :     // Label has been bound already so this is a backwards jump.
     352      191393 :     uint32_t delta = static_cast<uint32_t>(current_offset - label->offset());
     353             :     OperandScale operand_scale = Bytecodes::ScaleForUnsignedOperand(delta);
     354      191393 :     if (operand_scale > OperandScale::kSingle) {
     355             :       // Adjust for scaling byte prefix for wide jump offset.
     356        9241 :       delta += 1;
     357             :     }
     358             :     DCHECK_EQ(Bytecode::kJumpLoop, node->bytecode());
     359      191393 :     node->update_operand0(delta);
     360             :   } else {
     361             :     // The label has not yet been bound so this is a forward reference
     362             :     // that will be patched when the label is bound. We create a
     363             :     // reservation in the constant pool so the jump can be patched
     364             :     // when the label is bound. The reservation means the maximum size
     365             :     // of the operand for the constant is known and the jump can
     366             :     // be emitted into the bytecode stream with space for the operand.
     367     2877989 :     unbound_jumps_++;
     368             :     label->set_referrer(current_offset);
     369             :     OperandSize reserved_operand_size =
     370     2877989 :         constant_array_builder()->CreateReservedEntry();
     371             :     DCHECK_NE(Bytecode::kJumpLoop, node->bytecode());
     372     2877988 :     switch (reserved_operand_size) {
     373             :       case OperandSize::kNone:
     374           0 :         UNREACHABLE();
     375             :         break;
     376             :       case OperandSize::kByte:
     377     2794848 :         node->update_operand0(k8BitJumpPlaceholder);
     378     2794848 :         break;
     379             :       case OperandSize::kShort:
     380       83133 :         node->update_operand0(k16BitJumpPlaceholder);
     381       83133 :         break;
     382             :       case OperandSize::kQuad:
     383           7 :         node->update_operand0(k32BitJumpPlaceholder);
     384           7 :         break;
     385             :     }
     386             :   }
     387     3069381 :   EmitBytecode(node);
     388     3069380 : }
     389             : 
     390             : }  // namespace interpreter
     391             : }  // namespace internal
     392             : }  // namespace v8

Generated by: LCOV version 1.10