diff options
author | Michaël Zasso <targos@protonmail.com> | 2016-05-27 16:37:42 +0200 |
---|---|---|
committer | Michaël Zasso <targos@protonmail.com> | 2016-06-29 09:04:28 +0200 |
commit | 2cc29517966de7257a2f1b34c58c77225a21e05d (patch) | |
tree | 210bd177df2f06eec16e1e22edafdbcbffe66f8a /deps/v8/src/interpreter | |
parent | bbf3838c70aaec1dd296fa75ae334fd1c7866df3 (diff) | |
download | android-node-v8-2cc29517966de7257a2f1b34c58c77225a21e05d.tar.gz android-node-v8-2cc29517966de7257a2f1b34c58c77225a21e05d.tar.bz2 android-node-v8-2cc29517966de7257a2f1b34c58c77225a21e05d.zip |
deps: update V8 to 5.1.281.69
Pick up the latest branch-head for V8 5.1. This branch brings in
improved language support and performance improvements. For full
details: http://v8project.blogspot.com/2016/04/v8-release-51.html
* Picks up the latest branch head for 5.1 [1]
* Edit v8 gitignore to allow trace_event copy
* Update V8 DEP trace_event as per deps/v8/DEPS [2]
[1] https://chromium.googlesource.com/v8/v8.git/+/dc81244
[2] https://chromium.googlesource.com/chromium/src/base/trace_event/common/+/c8c8665
PR-URL: https://github.com/nodejs/node/pull/7016
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
Diffstat (limited to 'deps/v8/src/interpreter')
21 files changed, 2621 insertions, 2498 deletions
diff --git a/deps/v8/src/interpreter/bytecode-array-builder.cc b/deps/v8/src/interpreter/bytecode-array-builder.cc index 7103c72178..109b01eab3 100644 --- a/deps/v8/src/interpreter/bytecode-array-builder.cc +++ b/deps/v8/src/interpreter/bytecode-array-builder.cc @@ -4,6 +4,7 @@ #include "src/interpreter/bytecode-array-builder.h" #include "src/compiler.h" +#include "src/interpreter/interpreter-intrinsics.h" namespace v8 { namespace internal { @@ -17,49 +18,75 @@ class BytecodeArrayBuilder::PreviousBytecodeHelper BASE_EMBEDDED { // This helper is expected to be instantiated only when the last bytecode is // in the same basic block. DCHECK(array_builder_.LastBytecodeInSameBlock()); + bytecode_ = Bytecodes::FromByte( + array_builder_.bytecodes()->at(previous_bytecode_start_)); + operand_scale_ = OperandScale::kSingle; + if (Bytecodes::IsPrefixScalingBytecode(bytecode_)) { + operand_scale_ = Bytecodes::PrefixBytecodeToOperandScale(bytecode_); + bytecode_ = Bytecodes::FromByte( + array_builder_.bytecodes()->at(previous_bytecode_start_ + 1)); + } } // Returns the previous bytecode in the same basic block. MUST_USE_RESULT Bytecode GetBytecode() const { DCHECK_EQ(array_builder_.last_bytecode_start_, previous_bytecode_start_); - return Bytecodes::FromByte( - array_builder_.bytecodes()->at(previous_bytecode_start_)); + return bytecode_; } - // Returns the operand at operand_index for the previous bytecode in the - // same basic block. - MUST_USE_RESULT uint32_t GetOperand(int operand_index) const { - DCHECK_EQ(array_builder_.last_bytecode_start_, previous_bytecode_start_); - Bytecode bytecode = GetBytecode(); - DCHECK_GE(operand_index, 0); - DCHECK_LT(operand_index, Bytecodes::NumberOfOperands(bytecode)); - size_t operand_offset = - previous_bytecode_start_ + - Bytecodes::GetOperandOffset(bytecode, operand_index); - OperandSize size = Bytecodes::GetOperandSize(bytecode, operand_index); - switch (size) { - case OperandSize::kNone: - UNREACHABLE(); - break; - case OperandSize::kByte: - return static_cast<uint32_t>( - array_builder_.bytecodes()->at(operand_offset)); - case OperandSize::kShort: - uint16_t operand = - (array_builder_.bytecodes()->at(operand_offset) << 8) + - array_builder_.bytecodes()->at(operand_offset + 1); - return static_cast<uint32_t>(operand); - } - return 0; + MUST_USE_RESULT Register GetRegisterOperand(int operand_index) const { + return Register::FromOperand(GetSignedOperand(operand_index)); + } + + MUST_USE_RESULT uint32_t GetIndexOperand(int operand_index) const { + return GetUnsignedOperand(operand_index); } Handle<Object> GetConstantForIndexOperand(int operand_index) const { return array_builder_.constant_array_builder()->At( - GetOperand(operand_index)); + GetIndexOperand(operand_index)); } private: + // Returns the signed operand at operand_index for the previous + // bytecode in the same basic block. + MUST_USE_RESULT int32_t GetSignedOperand(int operand_index) const { + DCHECK_EQ(array_builder_.last_bytecode_start_, previous_bytecode_start_); + OperandType operand_type = + Bytecodes::GetOperandType(bytecode_, operand_index); + DCHECK(!Bytecodes::IsUnsignedOperandType(operand_type)); + const uint8_t* operand_start = GetOperandStart(operand_index); + return Bytecodes::DecodeSignedOperand(operand_start, operand_type, + operand_scale_); + } + + // Returns the unsigned operand at operand_index for the previous + // bytecode in the same basic block. + MUST_USE_RESULT uint32_t GetUnsignedOperand(int operand_index) const { + DCHECK_EQ(array_builder_.last_bytecode_start_, previous_bytecode_start_); + OperandType operand_type = + Bytecodes::GetOperandType(bytecode_, operand_index); + DCHECK(Bytecodes::IsUnsignedOperandType(operand_type)); + const uint8_t* operand_start = GetOperandStart(operand_index); + return Bytecodes::DecodeUnsignedOperand(operand_start, operand_type, + operand_scale_); + } + + const uint8_t* GetOperandStart(int operand_index) const { + size_t operand_offset = + previous_bytecode_start_ + prefix_offset() + + Bytecodes::GetOperandOffset(bytecode_, operand_index, operand_scale_); + return &(*array_builder_.bytecodes())[0] + operand_offset; + } + + int prefix_offset() const { + return Bytecodes::OperandScaleRequiresPrefixBytecode(operand_scale_) ? 1 + : 0; + } + const BytecodeArrayBuilder& array_builder_; + OperandScale operand_scale_; + Bytecode bytecode_; size_t previous_bytecode_start_; DISALLOW_COPY_AND_ASSIGN(PreviousBytecodeHelper); @@ -67,7 +94,8 @@ class BytecodeArrayBuilder::PreviousBytecodeHelper BASE_EMBEDDED { BytecodeArrayBuilder::BytecodeArrayBuilder(Isolate* isolate, Zone* zone, int parameter_count, - int context_count, int locals_count) + int context_count, int locals_count, + FunctionLiteral* literal) : isolate_(isolate), zone_(zone), bytecodes_(zone), @@ -82,11 +110,15 @@ BytecodeArrayBuilder::BytecodeArrayBuilder(Isolate* isolate, Zone* zone, parameter_count_(parameter_count), local_register_count_(locals_count), context_register_count_(context_count), - temporary_allocator_(zone, fixed_register_count()), - register_translator_(this) { + temporary_allocator_(zone, fixed_register_count()) { DCHECK_GE(parameter_count_, 0); DCHECK_GE(context_register_count_, 0); DCHECK_GE(local_register_count_, 0); + return_position_ = + literal ? std::max(literal->start_position(), literal->end_position() - 1) + : RelocInfo::kNoPosition; + LOG_CODE_EVENT(isolate_, CodeStartLinePosInfoRecordEvent( + source_position_table_builder())); } BytecodeArrayBuilder::~BytecodeArrayBuilder() { DCHECK_EQ(0, unbound_jumps_); } @@ -119,45 +151,49 @@ Handle<BytecodeArray> BytecodeArrayBuilder::ToBytecodeArray() { DCHECK(exit_seen_in_block_); int bytecode_size = static_cast<int>(bytecodes_.size()); - int register_count = - fixed_and_temporary_register_count() + translation_register_count(); + int register_count = fixed_and_temporary_register_count(); int frame_size = register_count * kPointerSize; Handle<FixedArray> constant_pool = constant_array_builder()->ToFixedArray(); Handle<FixedArray> handler_table = handler_table_builder()->ToHandlerTable(); - Handle<FixedArray> source_position_table = - source_position_table_builder()->ToFixedArray(); - Handle<BytecodeArray> output = isolate_->factory()->NewBytecodeArray( + Handle<ByteArray> source_position_table = + source_position_table_builder()->ToSourcePositionTable(); + Handle<BytecodeArray> bytecode_array = isolate_->factory()->NewBytecodeArray( bytecode_size, &bytecodes_.front(), frame_size, parameter_count(), constant_pool); - output->set_handler_table(*handler_table); - output->set_source_position_table(*source_position_table); + bytecode_array->set_handler_table(*handler_table); + bytecode_array->set_source_position_table(*source_position_table); + + void* line_info = source_position_table_builder()->DetachJITHandlerData(); + LOG_CODE_EVENT(isolate_, CodeEndLinePosInfoRecordEvent( + AbstractCode::cast(*bytecode_array), line_info)); + bytecode_generated_ = true; - return output; + return bytecode_array; } - template <size_t N> -void BytecodeArrayBuilder::Output(Bytecode bytecode, uint32_t(&operands)[N]) { +void BytecodeArrayBuilder::Output(Bytecode bytecode, uint32_t (&operands)[N], + OperandScale operand_scale) { // Don't output dead code. - if (exit_seen_in_block_) { - source_position_table_builder_.RevertPosition(bytecodes()->size()); - return; - } + if (exit_seen_in_block_) return; int operand_count = static_cast<int>(N); DCHECK_EQ(Bytecodes::NumberOfOperands(bytecode), operand_count); - int register_operand_count = Bytecodes::NumberOfRegisterOperands(bytecode); - if (register_operand_count > 0) { - register_translator()->TranslateInputRegisters(bytecode, operands, - operand_count); + last_bytecode_start_ = bytecodes()->size(); + // Emit prefix bytecode for scale if required. + if (Bytecodes::OperandScaleRequiresPrefixBytecode(operand_scale)) { + bytecodes()->push_back(Bytecodes::ToByte( + Bytecodes::OperandScaleToPrefixBytecode(operand_scale))); } - last_bytecode_start_ = bytecodes()->size(); + // Emit bytecode. bytecodes()->push_back(Bytecodes::ToByte(bytecode)); + + // Emit operands. for (int i = 0; i < operand_count; i++) { - DCHECK(OperandIsValid(bytecode, i, operands[i])); - switch (Bytecodes::GetOperandSize(bytecode, i)) { + DCHECK(OperandIsValid(bytecode, operand_scale, i, operands[i])); + switch (Bytecodes::GetOperandSize(bytecode, i, operand_scale)) { case OperandSize::kNone: UNREACHABLE(); break; @@ -171,58 +207,61 @@ void BytecodeArrayBuilder::Output(Bytecode bytecode, uint32_t(&operands)[N]) { operand_bytes + 2); break; } + case OperandSize::kQuad: { + uint8_t operand_bytes[4]; + WriteUnalignedUInt32(operand_bytes, operands[i]); + bytecodes()->insert(bytecodes()->end(), operand_bytes, + operand_bytes + 4); + break; + } } } - - if (register_operand_count > 0) { - register_translator()->TranslateOutputRegisters(); - } } +void BytecodeArrayBuilder::Output(Bytecode bytecode) { + // Don't output dead code. + if (exit_seen_in_block_) return; -void BytecodeArrayBuilder::Output(Bytecode bytecode, uint32_t operand0, - uint32_t operand1, uint32_t operand2, - uint32_t operand3) { - uint32_t operands[] = {operand0, operand1, operand2, operand3}; - Output(bytecode, operands); + DCHECK_EQ(Bytecodes::NumberOfOperands(bytecode), 0); + last_bytecode_start_ = bytecodes()->size(); + bytecodes()->push_back(Bytecodes::ToByte(bytecode)); } +void BytecodeArrayBuilder::OutputScaled(Bytecode bytecode, + OperandScale operand_scale, + uint32_t operand0, uint32_t operand1, + uint32_t operand2, uint32_t operand3) { + uint32_t operands[] = {operand0, operand1, operand2, operand3}; + Output(bytecode, operands, operand_scale); +} -void BytecodeArrayBuilder::Output(Bytecode bytecode, uint32_t operand0, - uint32_t operand1, uint32_t operand2) { +void BytecodeArrayBuilder::OutputScaled(Bytecode bytecode, + OperandScale operand_scale, + uint32_t operand0, uint32_t operand1, + uint32_t operand2) { uint32_t operands[] = {operand0, operand1, operand2}; - Output(bytecode, operands); + Output(bytecode, operands, operand_scale); } - -void BytecodeArrayBuilder::Output(Bytecode bytecode, uint32_t operand0, - uint32_t operand1) { +void BytecodeArrayBuilder::OutputScaled(Bytecode bytecode, + OperandScale operand_scale, + uint32_t operand0, uint32_t operand1) { uint32_t operands[] = {operand0, operand1}; - Output(bytecode, operands); + Output(bytecode, operands, operand_scale); } - -void BytecodeArrayBuilder::Output(Bytecode bytecode, uint32_t operand0) { +void BytecodeArrayBuilder::OutputScaled(Bytecode bytecode, + OperandScale operand_scale, + uint32_t operand0) { uint32_t operands[] = {operand0}; - Output(bytecode, operands); -} - - -void BytecodeArrayBuilder::Output(Bytecode bytecode) { - // Don't output dead code. - if (exit_seen_in_block_) { - source_position_table_builder_.RevertPosition(bytecodes()->size()); - return; - } - - DCHECK_EQ(Bytecodes::NumberOfOperands(bytecode), 0); - last_bytecode_start_ = bytecodes()->size(); - bytecodes()->push_back(Bytecodes::ToByte(bytecode)); + Output(bytecode, operands, operand_scale); } BytecodeArrayBuilder& BytecodeArrayBuilder::BinaryOperation(Token::Value op, Register reg) { - Output(BytecodeForBinaryOperation(op), reg.ToRawOperand()); + OperandScale operand_scale = OperandSizesToScale(SizeForRegisterOperand(reg)); + OutputScaled(BytecodeForBinaryOperation(op), operand_scale, + RegisterOperand(reg)); return *this; } @@ -245,7 +284,9 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::TypeOf() { BytecodeArrayBuilder& BytecodeArrayBuilder::CompareOperation(Token::Value op, Register reg) { - Output(BytecodeForCompareOperation(op), reg.ToRawOperand()); + OperandScale operand_scale = OperandSizesToScale(SizeForRegisterOperand(reg)); + OutputScaled(BytecodeForCompareOperation(op), operand_scale, + RegisterOperand(reg)); return *this; } @@ -255,10 +296,11 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::LoadLiteral( int32_t raw_smi = smi->value(); if (raw_smi == 0) { Output(Bytecode::kLdaZero); - } else if (raw_smi >= -128 && raw_smi <= 127) { - Output(Bytecode::kLdaSmi8, static_cast<uint8_t>(raw_smi)); } else { - LoadLiteral(Handle<Object>(smi, isolate_)); + OperandSize operand_size = SizeForSignedOperand(raw_smi); + OperandScale operand_scale = OperandSizesToScale(operand_size); + OutputScaled(Bytecode::kLdaSmi, operand_scale, + SignedOperand(raw_smi, operand_size)); } return *this; } @@ -266,13 +308,9 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::LoadLiteral( BytecodeArrayBuilder& BytecodeArrayBuilder::LoadLiteral(Handle<Object> object) { size_t entry = GetConstantPoolEntry(object); - if (FitsInIdx8Operand(entry)) { - Output(Bytecode::kLdaConstant, static_cast<uint8_t>(entry)); - } else if (FitsInIdx16Operand(entry)) { - Output(Bytecode::kLdaConstantWide, static_cast<uint16_t>(entry)); - } else { - UNIMPLEMENTED(); - } + OperandScale operand_scale = + OperandSizesToScale(SizeForUnsignedOperand(entry)); + OutputScaled(Bytecode::kLdaConstant, operand_scale, UnsignedOperand(entry)); return *this; } @@ -306,20 +344,12 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::LoadFalse() { return *this; } - -BytecodeArrayBuilder& BytecodeArrayBuilder::LoadBooleanConstant(bool value) { - if (value) { - LoadTrue(); - } else { - LoadFalse(); - } - return *this; -} - BytecodeArrayBuilder& BytecodeArrayBuilder::LoadAccumulatorWithRegister( Register reg) { if (!IsRegisterInAccumulator(reg)) { - Output(Bytecode::kLdar, reg.ToRawOperand()); + OperandScale operand_scale = + OperandSizesToScale(SizeForRegisterOperand(reg)); + OutputScaled(Bytecode::kLdar, operand_scale, RegisterOperand(reg)); } return *this; } @@ -328,7 +358,9 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::LoadAccumulatorWithRegister( BytecodeArrayBuilder& BytecodeArrayBuilder::StoreAccumulatorInRegister( Register reg) { if (!IsRegisterInAccumulator(reg)) { - Output(Bytecode::kStar, reg.ToRawOperand()); + OperandScale operand_scale = + OperandSizesToScale(SizeForRegisterOperand(reg)); + OutputScaled(Bytecode::kStar, operand_scale, RegisterOperand(reg)); } return *this; } @@ -337,164 +369,98 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::StoreAccumulatorInRegister( BytecodeArrayBuilder& BytecodeArrayBuilder::MoveRegister(Register from, Register to) { DCHECK(from != to); - if (FitsInReg8Operand(from) && FitsInReg8Operand(to)) { - Output(Bytecode::kMov, from.ToRawOperand(), to.ToRawOperand()); - } else if (FitsInReg16Operand(from) && FitsInReg16Operand(to)) { - Output(Bytecode::kMovWide, from.ToRawOperand(), to.ToRawOperand()); - } else { - UNIMPLEMENTED(); - } + OperandScale operand_scale = OperandSizesToScale(SizeForRegisterOperand(from), + SizeForRegisterOperand(to)); + OutputScaled(Bytecode::kMov, operand_scale, RegisterOperand(from), + RegisterOperand(to)); return *this; } -void BytecodeArrayBuilder::MoveRegisterUntranslated(Register from, - Register to) { - // Move bytecodes modify the stack. Checking validity is an - // essential mitigation against corrupting the stack. - if (FitsInReg8OperandUntranslated(from)) { - CHECK(RegisterIsValid(from, OperandType::kReg8) && - RegisterIsValid(to, OperandType::kReg16)); - } else if (FitsInReg8OperandUntranslated(to)) { - CHECK(RegisterIsValid(from, OperandType::kReg16) && - RegisterIsValid(to, OperandType::kReg8)); - } else { - UNIMPLEMENTED(); - } - Output(Bytecode::kMovWide, from.ToRawOperand(), to.ToRawOperand()); -} - BytecodeArrayBuilder& BytecodeArrayBuilder::LoadGlobal( const Handle<String> name, int feedback_slot, TypeofMode typeof_mode) { // TODO(rmcilroy): Potentially store typeof information in an // operand rather than having extra bytecodes. Bytecode bytecode = BytecodeForLoadGlobal(typeof_mode); size_t name_index = GetConstantPoolEntry(name); - if (FitsInIdx8Operand(name_index) && FitsInIdx8Operand(feedback_slot)) { - Output(bytecode, static_cast<uint8_t>(name_index), - static_cast<uint8_t>(feedback_slot)); - } else if (FitsInIdx16Operand(name_index) && - FitsInIdx16Operand(feedback_slot)) { - Output(BytecodeForWideOperands(bytecode), static_cast<uint16_t>(name_index), - static_cast<uint16_t>(feedback_slot)); - } else { - UNIMPLEMENTED(); - } + OperandScale operand_scale = + OperandSizesToScale(SizeForUnsignedOperand(name_index), + SizeForUnsignedOperand(feedback_slot)); + OutputScaled(bytecode, operand_scale, UnsignedOperand(name_index), + UnsignedOperand(feedback_slot)); return *this; } - BytecodeArrayBuilder& BytecodeArrayBuilder::StoreGlobal( const Handle<String> name, int feedback_slot, LanguageMode language_mode) { Bytecode bytecode = BytecodeForStoreGlobal(language_mode); size_t name_index = GetConstantPoolEntry(name); - if (FitsInIdx8Operand(name_index) && FitsInIdx8Operand(feedback_slot)) { - Output(bytecode, static_cast<uint8_t>(name_index), - static_cast<uint8_t>(feedback_slot)); - } else if (FitsInIdx16Operand(name_index) && - FitsInIdx16Operand(feedback_slot)) { - Output(BytecodeForWideOperands(bytecode), static_cast<uint16_t>(name_index), - static_cast<uint16_t>(feedback_slot)); - } else { - UNIMPLEMENTED(); - } + OperandScale operand_scale = + OperandSizesToScale(SizeForUnsignedOperand(name_index), + SizeForUnsignedOperand(feedback_slot)); + OutputScaled(bytecode, operand_scale, UnsignedOperand(name_index), + UnsignedOperand(feedback_slot)); return *this; } BytecodeArrayBuilder& BytecodeArrayBuilder::LoadContextSlot(Register context, int slot_index) { - DCHECK(slot_index >= 0); - if (FitsInIdx8Operand(slot_index)) { - Output(Bytecode::kLdaContextSlot, context.ToRawOperand(), - static_cast<uint8_t>(slot_index)); - } else if (FitsInIdx16Operand(slot_index)) { - Output(Bytecode::kLdaContextSlotWide, context.ToRawOperand(), - static_cast<uint16_t>(slot_index)); - } else { - UNIMPLEMENTED(); - } + OperandScale operand_scale = OperandSizesToScale( + SizeForRegisterOperand(context), SizeForUnsignedOperand(slot_index)); + OutputScaled(Bytecode::kLdaContextSlot, operand_scale, + RegisterOperand(context), UnsignedOperand(slot_index)); return *this; } BytecodeArrayBuilder& BytecodeArrayBuilder::StoreContextSlot(Register context, int slot_index) { - DCHECK(slot_index >= 0); - if (FitsInIdx8Operand(slot_index)) { - Output(Bytecode::kStaContextSlot, context.ToRawOperand(), - static_cast<uint8_t>(slot_index)); - } else if (FitsInIdx16Operand(slot_index)) { - Output(Bytecode::kStaContextSlotWide, context.ToRawOperand(), - static_cast<uint16_t>(slot_index)); - } else { - UNIMPLEMENTED(); - } + OperandScale operand_scale = OperandSizesToScale( + SizeForRegisterOperand(context), SizeForUnsignedOperand(slot_index)); + OutputScaled(Bytecode::kStaContextSlot, operand_scale, + RegisterOperand(context), UnsignedOperand(slot_index)); return *this; } - BytecodeArrayBuilder& BytecodeArrayBuilder::LoadLookupSlot( const Handle<String> name, TypeofMode typeof_mode) { Bytecode bytecode = (typeof_mode == INSIDE_TYPEOF) ? Bytecode::kLdaLookupSlotInsideTypeof : Bytecode::kLdaLookupSlot; size_t name_index = GetConstantPoolEntry(name); - if (FitsInIdx8Operand(name_index)) { - Output(bytecode, static_cast<uint8_t>(name_index)); - } else if (FitsInIdx16Operand(name_index)) { - Output(BytecodeForWideOperands(bytecode), - static_cast<uint16_t>(name_index)); - } else { - UNIMPLEMENTED(); - } + OperandScale operand_scale = + OperandSizesToScale(SizeForUnsignedOperand(name_index)); + OutputScaled(bytecode, operand_scale, UnsignedOperand(name_index)); return *this; } - BytecodeArrayBuilder& BytecodeArrayBuilder::StoreLookupSlot( const Handle<String> name, LanguageMode language_mode) { Bytecode bytecode = BytecodeForStoreLookupSlot(language_mode); size_t name_index = GetConstantPoolEntry(name); - if (FitsInIdx8Operand(name_index)) { - Output(bytecode, static_cast<uint8_t>(name_index)); - } else if (FitsInIdx16Operand(name_index)) { - Output(BytecodeForWideOperands(bytecode), - static_cast<uint16_t>(name_index)); - } else { - UNIMPLEMENTED(); - } + OperandScale operand_scale = + OperandSizesToScale(SizeForUnsignedOperand(name_index)); + OutputScaled(bytecode, operand_scale, UnsignedOperand(name_index)); return *this; } BytecodeArrayBuilder& BytecodeArrayBuilder::LoadNamedProperty( Register object, const Handle<Name> name, int feedback_slot) { size_t name_index = GetConstantPoolEntry(name); - if (FitsInIdx8Operand(name_index) && FitsInIdx8Operand(feedback_slot)) { - Output(Bytecode::kLoadIC, object.ToRawOperand(), - static_cast<uint8_t>(name_index), - static_cast<uint8_t>(feedback_slot)); - } else if (FitsInIdx16Operand(name_index) && - FitsInIdx16Operand(feedback_slot)) { - Output(Bytecode::kLoadICWide, object.ToRawOperand(), - static_cast<uint16_t>(name_index), - static_cast<uint16_t>(feedback_slot)); - } else { - UNIMPLEMENTED(); - } + OperandScale operand_scale = OperandSizesToScale( + SizeForRegisterOperand(object), SizeForUnsignedOperand(name_index), + SizeForUnsignedOperand(feedback_slot)); + OutputScaled(Bytecode::kLoadIC, operand_scale, RegisterOperand(object), + UnsignedOperand(name_index), UnsignedOperand(feedback_slot)); return *this; } BytecodeArrayBuilder& BytecodeArrayBuilder::LoadKeyedProperty( Register object, int feedback_slot) { - if (FitsInIdx8Operand(feedback_slot)) { - Output(Bytecode::kKeyedLoadIC, object.ToRawOperand(), - static_cast<uint8_t>(feedback_slot)); - } else if (FitsInIdx16Operand(feedback_slot)) { - Output(Bytecode::kKeyedLoadICWide, object.ToRawOperand(), - static_cast<uint16_t>(feedback_slot)); - } else { - UNIMPLEMENTED(); - } + OperandScale operand_scale = OperandSizesToScale( + SizeForRegisterOperand(object), SizeForUnsignedOperand(feedback_slot)); + OutputScaled(Bytecode::kKeyedLoadIC, operand_scale, RegisterOperand(object), + UnsignedOperand(feedback_slot)); return *this; } @@ -503,17 +469,11 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::StoreNamedProperty( LanguageMode language_mode) { Bytecode bytecode = BytecodeForStoreIC(language_mode); size_t name_index = GetConstantPoolEntry(name); - if (FitsInIdx8Operand(name_index) && FitsInIdx8Operand(feedback_slot)) { - Output(bytecode, object.ToRawOperand(), static_cast<uint8_t>(name_index), - static_cast<uint8_t>(feedback_slot)); - } else if (FitsInIdx16Operand(name_index) && - FitsInIdx16Operand(feedback_slot)) { - Output(BytecodeForWideOperands(bytecode), object.ToRawOperand(), - static_cast<uint16_t>(name_index), - static_cast<uint16_t>(feedback_slot)); - } else { - UNIMPLEMENTED(); - } + OperandScale operand_scale = OperandSizesToScale( + SizeForRegisterOperand(object), SizeForUnsignedOperand(name_index), + SizeForUnsignedOperand(feedback_slot)); + OutputScaled(bytecode, operand_scale, RegisterOperand(object), + UnsignedOperand(name_index), UnsignedOperand(feedback_slot)); return *this; } @@ -522,15 +482,11 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::StoreKeyedProperty( Register object, Register key, int feedback_slot, LanguageMode language_mode) { Bytecode bytecode = BytecodeForKeyedStoreIC(language_mode); - if (FitsInIdx8Operand(feedback_slot)) { - Output(bytecode, object.ToRawOperand(), key.ToRawOperand(), - static_cast<uint8_t>(feedback_slot)); - } else if (FitsInIdx16Operand(feedback_slot)) { - Output(BytecodeForWideOperands(bytecode), object.ToRawOperand(), - key.ToRawOperand(), static_cast<uint16_t>(feedback_slot)); - } else { - UNIMPLEMENTED(); - } + OperandScale operand_scale = OperandSizesToScale( + SizeForRegisterOperand(object), SizeForRegisterOperand(key), + SizeForUnsignedOperand(feedback_slot)); + OutputScaled(bytecode, operand_scale, RegisterOperand(object), + RegisterOperand(key), UnsignedOperand(feedback_slot)); return *this; } @@ -538,16 +494,10 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::StoreKeyedProperty( BytecodeArrayBuilder& BytecodeArrayBuilder::CreateClosure( Handle<SharedFunctionInfo> shared_info, PretenureFlag tenured) { size_t entry = GetConstantPoolEntry(shared_info); - DCHECK(FitsInImm8Operand(tenured)); - if (FitsInIdx8Operand(entry)) { - Output(Bytecode::kCreateClosure, static_cast<uint8_t>(entry), - static_cast<uint8_t>(tenured)); - } else if (FitsInIdx16Operand(entry)) { - Output(Bytecode::kCreateClosureWide, static_cast<uint16_t>(entry), - static_cast<uint8_t>(tenured)); - } else { - UNIMPLEMENTED(); - } + OperandScale operand_scale = + OperandSizesToScale(SizeForUnsignedOperand(entry)); + OutputScaled(Bytecode::kCreateClosure, operand_scale, UnsignedOperand(entry), + UnsignedOperand(static_cast<size_t>(tenured))); return *this; } @@ -565,73 +515,55 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::CreateArguments( BytecodeArrayBuilder& BytecodeArrayBuilder::CreateRegExpLiteral( Handle<String> pattern, int literal_index, int flags) { - DCHECK(FitsInImm8Operand(flags)); // Flags should fit in 8 bits. size_t pattern_entry = GetConstantPoolEntry(pattern); - if (FitsInIdx8Operand(literal_index) && FitsInIdx8Operand(pattern_entry)) { - Output(Bytecode::kCreateRegExpLiteral, static_cast<uint8_t>(pattern_entry), - static_cast<uint8_t>(literal_index), static_cast<uint8_t>(flags)); - } else if (FitsInIdx16Operand(literal_index) && - FitsInIdx16Operand(pattern_entry)) { - Output(Bytecode::kCreateRegExpLiteralWide, - static_cast<uint16_t>(pattern_entry), - static_cast<uint16_t>(literal_index), static_cast<uint8_t>(flags)); - } else { - UNIMPLEMENTED(); - } + OperandScale operand_scale = OperandSizesToScale( + SizeForUnsignedOperand(pattern_entry), + SizeForUnsignedOperand(literal_index), SizeForUnsignedOperand(flags)); + OutputScaled(Bytecode::kCreateRegExpLiteral, operand_scale, + UnsignedOperand(pattern_entry), UnsignedOperand(literal_index), + UnsignedOperand(flags)); return *this; } BytecodeArrayBuilder& BytecodeArrayBuilder::CreateArrayLiteral( Handle<FixedArray> constant_elements, int literal_index, int flags) { - DCHECK(FitsInImm8Operand(flags)); // Flags should fit in 8 bits. size_t constant_elements_entry = GetConstantPoolEntry(constant_elements); - if (FitsInIdx8Operand(literal_index) && - FitsInIdx8Operand(constant_elements_entry)) { - Output(Bytecode::kCreateArrayLiteral, - static_cast<uint8_t>(constant_elements_entry), - static_cast<uint8_t>(literal_index), static_cast<uint8_t>(flags)); - } else if (FitsInIdx16Operand(literal_index) && - FitsInIdx16Operand(constant_elements_entry)) { - Output(Bytecode::kCreateArrayLiteralWide, - static_cast<uint16_t>(constant_elements_entry), - static_cast<uint16_t>(literal_index), static_cast<uint8_t>(flags)); - } else { - UNIMPLEMENTED(); - } + OperandScale operand_scale = OperandSizesToScale( + SizeForUnsignedOperand(constant_elements_entry), + SizeForUnsignedOperand(literal_index), SizeForUnsignedOperand(flags)); + OutputScaled(Bytecode::kCreateArrayLiteral, operand_scale, + UnsignedOperand(constant_elements_entry), + UnsignedOperand(literal_index), UnsignedOperand(flags)); return *this; } BytecodeArrayBuilder& BytecodeArrayBuilder::CreateObjectLiteral( Handle<FixedArray> constant_properties, int literal_index, int flags) { - DCHECK(FitsInImm8Operand(flags)); // Flags should fit in 8 bits. size_t constant_properties_entry = GetConstantPoolEntry(constant_properties); - if (FitsInIdx8Operand(literal_index) && - FitsInIdx8Operand(constant_properties_entry)) { - Output(Bytecode::kCreateObjectLiteral, - static_cast<uint8_t>(constant_properties_entry), - static_cast<uint8_t>(literal_index), static_cast<uint8_t>(flags)); - } else if (FitsInIdx16Operand(literal_index) && - FitsInIdx16Operand(constant_properties_entry)) { - Output(Bytecode::kCreateObjectLiteralWide, - static_cast<uint16_t>(constant_properties_entry), - static_cast<uint16_t>(literal_index), static_cast<uint8_t>(flags)); - } else { - UNIMPLEMENTED(); - } + OperandScale operand_scale = OperandSizesToScale( + SizeForUnsignedOperand(constant_properties_entry), + SizeForUnsignedOperand(literal_index), SizeForUnsignedOperand(flags)); + OutputScaled(Bytecode::kCreateObjectLiteral, operand_scale, + UnsignedOperand(constant_properties_entry), + UnsignedOperand(literal_index), UnsignedOperand(flags)); return *this; } BytecodeArrayBuilder& BytecodeArrayBuilder::PushContext(Register context) { - Output(Bytecode::kPushContext, context.ToRawOperand()); + OperandScale operand_scale = + OperandSizesToScale(SizeForRegisterOperand(context)); + OutputScaled(Bytecode::kPushContext, operand_scale, RegisterOperand(context)); return *this; } BytecodeArrayBuilder& BytecodeArrayBuilder::PopContext(Register context) { - Output(Bytecode::kPopContext, context.ToRawOperand()); + OperandScale operand_scale = + OperandSizesToScale(SizeForRegisterOperand(context)); + OutputScaled(Bytecode::kPopContext, operand_scale, RegisterOperand(context)); return *this; } @@ -649,7 +581,6 @@ bool BytecodeArrayBuilder::NeedToBooleanCast() { case Bytecode::kTestEqual: case Bytecode::kTestNotEqual: case Bytecode::kTestEqualStrict: - case Bytecode::kTestNotEqualStrict: case Bytecode::kTestLessThan: case Bytecode::kTestLessThanOrEqual: case Bytecode::kTestGreaterThan: @@ -677,7 +608,6 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::CastAccumulatorToName() { case Bytecode::kToName: case Bytecode::kTypeOf: return *this; - case Bytecode::kLdaConstantWide: case Bytecode::kLdaConstant: { Handle<Object> object = previous_bytecode.GetConstantForIndexOperand(0); if (object->IsName()) return *this; @@ -716,8 +646,12 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::Bind(const BytecodeLabel& target, BytecodeLabel* label) { DCHECK(!label->is_bound()); DCHECK(target.is_bound()); - PatchJump(bytecodes()->begin() + target.offset(), - bytecodes()->begin() + label->offset()); + if (label->is_forward_target()) { + // An earlier jump instruction refers to this label. Update it's location. + PatchJump(bytecodes()->begin() + target.offset(), + bytecodes()->begin() + label->offset()); + // Now treat as if the label will only be back referred to. + } label->bind_to(target.offset()); LeaveBasicBlock(); return *this; @@ -746,38 +680,10 @@ Bytecode BytecodeArrayBuilder::GetJumpWithConstantOperand( return Bytecode::kJumpIfUndefinedConstant; default: UNREACHABLE(); - return static_cast<Bytecode>(-1); - } -} - - -// static -Bytecode BytecodeArrayBuilder::GetJumpWithConstantWideOperand( - Bytecode jump_bytecode) { - switch (jump_bytecode) { - case Bytecode::kJump: - return Bytecode::kJumpConstantWide; - case Bytecode::kJumpIfTrue: - return Bytecode::kJumpIfTrueConstantWide; - case Bytecode::kJumpIfFalse: - return Bytecode::kJumpIfFalseConstantWide; - case Bytecode::kJumpIfToBooleanTrue: - return Bytecode::kJumpIfToBooleanTrueConstantWide; - case Bytecode::kJumpIfToBooleanFalse: - return Bytecode::kJumpIfToBooleanFalseConstantWide; - case Bytecode::kJumpIfNotHole: - return Bytecode::kJumpIfNotHoleConstantWide; - case Bytecode::kJumpIfNull: - return Bytecode::kJumpIfNullConstantWide; - case Bytecode::kJumpIfUndefined: - return Bytecode::kJumpIfUndefinedConstantWide; - default: - UNREACHABLE(); - return static_cast<Bytecode>(-1); + return Bytecode::kIllegal; } } - // static Bytecode BytecodeArrayBuilder::GetJumpWithToBoolean(Bytecode jump_bytecode) { switch (jump_bytecode) { @@ -793,7 +699,7 @@ Bytecode BytecodeArrayBuilder::GetJumpWithToBoolean(Bytecode jump_bytecode) { default: UNREACHABLE(); } - return static_cast<Bytecode>(-1); + return Bytecode::kIllegal; } @@ -803,54 +709,88 @@ void BytecodeArrayBuilder::PatchIndirectJumpWith8BitOperand( DCHECK(Bytecodes::IsJumpImmediate(jump_bytecode)); ZoneVector<uint8_t>::iterator operand_location = jump_location + 1; DCHECK_EQ(*operand_location, 0); - if (FitsInImm8Operand(delta)) { - // The jump fits within the range of an Imm8 operand, so cancel + if (SizeForSignedOperand(delta) == OperandSize::kByte) { + // The jump fits within the range of an Imm operand, so cancel // the reservation and jump directly. constant_array_builder()->DiscardReservedEntry(OperandSize::kByte); *operand_location = static_cast<uint8_t>(delta); } else { - // The jump does not fit within the range of an Imm8 operand, so + // The jump does not fit within the range of an Imm operand, so // commit reservation putting the offset into the constant pool, // and update the jump instruction and operand. size_t entry = constant_array_builder()->CommitReservedEntry( OperandSize::kByte, handle(Smi::FromInt(delta), isolate())); - DCHECK(FitsInIdx8Operand(entry)); + DCHECK(SizeForUnsignedOperand(entry) == OperandSize::kByte); jump_bytecode = GetJumpWithConstantOperand(jump_bytecode); *jump_location = Bytecodes::ToByte(jump_bytecode); *operand_location = static_cast<uint8_t>(entry); } } - void BytecodeArrayBuilder::PatchIndirectJumpWith16BitOperand( const ZoneVector<uint8_t>::iterator& jump_location, int delta) { - DCHECK(Bytecodes::IsJumpConstantWide(Bytecodes::FromByte(*jump_location))); + Bytecode jump_bytecode = Bytecodes::FromByte(*jump_location); + DCHECK(Bytecodes::IsJumpImmediate(jump_bytecode)); ZoneVector<uint8_t>::iterator operand_location = jump_location + 1; - size_t entry = constant_array_builder()->CommitReservedEntry( - OperandSize::kShort, handle(Smi::FromInt(delta), isolate())); - DCHECK(FitsInIdx16Operand(entry)); uint8_t operand_bytes[2]; - WriteUnalignedUInt16(operand_bytes, static_cast<uint16_t>(entry)); + if (SizeForSignedOperand(delta) <= OperandSize::kShort) { + constant_array_builder()->DiscardReservedEntry(OperandSize::kShort); + WriteUnalignedUInt16(operand_bytes, static_cast<uint16_t>(delta)); + } else { + jump_bytecode = GetJumpWithConstantOperand(jump_bytecode); + *jump_location = Bytecodes::ToByte(jump_bytecode); + size_t entry = constant_array_builder()->CommitReservedEntry( + OperandSize::kShort, handle(Smi::FromInt(delta), isolate())); + WriteUnalignedUInt16(operand_bytes, static_cast<uint16_t>(entry)); + } DCHECK(*operand_location == 0 && *(operand_location + 1) == 0); *operand_location++ = operand_bytes[0]; *operand_location = operand_bytes[1]; } +void BytecodeArrayBuilder::PatchIndirectJumpWith32BitOperand( + const ZoneVector<uint8_t>::iterator& jump_location, int delta) { + DCHECK(Bytecodes::IsJumpImmediate(Bytecodes::FromByte(*jump_location))); + constant_array_builder()->DiscardReservedEntry(OperandSize::kQuad); + ZoneVector<uint8_t>::iterator operand_location = jump_location + 1; + uint8_t operand_bytes[4]; + WriteUnalignedUInt32(operand_bytes, static_cast<uint32_t>(delta)); + DCHECK(*operand_location == 0 && *(operand_location + 1) == 0 && + *(operand_location + 2) == 0 && *(operand_location + 3) == 0); + *operand_location++ = operand_bytes[0]; + *operand_location++ = operand_bytes[1]; + *operand_location++ = operand_bytes[2]; + *operand_location = operand_bytes[3]; +} void BytecodeArrayBuilder::PatchJump( const ZoneVector<uint8_t>::iterator& jump_target, const ZoneVector<uint8_t>::iterator& jump_location) { - Bytecode jump_bytecode = Bytecodes::FromByte(*jump_location); int delta = static_cast<int>(jump_target - jump_location); + Bytecode jump_bytecode = Bytecodes::FromByte(*jump_location); + int prefix_offset = 0; + OperandScale operand_scale = OperandScale::kSingle; + if (Bytecodes::IsPrefixScalingBytecode(jump_bytecode)) { + // If a prefix scaling bytecode is emitted the target offset is one + // less than the case of no prefix scaling bytecode. + delta -= 1; + prefix_offset = 1; + operand_scale = Bytecodes::PrefixBytecodeToOperandScale(jump_bytecode); + jump_bytecode = Bytecodes::FromByte(*(jump_location + prefix_offset)); + } + DCHECK(Bytecodes::IsJump(jump_bytecode)); - switch (Bytecodes::GetOperandSize(jump_bytecode, 0)) { - case OperandSize::kByte: + switch (operand_scale) { + case OperandScale::kSingle: PatchIndirectJumpWith8BitOperand(jump_location, delta); break; - case OperandSize::kShort: - PatchIndirectJumpWith16BitOperand(jump_location, delta); + case OperandScale::kDouble: + PatchIndirectJumpWith16BitOperand(jump_location + prefix_offset, delta); break; - case OperandSize::kNone: + case OperandScale::kQuadruple: + PatchIndirectJumpWith32BitOperand(jump_location + prefix_offset, delta); + break; + default: UNREACHABLE(); } unbound_jumps_--; @@ -860,10 +800,7 @@ void BytecodeArrayBuilder::PatchJump( BytecodeArrayBuilder& BytecodeArrayBuilder::OutputJump(Bytecode jump_bytecode, BytecodeLabel* label) { // Don't emit dead code. - if (exit_seen_in_block_) { - source_position_table_builder_.RevertPosition(bytecodes()->size()); - return *this; - } + if (exit_seen_in_block_) return *this; // Check if the value in accumulator is boolean, if not choose an // appropriate JumpIfToBoolean bytecode. @@ -877,22 +814,14 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::OutputJump(Bytecode jump_bytecode, CHECK_LE(bytecodes()->size(), static_cast<size_t>(kMaxInt)); size_t abs_delta = bytecodes()->size() - label->offset(); int delta = -static_cast<int>(abs_delta); - - if (FitsInImm8Operand(delta)) { - Output(jump_bytecode, static_cast<uint8_t>(delta)); - } else { - size_t entry = - GetConstantPoolEntry(handle(Smi::FromInt(delta), isolate())); - if (FitsInIdx8Operand(entry)) { - Output(GetJumpWithConstantOperand(jump_bytecode), - static_cast<uint8_t>(entry)); - } else if (FitsInIdx16Operand(entry)) { - Output(GetJumpWithConstantWideOperand(jump_bytecode), - static_cast<uint16_t>(entry)); - } else { - UNREACHABLE(); - } + OperandSize operand_size = SizeForSignedOperand(delta); + if (operand_size > OperandSize::kByte) { + // Adjust for scaling byte prefix for wide jump offset. + DCHECK_LE(delta, 0); + delta -= 1; } + OutputScaled(jump_bytecode, OperandSizesToScale(operand_size), + SignedOperand(delta, operand_size)); } else { // The label has not yet been bound so this is a forward reference // that will be patched when the label is bound. We create a @@ -904,16 +833,7 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::OutputJump(Bytecode jump_bytecode, unbound_jumps_++; OperandSize reserved_operand_size = constant_array_builder()->CreateReservedEntry(); - switch (reserved_operand_size) { - case OperandSize::kByte: - Output(jump_bytecode, 0); - break; - case OperandSize::kShort: - Output(GetJumpWithConstantWideOperand(jump_bytecode), 0); - break; - case OperandSize::kNone: - UNREACHABLE(); - } + OutputScaled(jump_bytecode, OperandSizesToScale(reserved_operand_size), 0); } LeaveBasicBlock(); return *this; @@ -970,6 +890,7 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::ReThrow() { BytecodeArrayBuilder& BytecodeArrayBuilder::Return() { + SetReturnPosition(); Output(Bytecode::kReturn); exit_seen_in_block_ = true; return *this; @@ -982,44 +903,40 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::Debugger() { BytecodeArrayBuilder& BytecodeArrayBuilder::ForInPrepare( Register cache_info_triple) { - if (FitsInReg8Operand(cache_info_triple)) { - Output(Bytecode::kForInPrepare, cache_info_triple.ToRawOperand()); - } else if (FitsInReg16Operand(cache_info_triple)) { - Output(Bytecode::kForInPrepareWide, cache_info_triple.ToRawOperand()); - } else { - UNIMPLEMENTED(); - } + OperandScale operand_scale = + OperandSizesToScale(SizeForRegisterOperand(cache_info_triple)); + OutputScaled(Bytecode::kForInPrepare, operand_scale, + RegisterOperand(cache_info_triple)); return *this; } - BytecodeArrayBuilder& BytecodeArrayBuilder::ForInDone(Register index, Register cache_length) { - Output(Bytecode::kForInDone, index.ToRawOperand(), - cache_length.ToRawOperand()); + OperandScale operand_scale = OperandSizesToScale( + SizeForRegisterOperand(index), SizeForRegisterOperand(cache_length)); + OutputScaled(Bytecode::kForInDone, operand_scale, RegisterOperand(index), + RegisterOperand(cache_length)); return *this; } - BytecodeArrayBuilder& BytecodeArrayBuilder::ForInNext( - Register receiver, Register index, Register cache_type_array_pair) { - if (FitsInReg8Operand(receiver) && FitsInReg8Operand(index) && - FitsInReg8Operand(cache_type_array_pair)) { - Output(Bytecode::kForInNext, receiver.ToRawOperand(), index.ToRawOperand(), - cache_type_array_pair.ToRawOperand()); - } else if (FitsInReg16Operand(receiver) && FitsInReg16Operand(index) && - FitsInReg16Operand(cache_type_array_pair)) { - Output(Bytecode::kForInNextWide, receiver.ToRawOperand(), - index.ToRawOperand(), cache_type_array_pair.ToRawOperand()); - } else { - UNIMPLEMENTED(); - } + Register receiver, Register index, Register cache_type_array_pair, + int feedback_slot) { + OperandScale operand_scale = OperandSizesToScale( + SizeForRegisterOperand(receiver), SizeForRegisterOperand(index), + SizeForRegisterOperand(cache_type_array_pair), + SizeForUnsignedOperand(feedback_slot)); + OutputScaled(Bytecode::kForInNext, operand_scale, RegisterOperand(receiver), + RegisterOperand(index), RegisterOperand(cache_type_array_pair), + UnsignedOperand(feedback_slot)); return *this; } BytecodeArrayBuilder& BytecodeArrayBuilder::ForInStep(Register index) { - Output(Bytecode::kForInStep, index.ToRawOperand()); + OperandScale operand_scale = + OperandSizesToScale(SizeForRegisterOperand(index)); + OutputScaled(Bytecode::kForInStep, operand_scale, RegisterOperand(index)); return *this; } @@ -1051,12 +968,12 @@ void BytecodeArrayBuilder::LeaveBasicBlock() { exit_seen_in_block_ = false; } -void BytecodeArrayBuilder::EnsureReturn(FunctionLiteral* literal) { +void BytecodeArrayBuilder::EnsureReturn() { if (!exit_seen_in_block_) { LoadUndefined(); - SetReturnPosition(literal); Return(); } + DCHECK(exit_seen_in_block_); } BytecodeArrayBuilder& BytecodeArrayBuilder::Call(Register callable, @@ -1065,23 +982,14 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::Call(Register callable, int feedback_slot, TailCallMode tail_call_mode) { Bytecode bytecode = BytecodeForCall(tail_call_mode); - if (FitsInReg8Operand(callable) && FitsInReg8Operand(receiver_args) && - FitsInIdx8Operand(receiver_args_count) && - FitsInIdx8Operand(feedback_slot)) { - Output(bytecode, callable.ToRawOperand(), receiver_args.ToRawOperand(), - static_cast<uint8_t>(receiver_args_count), - static_cast<uint8_t>(feedback_slot)); - } else if (FitsInReg16Operand(callable) && - FitsInReg16Operand(receiver_args) && - FitsInIdx16Operand(receiver_args_count) && - FitsInIdx16Operand(feedback_slot)) { - bytecode = BytecodeForWideOperands(bytecode); - Output(bytecode, callable.ToRawOperand(), receiver_args.ToRawOperand(), - static_cast<uint16_t>(receiver_args_count), - static_cast<uint16_t>(feedback_slot)); - } else { - UNIMPLEMENTED(); - } + OperandScale operand_scale = OperandSizesToScale( + SizeForRegisterOperand(callable), SizeForRegisterOperand(receiver_args), + SizeForUnsignedOperand(receiver_args_count), + SizeForUnsignedOperand(feedback_slot)); + OutputScaled(bytecode, operand_scale, RegisterOperand(callable), + RegisterOperand(receiver_args), + UnsignedOperand(receiver_args_count), + UnsignedOperand(feedback_slot)); return *this; } @@ -1092,17 +1000,11 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::New(Register constructor, DCHECK_EQ(0u, arg_count); first_arg = Register(0); } - if (FitsInReg8Operand(constructor) && FitsInReg8Operand(first_arg) && - FitsInIdx8Operand(arg_count)) { - Output(Bytecode::kNew, constructor.ToRawOperand(), first_arg.ToRawOperand(), - static_cast<uint8_t>(arg_count)); - } else if (FitsInReg16Operand(constructor) && FitsInReg16Operand(first_arg) && - FitsInIdx16Operand(arg_count)) { - Output(Bytecode::kNewWide, constructor.ToRawOperand(), - first_arg.ToRawOperand(), static_cast<uint16_t>(arg_count)); - } else { - UNIMPLEMENTED(); - } + OperandScale operand_scale = OperandSizesToScale( + SizeForRegisterOperand(constructor), SizeForRegisterOperand(first_arg), + SizeForUnsignedOperand(arg_count)); + OutputScaled(Bytecode::kNew, operand_scale, RegisterOperand(constructor), + RegisterOperand(first_arg), UnsignedOperand(arg_count)); return *this; } @@ -1110,20 +1012,18 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::New(Register constructor, BytecodeArrayBuilder& BytecodeArrayBuilder::CallRuntime( Runtime::FunctionId function_id, Register first_arg, size_t arg_count) { DCHECK_EQ(1, Runtime::FunctionForId(function_id)->result_size); - DCHECK(FitsInIdx16Operand(function_id)); + DCHECK(SizeForUnsignedOperand(function_id) <= OperandSize::kShort); if (!first_arg.is_valid()) { DCHECK_EQ(0u, arg_count); first_arg = Register(0); } - if (FitsInReg8Operand(first_arg) && FitsInIdx8Operand(arg_count)) { - Output(Bytecode::kCallRuntime, static_cast<uint16_t>(function_id), - first_arg.ToRawOperand(), static_cast<uint8_t>(arg_count)); - } else if (FitsInReg16Operand(first_arg) && FitsInIdx16Operand(arg_count)) { - Output(Bytecode::kCallRuntimeWide, static_cast<uint16_t>(function_id), - first_arg.ToRawOperand(), static_cast<uint16_t>(arg_count)); - } else { - UNIMPLEMENTED(); - } + Bytecode bytecode = IntrinsicsHelper::IsSupported(function_id) + ? Bytecode::kInvokeIntrinsic + : Bytecode::kCallRuntime; + OperandScale operand_scale = OperandSizesToScale( + SizeForRegisterOperand(first_arg), SizeForUnsignedOperand(arg_count)); + OutputScaled(bytecode, operand_scale, static_cast<uint16_t>(function_id), + RegisterOperand(first_arg), UnsignedOperand(arg_count)); return *this; } @@ -1132,180 +1032,145 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::CallRuntimeForPair( Runtime::FunctionId function_id, Register first_arg, size_t arg_count, Register first_return) { DCHECK_EQ(2, Runtime::FunctionForId(function_id)->result_size); - DCHECK(FitsInIdx16Operand(function_id)); + DCHECK(SizeForUnsignedOperand(function_id) <= OperandSize::kShort); if (!first_arg.is_valid()) { DCHECK_EQ(0u, arg_count); first_arg = Register(0); } - if (FitsInReg8Operand(first_arg) && FitsInIdx8Operand(arg_count) && - FitsInReg8Operand(first_return)) { - Output(Bytecode::kCallRuntimeForPair, static_cast<uint16_t>(function_id), - first_arg.ToRawOperand(), static_cast<uint8_t>(arg_count), - first_return.ToRawOperand()); - } else if (FitsInReg16Operand(first_arg) && FitsInIdx16Operand(arg_count) && - FitsInReg16Operand(first_return)) { - Output(Bytecode::kCallRuntimeForPairWide, - static_cast<uint16_t>(function_id), first_arg.ToRawOperand(), - static_cast<uint16_t>(arg_count), first_return.ToRawOperand()); - } else { - UNIMPLEMENTED(); - } + OperandScale operand_scale = OperandSizesToScale( + SizeForRegisterOperand(first_arg), SizeForUnsignedOperand(arg_count), + SizeForRegisterOperand(first_return)); + OutputScaled(Bytecode::kCallRuntimeForPair, operand_scale, + static_cast<uint16_t>(function_id), RegisterOperand(first_arg), + UnsignedOperand(arg_count), RegisterOperand(first_return)); return *this; } BytecodeArrayBuilder& BytecodeArrayBuilder::CallJSRuntime( int context_index, Register receiver_args, size_t receiver_args_count) { - DCHECK(FitsInIdx16Operand(context_index)); - if (FitsInReg8Operand(receiver_args) && - FitsInIdx8Operand(receiver_args_count)) { - Output(Bytecode::kCallJSRuntime, static_cast<uint16_t>(context_index), - receiver_args.ToRawOperand(), - static_cast<uint8_t>(receiver_args_count)); - } else if (FitsInReg16Operand(receiver_args) && - FitsInIdx16Operand(receiver_args_count)) { - Output(Bytecode::kCallJSRuntimeWide, static_cast<uint16_t>(context_index), - receiver_args.ToRawOperand(), - static_cast<uint16_t>(receiver_args_count)); - } else { - UNIMPLEMENTED(); - } + OperandScale operand_scale = + OperandSizesToScale(SizeForUnsignedOperand(context_index), + SizeForRegisterOperand(receiver_args), + SizeForUnsignedOperand(receiver_args_count)); + OutputScaled(Bytecode::kCallJSRuntime, operand_scale, + UnsignedOperand(context_index), RegisterOperand(receiver_args), + UnsignedOperand(receiver_args_count)); return *this; } BytecodeArrayBuilder& BytecodeArrayBuilder::Delete(Register object, LanguageMode language_mode) { - Output(BytecodeForDelete(language_mode), object.ToRawOperand()); + OperandScale operand_scale = + OperandSizesToScale(SizeForRegisterOperand(object)); + OutputScaled(BytecodeForDelete(language_mode), operand_scale, + RegisterOperand(object)); return *this; } - size_t BytecodeArrayBuilder::GetConstantPoolEntry(Handle<Object> object) { return constant_array_builder()->Insert(object); } -void BytecodeArrayBuilder::SetReturnPosition(FunctionLiteral* fun) { - int pos = std::max(fun->start_position(), fun->end_position() - 1); - source_position_table_builder_.AddStatementPosition(bytecodes_.size(), pos); +void BytecodeArrayBuilder::SetReturnPosition() { + if (return_position_ == RelocInfo::kNoPosition) return; + if (exit_seen_in_block_) return; + source_position_table_builder_.AddStatementPosition(bytecodes_.size(), + return_position_); } void BytecodeArrayBuilder::SetStatementPosition(Statement* stmt) { if (stmt->position() == RelocInfo::kNoPosition) return; + if (exit_seen_in_block_) return; source_position_table_builder_.AddStatementPosition(bytecodes_.size(), stmt->position()); } void BytecodeArrayBuilder::SetExpressionPosition(Expression* expr) { if (expr->position() == RelocInfo::kNoPosition) return; + if (exit_seen_in_block_) return; source_position_table_builder_.AddExpressionPosition(bytecodes_.size(), expr->position()); } +void BytecodeArrayBuilder::SetExpressionAsStatementPosition(Expression* expr) { + if (expr->position() == RelocInfo::kNoPosition) return; + if (exit_seen_in_block_) return; + source_position_table_builder_.AddStatementPosition(bytecodes_.size(), + expr->position()); +} + bool BytecodeArrayBuilder::TemporaryRegisterIsLive(Register reg) const { return temporary_register_allocator()->RegisterIsLive(reg); } -bool BytecodeArrayBuilder::OperandIsValid(Bytecode bytecode, int operand_index, +bool BytecodeArrayBuilder::OperandIsValid(Bytecode bytecode, + OperandScale operand_scale, + int operand_index, uint32_t operand_value) const { + OperandSize operand_size = + Bytecodes::GetOperandSize(bytecode, operand_index, operand_scale); OperandType operand_type = Bytecodes::GetOperandType(bytecode, operand_index); switch (operand_type) { case OperandType::kNone: return false; - case OperandType::kRegCount16: { - // Expect kRegCount16 is part of a range previous operand is a - // valid operand to start a range. - if (operand_index > 0) { - OperandType previous_operand_type = - Bytecodes::GetOperandType(bytecode, operand_index - 1); - return ((previous_operand_type == OperandType::kMaybeReg16 || - previous_operand_type == OperandType::kReg16) && - static_cast<uint16_t>(operand_value) == operand_value); - } else { - return false; - } - } - case OperandType::kRegCount8: { - // Expect kRegCount8 is part of a range previous operand is a - // valid operand to start a range. + case OperandType::kRegCount: { if (operand_index > 0) { OperandType previous_operand_type = Bytecodes::GetOperandType(bytecode, operand_index - 1); - return ((previous_operand_type == OperandType::kMaybeReg8 || - previous_operand_type == OperandType::kReg8 || - previous_operand_type == OperandType::kMaybeReg16) && - static_cast<uint8_t>(operand_value) == operand_value); - } else { - return false; + if (previous_operand_type != OperandType::kMaybeReg && + previous_operand_type != OperandType::kReg) { + return false; + } } + } // Fall-through + case OperandType::kFlag8: + case OperandType::kIdx: + case OperandType::kRuntimeId: + case OperandType::kImm: { + size_t unsigned_value = static_cast<size_t>(operand_value); + return SizeForUnsignedOperand(unsigned_value) <= operand_size; } - case OperandType::kIdx16: - return static_cast<uint16_t>(operand_value) == operand_value; - case OperandType::kImm8: - case OperandType::kIdx8: - return static_cast<uint8_t>(operand_value) == operand_value; - case OperandType::kMaybeReg8: + case OperandType::kMaybeReg: if (operand_value == 0) { return true; } - // Fall-through to kReg8 case. - case OperandType::kReg8: - case OperandType::kRegOut8: - return RegisterIsValid(Register::FromRawOperand(operand_value), - operand_type); - case OperandType::kRegOutPair8: - case OperandType::kRegOutPair16: - case OperandType::kRegPair8: - case OperandType::kRegPair16: { - Register reg0 = Register::FromRawOperand(operand_value); + // Fall-through to kReg case. + case OperandType::kReg: + case OperandType::kRegOut: { + Register reg = RegisterFromOperand(operand_value); + return RegisterIsValid(reg, operand_size); + } + case OperandType::kRegOutPair: + case OperandType::kRegPair: { + Register reg0 = RegisterFromOperand(operand_value); Register reg1 = Register(reg0.index() + 1); - return RegisterIsValid(reg0, operand_type) && - RegisterIsValid(reg1, operand_type); + // The size of reg1 is immaterial. + return RegisterIsValid(reg0, operand_size) && + RegisterIsValid(reg1, OperandSize::kQuad); } - case OperandType::kRegOutTriple8: - case OperandType::kRegOutTriple16: { - Register reg0 = Register::FromRawOperand(operand_value); + case OperandType::kRegOutTriple: { + Register reg0 = RegisterFromOperand(operand_value); Register reg1 = Register(reg0.index() + 1); Register reg2 = Register(reg0.index() + 2); - return RegisterIsValid(reg0, operand_type) && - RegisterIsValid(reg1, operand_type) && - RegisterIsValid(reg2, operand_type); - } - case OperandType::kMaybeReg16: - if (operand_value == 0) { - return true; - } - // Fall-through to kReg16 case. - case OperandType::kReg16: - case OperandType::kRegOut16: { - Register reg = Register::FromRawOperand(operand_value); - return RegisterIsValid(reg, operand_type); + // The size of reg1 and reg2 is immaterial. + return RegisterIsValid(reg0, operand_size) && + RegisterIsValid(reg1, OperandSize::kQuad) && + RegisterIsValid(reg2, OperandSize::kQuad); } } UNREACHABLE(); return false; } - bool BytecodeArrayBuilder::RegisterIsValid(Register reg, - OperandType reg_type) const { + OperandSize reg_size) const { if (!reg.is_valid()) { return false; } - switch (Bytecodes::SizeOfOperand(reg_type)) { - case OperandSize::kByte: - if (!FitsInReg8OperandUntranslated(reg)) { - return false; - } - break; - case OperandSize::kShort: - if (!FitsInReg16OperandUntranslated(reg)) { - return false; - } - break; - case OperandSize::kNone: - UNREACHABLE(); - return false; + if (SizeForRegisterOperand(reg) > reg_size) { + return false; } if (reg.is_current_context() || reg.is_function_closure() || @@ -1314,15 +1179,10 @@ bool BytecodeArrayBuilder::RegisterIsValid(Register reg, } else if (reg.is_parameter()) { int parameter_index = reg.ToParameterIndex(parameter_count()); return parameter_index >= 0 && parameter_index < parameter_count(); - } else if (RegisterTranslator::InTranslationWindow(reg)) { - return translation_register_count() > 0; + } else if (reg.index() < fixed_register_count()) { + return true; } else { - reg = RegisterTranslator::UntranslateRegister(reg); - if (reg.index() < fixed_register_count()) { - return true; - } else { - return TemporaryRegisterIsLive(reg); - } + return TemporaryRegisterIsLive(reg); } } @@ -1338,9 +1198,7 @@ bool BytecodeArrayBuilder::IsRegisterInAccumulator(Register reg) { PreviousBytecodeHelper previous_bytecode(*this); Bytecode bytecode = previous_bytecode.GetBytecode(); if (bytecode == Bytecode::kLdar || bytecode == Bytecode::kStar) { - Register previous_reg = - Register::FromOperand(previous_bytecode.GetOperand(0)); - return previous_reg == reg; + return previous_bytecode.GetRegisterOperand(0) == reg; } } return false; @@ -1374,7 +1232,7 @@ Bytecode BytecodeArrayBuilder::BytecodeForBinaryOperation(Token::Value op) { return Bytecode::kShiftRightLogical; default: UNREACHABLE(); - return static_cast<Bytecode>(-1); + return Bytecode::kIllegal; } } @@ -1388,7 +1246,7 @@ Bytecode BytecodeArrayBuilder::BytecodeForCountOperation(Token::Value op) { return Bytecode::kDec; default: UNREACHABLE(); - return static_cast<Bytecode>(-1); + return Bytecode::kIllegal; } } @@ -1402,8 +1260,6 @@ Bytecode BytecodeArrayBuilder::BytecodeForCompareOperation(Token::Value op) { return Bytecode::kTestNotEqual; case Token::Value::EQ_STRICT: return Bytecode::kTestEqualStrict; - case Token::Value::NE_STRICT: - return Bytecode::kTestNotEqualStrict; case Token::Value::LT: return Bytecode::kTestLessThan; case Token::Value::GT: @@ -1418,49 +1274,7 @@ Bytecode BytecodeArrayBuilder::BytecodeForCompareOperation(Token::Value op) { return Bytecode::kTestIn; default: UNREACHABLE(); - return static_cast<Bytecode>(-1); - } -} - - -// static -Bytecode BytecodeArrayBuilder::BytecodeForWideOperands(Bytecode bytecode) { - switch (bytecode) { - case Bytecode::kCall: - return Bytecode::kCallWide; - case Bytecode::kTailCall: - return Bytecode::kTailCallWide; - case Bytecode::kLoadIC: - return Bytecode::kLoadICWide; - case Bytecode::kKeyedLoadIC: - return Bytecode::kKeyedLoadICWide; - case Bytecode::kStoreICSloppy: - return Bytecode::kStoreICSloppyWide; - case Bytecode::kStoreICStrict: - return Bytecode::kStoreICStrictWide; - case Bytecode::kKeyedStoreICSloppy: - return Bytecode::kKeyedStoreICSloppyWide; - case Bytecode::kKeyedStoreICStrict: - return Bytecode::kKeyedStoreICStrictWide; - case Bytecode::kLdaGlobal: - return Bytecode::kLdaGlobalWide; - case Bytecode::kLdaGlobalInsideTypeof: - return Bytecode::kLdaGlobalInsideTypeofWide; - case Bytecode::kStaGlobalSloppy: - return Bytecode::kStaGlobalSloppyWide; - case Bytecode::kStaGlobalStrict: - return Bytecode::kStaGlobalStrictWide; - case Bytecode::kLdaLookupSlot: - return Bytecode::kLdaLookupSlotWide; - case Bytecode::kLdaLookupSlotInsideTypeof: - return Bytecode::kLdaLookupSlotInsideTypeofWide; - case Bytecode::kStaLookupSlotStrict: - return Bytecode::kStaLookupSlotStrictWide; - case Bytecode::kStaLookupSlotSloppy: - return Bytecode::kStaLookupSlotSloppyWide; - default: - UNREACHABLE(); - return static_cast<Bytecode>(-1); + return Bytecode::kIllegal; } } @@ -1472,12 +1286,10 @@ Bytecode BytecodeArrayBuilder::BytecodeForStoreIC(LanguageMode language_mode) { return Bytecode::kStoreICSloppy; case STRICT: return Bytecode::kStoreICStrict; - case STRONG: - UNIMPLEMENTED(); default: UNREACHABLE(); } - return static_cast<Bytecode>(-1); + return Bytecode::kIllegal; } @@ -1489,12 +1301,10 @@ Bytecode BytecodeArrayBuilder::BytecodeForKeyedStoreIC( return Bytecode::kKeyedStoreICSloppy; case STRICT: return Bytecode::kKeyedStoreICStrict; - case STRONG: - UNIMPLEMENTED(); default: UNREACHABLE(); } - return static_cast<Bytecode>(-1); + return Bytecode::kIllegal; } @@ -1513,12 +1323,10 @@ Bytecode BytecodeArrayBuilder::BytecodeForStoreGlobal( return Bytecode::kStaGlobalSloppy; case STRICT: return Bytecode::kStaGlobalStrict; - case STRONG: - UNIMPLEMENTED(); default: UNREACHABLE(); } - return static_cast<Bytecode>(-1); + return Bytecode::kIllegal; } @@ -1530,12 +1338,10 @@ Bytecode BytecodeArrayBuilder::BytecodeForStoreLookupSlot( return Bytecode::kStaLookupSlotSloppy; case STRICT: return Bytecode::kStaLookupSlotStrict; - case STRONG: - UNIMPLEMENTED(); default: UNREACHABLE(); } - return static_cast<Bytecode>(-1); + return Bytecode::kIllegal; } // static @@ -1550,7 +1356,7 @@ Bytecode BytecodeArrayBuilder::BytecodeForCreateArguments( return Bytecode::kCreateRestParameter; } UNREACHABLE(); - return static_cast<Bytecode>(-1); + return Bytecode::kIllegal; } @@ -1561,12 +1367,10 @@ Bytecode BytecodeArrayBuilder::BytecodeForDelete(LanguageMode language_mode) { return Bytecode::kDeletePropertySloppy; case STRICT: return Bytecode::kDeletePropertyStrict; - case STRONG: - UNIMPLEMENTED(); default: UNREACHABLE(); } - return static_cast<Bytecode>(-1); + return Bytecode::kIllegal; } // static @@ -1579,58 +1383,109 @@ Bytecode BytecodeArrayBuilder::BytecodeForCall(TailCallMode tail_call_mode) { default: UNREACHABLE(); } - return static_cast<Bytecode>(-1); + return Bytecode::kIllegal; } // static -bool BytecodeArrayBuilder::FitsInIdx8Operand(int value) { - return kMinUInt8 <= value && value <= kMaxUInt8; +OperandSize BytecodeArrayBuilder::SizeForRegisterOperand(Register value) { + if (value.is_byte_operand()) { + return OperandSize::kByte; + } else if (value.is_short_operand()) { + return OperandSize::kShort; + } else { + return OperandSize::kQuad; + } } - // static -bool BytecodeArrayBuilder::FitsInIdx8Operand(size_t value) { - return value <= static_cast<size_t>(kMaxUInt8); +OperandSize BytecodeArrayBuilder::SizeForSignedOperand(int value) { + if (kMinInt8 <= value && value <= kMaxInt8) { + return OperandSize::kByte; + } else if (kMinInt16 <= value && value <= kMaxInt16) { + return OperandSize::kShort; + } else { + return OperandSize::kQuad; + } } - // static -bool BytecodeArrayBuilder::FitsInImm8Operand(int value) { - return kMinInt8 <= value && value <= kMaxInt8; +OperandSize BytecodeArrayBuilder::SizeForUnsignedOperand(int value) { + DCHECK_GE(value, 0); + if (value <= kMaxUInt8) { + return OperandSize::kByte; + } else if (value <= kMaxUInt16) { + return OperandSize::kShort; + } else { + return OperandSize::kQuad; + } } - -// static -bool BytecodeArrayBuilder::FitsInIdx16Operand(int value) { - return kMinUInt16 <= value && value <= kMaxUInt16; +OperandSize BytecodeArrayBuilder::SizeForUnsignedOperand(size_t value) { + if (value <= static_cast<size_t>(kMaxUInt8)) { + return OperandSize::kByte; + } else if (value <= static_cast<size_t>(kMaxUInt16)) { + return OperandSize::kShort; + } else if (value <= kMaxUInt32) { + return OperandSize::kQuad; + } else { + UNREACHABLE(); + return OperandSize::kQuad; + } } - -// static -bool BytecodeArrayBuilder::FitsInIdx16Operand(size_t value) { - return value <= static_cast<size_t>(kMaxUInt16); +OperandScale BytecodeArrayBuilder::OperandSizesToScale(OperandSize size0, + OperandSize size1, + OperandSize size2, + OperandSize size3) { + OperandSize upper = std::max(size0, size1); + OperandSize lower = std::max(size2, size3); + OperandSize result = std::max(upper, lower); + // Operand sizes have been scaled before calling this function. + // Currently all scalable operands are byte sized at + // OperandScale::kSingle. + STATIC_ASSERT(static_cast<int>(OperandSize::kByte) == + static_cast<int>(OperandScale::kSingle) && + static_cast<int>(OperandSize::kShort) == + static_cast<int>(OperandScale::kDouble) && + static_cast<int>(OperandSize::kQuad) == + static_cast<int>(OperandScale::kQuadruple)); + OperandScale operand_scale = static_cast<OperandScale>(result); + DCHECK(operand_scale == OperandScale::kSingle || + operand_scale == OperandScale::kDouble || + operand_scale == OperandScale::kQuadruple); + return operand_scale; } - -// static -bool BytecodeArrayBuilder::FitsInReg8Operand(Register value) { - return RegisterTranslator::FitsInReg8Operand(value); +uint32_t BytecodeArrayBuilder::RegisterOperand(Register reg) { + return static_cast<uint32_t>(reg.ToOperand()); } -// static -bool BytecodeArrayBuilder::FitsInReg8OperandUntranslated(Register value) { - return value.is_byte_operand(); +Register BytecodeArrayBuilder::RegisterFromOperand(uint32_t operand) { + return Register::FromOperand(static_cast<int32_t>(operand)); } +uint32_t BytecodeArrayBuilder::SignedOperand(int value, OperandSize size) { + switch (size) { + case OperandSize::kByte: + return static_cast<uint8_t>(value & 0xff); + case OperandSize::kShort: + return static_cast<uint16_t>(value & 0xffff); + case OperandSize::kQuad: + return static_cast<uint32_t>(value); + case OperandSize::kNone: + UNREACHABLE(); + } + return 0; +} -// static -bool BytecodeArrayBuilder::FitsInReg16Operand(Register value) { - return RegisterTranslator::FitsInReg16Operand(value); +uint32_t BytecodeArrayBuilder::UnsignedOperand(int value) { + DCHECK_GE(value, 0); + return static_cast<uint32_t>(value); } -// static -bool BytecodeArrayBuilder::FitsInReg16OperandUntranslated(Register value) { - return value.is_short_operand(); +uint32_t BytecodeArrayBuilder::UnsignedOperand(size_t value) { + DCHECK_LE(value, kMaxUInt32); + return static_cast<uint32_t>(value); } } // namespace interpreter diff --git a/deps/v8/src/interpreter/bytecode-array-builder.h b/deps/v8/src/interpreter/bytecode-array-builder.h index fe69337184..4446a63596 100644 --- a/deps/v8/src/interpreter/bytecode-array-builder.h +++ b/deps/v8/src/interpreter/bytecode-array-builder.h @@ -10,7 +10,6 @@ #include "src/interpreter/bytecodes.h" #include "src/interpreter/constant-array-builder.h" #include "src/interpreter/handler-table-builder.h" -#include "src/interpreter/register-translator.h" #include "src/interpreter/source-position-table.h" #include "src/zone-containers.h" @@ -24,10 +23,11 @@ namespace interpreter { class BytecodeLabel; class Register; -class BytecodeArrayBuilder final : public ZoneObject, private RegisterMover { +class BytecodeArrayBuilder final : public ZoneObject { public: BytecodeArrayBuilder(Isolate* isolate, Zone* zone, int parameter_count, - int context_count, int locals_count); + int context_count, int locals_count, + FunctionLiteral* literal = nullptr); ~BytecodeArrayBuilder(); Handle<BytecodeArray> ToBytecodeArray(); @@ -65,13 +65,6 @@ class BytecodeArrayBuilder final : public ZoneObject, private RegisterMover { return temporary_register_allocator()->allocation_count(); } - // Returns the number of registers used for translating wide - // register operands into byte sized register operands. - int translation_register_count() const { - return RegisterTranslator::RegisterCountAdjustment( - fixed_and_temporary_register_count(), parameter_count()); - } - Register Parameter(int parameter_index) const; // Return true if the register |reg| represents a parameter or a @@ -89,7 +82,6 @@ class BytecodeArrayBuilder final : public ZoneObject, private RegisterMover { BytecodeArrayBuilder& LoadTheHole(); BytecodeArrayBuilder& LoadTrue(); BytecodeArrayBuilder& LoadFalse(); - BytecodeArrayBuilder& LoadBooleanConstant(bool value); // Global loads to the accumulator and stores from the accumulator. BytecodeArrayBuilder& LoadGlobal(const Handle<String> name, int feedback_slot, @@ -245,7 +237,8 @@ class BytecodeArrayBuilder final : public ZoneObject, private RegisterMover { BytecodeArrayBuilder& ForInPrepare(Register cache_info_triple); BytecodeArrayBuilder& ForInDone(Register index, Register cache_length); BytecodeArrayBuilder& ForInNext(Register receiver, Register index, - Register cache_type_array_pair); + Register cache_type_array_pair, + int feedback_slot); BytecodeArrayBuilder& ForInStep(Register index); // Exception handling. @@ -257,8 +250,11 @@ class BytecodeArrayBuilder final : public ZoneObject, private RegisterMover { // entry, so that it can be referenced by above exception handling support. int NewHandlerEntry() { return handler_table_builder()->NewHandlerEntry(); } + void InitializeReturnPosition(FunctionLiteral* literal); + void SetStatementPosition(Statement* stmt); void SetExpressionPosition(Expression* expr); + void SetExpressionAsStatementPosition(Expression* expr); // Accessors Zone* zone() const { return zone_; } @@ -269,7 +265,23 @@ class BytecodeArrayBuilder final : public ZoneObject, private RegisterMover { return &temporary_allocator_; } - void EnsureReturn(FunctionLiteral* literal); + void EnsureReturn(); + + static OperandScale OperandSizesToScale( + OperandSize size0, OperandSize size1 = OperandSize::kByte, + OperandSize size2 = OperandSize::kByte, + OperandSize size3 = OperandSize::kByte); + + static OperandSize SizeForRegisterOperand(Register reg); + static OperandSize SizeForSignedOperand(int value); + static OperandSize SizeForUnsignedOperand(int value); + static OperandSize SizeForUnsignedOperand(size_t value); + + static uint32_t RegisterOperand(Register reg); + static Register RegisterFromOperand(uint32_t operand); + static uint32_t SignedOperand(int value, OperandSize size); + static uint32_t UnsignedOperand(int value); + static uint32_t UnsignedOperand(size_t value); private: class PreviousBytecodeHelper; @@ -278,7 +290,6 @@ class BytecodeArrayBuilder final : public ZoneObject, private RegisterMover { static Bytecode BytecodeForBinaryOperation(Token::Value op); static Bytecode BytecodeForCountOperation(Token::Value op); static Bytecode BytecodeForCompareOperation(Token::Value op); - static Bytecode BytecodeForWideOperands(Bytecode bytecode); static Bytecode BytecodeForStoreIC(LanguageMode language_mode); static Bytecode BytecodeForKeyedStoreIC(LanguageMode language_mode); static Bytecode BytecodeForLoadGlobal(TypeofMode typeof_mode); @@ -288,32 +299,22 @@ class BytecodeArrayBuilder final : public ZoneObject, private RegisterMover { static Bytecode BytecodeForDelete(LanguageMode language_mode); static Bytecode BytecodeForCall(TailCallMode tail_call_mode); - static bool FitsInIdx8Operand(int value); - static bool FitsInIdx8Operand(size_t value); - static bool FitsInImm8Operand(int value); - static bool FitsInIdx16Operand(int value); - static bool FitsInIdx16Operand(size_t value); - static bool FitsInReg8Operand(Register value); - static bool FitsInReg8OperandUntranslated(Register value); - static bool FitsInReg16Operand(Register value); - static bool FitsInReg16OperandUntranslated(Register value); - - // RegisterMover interface. - void MoveRegisterUntranslated(Register from, Register to) override; - static Bytecode GetJumpWithConstantOperand(Bytecode jump_smi8_operand); - static Bytecode GetJumpWithConstantWideOperand(Bytecode jump_smi8_operand); static Bytecode GetJumpWithToBoolean(Bytecode jump_smi8_operand); template <size_t N> - INLINE(void Output(Bytecode bytecode, uint32_t(&operands)[N])); - void Output(Bytecode bytecode, uint32_t operand0, uint32_t operand1, - uint32_t operand2, uint32_t operand3); - void Output(Bytecode bytecode, uint32_t operand0, uint32_t operand1, - uint32_t operand2); - void Output(Bytecode bytecode, uint32_t operand0, uint32_t operand1); - void Output(Bytecode bytecode, uint32_t operand0); + INLINE(void Output(Bytecode bytecode, uint32_t (&operands)[N], + OperandScale operand_scale = OperandScale::kSingle)); void Output(Bytecode bytecode); + void OutputScaled(Bytecode bytecode, OperandScale operand_scale, + uint32_t operand0, uint32_t operand1, uint32_t operand2, + uint32_t operand3); + void OutputScaled(Bytecode bytecode, OperandScale operand_scale, + uint32_t operand0, uint32_t operand1, uint32_t operand2); + void OutputScaled(Bytecode bytecode, OperandScale operand_scale, + uint32_t operand0, uint32_t operand1); + void OutputScaled(Bytecode bytecode, OperandScale operand_scale, + uint32_t operand0); BytecodeArrayBuilder& OutputJump(Bytecode jump_bytecode, BytecodeLabel* label); @@ -323,19 +324,21 @@ class BytecodeArrayBuilder final : public ZoneObject, private RegisterMover { const ZoneVector<uint8_t>::iterator& jump_location, int delta); void PatchIndirectJumpWith16BitOperand( const ZoneVector<uint8_t>::iterator& jump_location, int delta); + void PatchIndirectJumpWith32BitOperand( + const ZoneVector<uint8_t>::iterator& jump_location, int delta); void LeaveBasicBlock(); - bool OperandIsValid(Bytecode bytecode, int operand_index, - uint32_t operand_value) const; - bool RegisterIsValid(Register reg, OperandType reg_type) const; + bool OperandIsValid(Bytecode bytecode, OperandScale operand_scale, + int operand_index, uint32_t operand_value) const; + bool RegisterIsValid(Register reg, OperandSize reg_size) const; bool LastBytecodeInSameBlock() const; bool NeedToBooleanCast(); bool IsRegisterInAccumulator(Register reg); - // Set position for implicit return. - void SetReturnPosition(FunctionLiteral* fun); + // Set position for return. + void SetReturnPosition(); // Gets a constant pool entry for the |object|. size_t GetConstantPoolEntry(Handle<Object> object); @@ -355,7 +358,6 @@ class BytecodeArrayBuilder final : public ZoneObject, private RegisterMover { SourcePositionTableBuilder* source_position_table_builder() { return &source_position_table_builder_; } - RegisterTranslator* register_translator() { return ®ister_translator_; } Isolate* isolate_; Zone* zone_; @@ -371,8 +373,8 @@ class BytecodeArrayBuilder final : public ZoneObject, private RegisterMover { int parameter_count_; int local_register_count_; int context_register_count_; + int return_position_; TemporaryRegisterAllocator temporary_allocator_; - RegisterTranslator register_translator_; DISALLOW_COPY_AND_ASSIGN(BytecodeArrayBuilder); }; diff --git a/deps/v8/src/interpreter/bytecode-array-iterator.cc b/deps/v8/src/interpreter/bytecode-array-iterator.cc index 0fea985efe..a17efcb6ca 100644 --- a/deps/v8/src/interpreter/bytecode-array-iterator.cc +++ b/deps/v8/src/interpreter/bytecode-array-iterator.cc @@ -12,103 +12,119 @@ namespace interpreter { BytecodeArrayIterator::BytecodeArrayIterator( Handle<BytecodeArray> bytecode_array) - : bytecode_array_(bytecode_array), bytecode_offset_(0) {} - + : bytecode_array_(bytecode_array), + bytecode_offset_(0), + operand_scale_(OperandScale::kSingle), + prefix_offset_(0) { + UpdateOperandScale(); +} void BytecodeArrayIterator::Advance() { - bytecode_offset_ += Bytecodes::Size(current_bytecode()); + bytecode_offset_ += current_bytecode_size(); + UpdateOperandScale(); } +void BytecodeArrayIterator::UpdateOperandScale() { + if (!done()) { + uint8_t current_byte = bytecode_array()->get(bytecode_offset_); + Bytecode current_bytecode = Bytecodes::FromByte(current_byte); + if (Bytecodes::IsPrefixScalingBytecode(current_bytecode)) { + operand_scale_ = + Bytecodes::PrefixBytecodeToOperandScale(current_bytecode); + prefix_offset_ = 1; + } else { + operand_scale_ = OperandScale::kSingle; + prefix_offset_ = 0; + } + } +} bool BytecodeArrayIterator::done() const { return bytecode_offset_ >= bytecode_array()->length(); } - Bytecode BytecodeArrayIterator::current_bytecode() const { DCHECK(!done()); - uint8_t current_byte = bytecode_array()->get(bytecode_offset_); - return interpreter::Bytecodes::FromByte(current_byte); + uint8_t current_byte = + bytecode_array()->get(bytecode_offset_ + current_prefix_offset()); + Bytecode current_bytecode = Bytecodes::FromByte(current_byte); + DCHECK(!Bytecodes::IsPrefixScalingBytecode(current_bytecode)); + return current_bytecode; } - int BytecodeArrayIterator::current_bytecode_size() const { - return Bytecodes::Size(current_bytecode()); + return current_prefix_offset() + + Bytecodes::Size(current_bytecode(), current_operand_scale()); } - -uint32_t BytecodeArrayIterator::GetRawOperand(int operand_index, - OperandType operand_type) const { +uint32_t BytecodeArrayIterator::GetUnsignedOperand( + int operand_index, OperandType operand_type) const { DCHECK_GE(operand_index, 0); DCHECK_LT(operand_index, Bytecodes::NumberOfOperands(current_bytecode())); DCHECK_EQ(operand_type, Bytecodes::GetOperandType(current_bytecode(), operand_index)); - uint8_t* operand_start = + DCHECK(Bytecodes::IsUnsignedOperandType(operand_type)); + const uint8_t* operand_start = bytecode_array()->GetFirstBytecodeAddress() + bytecode_offset_ + - Bytecodes::GetOperandOffset(current_bytecode(), operand_index); - switch (Bytecodes::SizeOfOperand(operand_type)) { - case OperandSize::kByte: - return static_cast<uint32_t>(*operand_start); - case OperandSize::kShort: - return ReadUnalignedUInt16(operand_start); - case OperandSize::kNone: - UNREACHABLE(); - } - return 0; + current_prefix_offset() + + Bytecodes::GetOperandOffset(current_bytecode(), operand_index, + current_operand_scale()); + return Bytecodes::DecodeUnsignedOperand(operand_start, operand_type, + current_operand_scale()); } +int32_t BytecodeArrayIterator::GetSignedOperand( + int operand_index, OperandType operand_type) const { + DCHECK_GE(operand_index, 0); + DCHECK_LT(operand_index, Bytecodes::NumberOfOperands(current_bytecode())); + DCHECK_EQ(operand_type, + Bytecodes::GetOperandType(current_bytecode(), operand_index)); + DCHECK(!Bytecodes::IsUnsignedOperandType(operand_type)); + const uint8_t* operand_start = + bytecode_array()->GetFirstBytecodeAddress() + bytecode_offset_ + + current_prefix_offset() + + Bytecodes::GetOperandOffset(current_bytecode(), operand_index, + current_operand_scale()); + return Bytecodes::DecodeSignedOperand(operand_start, operand_type, + current_operand_scale()); +} -int8_t BytecodeArrayIterator::GetImmediateOperand(int operand_index) const { - uint32_t operand = GetRawOperand(operand_index, OperandType::kImm8); - return static_cast<int8_t>(operand); +uint32_t BytecodeArrayIterator::GetFlagOperand(int operand_index) const { + DCHECK_EQ(Bytecodes::GetOperandType(current_bytecode(), operand_index), + OperandType::kFlag8); + return GetUnsignedOperand(operand_index, OperandType::kFlag8); } -int BytecodeArrayIterator::GetRegisterCountOperand(int operand_index) const { - OperandSize size = - Bytecodes::GetOperandSize(current_bytecode(), operand_index); - OperandType type = (size == OperandSize::kByte) ? OperandType::kRegCount8 - : OperandType::kRegCount16; - uint32_t operand = GetRawOperand(operand_index, type); - return static_cast<int>(operand); +int32_t BytecodeArrayIterator::GetImmediateOperand(int operand_index) const { + DCHECK_EQ(Bytecodes::GetOperandType(current_bytecode(), operand_index), + OperandType::kImm); + return GetSignedOperand(operand_index, OperandType::kImm); } +uint32_t BytecodeArrayIterator::GetRegisterCountOperand( + int operand_index) const { + DCHECK_EQ(Bytecodes::GetOperandType(current_bytecode(), operand_index), + OperandType::kRegCount); + return GetUnsignedOperand(operand_index, OperandType::kRegCount); +} -int BytecodeArrayIterator::GetIndexOperand(int operand_index) const { +uint32_t BytecodeArrayIterator::GetIndexOperand(int operand_index) const { OperandType operand_type = Bytecodes::GetOperandType(current_bytecode(), operand_index); - DCHECK(operand_type == OperandType::kIdx8 || - operand_type == OperandType::kIdx16); - uint32_t operand = GetRawOperand(operand_index, operand_type); - return static_cast<int>(operand); + DCHECK_EQ(operand_type, OperandType::kIdx); + return GetUnsignedOperand(operand_index, operand_type); } - Register BytecodeArrayIterator::GetRegisterOperand(int operand_index) const { OperandType operand_type = Bytecodes::GetOperandType(current_bytecode(), operand_index); - DCHECK(Bytecodes::IsRegisterOperandType(operand_type)); - uint32_t operand = GetRawOperand(operand_index, operand_type); - Register reg; - switch (Bytecodes::GetOperandSize(current_bytecode(), operand_index)) { - case OperandSize::kByte: - reg = Register::FromOperand(static_cast<uint8_t>(operand)); - break; - case OperandSize::kShort: - reg = Register::FromWideOperand(static_cast<uint16_t>(operand)); - break; - case OperandSize::kNone: - UNREACHABLE(); - reg = Register::invalid_value(); - break; - } - DCHECK_GE(reg.index(), - Register::FromParameterIndex(0, bytecode_array()->parameter_count()) - .index()); - DCHECK(reg.index() < bytecode_array()->register_count() || - (reg.index() == 0 && - Bytecodes::IsMaybeRegisterOperandType( - Bytecodes::GetOperandType(current_bytecode(), operand_index)))); - return reg; + const uint8_t* operand_start = + bytecode_array()->GetFirstBytecodeAddress() + bytecode_offset_ + + current_prefix_offset() + + Bytecodes::GetOperandOffset(current_bytecode(), operand_index, + current_operand_scale()); + return Bytecodes::DecodeRegisterOperand(operand_start, operand_type, + current_operand_scale()); } int BytecodeArrayIterator::GetRegisterOperandRange(int operand_index) const { @@ -116,20 +132,17 @@ int BytecodeArrayIterator::GetRegisterOperandRange(int operand_index) const { Bytecodes::GetOperandType(current_bytecode(), operand_index); DCHECK(Bytecodes::IsRegisterOperandType(operand_type)); switch (operand_type) { - case OperandType::kRegPair8: - case OperandType::kRegPair16: - case OperandType::kRegOutPair8: - case OperandType::kRegOutPair16: + case OperandType::kRegPair: + case OperandType::kRegOutPair: return 2; - case OperandType::kRegOutTriple8: - case OperandType::kRegOutTriple16: + case OperandType::kRegOutTriple: return 3; default: { if (operand_index + 1 != Bytecodes::NumberOfOperands(current_bytecode())) { OperandType next_operand_type = Bytecodes::GetOperandType(current_bytecode(), operand_index + 1); - if (Bytecodes::IsRegisterCountOperandType(next_operand_type)) { + if (OperandType::kRegCount == next_operand_type) { return GetRegisterCountOperand(operand_index + 1); } } @@ -138,6 +151,13 @@ int BytecodeArrayIterator::GetRegisterOperandRange(int operand_index) const { } } +uint32_t BytecodeArrayIterator::GetRuntimeIdOperand(int operand_index) const { + OperandType operand_type = + Bytecodes::GetOperandType(current_bytecode(), operand_index); + DCHECK(operand_type == OperandType::kRuntimeId); + return GetUnsignedOperand(operand_index, operand_type); +} + Handle<Object> BytecodeArrayIterator::GetConstantForIndexOperand( int operand_index) const { return FixedArray::get(bytecode_array()->constant_pool(), @@ -150,11 +170,10 @@ int BytecodeArrayIterator::GetJumpTargetOffset() const { Bytecode bytecode = current_bytecode(); if (interpreter::Bytecodes::IsJumpImmediate(bytecode)) { int relative_offset = GetImmediateOperand(0); - return current_offset() + relative_offset; - } else if (interpreter::Bytecodes::IsJumpConstant(bytecode) || - interpreter::Bytecodes::IsJumpConstantWide(bytecode)) { + return current_offset() + relative_offset + current_prefix_offset(); + } else if (interpreter::Bytecodes::IsJumpConstant(bytecode)) { Smi* smi = Smi::cast(*GetConstantForIndexOperand(0)); - return current_offset() + smi->value(); + return current_offset() + smi->value() + current_prefix_offset(); } else { UNREACHABLE(); return kMinInt; diff --git a/deps/v8/src/interpreter/bytecode-array-iterator.h b/deps/v8/src/interpreter/bytecode-array-iterator.h index 5379bbf028..b372894fd8 100644 --- a/deps/v8/src/interpreter/bytecode-array-iterator.h +++ b/deps/v8/src/interpreter/bytecode-array-iterator.h @@ -21,31 +21,38 @@ class BytecodeArrayIterator { bool done() const; Bytecode current_bytecode() const; int current_bytecode_size() const; - void set_current_offset(int offset) { bytecode_offset_ = offset; } int current_offset() const { return bytecode_offset_; } + OperandScale current_operand_scale() const { return operand_scale_; } + int current_prefix_offset() const { return prefix_offset_; } const Handle<BytecodeArray>& bytecode_array() const { return bytecode_array_; } - int8_t GetImmediateOperand(int operand_index) const; - int GetIndexOperand(int operand_index) const; - int GetRegisterCountOperand(int operand_index) const; + uint32_t GetFlagOperand(int operand_index) const; + int32_t GetImmediateOperand(int operand_index) const; + uint32_t GetIndexOperand(int operand_index) const; + uint32_t GetRegisterCountOperand(int operand_index) const; Register GetRegisterOperand(int operand_index) const; int GetRegisterOperandRange(int operand_index) const; + uint32_t GetRuntimeIdOperand(int operand_index) const; Handle<Object> GetConstantForIndexOperand(int operand_index) const; - // Get the raw byte for the given operand. Note: you should prefer using the - // typed versions above which cast the return to an appropriate type. - uint32_t GetRawOperand(int operand_index, OperandType operand_type) const; - // Returns the absolute offset of the branch target at the current // bytecode. It is an error to call this method if the bytecode is // not for a jump or conditional jump. int GetJumpTargetOffset() const; private: + uint32_t GetUnsignedOperand(int operand_index, + OperandType operand_type) const; + int32_t GetSignedOperand(int operand_index, OperandType operand_type) const; + + void UpdateOperandScale(); + Handle<BytecodeArray> bytecode_array_; int bytecode_offset_; + OperandScale operand_scale_; + int prefix_offset_; DISALLOW_COPY_AND_ASSIGN(BytecodeArrayIterator); }; diff --git a/deps/v8/src/interpreter/bytecode-generator.cc b/deps/v8/src/interpreter/bytecode-generator.cc index 6f4dc275c1..b0fa245e18 100644 --- a/deps/v8/src/interpreter/bytecode-generator.cc +++ b/deps/v8/src/interpreter/bytecode-generator.cc @@ -72,6 +72,7 @@ class BytecodeGenerator::ContextScope BASE_EMBEDDED { Scope* scope() const { return scope_; } Register reg() const { return register_; } + bool ShouldPopContext() { return should_pop_context_; } private: const BytecodeArrayBuilder* builder() const { return generator_->builder(); } @@ -212,9 +213,9 @@ class BytecodeGenerator::ControlScopeForTopLevel final protected: bool Execute(Command command, Statement* statement) override { switch (command) { - case CMD_BREAK: + case CMD_BREAK: // We should never see break/continue in top-level. case CMD_CONTINUE: - break; + UNREACHABLE(); case CMD_RETURN: generator()->builder()->Return(); return true; @@ -362,15 +363,20 @@ class BytecodeGenerator::ControlScopeForTryFinally final void BytecodeGenerator::ControlScope::PerformCommand(Command command, Statement* statement) { ControlScope* current = this; - ContextScope* context = this->context(); + ContextScope* context = generator()->execution_context(); + // Pop context to the expected depth but do not pop the outermost context. + if (context != current->context() && context->ShouldPopContext()) { + generator()->builder()->PopContext(current->context()->reg()); + } do { - if (current->Execute(command, statement)) { return; } + if (current->Execute(command, statement)) { + return; + } current = current->outer(); if (current->context() != context) { // Pop context to the expected depth. // TODO(rmcilroy): Only emit a single context pop. generator()->builder()->PopContext(current->context()->reg()); - context = current->context(); } } while (current != nullptr); UNREACHABLE(); @@ -450,7 +456,7 @@ class BytecodeGenerator::ExpressionResultScope { virtual ~ExpressionResultScope() { generator_->set_execution_result(outer_); - DCHECK(result_identified()); + DCHECK(result_identified() || generator_->HasStackOverflow()); } bool IsEffect() const { return kind_ == Expression::kEffect; } @@ -462,6 +468,7 @@ class BytecodeGenerator::ExpressionResultScope { protected: ExpressionResultScope* outer() const { return outer_; } BytecodeArrayBuilder* builder() const { return generator_->builder(); } + BytecodeGenerator* generator() const { return generator_; } const RegisterAllocationScope* allocator() const { return &allocator_; } void set_result_identified() { @@ -536,7 +543,12 @@ class BytecodeGenerator::RegisterResultScope final set_result_identified(); } - Register ResultRegister() const { return result_register_; } + Register ResultRegister() { + if (generator()->HasStackOverflow() && !result_identified()) { + SetResultInAccumulator(); + } + return result_register_; + } private: Register result_register_; @@ -565,7 +577,8 @@ Handle<BytecodeArray> BytecodeGenerator::MakeBytecode(CompilationInfo* info) { // Initialize bytecode array builder. set_builder(new (zone()) BytecodeArrayBuilder( isolate(), zone(), info->num_parameters_including_this(), - scope()->MaxNestedContextChainLength(), scope()->num_stack_slots())); + scope()->MaxNestedContextChainLength(), scope()->num_stack_slots(), + info->literal())); // Initialize the incoming context. ContextScope incoming_context(this, scope(), false); @@ -584,7 +597,7 @@ Handle<BytecodeArray> BytecodeGenerator::MakeBytecode(CompilationInfo* info) { MakeBytecodeBody(); } - builder()->EnsureReturn(info->literal()); + builder()->EnsureReturn(); set_scope(nullptr); set_info(nullptr); return builder()->ToBytecodeArray(); @@ -611,12 +624,6 @@ void BytecodeGenerator::MakeBytecodeBody() { UNIMPLEMENTED(); } - // Visit illegal re-declaration and bail out if it exists. - if (scope()->HasIllegalRedeclaration()) { - VisitForEffect(scope()->GetIllegalRedeclaration()); - return; - } - // Visit declarations within the function scope. VisitDeclarations(scope()->declarations()); @@ -826,6 +833,7 @@ void BytecodeGenerator::VisitEmptyStatement(EmptyStatement* stmt) { void BytecodeGenerator::VisitIfStatement(IfStatement* stmt) { + builder()->SetStatementPosition(stmt); BytecodeLabel else_label, end_label; if (stmt->condition()->ToBooleanIsTrue()) { // Generate then block unconditionally as always true. @@ -861,23 +869,26 @@ void BytecodeGenerator::VisitSloppyBlockFunctionStatement( void BytecodeGenerator::VisitContinueStatement(ContinueStatement* stmt) { + builder()->SetStatementPosition(stmt); execution_control()->Continue(stmt->target()); } void BytecodeGenerator::VisitBreakStatement(BreakStatement* stmt) { + builder()->SetStatementPosition(stmt); execution_control()->Break(stmt->target()); } void BytecodeGenerator::VisitReturnStatement(ReturnStatement* stmt) { - VisitForAccumulatorValue(stmt->expression()); builder()->SetStatementPosition(stmt); + VisitForAccumulatorValue(stmt->expression()); execution_control()->ReturnAccumulator(); } void BytecodeGenerator::VisitWithStatement(WithStatement* stmt) { + builder()->SetStatementPosition(stmt); VisitForAccumulatorValue(stmt->expression()); builder()->CastAccumulatorToJSObject(); VisitNewLocalWithContext(); @@ -893,6 +904,8 @@ void BytecodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) { ControlScopeForBreakable scope(this, stmt, &switch_builder); int default_index = -1; + builder()->SetStatementPosition(stmt); + // Keep the switch value in a register until a case matches. Register tag = VisitForRegisterValue(stmt->tag()); @@ -959,6 +972,7 @@ void BytecodeGenerator::VisitDoWhileStatement(DoWhileStatement* stmt) { } else { VisitIterationBody(stmt, &loop_builder); loop_builder.Condition(); + builder()->SetExpressionAsStatementPosition(stmt->cond()); VisitForAccumulatorValue(stmt->cond()); loop_builder.JumpToHeaderIfTrue(); } @@ -975,6 +989,7 @@ void BytecodeGenerator::VisitWhileStatement(WhileStatement* stmt) { loop_builder.LoopHeader(); loop_builder.Condition(); if (!stmt->cond()->ToBooleanIsTrue()) { + builder()->SetExpressionAsStatementPosition(stmt->cond()); VisitForAccumulatorValue(stmt->cond()); loop_builder.BreakIfFalse(); } @@ -998,12 +1013,14 @@ void BytecodeGenerator::VisitForStatement(ForStatement* stmt) { loop_builder.LoopHeader(); loop_builder.Condition(); if (stmt->cond() && !stmt->cond()->ToBooleanIsTrue()) { + builder()->SetExpressionAsStatementPosition(stmt->cond()); VisitForAccumulatorValue(stmt->cond()); loop_builder.BreakIfFalse(); } VisitIterationBody(stmt, &loop_builder); if (stmt->next() != nullptr) { loop_builder.Next(); + builder()->SetStatementPosition(stmt->next()); Visit(stmt->next()); } loop_builder.JumpToHeader(); @@ -1087,28 +1104,28 @@ void BytecodeGenerator::VisitForInAssignment(Expression* expr, void BytecodeGenerator::VisitForInStatement(ForInStatement* stmt) { if (stmt->subject()->IsNullLiteral() || - stmt->subject()->IsUndefinedLiteral(isolate())) { + stmt->subject()->IsUndefinedLiteral()) { // ForIn generates lots of code, skip if it wouldn't produce any effects. return; } LoopBuilder loop_builder(builder()); - BytecodeLabel subject_null_label, subject_undefined_label, not_object_label; + BytecodeLabel subject_null_label, subject_undefined_label; // Prepare the state for executing ForIn. + builder()->SetExpressionAsStatementPosition(stmt->subject()); VisitForAccumulatorValue(stmt->subject()); builder()->JumpIfUndefined(&subject_undefined_label); builder()->JumpIfNull(&subject_null_label); Register receiver = register_allocator()->NewRegister(); builder()->CastAccumulatorToJSObject(); - builder()->JumpIfNull(¬_object_label); builder()->StoreAccumulatorInRegister(receiver); register_allocator()->PrepareForConsecutiveAllocations(3); Register cache_type = register_allocator()->NextConsecutiveRegister(); Register cache_array = register_allocator()->NextConsecutiveRegister(); Register cache_length = register_allocator()->NextConsecutiveRegister(); - // Used as kRegTriple8 and kRegPair8 in ForInPrepare and ForInNext. + // Used as kRegTriple and kRegPair in ForInPrepare and ForInNext. USE(cache_array); builder()->ForInPrepare(cache_type); @@ -1119,11 +1136,13 @@ void BytecodeGenerator::VisitForInStatement(ForInStatement* stmt) { // The loop loop_builder.LoopHeader(); + builder()->SetExpressionAsStatementPosition(stmt->each()); loop_builder.Condition(); builder()->ForInDone(index, cache_length); loop_builder.BreakIfTrue(); DCHECK(Register::AreContiguous(cache_type, cache_array)); - builder()->ForInNext(receiver, index, cache_type); + FeedbackVectorSlot slot = stmt->ForInFeedbackSlot(); + builder()->ForInNext(receiver, index, cache_type, feedback_index(slot)); loop_builder.ContinueIfUndefined(); VisitForInAssignment(stmt->each(), stmt->EachFeedbackSlot()); VisitIterationBody(stmt, &loop_builder); @@ -1132,7 +1151,6 @@ void BytecodeGenerator::VisitForInStatement(ForInStatement* stmt) { builder()->StoreAccumulatorInRegister(index); loop_builder.JumpToHeader(); loop_builder.EndLoop(); - builder()->Bind(¬_object_label); builder()->Bind(&subject_null_label); builder()->Bind(&subject_undefined_label); } @@ -1146,6 +1164,7 @@ void BytecodeGenerator::VisitForOfStatement(ForOfStatement* stmt) { loop_builder.LoopHeader(); loop_builder.Next(); + builder()->SetExpressionAsStatementPosition(stmt->next_result()); VisitForEffect(stmt->next_result()); VisitForAccumulatorValue(stmt->result_done()); loop_builder.BreakIfTrue(); @@ -1180,8 +1199,10 @@ void BytecodeGenerator::VisitTryCatchStatement(TryCatchStatement* stmt) { VisitNewLocalCatchContext(stmt->variable()); builder()->StoreAccumulatorInRegister(context); - // Clear message object as we enter the catch block. - builder()->CallRuntime(Runtime::kInterpreterClearPendingMessage, no_reg, 0); + // If requested, clear message object as we enter the catch block. + if (stmt->clear_pending_message()) { + builder()->CallRuntime(Runtime::kInterpreterClearPendingMessage, no_reg, 0); + } // Load the catch context into the accumulator. builder()->LoadAccumulatorWithRegister(context); @@ -1267,7 +1288,9 @@ void BytecodeGenerator::VisitFunctionLiteral(FunctionLiteral* expr) { // Find or build a shared function info. Handle<SharedFunctionInfo> shared_info = Compiler::GetSharedFunctionInfo(expr, info()->script(), info()); - CHECK(!shared_info.is_null()); // TODO(rmcilroy): Set stack overflow? + if (shared_info.is_null()) { + return SetStackOverflow(); + } builder()->CreateClosure(shared_info, expr->pretenure() ? TENURED : NOT_TENURED); execution_result()->SetResultInAccumulator(); @@ -1679,11 +1702,6 @@ void BytecodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { } } - // Transform literals that contain functions to fast properties. - if (expr->has_function()) { - builder()->CallRuntime(Runtime::kToFastProperties, literal, 1); - } - execution_result()->SetResultInRegister(literal); } @@ -1729,6 +1747,7 @@ void BytecodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) { void BytecodeGenerator::VisitVariableProxy(VariableProxy* proxy) { + builder()->SetExpressionPosition(proxy); VisitVariableLoad(proxy->var(), proxy->VariableFeedbackSlot()); } @@ -2173,6 +2192,7 @@ void BytecodeGenerator::VisitAssignment(Assignment* expr) { } // Store the value. + builder()->SetExpressionPosition(expr); FeedbackVectorSlot slot = expr->AssignmentSlot(); switch (assign_type) { case VARIABLE: { @@ -2210,6 +2230,7 @@ void BytecodeGenerator::VisitYield(Yield* expr) { UNIMPLEMENTED(); } void BytecodeGenerator::VisitThrow(Throw* expr) { VisitForAccumulatorValue(expr->exception()); + builder()->SetExpressionPosition(expr); builder()->Throw(); // Throw statments are modeled as expression instead of statments. These are // converted from assignment statements in Rewriter::ReWrite pass. An @@ -2222,6 +2243,7 @@ void BytecodeGenerator::VisitThrow(Throw* expr) { void BytecodeGenerator::VisitPropertyLoad(Register obj, Property* expr) { LhsKind property_kind = Property::GetAssignType(expr); FeedbackVectorSlot slot = expr->PropertyFeedbackSlot(); + builder()->SetExpressionPosition(expr); switch (property_kind) { case VARIABLE: UNREACHABLE(); @@ -2718,9 +2740,7 @@ void BytecodeGenerator::VisitCountOperation(CountOperation* expr) { } // Convert old value into a number. - if (!is_strong(language_mode())) { - builder()->CastAccumulatorToNumber(); - } + builder()->CastAccumulatorToNumber(); // Save result for postfix expressions. if (is_postfix) { @@ -2732,6 +2752,7 @@ void BytecodeGenerator::VisitCountOperation(CountOperation* expr) { builder()->CountOperation(expr->binary_op()); // Store the value. + builder()->SetExpressionPosition(expr); FeedbackVectorSlot feedback_slot = expr->CountSlot(); switch (assign_type) { case VARIABLE: { @@ -2791,6 +2812,7 @@ void BytecodeGenerator::VisitBinaryOperation(BinaryOperation* binop) { void BytecodeGenerator::VisitCompareOperation(CompareOperation* expr) { Register lhs = VisitForRegisterValue(expr->left()); VisitForAccumulatorValue(expr->right()); + builder()->SetExpressionPosition(expr); builder()->CompareOperation(expr->op(), lhs); execution_result()->SetResultInAccumulator(); } @@ -3129,12 +3151,12 @@ void BytecodeGenerator::VisitInScope(Statement* stmt, Scope* scope) { LanguageMode BytecodeGenerator::language_mode() const { - return info()->language_mode(); + return execution_context()->scope()->language_mode(); } int BytecodeGenerator::feedback_index(FeedbackVectorSlot slot) const { - return info()->feedback_vector()->GetIndex(slot); + return info()->shared_info()->feedback_vector()->GetIndex(slot); } } // namespace interpreter diff --git a/deps/v8/src/interpreter/bytecode-register-allocator.cc b/deps/v8/src/interpreter/bytecode-register-allocator.cc index 0a617c048a..9bdde9a470 100644 --- a/deps/v8/src/interpreter/bytecode-register-allocator.cc +++ b/deps/v8/src/interpreter/bytecode-register-allocator.cc @@ -95,17 +95,6 @@ int TemporaryRegisterAllocator::PrepareForConsecutiveTemporaryRegisters( start = run_end; run_length = 0; } - Register reg_start(*start); - Register reg_expected(expected); - if (RegisterTranslator::DistanceToTranslationWindow(reg_start) > 0 && - RegisterTranslator::DistanceToTranslationWindow(reg_expected) <= 0) { - // Run straddles the lower edge of the translation window. Registers - // after the start of this boundary are displaced by the register - // translator to provide a hole for translation. Runs either side - // of the boundary are fine. - start = run_end; - run_length = 0; - } if (++run_length == count) { return *start; } @@ -121,16 +110,6 @@ int TemporaryRegisterAllocator::PrepareForConsecutiveTemporaryRegisters( // Pad temporaries if extended run would cross translation boundary. Register reg_first(*start); Register reg_last(*start + static_cast<int>(count) - 1); - DCHECK_GT(RegisterTranslator::DistanceToTranslationWindow(reg_first), - RegisterTranslator::DistanceToTranslationWindow(reg_last)); - while (RegisterTranslator::DistanceToTranslationWindow(reg_first) > 0 && - RegisterTranslator::DistanceToTranslationWindow(reg_last) <= 0) { - auto pos_insert_pair = - free_temporaries_.insert(AllocateTemporaryRegister()); - reg_first = Register(*pos_insert_pair.first); - reg_last = Register(reg_first.index() + static_cast<int>(count) - 1); - run_length = 0; - } // Ensure enough registers for run. while (run_length++ < count) { @@ -139,10 +118,6 @@ int TemporaryRegisterAllocator::PrepareForConsecutiveTemporaryRegisters( int run_start = last_temporary_register().index() - static_cast<int>(count) + 1; - DCHECK(RegisterTranslator::DistanceToTranslationWindow(Register(run_start)) <= - 0 || - RegisterTranslator::DistanceToTranslationWindow( - Register(run_start + static_cast<int>(count) - 1)) > 0); return run_start; } diff --git a/deps/v8/src/interpreter/bytecode-traits.h b/deps/v8/src/interpreter/bytecode-traits.h index b8136051bb..c724827356 100644 --- a/deps/v8/src/interpreter/bytecode-traits.h +++ b/deps/v8/src/interpreter/bytecode-traits.h @@ -11,22 +11,35 @@ namespace v8 { namespace internal { namespace interpreter { -// TODO(rmcilroy): consider simplifying this to avoid the template magic. +template <OperandTypeInfo> +struct OperandTypeInfoTraits { + static const bool kIsScalable = false; + static const bool kIsUnsigned = false; + static const OperandSize kUnscaledSize = OperandSize::kNone; +}; -// Template helpers to deduce the number of operands each bytecode has. -#define OPERAND_TERM OperandType::kNone, OperandType::kNone, OperandType::kNone +#define DECLARE_OPERAND_TYPE_INFO(Name, Scalable, Unsigned, BaseSize) \ + template <> \ + struct OperandTypeInfoTraits<OperandTypeInfo::k##Name> { \ + static const bool kIsScalable = Scalable; \ + static const bool kIsUnsigned = Unsigned; \ + static const OperandSize kUnscaledSize = BaseSize; \ + }; +OPERAND_TYPE_INFO_LIST(DECLARE_OPERAND_TYPE_INFO) +#undef DECLARE_OPERAND_TYPE_INFO template <OperandType> -struct OperandTraits {}; +struct OperandTraits { + typedef OperandTypeInfoTraits<OperandTypeInfo::kNone> TypeInfo; +}; -#define DECLARE_OPERAND_SIZE(Name, Size) \ - template <> \ - struct OperandTraits<OperandType::k##Name> { \ - static const OperandSize kSizeType = Size; \ - static const int kSize = static_cast<int>(Size); \ +#define DECLARE_OPERAND_TYPE_TRAITS(Name, InfoType) \ + template <> \ + struct OperandTraits<OperandType::k##Name> { \ + typedef OperandTypeInfoTraits<InfoType> TypeInfo; \ }; -OPERAND_TYPE_LIST(DECLARE_OPERAND_SIZE) -#undef DECLARE_OPERAND_SIZE +OPERAND_TYPE_LIST(DECLARE_OPERAND_TYPE_TRAITS) +#undef DECLARE_OPERAND_TYPE_TRAITS template <OperandType> struct RegisterOperandTraits { @@ -41,13 +54,13 @@ struct RegisterOperandTraits { REGISTER_OPERAND_TYPE_LIST(DECLARE_REGISTER_OPERAND) #undef DECLARE_REGISTER_OPERAND -template <OperandType... Args> +template <AccumulatorUse, OperandType...> struct BytecodeTraits {}; -template <OperandType operand_0, OperandType operand_1, OperandType operand_2, - OperandType operand_3> -struct BytecodeTraits<operand_0, operand_1, operand_2, operand_3, - OPERAND_TERM> { +template <AccumulatorUse accumulator_use, OperandType operand_0, + OperandType operand_1, OperandType operand_2, OperandType operand_3> +struct BytecodeTraits<accumulator_use, operand_0, operand_1, operand_2, + operand_3> { static OperandType GetOperandType(int i) { DCHECK(0 <= i && i < kOperandCount); const OperandType kOperands[] = {operand_0, operand_1, operand_2, @@ -55,32 +68,20 @@ struct BytecodeTraits<operand_0, operand_1, operand_2, operand_3, return kOperands[i]; } - static inline OperandSize GetOperandSize(int i) { - DCHECK(0 <= i && i < kOperandCount); - const OperandSize kOperandSizes[] = - {OperandTraits<operand_0>::kSizeType, - OperandTraits<operand_1>::kSizeType, - OperandTraits<operand_2>::kSizeType, - OperandTraits<operand_3>::kSizeType}; - return kOperandSizes[i]; - } - - static inline int GetOperandOffset(int i) { - DCHECK(0 <= i && i < kOperandCount); - const int kOffset0 = 1; - const int kOffset1 = kOffset0 + OperandTraits<operand_0>::kSize; - const int kOffset2 = kOffset1 + OperandTraits<operand_1>::kSize; - const int kOffset3 = kOffset2 + OperandTraits<operand_2>::kSize; - const int kOperandOffsets[] = {kOffset0, kOffset1, kOffset2, kOffset3}; - return kOperandOffsets[i]; - } - template <OperandType ot> static inline bool HasAnyOperandsOfType() { return operand_0 == ot || operand_1 == ot || operand_2 == ot || operand_3 == ot; } + static inline bool IsScalable() { + return (OperandTraits<operand_0>::TypeInfo::kIsScalable | + OperandTraits<operand_1>::TypeInfo::kIsScalable | + OperandTraits<operand_2>::TypeInfo::kIsScalable | + OperandTraits<operand_3>::TypeInfo::kIsScalable); + } + + static const AccumulatorUse kAccumulatorUse = accumulator_use; static const int kOperandCount = 4; static const int kRegisterOperandCount = RegisterOperandTraits<operand_0>::kIsRegisterOperand + @@ -92,42 +93,29 @@ struct BytecodeTraits<operand_0, operand_1, operand_2, operand_3, (RegisterOperandTraits<operand_1>::kIsRegisterOperand << 1) + (RegisterOperandTraits<operand_2>::kIsRegisterOperand << 2) + (RegisterOperandTraits<operand_3>::kIsRegisterOperand << 3); - static const int kSize = - 1 + OperandTraits<operand_0>::kSize + OperandTraits<operand_1>::kSize + - OperandTraits<operand_2>::kSize + OperandTraits<operand_3>::kSize; }; -template <OperandType operand_0, OperandType operand_1, OperandType operand_2> -struct BytecodeTraits<operand_0, operand_1, operand_2, OPERAND_TERM> { +template <AccumulatorUse accumulator_use, OperandType operand_0, + OperandType operand_1, OperandType operand_2> +struct BytecodeTraits<accumulator_use, operand_0, operand_1, operand_2> { static inline OperandType GetOperandType(int i) { DCHECK(0 <= i && i <= 2); const OperandType kOperands[] = {operand_0, operand_1, operand_2}; return kOperands[i]; } - static inline OperandSize GetOperandSize(int i) { - DCHECK(0 <= i && i < kOperandCount); - const OperandSize kOperandSizes[] = - {OperandTraits<operand_0>::kSizeType, - OperandTraits<operand_1>::kSizeType, - OperandTraits<operand_2>::kSizeType}; - return kOperandSizes[i]; - } - - static inline int GetOperandOffset(int i) { - DCHECK(0 <= i && i < kOperandCount); - const int kOffset0 = 1; - const int kOffset1 = kOffset0 + OperandTraits<operand_0>::kSize; - const int kOffset2 = kOffset1 + OperandTraits<operand_1>::kSize; - const int kOperandOffsets[] = {kOffset0, kOffset1, kOffset2}; - return kOperandOffsets[i]; - } - template <OperandType ot> static inline bool HasAnyOperandsOfType() { return operand_0 == ot || operand_1 == ot || operand_2 == ot; } + static inline bool IsScalable() { + return (OperandTraits<operand_0>::TypeInfo::kIsScalable | + OperandTraits<operand_1>::TypeInfo::kIsScalable | + OperandTraits<operand_2>::TypeInfo::kIsScalable); + } + + static const AccumulatorUse kAccumulatorUse = accumulator_use; static const int kOperandCount = 3; static const int kRegisterOperandCount = RegisterOperandTraits<operand_0>::kIsRegisterOperand + @@ -137,40 +125,28 @@ struct BytecodeTraits<operand_0, operand_1, operand_2, OPERAND_TERM> { RegisterOperandTraits<operand_0>::kIsRegisterOperand + (RegisterOperandTraits<operand_1>::kIsRegisterOperand << 1) + (RegisterOperandTraits<operand_2>::kIsRegisterOperand << 2); - static const int kSize = - 1 + OperandTraits<operand_0>::kSize + OperandTraits<operand_1>::kSize + - OperandTraits<operand_2>::kSize; }; -template <OperandType operand_0, OperandType operand_1> -struct BytecodeTraits<operand_0, operand_1, OPERAND_TERM> { +template <AccumulatorUse accumulator_use, OperandType operand_0, + OperandType operand_1> +struct BytecodeTraits<accumulator_use, operand_0, operand_1> { static inline OperandType GetOperandType(int i) { DCHECK(0 <= i && i < kOperandCount); const OperandType kOperands[] = {operand_0, operand_1}; return kOperands[i]; } - static inline OperandSize GetOperandSize(int i) { - DCHECK(0 <= i && i < kOperandCount); - const OperandSize kOperandSizes[] = - {OperandTraits<operand_0>::kSizeType, - OperandTraits<operand_1>::kSizeType}; - return kOperandSizes[i]; - } - - static inline int GetOperandOffset(int i) { - DCHECK(0 <= i && i < kOperandCount); - const int kOffset0 = 1; - const int kOffset1 = kOffset0 + OperandTraits<operand_0>::kSize; - const int kOperandOffsets[] = {kOffset0, kOffset1}; - return kOperandOffsets[i]; - } - template <OperandType ot> static inline bool HasAnyOperandsOfType() { return operand_0 == ot || operand_1 == ot; } + static inline bool IsScalable() { + return (OperandTraits<operand_0>::TypeInfo::kIsScalable | + OperandTraits<operand_1>::TypeInfo::kIsScalable); + } + + static const AccumulatorUse kAccumulatorUse = accumulator_use; static const int kOperandCount = 2; static const int kRegisterOperandCount = RegisterOperandTraits<operand_0>::kIsRegisterOperand + @@ -178,68 +154,91 @@ struct BytecodeTraits<operand_0, operand_1, OPERAND_TERM> { static const int kRegisterOperandBitmap = RegisterOperandTraits<operand_0>::kIsRegisterOperand + (RegisterOperandTraits<operand_1>::kIsRegisterOperand << 1); - static const int kSize = - 1 + OperandTraits<operand_0>::kSize + OperandTraits<operand_1>::kSize; }; -template <OperandType operand_0> -struct BytecodeTraits<operand_0, OPERAND_TERM> { +template <AccumulatorUse accumulator_use, OperandType operand_0> +struct BytecodeTraits<accumulator_use, operand_0> { static inline OperandType GetOperandType(int i) { DCHECK(i == 0); return operand_0; } - static inline OperandSize GetOperandSize(int i) { - DCHECK(i == 0); - return OperandTraits<operand_0>::kSizeType; - } - - static inline int GetOperandOffset(int i) { - DCHECK(i == 0); - return 1; - } - template <OperandType ot> static inline bool HasAnyOperandsOfType() { return operand_0 == ot; } + static inline bool IsScalable() { + return OperandTraits<operand_0>::TypeInfo::kIsScalable; + } + + static const AccumulatorUse kAccumulatorUse = accumulator_use; static const int kOperandCount = 1; static const int kRegisterOperandCount = RegisterOperandTraits<operand_0>::kIsRegisterOperand; static const int kRegisterOperandBitmap = RegisterOperandTraits<operand_0>::kIsRegisterOperand; - static const int kSize = 1 + OperandTraits<operand_0>::kSize; }; -template <> -struct BytecodeTraits<OperandType::kNone, OPERAND_TERM> { +template <AccumulatorUse accumulator_use> +struct BytecodeTraits<accumulator_use> { static inline OperandType GetOperandType(int i) { UNREACHABLE(); return OperandType::kNone; } - static inline OperandSize GetOperandSize(int i) { - UNREACHABLE(); - return OperandSize::kNone; - } - - static inline int GetOperandOffset(int i) { - UNREACHABLE(); - return 1; - } - template <OperandType ot> static inline bool HasAnyOperandsOfType() { return false; } + static inline bool IsScalable() { return false; } + + static const AccumulatorUse kAccumulatorUse = accumulator_use; static const int kOperandCount = 0; static const int kRegisterOperandCount = 0; static const int kRegisterOperandBitmap = 0; - static const int kSize = 1 + OperandTraits<OperandType::kNone>::kSize; }; +template <bool> +struct OperandScaler { + static int Multiply(int size, int operand_scale) { return 0; } +}; + +template <> +struct OperandScaler<false> { + static int Multiply(int size, int operand_scale) { return size; } +}; + +template <> +struct OperandScaler<true> { + static int Multiply(int size, int operand_scale) { + return size * operand_scale; + } +}; + +static OperandSize ScaledOperandSize(OperandType operand_type, + OperandScale operand_scale) { + switch (operand_type) { +#define CASE(Name, TypeInfo) \ + case OperandType::k##Name: { \ + OperandSize base_size = OperandTypeInfoTraits<TypeInfo>::kUnscaledSize; \ + int size = \ + OperandScaler<OperandTypeInfoTraits<TypeInfo>::kIsScalable>::Multiply( \ + static_cast<int>(base_size), static_cast<int>(operand_scale)); \ + OperandSize operand_size = static_cast<OperandSize>(size); \ + DCHECK(operand_size == OperandSize::kByte || \ + operand_size == OperandSize::kShort || \ + operand_size == OperandSize::kQuad); \ + return operand_size; \ + } + OPERAND_TYPE_LIST(CASE) +#undef CASE + } + UNREACHABLE(); + return OperandSize::kNone; +} + } // namespace interpreter } // namespace internal } // namespace v8 diff --git a/deps/v8/src/interpreter/bytecodes.cc b/deps/v8/src/interpreter/bytecodes.cc index c3b17c7b10..fd27f391aa 100644 --- a/deps/v8/src/interpreter/bytecodes.cc +++ b/deps/v8/src/interpreter/bytecodes.cc @@ -4,8 +4,11 @@ #include "src/interpreter/bytecodes.h" +#include <iomanip> + #include "src/frames.h" #include "src/interpreter/bytecode-traits.h" +#include "src/interpreter/interpreter.h" namespace v8 { namespace internal { @@ -25,6 +28,35 @@ const char* Bytecodes::ToString(Bytecode bytecode) { return ""; } +// static +std::string Bytecodes::ToString(Bytecode bytecode, OperandScale operand_scale) { + static const char kSeparator = '.'; + + std::string value(ToString(bytecode)); + if (operand_scale > OperandScale::kSingle) { + Bytecode prefix_bytecode = OperandScaleToPrefixBytecode(operand_scale); + std::string suffix = ToString(prefix_bytecode); + return value.append(1, kSeparator).append(suffix); + } else { + return value; + } +} + +// static +const char* Bytecodes::AccumulatorUseToString(AccumulatorUse accumulator_use) { + switch (accumulator_use) { + case AccumulatorUse::kNone: + return "None"; + case AccumulatorUse::kRead: + return "Read"; + case AccumulatorUse::kWrite: + return "Write"; + case AccumulatorUse::kReadWrite: + return "ReadWrite"; + } + UNREACHABLE(); + return ""; +} // static const char* Bytecodes::OperandTypeToString(OperandType operand_type) { @@ -39,6 +71,20 @@ const char* Bytecodes::OperandTypeToString(OperandType operand_type) { return ""; } +// static +const char* Bytecodes::OperandScaleToString(OperandScale operand_scale) { + switch (operand_scale) { + case OperandScale::kSingle: + return "Single"; + case OperandScale::kDouble: + return "Double"; + case OperandScale::kQuadruple: + return "Quadruple"; + case OperandScale::kInvalid: + UNREACHABLE(); + } + return ""; +} // static const char* Bytecodes::OperandSizeToString(OperandSize operand_size) { @@ -49,6 +95,8 @@ const char* Bytecodes::OperandSizeToString(OperandSize operand_size) { return "Byte"; case OperandSize::kShort: return "Short"; + case OperandSize::kQuad: + return "Quad"; } UNREACHABLE(); return ""; @@ -72,31 +120,34 @@ Bytecode Bytecodes::FromByte(uint8_t value) { // static Bytecode Bytecodes::GetDebugBreak(Bytecode bytecode) { - switch (Size(bytecode)) { -#define CASE(Name, ...) \ - case BytecodeTraits<__VA_ARGS__, OPERAND_TERM>::kSize: \ - return Bytecode::k##Name; - DEBUG_BREAK_BYTECODE_LIST(CASE) -#undef CASE - default: - break; + DCHECK(!IsDebugBreak(bytecode)); + if (bytecode == Bytecode::kWide) { + return Bytecode::kDebugBreakWide; + } + if (bytecode == Bytecode::kExtraWide) { + return Bytecode::kDebugBreakExtraWide; } + int bytecode_size = Size(bytecode, OperandScale::kSingle); +#define RETURN_IF_DEBUG_BREAK_SIZE_MATCHES(Name, ...) \ + if (bytecode_size == Size(Bytecode::k##Name, OperandScale::kSingle)) { \ + return Bytecode::k##Name; \ + } + DEBUG_BREAK_PLAIN_BYTECODE_LIST(RETURN_IF_DEBUG_BREAK_SIZE_MATCHES) +#undef RETURN_IF_DEBUG_BREAK_SIZE_MATCHES UNREACHABLE(); - return static_cast<Bytecode>(-1); + return Bytecode::kIllegal; } // static -int Bytecodes::Size(Bytecode bytecode) { - DCHECK(bytecode <= Bytecode::kLast); - switch (bytecode) { -#define CASE(Name, ...) \ - case Bytecode::k##Name: \ - return BytecodeTraits<__VA_ARGS__, OPERAND_TERM>::kSize; - BYTECODE_LIST(CASE) -#undef CASE +int Bytecodes::Size(Bytecode bytecode, OperandScale operand_scale) { + int size = 1; + for (int i = 0; i < NumberOfOperands(bytecode); i++) { + OperandSize operand_size = GetOperandSize(bytecode, i, operand_scale); + int delta = static_cast<int>(operand_size); + DCHECK(base::bits::IsPowerOfTwo32(static_cast<uint32_t>(delta))); + size += delta; } - UNREACHABLE(); - return 0; + return size; } @@ -106,7 +157,7 @@ int Bytecodes::NumberOfOperands(Bytecode bytecode) { switch (bytecode) { #define CASE(Name, ...) \ case Bytecode::k##Name: \ - return BytecodeTraits<__VA_ARGS__, OPERAND_TERM>::kOperandCount; + return BytecodeTraits<__VA_ARGS__>::kOperandCount; BYTECODE_LIST(CASE) #undef CASE } @@ -119,9 +170,9 @@ int Bytecodes::NumberOfOperands(Bytecode bytecode) { int Bytecodes::NumberOfRegisterOperands(Bytecode bytecode) { DCHECK(bytecode <= Bytecode::kLast); switch (bytecode) { -#define CASE(Name, ...) \ - case Bytecode::k##Name: \ - typedef BytecodeTraits<__VA_ARGS__, OPERAND_TERM> Name##Trait; \ +#define CASE(Name, ...) \ + case Bytecode::k##Name: \ + typedef BytecodeTraits<__VA_ARGS__> Name##Trait; \ return Name##Trait::kRegisterOperandCount; BYTECODE_LIST(CASE) #undef CASE @@ -131,42 +182,92 @@ int Bytecodes::NumberOfRegisterOperands(Bytecode bytecode) { } // static -OperandType Bytecodes::GetOperandType(Bytecode bytecode, int i) { +Bytecode Bytecodes::OperandScaleToPrefixBytecode(OperandScale operand_scale) { + switch (operand_scale) { + case OperandScale::kQuadruple: + return Bytecode::kExtraWide; + case OperandScale::kDouble: + return Bytecode::kWide; + default: + UNREACHABLE(); + return Bytecode::kIllegal; + } +} + +// static +bool Bytecodes::OperandScaleRequiresPrefixBytecode(OperandScale operand_scale) { + return operand_scale != OperandScale::kSingle; +} + +// static +OperandScale Bytecodes::PrefixBytecodeToOperandScale(Bytecode bytecode) { + switch (bytecode) { + case Bytecode::kExtraWide: + case Bytecode::kDebugBreakExtraWide: + return OperandScale::kQuadruple; + case Bytecode::kWide: + case Bytecode::kDebugBreakWide: + return OperandScale::kDouble; + default: + UNREACHABLE(); + return OperandScale::kSingle; + } +} + +// static +AccumulatorUse Bytecodes::GetAccumulatorUse(Bytecode bytecode) { DCHECK(bytecode <= Bytecode::kLast); switch (bytecode) { #define CASE(Name, ...) \ case Bytecode::k##Name: \ - return BytecodeTraits<__VA_ARGS__, OPERAND_TERM>::GetOperandType(i); + return BytecodeTraits<__VA_ARGS__>::kAccumulatorUse; BYTECODE_LIST(CASE) #undef CASE } UNREACHABLE(); - return OperandType::kNone; + return AccumulatorUse::kNone; } +// static +bool Bytecodes::ReadsAccumulator(Bytecode bytecode) { + return (GetAccumulatorUse(bytecode) & AccumulatorUse::kRead) == + AccumulatorUse::kRead; +} // static -OperandSize Bytecodes::GetOperandSize(Bytecode bytecode, int i) { +bool Bytecodes::WritesAccumulator(Bytecode bytecode) { + return (GetAccumulatorUse(bytecode) & AccumulatorUse::kWrite) == + AccumulatorUse::kWrite; +} + +// static +OperandType Bytecodes::GetOperandType(Bytecode bytecode, int i) { DCHECK(bytecode <= Bytecode::kLast); switch (bytecode) { #define CASE(Name, ...) \ case Bytecode::k##Name: \ - return BytecodeTraits<__VA_ARGS__, OPERAND_TERM>::GetOperandSize(i); + return BytecodeTraits<__VA_ARGS__>::GetOperandType(i); BYTECODE_LIST(CASE) #undef CASE } UNREACHABLE(); - return OperandSize::kNone; + return OperandType::kNone; } +// static +OperandSize Bytecodes::GetOperandSize(Bytecode bytecode, int i, + OperandScale operand_scale) { + OperandType op_type = GetOperandType(bytecode, i); + return ScaledOperandSize(op_type, operand_scale); +} // static int Bytecodes::GetRegisterOperandBitmap(Bytecode bytecode) { DCHECK(bytecode <= Bytecode::kLast); switch (bytecode) { -#define CASE(Name, ...) \ - case Bytecode::k##Name: \ - typedef BytecodeTraits<__VA_ARGS__, OPERAND_TERM> Name##Trait; \ +#define CASE(Name, ...) \ + case Bytecode::k##Name: \ + typedef BytecodeTraits<__VA_ARGS__> Name##Trait; \ return Name##Trait::kRegisterOperandBitmap; BYTECODE_LIST(CASE) #undef CASE @@ -176,34 +277,25 @@ int Bytecodes::GetRegisterOperandBitmap(Bytecode bytecode) { } // static -int Bytecodes::GetOperandOffset(Bytecode bytecode, int i) { - DCHECK(bytecode <= Bytecode::kLast); - switch (bytecode) { -#define CASE(Name, ...) \ - case Bytecode::k##Name: \ - return BytecodeTraits<__VA_ARGS__, OPERAND_TERM>::GetOperandOffset(i); - BYTECODE_LIST(CASE) -#undef CASE +int Bytecodes::GetOperandOffset(Bytecode bytecode, int i, + OperandScale operand_scale) { + // TODO(oth): restore this to a statically determined constant. + int offset = 1; + for (int operand_index = 0; operand_index < i; ++operand_index) { + OperandSize operand_size = + GetOperandSize(bytecode, operand_index, operand_scale); + offset += static_cast<int>(operand_size); } - UNREACHABLE(); - return 0; + return offset; } - // static -OperandSize Bytecodes::SizeOfOperand(OperandType operand_type) { - switch (operand_type) { -#define CASE(Name, Size) \ - case OperandType::k##Name: \ - return Size; - OPERAND_TYPE_LIST(CASE) -#undef CASE - } - UNREACHABLE(); - return OperandSize::kNone; +OperandSize Bytecodes::SizeOfOperand(OperandType operand_type, + OperandScale operand_scale) { + return static_cast<OperandSize>( + ScaledOperandSize(operand_type, operand_scale)); } - // static bool Bytecodes::IsConditionalJumpImmediate(Bytecode bytecode) { return bytecode == Bytecode::kJumpIfTrue || @@ -227,24 +319,10 @@ bool Bytecodes::IsConditionalJumpConstant(Bytecode bytecode) { bytecode == Bytecode::kJumpIfUndefinedConstant; } - -// static -bool Bytecodes::IsConditionalJumpConstantWide(Bytecode bytecode) { - return bytecode == Bytecode::kJumpIfTrueConstantWide || - bytecode == Bytecode::kJumpIfFalseConstantWide || - bytecode == Bytecode::kJumpIfToBooleanTrueConstantWide || - bytecode == Bytecode::kJumpIfToBooleanFalseConstantWide || - bytecode == Bytecode::kJumpIfNotHoleConstantWide || - bytecode == Bytecode::kJumpIfNullConstantWide || - bytecode == Bytecode::kJumpIfUndefinedConstantWide; -} - - // static bool Bytecodes::IsConditionalJump(Bytecode bytecode) { return IsConditionalJumpImmediate(bytecode) || - IsConditionalJumpConstant(bytecode) || - IsConditionalJumpConstantWide(bytecode); + IsConditionalJumpConstant(bytecode); } @@ -260,26 +338,23 @@ bool Bytecodes::IsJumpConstant(Bytecode bytecode) { IsConditionalJumpConstant(bytecode); } - -// static -bool Bytecodes::IsJumpConstantWide(Bytecode bytecode) { - return bytecode == Bytecode::kJumpConstantWide || - IsConditionalJumpConstantWide(bytecode); -} - - // static bool Bytecodes::IsJump(Bytecode bytecode) { - return IsJumpImmediate(bytecode) || IsJumpConstant(bytecode) || - IsJumpConstantWide(bytecode); + return IsJumpImmediate(bytecode) || IsJumpConstant(bytecode); } // static bool Bytecodes::IsCallOrNew(Bytecode bytecode) { return bytecode == Bytecode::kCall || bytecode == Bytecode::kTailCall || - bytecode == Bytecode::kNew || bytecode == Bytecode::kCallWide || - bytecode == Bytecode::kTailCallWide || bytecode == Bytecode::kNewWide; + bytecode == Bytecode::kNew; +} + +// static +bool Bytecodes::IsCallRuntime(Bytecode bytecode) { + return bytecode == Bytecode::kCallRuntime || + bytecode == Bytecode::kCallRuntimeForPair || + bytecode == Bytecode::kInvokeIntrinsic; } // static @@ -296,31 +371,40 @@ bool Bytecodes::IsDebugBreak(Bytecode bytecode) { } // static -bool Bytecodes::IsJumpOrReturn(Bytecode bytecode) { - return bytecode == Bytecode::kReturn || IsJump(bytecode); -} - -// static -bool Bytecodes::IsIndexOperandType(OperandType operand_type) { - return operand_type == OperandType::kIdx8 || - operand_type == OperandType::kIdx16; +bool Bytecodes::IsBytecodeWithScalableOperands(Bytecode bytecode) { + switch (bytecode) { +#define CASE(Name, ...) \ + case Bytecode::k##Name: \ + typedef BytecodeTraits<__VA_ARGS__> Name##Trait; \ + return Name##Trait::IsScalable(); + BYTECODE_LIST(CASE) +#undef CASE + } + UNREACHABLE(); + return false; } // static -bool Bytecodes::IsImmediateOperandType(OperandType operand_type) { - return operand_type == OperandType::kImm8; +bool Bytecodes::IsPrefixScalingBytecode(Bytecode bytecode) { + switch (bytecode) { + case Bytecode::kExtraWide: + case Bytecode::kDebugBreakExtraWide: + case Bytecode::kWide: + case Bytecode::kDebugBreakWide: + return true; + default: + return false; + } } // static -bool Bytecodes::IsRegisterCountOperandType(OperandType operand_type) { - return (operand_type == OperandType::kRegCount8 || - operand_type == OperandType::kRegCount16); +bool Bytecodes::IsJumpOrReturn(Bytecode bytecode) { + return bytecode == Bytecode::kReturn || IsJump(bytecode); } // static bool Bytecodes::IsMaybeRegisterOperandType(OperandType operand_type) { - return (operand_type == OperandType::kMaybeReg8 || - operand_type == OperandType::kMaybeReg16); + return operand_type == OperandType::kMaybeReg; } // static @@ -376,41 +460,102 @@ bool Bytecodes::IsRegisterOutputOperandType(OperandType operand_type) { return false; } -namespace { -static Register DecodeRegister(const uint8_t* operand_start, - OperandType operand_type) { - switch (Bytecodes::SizeOfOperand(operand_type)) { +// static +bool Bytecodes::IsUnsignedOperandType(OperandType operand_type) { + switch (operand_type) { +#define CASE(Name, _) \ + case OperandType::k##Name: \ + return OperandTraits<OperandType::k##Name>::TypeInfo::kIsUnsigned; + OPERAND_TYPE_LIST(CASE) +#undef CASE + } + UNREACHABLE(); + return false; +} + +// static +OperandScale Bytecodes::NextOperandScale(OperandScale operand_scale) { + DCHECK(operand_scale >= OperandScale::kSingle && + operand_scale <= OperandScale::kMaxValid); + return static_cast<OperandScale>(2 * static_cast<int>(operand_scale)); +} + +// static +Register Bytecodes::DecodeRegisterOperand(const uint8_t* operand_start, + OperandType operand_type, + OperandScale operand_scale) { + DCHECK(Bytecodes::IsRegisterOperandType(operand_type)); + int32_t operand = + DecodeSignedOperand(operand_start, operand_type, operand_scale); + return Register::FromOperand(operand); +} + +// static +int32_t Bytecodes::DecodeSignedOperand(const uint8_t* operand_start, + OperandType operand_type, + OperandScale operand_scale) { + DCHECK(!Bytecodes::IsUnsignedOperandType(operand_type)); + switch (Bytecodes::SizeOfOperand(operand_type, operand_scale)) { case OperandSize::kByte: - return Register::FromOperand(*operand_start); + return static_cast<int8_t>(*operand_start); case OperandSize::kShort: - return Register::FromWideOperand(ReadUnalignedUInt16(operand_start)); - case OperandSize::kNone: { + return static_cast<int16_t>(ReadUnalignedUInt16(operand_start)); + case OperandSize::kQuad: + return static_cast<int32_t>(ReadUnalignedUInt32(operand_start)); + case OperandSize::kNone: UNREACHABLE(); - } } - return Register(); + return 0; } -} // namespace +// static +uint32_t Bytecodes::DecodeUnsignedOperand(const uint8_t* operand_start, + OperandType operand_type, + OperandScale operand_scale) { + DCHECK(Bytecodes::IsUnsignedOperandType(operand_type)); + switch (Bytecodes::SizeOfOperand(operand_type, operand_scale)) { + case OperandSize::kByte: + return *operand_start; + case OperandSize::kShort: + return ReadUnalignedUInt16(operand_start); + case OperandSize::kQuad: + return ReadUnalignedUInt32(operand_start); + case OperandSize::kNone: + UNREACHABLE(); + } + return 0; +} // static std::ostream& Bytecodes::Decode(std::ostream& os, const uint8_t* bytecode_start, int parameter_count) { - Vector<char> buf = Vector<char>::New(50); - Bytecode bytecode = Bytecodes::FromByte(bytecode_start[0]); - int bytecode_size = Bytecodes::Size(bytecode); + int prefix_offset = 0; + OperandScale operand_scale = OperandScale::kSingle; + if (IsPrefixScalingBytecode(bytecode)) { + prefix_offset = 1; + operand_scale = Bytecodes::PrefixBytecodeToOperandScale(bytecode); + bytecode = Bytecodes::FromByte(bytecode_start[1]); + } + + // Prepare to print bytecode and operands as hex digits. + std::ios saved_format(nullptr); + saved_format.copyfmt(saved_format); + os.fill('0'); + os.flags(std::ios::hex); - for (int i = 0; i < bytecode_size; i++) { - SNPrintF(buf, "%02x ", bytecode_start[i]); - os << buf.start(); + int bytecode_size = Bytecodes::Size(bytecode, operand_scale); + for (int i = 0; i < prefix_offset + bytecode_size; i++) { + os << std::setw(2) << static_cast<uint32_t>(bytecode_start[i]) << ' '; } + os.copyfmt(saved_format); + const int kBytecodeColumnSize = 6; - for (int i = bytecode_size; i < kBytecodeColumnSize; i++) { + for (int i = prefix_offset + bytecode_size; i < kBytecodeColumnSize; i++) { os << " "; } - os << bytecode << " "; + os << Bytecodes::ToString(bytecode, operand_scale) << " "; // Operands for the debug break are from the original instruction. if (IsDebugBreak(bytecode)) return os; @@ -420,42 +565,42 @@ std::ostream& Bytecodes::Decode(std::ostream& os, const uint8_t* bytecode_start, for (int i = 0; i < number_of_operands; i++) { OperandType op_type = GetOperandType(bytecode, i); const uint8_t* operand_start = - &bytecode_start[GetOperandOffset(bytecode, i)]; + &bytecode_start[prefix_offset + + GetOperandOffset(bytecode, i, operand_scale)]; switch (op_type) { - case interpreter::OperandType::kRegCount8: - os << "#" << static_cast<unsigned int>(*operand_start); - break; - case interpreter::OperandType::kRegCount16: - os << '#' << ReadUnalignedUInt16(operand_start); + case interpreter::OperandType::kRegCount: + os << "#" + << DecodeUnsignedOperand(operand_start, op_type, operand_scale); break; - case interpreter::OperandType::kIdx8: - os << "[" << static_cast<unsigned int>(*operand_start) << "]"; + case interpreter::OperandType::kIdx: + case interpreter::OperandType::kRuntimeId: + os << "[" + << DecodeUnsignedOperand(operand_start, op_type, operand_scale) + << "]"; break; - case interpreter::OperandType::kIdx16: - os << "[" << ReadUnalignedUInt16(operand_start) << "]"; + case interpreter::OperandType::kImm: + os << "[" << DecodeSignedOperand(operand_start, op_type, operand_scale) + << "]"; break; - case interpreter::OperandType::kImm8: - os << "#" << static_cast<int>(static_cast<int8_t>(*operand_start)); + case interpreter::OperandType::kFlag8: + os << "#" + << DecodeUnsignedOperand(operand_start, op_type, operand_scale); break; - case interpreter::OperandType::kMaybeReg8: - case interpreter::OperandType::kMaybeReg16: - case interpreter::OperandType::kReg8: - case interpreter::OperandType::kReg16: - case interpreter::OperandType::kRegOut8: - case interpreter::OperandType::kRegOut16: { - Register reg = DecodeRegister(operand_start, op_type); + case interpreter::OperandType::kMaybeReg: + case interpreter::OperandType::kReg: + case interpreter::OperandType::kRegOut: { + Register reg = + DecodeRegisterOperand(operand_start, op_type, operand_scale); os << reg.ToString(parameter_count); break; } - case interpreter::OperandType::kRegOutTriple8: - case interpreter::OperandType::kRegOutTriple16: + case interpreter::OperandType::kRegOutTriple: range += 1; - case interpreter::OperandType::kRegOutPair8: - case interpreter::OperandType::kRegOutPair16: - case interpreter::OperandType::kRegPair8: - case interpreter::OperandType::kRegPair16: { + case interpreter::OperandType::kRegOutPair: + case interpreter::OperandType::kRegPair: { range += 1; - Register first_reg = DecodeRegister(operand_start, op_type); + Register first_reg = + DecodeRegisterOperand(operand_start, op_type, operand_scale); Register last_reg = Register(first_reg.index() + range); os << first_reg.ToString(parameter_count) << "-" << last_reg.ToString(parameter_count); @@ -472,20 +617,33 @@ std::ostream& Bytecodes::Decode(std::ostream& os, const uint8_t* bytecode_start, return os; } +// static +bool Bytecodes::BytecodeHasHandler(Bytecode bytecode, + OperandScale operand_scale) { + return operand_scale == OperandScale::kSingle || + Bytecodes::IsBytecodeWithScalableOperands(bytecode); +} + std::ostream& operator<<(std::ostream& os, const Bytecode& bytecode) { return os << Bytecodes::ToString(bytecode); } - -std::ostream& operator<<(std::ostream& os, const OperandType& operand_type) { - return os << Bytecodes::OperandTypeToString(operand_type); +std::ostream& operator<<(std::ostream& os, const AccumulatorUse& use) { + return os << Bytecodes::AccumulatorUseToString(use); } - std::ostream& operator<<(std::ostream& os, const OperandSize& operand_size) { return os << Bytecodes::OperandSizeToString(operand_size); } +std::ostream& operator<<(std::ostream& os, const OperandScale& operand_scale) { + return os << Bytecodes::OperandScaleToString(operand_scale); +} + +std::ostream& operator<<(std::ostream& os, const OperandType& operand_type) { + return os << Bytecodes::OperandTypeToString(operand_type); +} + static const int kLastParamRegisterIndex = -InterpreterFrameConstants::kLastParamFromRegisterPointer / kPointerSize; static const int kFunctionClosureRegisterIndex = @@ -495,29 +653,17 @@ static const int kCurrentContextRegisterIndex = static const int kNewTargetRegisterIndex = -InterpreterFrameConstants::kNewTargetFromRegisterPointer / kPointerSize; -// The register space is a signed 16-bit space. Register operands -// occupy range above 0. Parameter indices are biased with the -// negative value kLastParamRegisterIndex for ease of access in the -// interpreter. -static const int kMaxParameterIndex = kMaxInt16 + kLastParamRegisterIndex; -static const int kMaxRegisterIndex = -kMinInt16; -static const int kMaxReg8Index = -kMinInt8; -static const int kMinReg8Index = -kMaxInt8; -static const int kMaxReg16Index = -kMinInt16; -static const int kMinReg16Index = -kMaxInt16; - bool Register::is_byte_operand() const { - return index_ >= kMinReg8Index && index_ <= kMaxReg8Index; + return index_ >= -kMaxInt8 && index_ <= -kMinInt8; } bool Register::is_short_operand() const { - return index_ >= kMinReg16Index && index_ <= kMaxReg16Index; + return index_ >= -kMaxInt16 && index_ <= -kMinInt16; } Register Register::FromParameterIndex(int index, int parameter_count) { DCHECK_GE(index, 0); DCHECK_LT(index, parameter_count); - DCHECK_LE(parameter_count, kMaxParameterIndex + 1); int register_index = kLastParamRegisterIndex - parameter_count + index + 1; DCHECK_LT(register_index, 0); return Register(register_index); @@ -557,44 +703,6 @@ bool Register::is_new_target() const { return index() == kNewTargetRegisterIndex; } -int Register::MaxParameterIndex() { return kMaxParameterIndex; } - -int Register::MaxRegisterIndex() { return kMaxRegisterIndex; } - -int Register::MaxRegisterIndexForByteOperand() { return kMaxReg8Index; } - -uint8_t Register::ToOperand() const { - DCHECK(is_byte_operand()); - return static_cast<uint8_t>(-index_); -} - - -Register Register::FromOperand(uint8_t operand) { - return Register(-static_cast<int8_t>(operand)); -} - - -uint16_t Register::ToWideOperand() const { - DCHECK(is_short_operand()); - return static_cast<uint16_t>(-index_); -} - - -Register Register::FromWideOperand(uint16_t operand) { - return Register(-static_cast<int16_t>(operand)); -} - - -uint32_t Register::ToRawOperand() const { - return static_cast<uint32_t>(-index_); -} - - -Register Register::FromRawOperand(uint32_t operand) { - return Register(-static_cast<int32_t>(operand)); -} - - bool Register::AreContiguous(Register reg1, Register reg2, Register reg3, Register reg4, Register reg5) { if (reg1.index() + 1 != reg2.index()) { diff --git a/deps/v8/src/interpreter/bytecodes.h b/deps/v8/src/interpreter/bytecodes.h index d4863b1662..23612713aa 100644 --- a/deps/v8/src/interpreter/bytecodes.h +++ b/deps/v8/src/interpreter/bytecodes.h @@ -15,37 +15,24 @@ namespace v8 { namespace internal { namespace interpreter { -#define INVALID_OPERAND_TYPE_LIST(V) \ - V(None, OperandSize::kNone) - -#define REGISTER_INPUT_OPERAND_TYPE_LIST(V) \ - /* Byte operands. */ \ - V(MaybeReg8, OperandSize::kByte) \ - V(Reg8, OperandSize::kByte) \ - V(RegPair8, OperandSize::kByte) \ - /* Short operands. */ \ - V(MaybeReg16, OperandSize::kShort) \ - V(Reg16, OperandSize::kShort) \ - V(RegPair16, OperandSize::kShort) - -#define REGISTER_OUTPUT_OPERAND_TYPE_LIST(V) \ - /* Byte operands. */ \ - V(RegOut8, OperandSize::kByte) \ - V(RegOutPair8, OperandSize::kByte) \ - V(RegOutTriple8, OperandSize::kByte) \ - /* Short operands. */ \ - V(RegOut16, OperandSize::kShort) \ - V(RegOutPair16, OperandSize::kShort) \ - V(RegOutTriple16, OperandSize::kShort) - -#define SCALAR_OPERAND_TYPE_LIST(V) \ - /* Byte operands. */ \ - V(Idx8, OperandSize::kByte) \ - V(Imm8, OperandSize::kByte) \ - V(RegCount8, OperandSize::kByte) \ - /* Short operands. */ \ - V(Idx16, OperandSize::kShort) \ - V(RegCount16, OperandSize::kShort) +#define INVALID_OPERAND_TYPE_LIST(V) V(None, OperandTypeInfo::kNone) + +#define REGISTER_INPUT_OPERAND_TYPE_LIST(V) \ + V(MaybeReg, OperandTypeInfo::kScalableSignedByte) \ + V(Reg, OperandTypeInfo::kScalableSignedByte) \ + V(RegPair, OperandTypeInfo::kScalableSignedByte) + +#define REGISTER_OUTPUT_OPERAND_TYPE_LIST(V) \ + V(RegOut, OperandTypeInfo::kScalableSignedByte) \ + V(RegOutPair, OperandTypeInfo::kScalableSignedByte) \ + V(RegOutTriple, OperandTypeInfo::kScalableSignedByte) + +#define SCALAR_OPERAND_TYPE_LIST(V) \ + V(Flag8, OperandTypeInfo::kFixedUnsignedByte) \ + V(Idx, OperandTypeInfo::kScalableUnsignedByte) \ + V(Imm, OperandTypeInfo::kScalableSignedByte) \ + V(RegCount, OperandTypeInfo::kScalableUnsignedByte) \ + V(RuntimeId, OperandTypeInfo::kFixedUnsignedShort) #define REGISTER_OPERAND_TYPE_LIST(V) \ REGISTER_INPUT_OPERAND_TYPE_LIST(V) \ @@ -60,235 +47,258 @@ namespace interpreter { NON_REGISTER_OPERAND_TYPE_LIST(V) \ REGISTER_OPERAND_TYPE_LIST(V) -// Define one debug break bytecode for each operands size. -#define DEBUG_BREAK_BYTECODE_LIST(V) \ - V(DebugBreak0, OperandType::kNone) \ - V(DebugBreak1, OperandType::kReg8) \ - V(DebugBreak2, OperandType::kReg16) \ - V(DebugBreak3, OperandType::kReg16, OperandType::kReg8) \ - V(DebugBreak4, OperandType::kReg16, OperandType::kReg16) \ - V(DebugBreak5, OperandType::kReg16, OperandType::kReg16, OperandType::kReg8) \ - V(DebugBreak6, OperandType::kReg16, OperandType::kReg16, \ - OperandType::kReg16) \ - V(DebugBreak7, OperandType::kReg16, OperandType::kReg16, \ - OperandType::kReg16, OperandType::kReg8) \ - V(DebugBreak8, OperandType::kReg16, OperandType::kReg16, \ - OperandType::kReg16, OperandType::kReg16) +// Define one debug break bytecode for each possible size of unscaled +// bytecodes. Format is V(<bytecode>, <accumulator_use>, <operands>). +#define DEBUG_BREAK_PLAIN_BYTECODE_LIST(V) \ + V(DebugBreak0, AccumulatorUse::kRead) \ + V(DebugBreak1, AccumulatorUse::kRead, OperandType::kReg) \ + V(DebugBreak2, AccumulatorUse::kRead, OperandType::kReg, OperandType::kReg) \ + V(DebugBreak3, AccumulatorUse::kRead, OperandType::kReg, OperandType::kReg, \ + OperandType::kReg) \ + V(DebugBreak4, AccumulatorUse::kRead, OperandType::kReg, OperandType::kReg, \ + OperandType::kReg, OperandType::kReg) \ + V(DebugBreak5, AccumulatorUse::kRead, OperandType::kRuntimeId, \ + OperandType::kReg, OperandType::kReg) \ + V(DebugBreak6, AccumulatorUse::kRead, OperandType::kRuntimeId, \ + OperandType::kReg, OperandType::kReg, OperandType::kReg) + +// Define one debug break for each widening prefix. +#define DEBUG_BREAK_PREFIX_BYTECODE_LIST(V) \ + V(DebugBreakWide, AccumulatorUse::kRead) \ + V(DebugBreakExtraWide, AccumulatorUse::kRead) + +#define DEBUG_BREAK_BYTECODE_LIST(V) \ + DEBUG_BREAK_PLAIN_BYTECODE_LIST(V) \ + DEBUG_BREAK_PREFIX_BYTECODE_LIST(V) // The list of bytecodes which are interpreted by the interpreter. -#define BYTECODE_LIST(V) \ - \ - /* Loading the accumulator */ \ - V(LdaZero, OperandType::kNone) \ - V(LdaSmi8, OperandType::kImm8) \ - V(LdaUndefined, OperandType::kNone) \ - V(LdaNull, OperandType::kNone) \ - V(LdaTheHole, OperandType::kNone) \ - V(LdaTrue, OperandType::kNone) \ - V(LdaFalse, OperandType::kNone) \ - V(LdaConstant, OperandType::kIdx8) \ - V(LdaConstantWide, OperandType::kIdx16) \ - \ - /* Globals */ \ - V(LdaGlobal, OperandType::kIdx8, OperandType::kIdx8) \ - V(LdaGlobalInsideTypeof, OperandType::kIdx8, OperandType::kIdx8) \ - V(LdaGlobalWide, OperandType::kIdx16, OperandType::kIdx16) \ - V(LdaGlobalInsideTypeofWide, OperandType::kIdx16, OperandType::kIdx16) \ - V(StaGlobalSloppy, OperandType::kIdx8, OperandType::kIdx8) \ - V(StaGlobalStrict, OperandType::kIdx8, OperandType::kIdx8) \ - V(StaGlobalSloppyWide, OperandType::kIdx16, OperandType::kIdx16) \ - V(StaGlobalStrictWide, OperandType::kIdx16, OperandType::kIdx16) \ - \ - /* Context operations */ \ - V(PushContext, OperandType::kReg8) \ - V(PopContext, OperandType::kReg8) \ - V(LdaContextSlot, OperandType::kReg8, OperandType::kIdx8) \ - V(StaContextSlot, OperandType::kReg8, OperandType::kIdx8) \ - V(LdaContextSlotWide, OperandType::kReg8, OperandType::kIdx16) \ - V(StaContextSlotWide, OperandType::kReg8, OperandType::kIdx16) \ - \ - /* Load-Store lookup slots */ \ - V(LdaLookupSlot, OperandType::kIdx8) \ - V(LdaLookupSlotInsideTypeof, OperandType::kIdx8) \ - V(LdaLookupSlotWide, OperandType::kIdx16) \ - V(LdaLookupSlotInsideTypeofWide, OperandType::kIdx16) \ - V(StaLookupSlotSloppy, OperandType::kIdx8) \ - V(StaLookupSlotStrict, OperandType::kIdx8) \ - V(StaLookupSlotSloppyWide, OperandType::kIdx16) \ - V(StaLookupSlotStrictWide, OperandType::kIdx16) \ - \ - /* Register-accumulator transfers */ \ - V(Ldar, OperandType::kReg8) \ - V(Star, OperandType::kRegOut8) \ - \ - /* Register-register transfers */ \ - V(Mov, OperandType::kReg8, OperandType::kRegOut8) \ - V(MovWide, OperandType::kReg16, OperandType::kRegOut16) \ - \ - /* LoadIC operations */ \ - V(LoadIC, OperandType::kReg8, OperandType::kIdx8, OperandType::kIdx8) \ - V(KeyedLoadIC, OperandType::kReg8, OperandType::kIdx8) \ - V(LoadICWide, OperandType::kReg8, OperandType::kIdx16, OperandType::kIdx16) \ - V(KeyedLoadICWide, OperandType::kReg8, OperandType::kIdx16) \ - \ - /* StoreIC operations */ \ - V(StoreICSloppy, OperandType::kReg8, OperandType::kIdx8, OperandType::kIdx8) \ - V(StoreICStrict, OperandType::kReg8, OperandType::kIdx8, OperandType::kIdx8) \ - V(KeyedStoreICSloppy, OperandType::kReg8, OperandType::kReg8, \ - OperandType::kIdx8) \ - V(KeyedStoreICStrict, OperandType::kReg8, OperandType::kReg8, \ - OperandType::kIdx8) \ - V(StoreICSloppyWide, OperandType::kReg8, OperandType::kIdx16, \ - OperandType::kIdx16) \ - V(StoreICStrictWide, OperandType::kReg8, OperandType::kIdx16, \ - OperandType::kIdx16) \ - V(KeyedStoreICSloppyWide, OperandType::kReg8, OperandType::kReg8, \ - OperandType::kIdx16) \ - V(KeyedStoreICStrictWide, OperandType::kReg8, OperandType::kReg8, \ - OperandType::kIdx16) \ - \ - /* Binary Operators */ \ - V(Add, OperandType::kReg8) \ - V(Sub, OperandType::kReg8) \ - V(Mul, OperandType::kReg8) \ - V(Div, OperandType::kReg8) \ - V(Mod, OperandType::kReg8) \ - V(BitwiseOr, OperandType::kReg8) \ - V(BitwiseXor, OperandType::kReg8) \ - V(BitwiseAnd, OperandType::kReg8) \ - V(ShiftLeft, OperandType::kReg8) \ - V(ShiftRight, OperandType::kReg8) \ - V(ShiftRightLogical, OperandType::kReg8) \ - \ - /* Unary Operators */ \ - V(Inc, OperandType::kNone) \ - V(Dec, OperandType::kNone) \ - V(LogicalNot, OperandType::kNone) \ - V(TypeOf, OperandType::kNone) \ - V(DeletePropertyStrict, OperandType::kReg8) \ - V(DeletePropertySloppy, OperandType::kReg8) \ - \ - /* Call operations */ \ - V(Call, OperandType::kReg8, OperandType::kReg8, OperandType::kRegCount8, \ - OperandType::kIdx8) \ - V(CallWide, OperandType::kReg16, OperandType::kReg16, \ - OperandType::kRegCount16, OperandType::kIdx16) \ - V(TailCall, OperandType::kReg8, OperandType::kReg8, OperandType::kRegCount8, \ - OperandType::kIdx8) \ - V(TailCallWide, OperandType::kReg16, OperandType::kReg16, \ - OperandType::kRegCount16, OperandType::kIdx16) \ - V(CallRuntime, OperandType::kIdx16, OperandType::kMaybeReg8, \ - OperandType::kRegCount8) \ - V(CallRuntimeWide, OperandType::kIdx16, OperandType::kMaybeReg16, \ - OperandType::kRegCount8) \ - V(CallRuntimeForPair, OperandType::kIdx16, OperandType::kMaybeReg8, \ - OperandType::kRegCount8, OperandType::kRegOutPair8) \ - V(CallRuntimeForPairWide, OperandType::kIdx16, OperandType::kMaybeReg16, \ - OperandType::kRegCount8, OperandType::kRegOutPair16) \ - V(CallJSRuntime, OperandType::kIdx16, OperandType::kReg8, \ - OperandType::kRegCount8) \ - V(CallJSRuntimeWide, OperandType::kIdx16, OperandType::kReg16, \ - OperandType::kRegCount16) \ - \ - /* New operator */ \ - V(New, OperandType::kReg8, OperandType::kMaybeReg8, OperandType::kRegCount8) \ - V(NewWide, OperandType::kReg16, OperandType::kMaybeReg16, \ - OperandType::kRegCount16) \ - \ - /* Test Operators */ \ - V(TestEqual, OperandType::kReg8) \ - V(TestNotEqual, OperandType::kReg8) \ - V(TestEqualStrict, OperandType::kReg8) \ - V(TestNotEqualStrict, OperandType::kReg8) \ - V(TestLessThan, OperandType::kReg8) \ - V(TestGreaterThan, OperandType::kReg8) \ - V(TestLessThanOrEqual, OperandType::kReg8) \ - V(TestGreaterThanOrEqual, OperandType::kReg8) \ - V(TestInstanceOf, OperandType::kReg8) \ - V(TestIn, OperandType::kReg8) \ - \ - /* Cast operators */ \ - V(ToName, OperandType::kNone) \ - V(ToNumber, OperandType::kNone) \ - V(ToObject, OperandType::kNone) \ - \ - /* Literals */ \ - V(CreateRegExpLiteral, OperandType::kIdx8, OperandType::kIdx8, \ - OperandType::kImm8) \ - V(CreateArrayLiteral, OperandType::kIdx8, OperandType::kIdx8, \ - OperandType::kImm8) \ - V(CreateObjectLiteral, OperandType::kIdx8, OperandType::kIdx8, \ - OperandType::kImm8) \ - V(CreateRegExpLiteralWide, OperandType::kIdx16, OperandType::kIdx16, \ - OperandType::kImm8) \ - V(CreateArrayLiteralWide, OperandType::kIdx16, OperandType::kIdx16, \ - OperandType::kImm8) \ - V(CreateObjectLiteralWide, OperandType::kIdx16, OperandType::kIdx16, \ - OperandType::kImm8) \ - \ - /* Closure allocation */ \ - V(CreateClosure, OperandType::kIdx8, OperandType::kImm8) \ - V(CreateClosureWide, OperandType::kIdx16, OperandType::kImm8) \ - \ - /* Arguments allocation */ \ - V(CreateMappedArguments, OperandType::kNone) \ - V(CreateUnmappedArguments, OperandType::kNone) \ - V(CreateRestParameter, OperandType::kNone) \ - \ - /* Control Flow */ \ - V(Jump, OperandType::kImm8) \ - V(JumpConstant, OperandType::kIdx8) \ - V(JumpConstantWide, OperandType::kIdx16) \ - V(JumpIfTrue, OperandType::kImm8) \ - V(JumpIfTrueConstant, OperandType::kIdx8) \ - V(JumpIfTrueConstantWide, OperandType::kIdx16) \ - V(JumpIfFalse, OperandType::kImm8) \ - V(JumpIfFalseConstant, OperandType::kIdx8) \ - V(JumpIfFalseConstantWide, OperandType::kIdx16) \ - V(JumpIfToBooleanTrue, OperandType::kImm8) \ - V(JumpIfToBooleanTrueConstant, OperandType::kIdx8) \ - V(JumpIfToBooleanTrueConstantWide, OperandType::kIdx16) \ - V(JumpIfToBooleanFalse, OperandType::kImm8) \ - V(JumpIfToBooleanFalseConstant, OperandType::kIdx8) \ - V(JumpIfToBooleanFalseConstantWide, OperandType::kIdx16) \ - V(JumpIfNull, OperandType::kImm8) \ - V(JumpIfNullConstant, OperandType::kIdx8) \ - V(JumpIfNullConstantWide, OperandType::kIdx16) \ - V(JumpIfUndefined, OperandType::kImm8) \ - V(JumpIfUndefinedConstant, OperandType::kIdx8) \ - V(JumpIfUndefinedConstantWide, OperandType::kIdx16) \ - V(JumpIfNotHole, OperandType::kImm8) \ - V(JumpIfNotHoleConstant, OperandType::kIdx8) \ - V(JumpIfNotHoleConstantWide, OperandType::kIdx16) \ - \ - /* Complex flow control For..in */ \ - V(ForInPrepare, OperandType::kRegOutTriple8) \ - V(ForInPrepareWide, OperandType::kRegOutTriple16) \ - V(ForInDone, OperandType::kReg8, OperandType::kReg8) \ - V(ForInNext, OperandType::kReg8, OperandType::kReg8, OperandType::kRegPair8) \ - V(ForInNextWide, OperandType::kReg16, OperandType::kReg16, \ - OperandType::kRegPair16) \ - V(ForInStep, OperandType::kReg8) \ - \ - /* Perform a stack guard check */ \ - V(StackCheck, OperandType::kNone) \ - \ - /* Non-local flow control */ \ - V(Throw, OperandType::kNone) \ - V(ReThrow, OperandType::kNone) \ - V(Return, OperandType::kNone) \ - \ - /* Debugger */ \ - V(Debugger, OperandType::kNone) \ - DEBUG_BREAK_BYTECODE_LIST(V) - -// Enumeration of the size classes of operand types used by bytecodes. +#define BYTECODE_LIST(V) \ + /* Extended width operands */ \ + V(Wide, AccumulatorUse::kNone) \ + V(ExtraWide, AccumulatorUse::kNone) \ + \ + /* Loading the accumulator */ \ + V(LdaZero, AccumulatorUse::kWrite) \ + V(LdaSmi, AccumulatorUse::kWrite, OperandType::kImm) \ + V(LdaUndefined, AccumulatorUse::kWrite) \ + V(LdaNull, AccumulatorUse::kWrite) \ + V(LdaTheHole, AccumulatorUse::kWrite) \ + V(LdaTrue, AccumulatorUse::kWrite) \ + V(LdaFalse, AccumulatorUse::kWrite) \ + V(LdaConstant, AccumulatorUse::kWrite, OperandType::kIdx) \ + \ + /* Globals */ \ + V(LdaGlobal, AccumulatorUse::kWrite, OperandType::kIdx, OperandType::kIdx) \ + V(LdaGlobalInsideTypeof, AccumulatorUse::kWrite, OperandType::kIdx, \ + OperandType::kIdx) \ + V(StaGlobalSloppy, AccumulatorUse::kRead, OperandType::kIdx, \ + OperandType::kIdx) \ + V(StaGlobalStrict, AccumulatorUse::kRead, OperandType::kIdx, \ + OperandType::kIdx) \ + \ + /* Context operations */ \ + V(PushContext, AccumulatorUse::kRead, OperandType::kReg) \ + V(PopContext, AccumulatorUse::kNone, OperandType::kReg) \ + V(LdaContextSlot, AccumulatorUse::kWrite, OperandType::kReg, \ + OperandType::kIdx) \ + V(StaContextSlot, AccumulatorUse::kRead, OperandType::kReg, \ + OperandType::kIdx) \ + \ + /* Load-Store lookup slots */ \ + V(LdaLookupSlot, AccumulatorUse::kWrite, OperandType::kIdx) \ + V(LdaLookupSlotInsideTypeof, AccumulatorUse::kWrite, OperandType::kIdx) \ + V(StaLookupSlotSloppy, AccumulatorUse::kReadWrite, OperandType::kIdx) \ + V(StaLookupSlotStrict, AccumulatorUse::kReadWrite, OperandType::kIdx) \ + \ + /* Register-accumulator transfers */ \ + V(Ldar, AccumulatorUse::kWrite, OperandType::kReg) \ + V(Star, AccumulatorUse::kRead, OperandType::kRegOut) \ + \ + /* Register-register transfers */ \ + V(Mov, AccumulatorUse::kNone, OperandType::kReg, OperandType::kRegOut) \ + \ + /* LoadIC operations */ \ + V(LoadIC, AccumulatorUse::kWrite, OperandType::kReg, OperandType::kIdx, \ + OperandType::kIdx) \ + V(KeyedLoadIC, AccumulatorUse::kReadWrite, OperandType::kReg, \ + OperandType::kIdx) \ + \ + /* StoreIC operations */ \ + V(StoreICSloppy, AccumulatorUse::kRead, OperandType::kReg, \ + OperandType::kIdx, OperandType::kIdx) \ + V(StoreICStrict, AccumulatorUse::kRead, OperandType::kReg, \ + OperandType::kIdx, OperandType::kIdx) \ + V(KeyedStoreICSloppy, AccumulatorUse::kRead, OperandType::kReg, \ + OperandType::kReg, OperandType::kIdx) \ + V(KeyedStoreICStrict, AccumulatorUse::kRead, OperandType::kReg, \ + OperandType::kReg, OperandType::kIdx) \ + \ + /* Binary Operators */ \ + V(Add, AccumulatorUse::kReadWrite, OperandType::kReg) \ + V(Sub, AccumulatorUse::kReadWrite, OperandType::kReg) \ + V(Mul, AccumulatorUse::kReadWrite, OperandType::kReg) \ + V(Div, AccumulatorUse::kReadWrite, OperandType::kReg) \ + V(Mod, AccumulatorUse::kReadWrite, OperandType::kReg) \ + V(BitwiseOr, AccumulatorUse::kReadWrite, OperandType::kReg) \ + V(BitwiseXor, AccumulatorUse::kReadWrite, OperandType::kReg) \ + V(BitwiseAnd, AccumulatorUse::kReadWrite, OperandType::kReg) \ + V(ShiftLeft, AccumulatorUse::kReadWrite, OperandType::kReg) \ + V(ShiftRight, AccumulatorUse::kReadWrite, OperandType::kReg) \ + V(ShiftRightLogical, AccumulatorUse::kReadWrite, OperandType::kReg) \ + \ + /* Unary Operators */ \ + V(Inc, AccumulatorUse::kReadWrite) \ + V(Dec, AccumulatorUse::kReadWrite) \ + V(LogicalNot, AccumulatorUse::kReadWrite) \ + V(TypeOf, AccumulatorUse::kReadWrite) \ + V(DeletePropertyStrict, AccumulatorUse::kReadWrite, OperandType::kReg) \ + V(DeletePropertySloppy, AccumulatorUse::kReadWrite, OperandType::kReg) \ + \ + /* Call operations */ \ + V(Call, AccumulatorUse::kWrite, OperandType::kReg, OperandType::kReg, \ + OperandType::kRegCount, OperandType::kIdx) \ + V(TailCall, AccumulatorUse::kWrite, OperandType::kReg, OperandType::kReg, \ + OperandType::kRegCount, OperandType::kIdx) \ + V(CallRuntime, AccumulatorUse::kWrite, OperandType::kRuntimeId, \ + OperandType::kMaybeReg, OperandType::kRegCount) \ + V(CallRuntimeForPair, AccumulatorUse::kNone, OperandType::kRuntimeId, \ + OperandType::kMaybeReg, OperandType::kRegCount, OperandType::kRegOutPair) \ + V(CallJSRuntime, AccumulatorUse::kWrite, OperandType::kIdx, \ + OperandType::kReg, OperandType::kRegCount) \ + \ + /* Intrinsics */ \ + V(InvokeIntrinsic, AccumulatorUse::kWrite, OperandType::kRuntimeId, \ + OperandType::kMaybeReg, OperandType::kRegCount) \ + \ + /* New operator */ \ + V(New, AccumulatorUse::kReadWrite, OperandType::kReg, \ + OperandType::kMaybeReg, OperandType::kRegCount) \ + \ + /* Test Operators */ \ + V(TestEqual, AccumulatorUse::kReadWrite, OperandType::kReg) \ + V(TestNotEqual, AccumulatorUse::kReadWrite, OperandType::kReg) \ + V(TestEqualStrict, AccumulatorUse::kReadWrite, OperandType::kReg) \ + V(TestLessThan, AccumulatorUse::kReadWrite, OperandType::kReg) \ + V(TestGreaterThan, AccumulatorUse::kReadWrite, OperandType::kReg) \ + V(TestLessThanOrEqual, AccumulatorUse::kReadWrite, OperandType::kReg) \ + V(TestGreaterThanOrEqual, AccumulatorUse::kReadWrite, OperandType::kReg) \ + V(TestInstanceOf, AccumulatorUse::kReadWrite, OperandType::kReg) \ + V(TestIn, AccumulatorUse::kReadWrite, OperandType::kReg) \ + \ + /* Cast operators */ \ + V(ToName, AccumulatorUse::kReadWrite) \ + V(ToNumber, AccumulatorUse::kReadWrite) \ + V(ToObject, AccumulatorUse::kReadWrite) \ + \ + /* Literals */ \ + V(CreateRegExpLiteral, AccumulatorUse::kWrite, OperandType::kIdx, \ + OperandType::kIdx, OperandType::kFlag8) \ + V(CreateArrayLiteral, AccumulatorUse::kWrite, OperandType::kIdx, \ + OperandType::kIdx, OperandType::kFlag8) \ + V(CreateObjectLiteral, AccumulatorUse::kWrite, OperandType::kIdx, \ + OperandType::kIdx, OperandType::kFlag8) \ + \ + /* Closure allocation */ \ + V(CreateClosure, AccumulatorUse::kWrite, OperandType::kIdx, \ + OperandType::kFlag8) \ + \ + /* Arguments allocation */ \ + V(CreateMappedArguments, AccumulatorUse::kWrite) \ + V(CreateUnmappedArguments, AccumulatorUse::kWrite) \ + V(CreateRestParameter, AccumulatorUse::kWrite) \ + \ + /* Control Flow */ \ + V(Jump, AccumulatorUse::kNone, OperandType::kImm) \ + V(JumpConstant, AccumulatorUse::kNone, OperandType::kIdx) \ + V(JumpIfTrue, AccumulatorUse::kRead, OperandType::kImm) \ + V(JumpIfTrueConstant, AccumulatorUse::kRead, OperandType::kIdx) \ + V(JumpIfFalse, AccumulatorUse::kRead, OperandType::kImm) \ + V(JumpIfFalseConstant, AccumulatorUse::kRead, OperandType::kIdx) \ + V(JumpIfToBooleanTrue, AccumulatorUse::kRead, OperandType::kImm) \ + V(JumpIfToBooleanTrueConstant, AccumulatorUse::kRead, OperandType::kIdx) \ + V(JumpIfToBooleanFalse, AccumulatorUse::kRead, OperandType::kImm) \ + V(JumpIfToBooleanFalseConstant, AccumulatorUse::kRead, OperandType::kIdx) \ + V(JumpIfNull, AccumulatorUse::kRead, OperandType::kImm) \ + V(JumpIfNullConstant, AccumulatorUse::kRead, OperandType::kIdx) \ + V(JumpIfUndefined, AccumulatorUse::kRead, OperandType::kImm) \ + V(JumpIfUndefinedConstant, AccumulatorUse::kRead, OperandType::kIdx) \ + V(JumpIfNotHole, AccumulatorUse::kRead, OperandType::kImm) \ + V(JumpIfNotHoleConstant, AccumulatorUse::kRead, OperandType::kIdx) \ + \ + /* Complex flow control For..in */ \ + V(ForInPrepare, AccumulatorUse::kRead, OperandType::kRegOutTriple) \ + V(ForInDone, AccumulatorUse::kWrite, OperandType::kReg, OperandType::kReg) \ + V(ForInNext, AccumulatorUse::kWrite, OperandType::kReg, OperandType::kReg, \ + OperandType::kRegPair, OperandType::kIdx) \ + V(ForInStep, AccumulatorUse::kWrite, OperandType::kReg) \ + \ + /* Perform a stack guard check */ \ + V(StackCheck, AccumulatorUse::kNone) \ + \ + /* Non-local flow control */ \ + V(Throw, AccumulatorUse::kRead) \ + V(ReThrow, AccumulatorUse::kRead) \ + V(Return, AccumulatorUse::kNone) \ + \ + /* Debugger */ \ + V(Debugger, AccumulatorUse::kNone) \ + DEBUG_BREAK_BYTECODE_LIST(V) \ + \ + /* Illegal bytecode (terminates execution) */ \ + V(Illegal, AccumulatorUse::kNone) + +enum class AccumulatorUse : uint8_t { + kNone = 0, + kRead = 1 << 0, + kWrite = 1 << 1, + kReadWrite = kRead | kWrite +}; + +V8_INLINE AccumulatorUse operator&(AccumulatorUse lhs, AccumulatorUse rhs) { + int result = static_cast<int>(lhs) & static_cast<int>(rhs); + return static_cast<AccumulatorUse>(result); +} + +V8_INLINE AccumulatorUse operator|(AccumulatorUse lhs, AccumulatorUse rhs) { + int result = static_cast<int>(lhs) | static_cast<int>(rhs); + return static_cast<AccumulatorUse>(result); +} + +// Enumeration of scaling factors applicable to scalable operands. Code +// relies on being able to cast values to integer scaling values. +enum class OperandScale : uint8_t { + kSingle = 1, + kDouble = 2, + kQuadruple = 4, + kMaxValid = kQuadruple, + kInvalid = 8, +}; + +// Enumeration of the size classes of operand types used by +// bytecodes. Code relies on being able to cast values to integer +// types to get the size in bytes. enum class OperandSize : uint8_t { kNone = 0, kByte = 1, kShort = 2, + kQuad = 4, + kLast = kQuad }; +// Primitive operand info used that summarize properties of operands. +// Columns are Name, IsScalable, IsUnsigned, UnscaledSize. +#define OPERAND_TYPE_INFO_LIST(V) \ + V(None, false, false, OperandSize::kNone) \ + V(ScalableSignedByte, true, false, OperandSize::kByte) \ + V(ScalableUnsignedByte, true, true, OperandSize::kByte) \ + V(FixedUnsignedByte, false, true, OperandSize::kByte) \ + V(FixedUnsignedShort, false, true, OperandSize::kShort) + +enum class OperandTypeInfo : uint8_t { +#define DECLARE_OPERAND_TYPE_INFO(Name, ...) k##Name, + OPERAND_TYPE_INFO_LIST(DECLARE_OPERAND_TYPE_INFO) +#undef DECLARE_OPERAND_TYPE_INFO +}; // Enumeration of operand types used by bytecodes. enum class OperandType : uint8_t { @@ -330,9 +340,6 @@ class Register { static Register FromParameterIndex(int index, int parameter_count); int ToParameterIndex(int parameter_count) const; - static int MaxParameterIndex(); - static int MaxRegisterIndex(); - static int MaxRegisterIndexForByteOperand(); // Returns an invalid register. static Register invalid_value() { return Register(); } @@ -349,14 +356,8 @@ class Register { static Register new_target(); bool is_new_target() const; - static Register FromOperand(uint8_t operand); - uint8_t ToOperand() const; - - static Register FromWideOperand(uint16_t operand); - uint16_t ToWideOperand() const; - - static Register FromRawOperand(uint32_t raw_operand); - uint32_t ToRawOperand() const; + int32_t ToOperand() const { return -index_; } + static Register FromOperand(int32_t operand) { return Register(-operand); } static bool AreContiguous(Register reg1, Register reg2, Register reg3 = Register(), @@ -399,9 +400,18 @@ class Bytecodes { // Returns string representation of |bytecode|. static const char* ToString(Bytecode bytecode); + // Returns string representation of |bytecode|. + static std::string ToString(Bytecode bytecode, OperandScale operand_scale); + + // Returns string representation of |accumulator_use|. + static const char* AccumulatorUseToString(AccumulatorUse accumulator_use); + // Returns string representation of |operand_type|. static const char* OperandTypeToString(OperandType operand_type); + // Returns string representation of |operand_scale|. + static const char* OperandScaleToString(OperandScale operand_scale); + // Returns string representation of |operand_size|. static const char* OperandSizeToString(OperandSize operand_size); @@ -417,57 +427,72 @@ class Bytecodes { // Returns the number of register operands expected by |bytecode|. static int NumberOfRegisterOperands(Bytecode bytecode); + // Returns the prefix bytecode representing an operand scale to be + // applied to a a bytecode. + static Bytecode OperandScaleToPrefixBytecode(OperandScale operand_scale); + + // Returns true if the operand scale requires a prefix bytecode. + static bool OperandScaleRequiresPrefixBytecode(OperandScale operand_scale); + + // Returns the scaling applied to scalable operands if bytecode is + // is a scaling prefix. + static OperandScale PrefixBytecodeToOperandScale(Bytecode bytecode); + + // Returns how accumulator is used by |bytecode|. + static AccumulatorUse GetAccumulatorUse(Bytecode bytecode); + + // Returns true if |bytecode| reads the accumulator. + static bool ReadsAccumulator(Bytecode bytecode); + + // Returns true if |bytecode| writes the accumulator. + static bool WritesAccumulator(Bytecode bytecode); + // Returns the i-th operand of |bytecode|. static OperandType GetOperandType(Bytecode bytecode, int i); // Returns the size of the i-th operand of |bytecode|. - static OperandSize GetOperandSize(Bytecode bytecode, int i); + static OperandSize GetOperandSize(Bytecode bytecode, int i, + OperandScale operand_scale); // Returns the offset of the i-th operand of |bytecode| relative to the start // of the bytecode. - static int GetOperandOffset(Bytecode bytecode, int i); + static int GetOperandOffset(Bytecode bytecode, int i, + OperandScale operand_scale); // Returns a zero-based bitmap of the register operand positions of // |bytecode|. static int GetRegisterOperandBitmap(Bytecode bytecode); - // Returns a debug break bytecode with a matching operand size. + // Returns a debug break bytecode to replace |bytecode|. static Bytecode GetDebugBreak(Bytecode bytecode); - // Returns the size of the bytecode including its operands. - static int Size(Bytecode bytecode); + // Returns the size of the bytecode including its operands for the + // given |operand_scale|. + static int Size(Bytecode bytecode, OperandScale operand_scale); // Returns the size of |operand|. - static OperandSize SizeOfOperand(OperandType operand); + static OperandSize SizeOfOperand(OperandType operand, OperandScale scale); // Returns true if the bytecode is a conditional jump taking - // an immediate byte operand (OperandType::kImm8). + // an immediate byte operand (OperandType::kImm). static bool IsConditionalJumpImmediate(Bytecode bytecode); // Returns true if the bytecode is a conditional jump taking - // a constant pool entry (OperandType::kIdx8). + // a constant pool entry (OperandType::kIdx). static bool IsConditionalJumpConstant(Bytecode bytecode); // Returns true if the bytecode is a conditional jump taking - // a constant pool entry (OperandType::kIdx16). - static bool IsConditionalJumpConstantWide(Bytecode bytecode); - - // Returns true if the bytecode is a conditional jump taking // any kind of operand. static bool IsConditionalJump(Bytecode bytecode); // Returns true if the bytecode is a jump or a conditional jump taking - // an immediate byte operand (OperandType::kImm8). + // an immediate byte operand (OperandType::kImm). static bool IsJumpImmediate(Bytecode bytecode); // Returns true if the bytecode is a jump or conditional jump taking a - // constant pool entry (OperandType::kIdx8). + // constant pool entry (OperandType::kIdx). static bool IsJumpConstant(Bytecode bytecode); - // Returns true if the bytecode is a jump or conditional jump taking a - // constant pool entry (OperandType::kIdx16). - static bool IsJumpConstantWide(Bytecode bytecode); - // Returns true if the bytecode is a jump or conditional jump taking // any kind of operand. static bool IsJump(Bytecode bytecode); @@ -478,18 +503,17 @@ class Bytecodes { // Returns true if the bytecode is a call or a constructor call. static bool IsCallOrNew(Bytecode bytecode); + // Returns true if the bytecode is a call to the runtime. + static bool IsCallRuntime(Bytecode bytecode); + // Returns true if the bytecode is a debug break. static bool IsDebugBreak(Bytecode bytecode); - // Returns true if |operand_type| is a register index operand (kIdx8/kIdx16). - static bool IsIndexOperandType(OperandType operand_type); + // Returns true if the bytecode has wider operand forms. + static bool IsBytecodeWithScalableOperands(Bytecode bytecode); - // Returns true if |operand_type| represents an immediate. - static bool IsImmediateOperandType(OperandType operand_type); - - // Returns true if |operand_type| is a register count operand - // (kRegCount8/kRegCount16). - static bool IsRegisterCountOperandType(OperandType operand_type); + // Returns true if the bytecode is a scaling prefix bytecode. + static bool IsPrefixScalingBytecode(Bytecode bytecode); // Returns true if |operand_type| is any type of register operand. static bool IsRegisterOperandType(OperandType operand_type); @@ -501,20 +525,52 @@ class Bytecodes { static bool IsRegisterOutputOperandType(OperandType operand_type); // Returns true if |operand_type| is a maybe register operand - // (kMaybeReg8/kMaybeReg16). + // (kMaybeReg). static bool IsMaybeRegisterOperandType(OperandType operand_type); + // Returns true if |operand_type| is a runtime-id operand (kRuntimeId). + static bool IsRuntimeIdOperandType(OperandType operand_type); + + // Returns true if |operand_type| is unsigned, false if signed. + static bool IsUnsignedOperandType(OperandType operand_type); + + // Decodes a register operand in a byte array. + static Register DecodeRegisterOperand(const uint8_t* operand_start, + OperandType operand_type, + OperandScale operand_scale); + + // Decodes a signed operand in a byte array. + static int32_t DecodeSignedOperand(const uint8_t* operand_start, + OperandType operand_type, + OperandScale operand_scale); + + // Decodes an unsigned operand in a byte array. + static uint32_t DecodeUnsignedOperand(const uint8_t* operand_start, + OperandType operand_type, + OperandScale operand_scale); + // Decode a single bytecode and operands to |os|. static std::ostream& Decode(std::ostream& os, const uint8_t* bytecode_start, int number_of_parameters); + // Returns true if a handler is generated for a bytecode at a given + // operand scale. All bytecodes have handlers at OperandScale::kSingle, + // but only bytecodes with scalable operands have handlers with larger + // OperandScale values. + static bool BytecodeHasHandler(Bytecode bytecode, OperandScale operand_scale); + + // Return the next larger operand scale. + static OperandScale NextOperandScale(OperandScale operand_scale); + private: DISALLOW_IMPLICIT_CONSTRUCTORS(Bytecodes); }; std::ostream& operator<<(std::ostream& os, const Bytecode& bytecode); +std::ostream& operator<<(std::ostream& os, const AccumulatorUse& use); +std::ostream& operator<<(std::ostream& os, const OperandScale& operand_scale); +std::ostream& operator<<(std::ostream& os, const OperandSize& operand_size); std::ostream& operator<<(std::ostream& os, const OperandType& operand_type); -std::ostream& operator<<(std::ostream& os, const OperandSize& operand_type); } // namespace interpreter } // namespace internal diff --git a/deps/v8/src/interpreter/constant-array-builder.cc b/deps/v8/src/interpreter/constant-array-builder.cc index e8b1281b5a..7ce50b580e 100644 --- a/deps/v8/src/interpreter/constant-array-builder.cc +++ b/deps/v8/src/interpreter/constant-array-builder.cc @@ -11,28 +11,25 @@ namespace v8 { namespace internal { namespace interpreter { -ConstantArrayBuilder::ConstantArraySlice::ConstantArraySlice(Zone* zone, - size_t start_index, - size_t capacity) +ConstantArrayBuilder::ConstantArraySlice::ConstantArraySlice( + Zone* zone, size_t start_index, size_t capacity, OperandSize operand_size) : start_index_(start_index), capacity_(capacity), reserved_(0), + operand_size_(operand_size), constants_(zone) {} - void ConstantArrayBuilder::ConstantArraySlice::Reserve() { DCHECK_GT(available(), 0u); reserved_++; DCHECK_LE(reserved_, capacity() - constants_.size()); } - void ConstantArrayBuilder::ConstantArraySlice::Unreserve() { DCHECK_GT(reserved_, 0u); reserved_--; } - size_t ConstantArrayBuilder::ConstantArraySlice::Allocate( Handle<Object> object) { DCHECK_GT(available(), 0u); @@ -42,45 +39,57 @@ size_t ConstantArrayBuilder::ConstantArraySlice::Allocate( return index + start_index(); } - Handle<Object> ConstantArrayBuilder::ConstantArraySlice::At( size_t index) const { + DCHECK_GE(index, start_index()); + DCHECK_LT(index, start_index() + size()); return constants_[index - start_index()]; } - -STATIC_CONST_MEMBER_DEFINITION const size_t ConstantArrayBuilder::kMaxCapacity; -STATIC_CONST_MEMBER_DEFINITION const size_t ConstantArrayBuilder::kLowCapacity; - +STATIC_CONST_MEMBER_DEFINITION const size_t ConstantArrayBuilder::k8BitCapacity; +STATIC_CONST_MEMBER_DEFINITION const size_t + ConstantArrayBuilder::k16BitCapacity; +STATIC_CONST_MEMBER_DEFINITION const size_t + ConstantArrayBuilder::k32BitCapacity; ConstantArrayBuilder::ConstantArrayBuilder(Isolate* isolate, Zone* zone) - : isolate_(isolate), - idx8_slice_(zone, 0, kLowCapacity), - idx16_slice_(zone, kLowCapacity, kHighCapacity), - constants_map_(isolate->heap(), zone) { - STATIC_ASSERT(kMaxCapacity == static_cast<size_t>(kMaxUInt16 + 1)); - DCHECK_EQ(idx8_slice_.start_index(), 0u); - DCHECK_EQ(idx8_slice_.capacity(), kLowCapacity); - DCHECK_EQ(idx16_slice_.start_index(), kLowCapacity); - DCHECK_EQ(idx16_slice_.capacity(), kMaxCapacity - kLowCapacity); + : isolate_(isolate), constants_map_(isolate->heap(), zone) { + idx_slice_[0] = + new (zone) ConstantArraySlice(zone, 0, k8BitCapacity, OperandSize::kByte); + idx_slice_[1] = new (zone) ConstantArraySlice( + zone, k8BitCapacity, k16BitCapacity, OperandSize::kShort); + idx_slice_[2] = new (zone) ConstantArraySlice( + zone, k8BitCapacity + k16BitCapacity, k32BitCapacity, OperandSize::kQuad); } - size_t ConstantArrayBuilder::size() const { - if (idx16_slice_.size() > 0) { - return idx16_slice_.start_index() + idx16_slice_.size(); - } else { - return idx8_slice_.size(); + size_t i = arraysize(idx_slice_); + while (i > 0) { + ConstantArraySlice* slice = idx_slice_[--i]; + if (slice->size() > 0) { + return slice->start_index() + slice->size(); + } } + return idx_slice_[0]->size(); } +const ConstantArrayBuilder::ConstantArraySlice* +ConstantArrayBuilder::IndexToSlice(size_t index) const { + for (const ConstantArraySlice* slice : idx_slice_) { + if (index <= slice->max_index()) { + return slice; + } + } + UNREACHABLE(); + return nullptr; +} Handle<Object> ConstantArrayBuilder::At(size_t index) const { - if (index >= idx16_slice_.start_index()) { - return idx16_slice_.At(index); - } else if (index < idx8_slice_.size()) { - return idx8_slice_.At(index); + const ConstantArraySlice* slice = IndexToSlice(index); + if (index < slice->start_index() + slice->size()) { + return slice->At(index); } else { + DCHECK_LT(index, slice->capacity()); return isolate_->factory()->the_hole_value(); } } @@ -88,49 +97,82 @@ Handle<Object> ConstantArrayBuilder::At(size_t index) const { Handle<FixedArray> ConstantArrayBuilder::ToFixedArray() { Handle<FixedArray> fixed_array = isolate_->factory()->NewFixedArray( static_cast<int>(size()), PretenureFlag::TENURED); - for (int i = 0; i < fixed_array->length(); i++) { - fixed_array->set(i, *At(static_cast<size_t>(i))); + int array_index = 0; + for (const ConstantArraySlice* slice : idx_slice_) { + if (array_index == fixed_array->length()) { + break; + } + DCHECK(array_index == 0 || + base::bits::IsPowerOfTwo32(static_cast<uint32_t>(array_index))); + // Copy objects from slice into array. + for (size_t i = 0; i < slice->size(); ++i) { + fixed_array->set(array_index++, *slice->At(slice->start_index() + i)); + } + // Insert holes where reservations led to unused slots. + size_t padding = + std::min(static_cast<size_t>(fixed_array->length() - array_index), + slice->capacity() - slice->size()); + for (size_t i = 0; i < padding; i++) { + fixed_array->set(array_index++, *isolate_->factory()->the_hole_value()); + } } + DCHECK_EQ(array_index, fixed_array->length()); constants_map()->Clear(); return fixed_array; } - size_t ConstantArrayBuilder::Insert(Handle<Object> object) { index_t* entry = constants_map()->Find(object); return (entry == nullptr) ? AllocateEntry(object) : *entry; } - ConstantArrayBuilder::index_t ConstantArrayBuilder::AllocateEntry( Handle<Object> object) { DCHECK(!object->IsOddball()); - size_t index; index_t* entry = constants_map()->Get(object); - if (idx8_slice_.available() > 0) { - index = idx8_slice_.Allocate(object); - } else { - index = idx16_slice_.Allocate(object); + for (size_t i = 0; i < arraysize(idx_slice_); ++i) { + if (idx_slice_[i]->available() > 0) { + size_t index = idx_slice_[i]->Allocate(object); + *entry = static_cast<index_t>(index); + return *entry; + break; + } } - CHECK_LT(index, kMaxCapacity); - *entry = static_cast<index_t>(index); - return *entry; + UNREACHABLE(); + return kMaxUInt32; } - OperandSize ConstantArrayBuilder::CreateReservedEntry() { - if (idx8_slice_.available() > 0) { - idx8_slice_.Reserve(); - return OperandSize::kByte; - } else if (idx16_slice_.available() > 0) { - idx16_slice_.Reserve(); - return OperandSize::kShort; - } else { - UNREACHABLE(); - return OperandSize::kNone; + for (size_t i = 0; i < arraysize(idx_slice_); ++i) { + if (idx_slice_[i]->available() > 0) { + idx_slice_[i]->Reserve(); + return idx_slice_[i]->operand_size(); + } } + UNREACHABLE(); + return OperandSize::kNone; } +ConstantArrayBuilder::ConstantArraySlice* +ConstantArrayBuilder::OperandSizeToSlice(OperandSize operand_size) const { + ConstantArraySlice* slice = nullptr; + switch (operand_size) { + case OperandSize::kNone: + UNREACHABLE(); + break; + case OperandSize::kByte: + slice = idx_slice_[0]; + break; + case OperandSize::kShort: + slice = idx_slice_[1]; + break; + case OperandSize::kQuad: + slice = idx_slice_[2]; + break; + } + DCHECK(slice->operand_size() == operand_size); + return slice; +} size_t ConstantArrayBuilder::CommitReservedEntry(OperandSize operand_size, Handle<Object> object) { @@ -140,33 +182,20 @@ size_t ConstantArrayBuilder::CommitReservedEntry(OperandSize operand_size, if (nullptr == entry) { index = AllocateEntry(object); } else { - if (operand_size == OperandSize::kByte && - *entry >= idx8_slice_.capacity()) { - // The object is already in the constant array, but has an index - // outside the range of an idx8 operand so we need to create a - // duplicate entry in the idx8 operand range to satisfy the - // commitment. - *entry = static_cast<index_t>(idx8_slice_.Allocate(object)); + ConstantArraySlice* slice = OperandSizeToSlice(operand_size); + if (*entry > slice->max_index()) { + // The object is already in the constant array, but may have an + // index too big for the reserved operand_size. So, duplicate + // entry with the smaller operand size. + *entry = static_cast<index_t>(slice->Allocate(object)); } index = *entry; } - DCHECK(operand_size == OperandSize::kShort || index < idx8_slice_.capacity()); - DCHECK_LT(index, kMaxCapacity); return index; } - void ConstantArrayBuilder::DiscardReservedEntry(OperandSize operand_size) { - switch (operand_size) { - case OperandSize::kByte: - idx8_slice_.Unreserve(); - return; - case OperandSize::kShort: - idx16_slice_.Unreserve(); - return; - default: - UNREACHABLE(); - } + OperandSizeToSlice(operand_size)->Unreserve(); } } // namespace interpreter diff --git a/deps/v8/src/interpreter/constant-array-builder.h b/deps/v8/src/interpreter/constant-array-builder.h index d7e41e3771..1a68646251 100644 --- a/deps/v8/src/interpreter/constant-array-builder.h +++ b/deps/v8/src/interpreter/constant-array-builder.h @@ -23,13 +23,14 @@ namespace interpreter { class ConstantArrayBuilder final BASE_EMBEDDED { public: // Capacity of the 8-bit operand slice. - static const size_t kLowCapacity = 1u << kBitsPerByte; - - // Capacity of the combined 8-bit and 16-bit operand slices. - static const size_t kMaxCapacity = 1u << (2 * kBitsPerByte); + static const size_t k8BitCapacity = 1u << kBitsPerByte; // Capacity of the 16-bit operand slice. - static const size_t kHighCapacity = kMaxCapacity - kLowCapacity; + static const size_t k16BitCapacity = (1u << 2 * kBitsPerByte) - k8BitCapacity; + + // Capacity of the 32-bit operand slice. + static const size_t k32BitCapacity = + kMaxUInt32 - k16BitCapacity - k8BitCapacity + 1; ConstantArrayBuilder(Isolate* isolate, Zone* zone); @@ -60,12 +61,13 @@ class ConstantArrayBuilder final BASE_EMBEDDED { void DiscardReservedEntry(OperandSize operand_size); private: - typedef uint16_t index_t; + typedef uint32_t index_t; index_t AllocateEntry(Handle<Object> object); - struct ConstantArraySlice final { - ConstantArraySlice(Zone* zone, size_t start_index, size_t capacity); + struct ConstantArraySlice final : public ZoneObject { + ConstantArraySlice(Zone* zone, size_t start_index, size_t capacity, + OperandSize operand_size); void Reserve(); void Unreserve(); size_t Allocate(Handle<Object> object); @@ -76,21 +78,26 @@ class ConstantArrayBuilder final BASE_EMBEDDED { inline size_t capacity() const { return capacity_; } inline size_t size() const { return constants_.size(); } inline size_t start_index() const { return start_index_; } + inline size_t max_index() const { return start_index_ + capacity() - 1; } + inline OperandSize operand_size() const { return operand_size_; } private: const size_t start_index_; const size_t capacity_; size_t reserved_; + OperandSize operand_size_; ZoneVector<Handle<Object>> constants_; DISALLOW_COPY_AND_ASSIGN(ConstantArraySlice); }; + const ConstantArraySlice* IndexToSlice(size_t index) const; + ConstantArraySlice* OperandSizeToSlice(OperandSize operand_size) const; + IdentityMap<index_t>* constants_map() { return &constants_map_; } Isolate* isolate_; - ConstantArraySlice idx8_slice_; - ConstantArraySlice idx16_slice_; + ConstantArraySlice* idx_slice_[3]; IdentityMap<index_t> constants_map_; }; diff --git a/deps/v8/src/interpreter/interpreter-assembler.cc b/deps/v8/src/interpreter/interpreter-assembler.cc index 440e879c48..2663e4a876 100644 --- a/deps/v8/src/interpreter/interpreter-assembler.cc +++ b/deps/v8/src/interpreter/interpreter-assembler.cc @@ -22,12 +22,16 @@ namespace interpreter { using compiler::Node; InterpreterAssembler::InterpreterAssembler(Isolate* isolate, Zone* zone, - Bytecode bytecode) - : compiler::CodeStubAssembler( - isolate, zone, InterpreterDispatchDescriptor(isolate), - Code::ComputeFlags(Code::STUB), Bytecodes::ToString(bytecode), 0), + Bytecode bytecode, + OperandScale operand_scale) + : compiler::CodeStubAssembler(isolate, zone, + InterpreterDispatchDescriptor(isolate), + Code::ComputeFlags(Code::BYTECODE_HANDLER), + Bytecodes::ToString(bytecode), 0), bytecode_(bytecode), + operand_scale_(operand_scale), accumulator_(this, MachineRepresentation::kTagged), + accumulator_use_(AccumulatorUse::kNone), context_(this, MachineRepresentation::kTagged), bytecode_array_(this, MachineRepresentation::kTagged), disable_stack_check_across_call_(false), @@ -42,11 +46,26 @@ InterpreterAssembler::InterpreterAssembler(Isolate* isolate, Zone* zone, } } -InterpreterAssembler::~InterpreterAssembler() {} +InterpreterAssembler::~InterpreterAssembler() { + // If the following check fails the handler does not use the + // accumulator in the way described in the bytecode definitions in + // bytecodes.h. + DCHECK_EQ(accumulator_use_, Bytecodes::GetAccumulatorUse(bytecode_)); +} + +Node* InterpreterAssembler::GetAccumulatorUnchecked() { + return accumulator_.value(); +} -Node* InterpreterAssembler::GetAccumulator() { return accumulator_.value(); } +Node* InterpreterAssembler::GetAccumulator() { + DCHECK(Bytecodes::ReadsAccumulator(bytecode_)); + accumulator_use_ = accumulator_use_ | AccumulatorUse::kRead; + return GetAccumulatorUnchecked(); +} void InterpreterAssembler::SetAccumulator(Node* value) { + DCHECK(Bytecodes::WritesAccumulator(bytecode_)); + accumulator_use_ = accumulator_use_ | AccumulatorUse::kWrite; accumulator_.Bind(value); } @@ -79,11 +98,11 @@ Node* InterpreterAssembler::RegisterLocation(Node* reg_index) { Node* InterpreterAssembler::LoadRegister(int offset) { return Load(MachineType::AnyTagged(), RegisterFileRawPointer(), - Int32Constant(offset)); + IntPtrConstant(offset)); } Node* InterpreterAssembler::LoadRegister(Register reg) { - return LoadRegister(reg.ToOperand() << kPointerSizeLog2); + return LoadRegister(IntPtrConstant(-reg.index())); } Node* InterpreterAssembler::RegisterFrameOffset(Node* index) { @@ -97,12 +116,12 @@ Node* InterpreterAssembler::LoadRegister(Node* reg_index) { Node* InterpreterAssembler::StoreRegister(Node* value, int offset) { return StoreNoWriteBarrier(MachineRepresentation::kTagged, - RegisterFileRawPointer(), Int32Constant(offset), + RegisterFileRawPointer(), IntPtrConstant(offset), value); } Node* InterpreterAssembler::StoreRegister(Node* value, Register reg) { - return StoreRegister(value, reg.ToOperand() << kPointerSizeLog2); + return StoreRegister(value, IntPtrConstant(-reg.index())); } Node* InterpreterAssembler::StoreRegister(Node* value, Node* reg_index) { @@ -113,27 +132,31 @@ Node* InterpreterAssembler::StoreRegister(Node* value, Node* reg_index) { Node* InterpreterAssembler::NextRegister(Node* reg_index) { // Register indexes are negative, so the next index is minus one. - return IntPtrAdd(reg_index, Int32Constant(-1)); + return IntPtrAdd(reg_index, IntPtrConstant(-1)); +} + +Node* InterpreterAssembler::OperandOffset(int operand_index) { + return IntPtrConstant( + Bytecodes::GetOperandOffset(bytecode_, operand_index, operand_scale())); } -Node* InterpreterAssembler::BytecodeOperand(int operand_index) { +Node* InterpreterAssembler::BytecodeOperandUnsignedByte(int operand_index) { DCHECK_LT(operand_index, Bytecodes::NumberOfOperands(bytecode_)); - DCHECK_EQ(OperandSize::kByte, - Bytecodes::GetOperandSize(bytecode_, operand_index)); - return Load( - MachineType::Uint8(), BytecodeArrayTaggedPointer(), - IntPtrAdd(BytecodeOffset(), Int32Constant(Bytecodes::GetOperandOffset( - bytecode_, operand_index)))); + DCHECK_EQ(OperandSize::kByte, Bytecodes::GetOperandSize( + bytecode_, operand_index, operand_scale())); + Node* operand_offset = OperandOffset(operand_index); + return Load(MachineType::Uint8(), BytecodeArrayTaggedPointer(), + IntPtrAdd(BytecodeOffset(), operand_offset)); } -Node* InterpreterAssembler::BytecodeOperandSignExtended(int operand_index) { +Node* InterpreterAssembler::BytecodeOperandSignedByte(int operand_index) { DCHECK_LT(operand_index, Bytecodes::NumberOfOperands(bytecode_)); - DCHECK_EQ(OperandSize::kByte, - Bytecodes::GetOperandSize(bytecode_, operand_index)); - Node* load = Load( - MachineType::Int8(), BytecodeArrayTaggedPointer(), - IntPtrAdd(BytecodeOffset(), Int32Constant(Bytecodes::GetOperandOffset( - bytecode_, operand_index)))); + DCHECK_EQ(OperandSize::kByte, Bytecodes::GetOperandSize( + bytecode_, operand_index, operand_scale())); + Node* operand_offset = OperandOffset(operand_index); + Node* load = Load(MachineType::Int8(), BytecodeArrayTaggedPointer(), + IntPtrAdd(BytecodeOffset(), operand_offset)); + // Ensure that we sign extend to full pointer size if (kPointerSize == 8) { load = ChangeInt32ToInt64(load); @@ -141,58 +164,85 @@ Node* InterpreterAssembler::BytecodeOperandSignExtended(int operand_index) { return load; } -Node* InterpreterAssembler::BytecodeOperandShort(int operand_index) { - DCHECK_LT(operand_index, Bytecodes::NumberOfOperands(bytecode_)); - DCHECK_EQ(OperandSize::kShort, - Bytecodes::GetOperandSize(bytecode_, operand_index)); - if (TargetSupportsUnalignedAccess()) { - return Load( - MachineType::Uint16(), BytecodeArrayTaggedPointer(), - IntPtrAdd(BytecodeOffset(), Int32Constant(Bytecodes::GetOperandOffset( - bytecode_, operand_index)))); - } else { - int offset = Bytecodes::GetOperandOffset(bytecode_, operand_index); - Node* first_byte = Load(MachineType::Uint8(), BytecodeArrayTaggedPointer(), - IntPtrAdd(BytecodeOffset(), Int32Constant(offset))); - Node* second_byte = - Load(MachineType::Uint8(), BytecodeArrayTaggedPointer(), - IntPtrAdd(BytecodeOffset(), Int32Constant(offset + 1))); +compiler::Node* InterpreterAssembler::BytecodeOperandReadUnaligned( + int relative_offset, MachineType result_type) { + static const int kMaxCount = 4; + DCHECK(!TargetSupportsUnalignedAccess()); + + int count; + switch (result_type.representation()) { + case MachineRepresentation::kWord16: + count = 2; + break; + case MachineRepresentation::kWord32: + count = 4; + break; + default: + UNREACHABLE(); + break; + } + MachineType msb_type = + result_type.IsSigned() ? MachineType::Int8() : MachineType::Uint8(); + #if V8_TARGET_LITTLE_ENDIAN - return WordOr(WordShl(second_byte, kBitsPerByte), first_byte); + const int kStep = -1; + int msb_offset = count - 1; #elif V8_TARGET_BIG_ENDIAN - return WordOr(WordShl(first_byte, kBitsPerByte), second_byte); + const int kStep = 1; + int msb_offset = 0; #else #error "Unknown Architecture" #endif + + // Read the most signicant bytecode into bytes[0] and then in order + // down to least significant in bytes[count - 1]. + DCHECK(count <= kMaxCount); + compiler::Node* bytes[kMaxCount]; + for (int i = 0; i < count; i++) { + MachineType machine_type = (i == 0) ? msb_type : MachineType::Uint8(); + Node* offset = IntPtrConstant(relative_offset + msb_offset + i * kStep); + Node* array_offset = IntPtrAdd(BytecodeOffset(), offset); + bytes[i] = Load(machine_type, BytecodeArrayTaggedPointer(), array_offset); + } + + // Pack LSB to MSB. + Node* result = bytes[--count]; + for (int i = 1; --count >= 0; i++) { + Node* shift = Int32Constant(i * kBitsPerByte); + Node* value = Word32Shl(bytes[count], shift); + result = Word32Or(value, result); } + return result; } -Node* InterpreterAssembler::BytecodeOperandShortSignExtended( - int operand_index) { +Node* InterpreterAssembler::BytecodeOperandUnsignedShort(int operand_index) { DCHECK_LT(operand_index, Bytecodes::NumberOfOperands(bytecode_)); - DCHECK_EQ(OperandSize::kShort, - Bytecodes::GetOperandSize(bytecode_, operand_index)); - int operand_offset = Bytecodes::GetOperandOffset(bytecode_, operand_index); + DCHECK_EQ( + OperandSize::kShort, + Bytecodes::GetOperandSize(bytecode_, operand_index, operand_scale())); + int operand_offset = + Bytecodes::GetOperandOffset(bytecode_, operand_index, operand_scale()); + if (TargetSupportsUnalignedAccess()) { + return Load(MachineType::Uint16(), BytecodeArrayTaggedPointer(), + IntPtrAdd(BytecodeOffset(), IntPtrConstant(operand_offset))); + } else { + return BytecodeOperandReadUnaligned(operand_offset, MachineType::Uint16()); + } +} + +Node* InterpreterAssembler::BytecodeOperandSignedShort(int operand_index) { + DCHECK_LT(operand_index, Bytecodes::NumberOfOperands(bytecode_)); + DCHECK_EQ( + OperandSize::kShort, + Bytecodes::GetOperandSize(bytecode_, operand_index, operand_scale())); + int operand_offset = + Bytecodes::GetOperandOffset(bytecode_, operand_index, operand_scale()); Node* load; if (TargetSupportsUnalignedAccess()) { load = Load(MachineType::Int16(), BytecodeArrayTaggedPointer(), - IntPtrAdd(BytecodeOffset(), Int32Constant(operand_offset))); + IntPtrAdd(BytecodeOffset(), IntPtrConstant(operand_offset))); } else { -#if V8_TARGET_LITTLE_ENDIAN - Node* hi_byte_offset = Int32Constant(operand_offset + 1); - Node* lo_byte_offset = Int32Constant(operand_offset); -#elif V8_TARGET_BIG_ENDIAN - Node* hi_byte_offset = Int32Constant(operand_offset); - Node* lo_byte_offset = Int32Constant(operand_offset + 1); -#else -#error "Unknown Architecture" -#endif - Node* hi_byte = Load(MachineType::Int8(), BytecodeArrayTaggedPointer(), - IntPtrAdd(BytecodeOffset(), hi_byte_offset)); - Node* lo_byte = Load(MachineType::Uint8(), BytecodeArrayTaggedPointer(), - IntPtrAdd(BytecodeOffset(), lo_byte_offset)); - hi_byte = Word32Shl(hi_byte, Int32Constant(kBitsPerByte)); - load = Word32Or(hi_byte, lo_byte); + load = BytecodeOperandReadUnaligned(operand_offset, MachineType::Int16()); } // Ensure that we sign extend to full pointer size @@ -202,57 +252,123 @@ Node* InterpreterAssembler::BytecodeOperandShortSignExtended( return load; } -Node* InterpreterAssembler::BytecodeOperandCount(int operand_index) { - switch (Bytecodes::GetOperandSize(bytecode_, operand_index)) { +Node* InterpreterAssembler::BytecodeOperandUnsignedQuad(int operand_index) { + DCHECK_LT(operand_index, Bytecodes::NumberOfOperands(bytecode_)); + DCHECK_EQ(OperandSize::kQuad, Bytecodes::GetOperandSize( + bytecode_, operand_index, operand_scale())); + int operand_offset = + Bytecodes::GetOperandOffset(bytecode_, operand_index, operand_scale()); + if (TargetSupportsUnalignedAccess()) { + return Load(MachineType::Uint32(), BytecodeArrayTaggedPointer(), + IntPtrAdd(BytecodeOffset(), IntPtrConstant(operand_offset))); + } else { + return BytecodeOperandReadUnaligned(operand_offset, MachineType::Uint32()); + } +} + +Node* InterpreterAssembler::BytecodeOperandSignedQuad(int operand_index) { + DCHECK_LT(operand_index, Bytecodes::NumberOfOperands(bytecode_)); + DCHECK_EQ(OperandSize::kQuad, Bytecodes::GetOperandSize( + bytecode_, operand_index, operand_scale())); + int operand_offset = + Bytecodes::GetOperandOffset(bytecode_, operand_index, operand_scale()); + Node* load; + if (TargetSupportsUnalignedAccess()) { + load = Load(MachineType::Int32(), BytecodeArrayTaggedPointer(), + IntPtrAdd(BytecodeOffset(), IntPtrConstant(operand_offset))); + } else { + load = BytecodeOperandReadUnaligned(operand_offset, MachineType::Int32()); + } + + // Ensure that we sign extend to full pointer size + if (kPointerSize == 8) { + load = ChangeInt32ToInt64(load); + } + return load; +} + +Node* InterpreterAssembler::BytecodeSignedOperand(int operand_index, + OperandSize operand_size) { + DCHECK(!Bytecodes::IsUnsignedOperandType( + Bytecodes::GetOperandType(bytecode_, operand_index))); + switch (operand_size) { case OperandSize::kByte: - DCHECK_EQ(OperandType::kRegCount8, - Bytecodes::GetOperandType(bytecode_, operand_index)); - return BytecodeOperand(operand_index); + return BytecodeOperandSignedByte(operand_index); case OperandSize::kShort: - DCHECK_EQ(OperandType::kRegCount16, - Bytecodes::GetOperandType(bytecode_, operand_index)); - return BytecodeOperandShort(operand_index); + return BytecodeOperandSignedShort(operand_index); + case OperandSize::kQuad: + return BytecodeOperandSignedQuad(operand_index); case OperandSize::kNone: UNREACHABLE(); } return nullptr; } -Node* InterpreterAssembler::BytecodeOperandImm(int operand_index) { - DCHECK_EQ(OperandType::kImm8, - Bytecodes::GetOperandType(bytecode_, operand_index)); - return BytecodeOperandSignExtended(operand_index); -} - -Node* InterpreterAssembler::BytecodeOperandIdx(int operand_index) { - switch (Bytecodes::GetOperandSize(bytecode_, operand_index)) { +Node* InterpreterAssembler::BytecodeUnsignedOperand(int operand_index, + OperandSize operand_size) { + DCHECK(Bytecodes::IsUnsignedOperandType( + Bytecodes::GetOperandType(bytecode_, operand_index))); + switch (operand_size) { case OperandSize::kByte: - DCHECK_EQ(OperandType::kIdx8, - Bytecodes::GetOperandType(bytecode_, operand_index)); - return BytecodeOperand(operand_index); + return BytecodeOperandUnsignedByte(operand_index); case OperandSize::kShort: - DCHECK_EQ(OperandType::kIdx16, - Bytecodes::GetOperandType(bytecode_, operand_index)); - return BytecodeOperandShort(operand_index); + return BytecodeOperandUnsignedShort(operand_index); + case OperandSize::kQuad: + return BytecodeOperandUnsignedQuad(operand_index); case OperandSize::kNone: UNREACHABLE(); } return nullptr; } +Node* InterpreterAssembler::BytecodeOperandCount(int operand_index) { + DCHECK_EQ(OperandType::kRegCount, + Bytecodes::GetOperandType(bytecode_, operand_index)); + OperandSize operand_size = + Bytecodes::GetOperandSize(bytecode_, operand_index, operand_scale()); + return BytecodeUnsignedOperand(operand_index, operand_size); +} + +Node* InterpreterAssembler::BytecodeOperandFlag(int operand_index) { + DCHECK_EQ(OperandType::kFlag8, + Bytecodes::GetOperandType(bytecode_, operand_index)); + OperandSize operand_size = + Bytecodes::GetOperandSize(bytecode_, operand_index, operand_scale()); + DCHECK_EQ(operand_size, OperandSize::kByte); + return BytecodeUnsignedOperand(operand_index, operand_size); +} + +Node* InterpreterAssembler::BytecodeOperandImm(int operand_index) { + DCHECK_EQ(OperandType::kImm, + Bytecodes::GetOperandType(bytecode_, operand_index)); + OperandSize operand_size = + Bytecodes::GetOperandSize(bytecode_, operand_index, operand_scale()); + return BytecodeSignedOperand(operand_index, operand_size); +} + +Node* InterpreterAssembler::BytecodeOperandIdx(int operand_index) { + DCHECK(OperandType::kIdx == + Bytecodes::GetOperandType(bytecode_, operand_index)); + OperandSize operand_size = + Bytecodes::GetOperandSize(bytecode_, operand_index, operand_scale()); + return BytecodeUnsignedOperand(operand_index, operand_size); +} + Node* InterpreterAssembler::BytecodeOperandReg(int operand_index) { - OperandType operand_type = - Bytecodes::GetOperandType(bytecode_, operand_index); - if (Bytecodes::IsRegisterOperandType(operand_type)) { - OperandSize operand_size = Bytecodes::SizeOfOperand(operand_type); - if (operand_size == OperandSize::kByte) { - return BytecodeOperandSignExtended(operand_index); - } else if (operand_size == OperandSize::kShort) { - return BytecodeOperandShortSignExtended(operand_index); - } - } - UNREACHABLE(); - return nullptr; + DCHECK(Bytecodes::IsRegisterOperandType( + Bytecodes::GetOperandType(bytecode_, operand_index))); + OperandSize operand_size = + Bytecodes::GetOperandSize(bytecode_, operand_index, operand_scale()); + return BytecodeSignedOperand(operand_index, operand_size); +} + +Node* InterpreterAssembler::BytecodeOperandRuntimeId(int operand_index) { + DCHECK(OperandType::kRuntimeId == + Bytecodes::GetOperandType(bytecode_, operand_index)); + OperandSize operand_size = + Bytecodes::GetOperandSize(bytecode_, operand_index, operand_scale()); + DCHECK_EQ(operand_size, OperandSize::kShort); + return BytecodeUnsignedOperand(operand_index, operand_size); } Node* InterpreterAssembler::LoadConstantPoolEntry(Node* index) { @@ -264,14 +380,6 @@ Node* InterpreterAssembler::LoadConstantPoolEntry(Node* index) { return Load(MachineType::AnyTagged(), constant_pool, entry_offset); } -Node* InterpreterAssembler::LoadFixedArrayElement(Node* fixed_array, - int index) { - Node* entry_offset = - IntPtrAdd(IntPtrConstant(FixedArray::kHeaderSize - kHeapObjectTag), - WordShl(Int32Constant(index), kPointerSizeLog2)); - return Load(MachineType::AnyTagged(), fixed_array, entry_offset); -} - Node* InterpreterAssembler::LoadObjectField(Node* object, int offset) { return Load(MachineType::AnyTagged(), object, IntPtrConstant(offset - kHeapObjectTag)); @@ -285,7 +393,7 @@ Node* InterpreterAssembler::LoadContextSlot(Node* context, int slot_index) { Node* InterpreterAssembler::LoadContextSlot(Node* context, Node* slot_index) { Node* offset = IntPtrAdd(WordShl(slot_index, kPointerSizeLog2), - Int32Constant(Context::kHeaderSize - kHeapObjectTag)); + IntPtrConstant(Context::kHeaderSize - kHeapObjectTag)); return Load(MachineType::AnyTagged(), context, offset); } @@ -293,7 +401,7 @@ Node* InterpreterAssembler::StoreContextSlot(Node* context, Node* slot_index, Node* value) { Node* offset = IntPtrAdd(WordShl(slot_index, kPointerSizeLog2), - Int32Constant(Context::kHeaderSize - kHeapObjectTag)); + IntPtrConstant(Context::kHeaderSize - kHeapObjectTag)); return Store(MachineRepresentation::kTagged, context, offset, value); } @@ -311,8 +419,6 @@ Node* InterpreterAssembler::LoadTypeFeedbackVector() { void InterpreterAssembler::CallPrologue() { StoreRegister(SmiTag(BytecodeOffset()), InterpreterFrameConstants::kBytecodeOffsetFromRegisterPointer); - StoreRegister(BytecodeArrayTaggedPointer(), - InterpreterFrameConstants::kBytecodeArrayFromRegisterPointer); if (FLAG_debug_code && !disable_stack_check_across_call_) { DCHECK(stack_pointer_before_call_ == nullptr); @@ -368,7 +474,7 @@ Node* InterpreterAssembler::CallRuntimeN(Node* function_id, Node* context, Node* function = IntPtrAdd(function_table, function_offset); Node* function_entry = Load(MachineType::Pointer(), function, - Int32Constant(offsetof(Runtime::Function, entry))); + IntPtrConstant(offsetof(Runtime::Function, entry))); return CallStub(callable.descriptor(), code_target, context, arg_count, first_arg, function_entry, result_size); @@ -405,7 +511,7 @@ void InterpreterAssembler::UpdateInterruptBudget(Node* weight) { } Node* InterpreterAssembler::Advance(int delta) { - return IntPtrAdd(BytecodeOffset(), Int32Constant(delta)); + return IntPtrAdd(BytecodeOffset(), IntPtrConstant(delta)); } Node* InterpreterAssembler::Advance(Node* delta) { @@ -438,18 +544,21 @@ void InterpreterAssembler::JumpIfWordNotEqual(Node* lhs, Node* rhs, } void InterpreterAssembler::Dispatch() { - DispatchTo(Advance(Bytecodes::Size(bytecode_))); + DispatchTo(Advance(Bytecodes::Size(bytecode_, operand_scale_))); } void InterpreterAssembler::DispatchTo(Node* new_bytecode_offset) { Node* target_bytecode = Load( MachineType::Uint8(), BytecodeArrayTaggedPointer(), new_bytecode_offset); + if (kPointerSize == 8) { + target_bytecode = ChangeUint32ToUint64(target_bytecode); + } // TODO(rmcilroy): Create a code target dispatch table to avoid conversion // from code object on every dispatch. Node* target_code_object = Load(MachineType::Pointer(), DispatchTableRawPointer(), - Word32Shl(target_bytecode, Int32Constant(kPointerSizeLog2))); + WordShl(target_bytecode, IntPtrConstant(kPointerSizeLog2))); DispatchToBytecodeHandler(target_code_object, new_bytecode_offset); } @@ -461,12 +570,46 @@ void InterpreterAssembler::DispatchToBytecodeHandler(Node* handler, } InterpreterDispatchDescriptor descriptor(isolate()); - Node* args[] = {GetAccumulator(), RegisterFileRawPointer(), + Node* args[] = {GetAccumulatorUnchecked(), RegisterFileRawPointer(), bytecode_offset, BytecodeArrayTaggedPointer(), DispatchTableRawPointer(), GetContext()}; TailCall(descriptor, handler, args, 0); } +void InterpreterAssembler::DispatchWide(OperandScale operand_scale) { + // Dispatching a wide bytecode requires treating the prefix + // bytecode a base pointer into the dispatch table and dispatching + // the bytecode that follows relative to this base. + // + // Indices 0-255 correspond to bytecodes with operand_scale == 0 + // Indices 256-511 correspond to bytecodes with operand_scale == 1 + // Indices 512-767 correspond to bytecodes with operand_scale == 2 + Node* next_bytecode_offset = Advance(1); + Node* next_bytecode = Load(MachineType::Uint8(), BytecodeArrayTaggedPointer(), + next_bytecode_offset); + if (kPointerSize == 8) { + next_bytecode = ChangeUint32ToUint64(next_bytecode); + } + Node* base_index; + switch (operand_scale) { + case OperandScale::kDouble: + base_index = IntPtrConstant(1 << kBitsPerByte); + break; + case OperandScale::kQuadruple: + base_index = IntPtrConstant(2 << kBitsPerByte); + break; + default: + UNREACHABLE(); + base_index = nullptr; + } + Node* target_index = IntPtrAdd(base_index, next_bytecode); + Node* target_code_object = + Load(MachineType::Pointer(), DispatchTableRawPointer(), + WordShl(target_index, kPointerSizeLog2)); + + DispatchToBytecodeHandler(target_code_object, next_bytecode_offset); +} + void InterpreterAssembler::InterpreterReturn() { // TODO(rmcilroy): Investigate whether it is worth supporting self // optimization of primitive functions like FullCodegen. @@ -505,27 +648,29 @@ void InterpreterAssembler::StackCheck() { void InterpreterAssembler::Abort(BailoutReason bailout_reason) { disable_stack_check_across_call_ = true; Node* abort_id = SmiTag(Int32Constant(bailout_reason)); - Node* ret_value = CallRuntime(Runtime::kAbort, GetContext(), abort_id); + CallRuntime(Runtime::kAbort, GetContext(), abort_id); disable_stack_check_across_call_ = false; - // Unreached, but keeps turbofan happy. - Return(ret_value); } void InterpreterAssembler::AbortIfWordNotEqual(Node* lhs, Node* rhs, BailoutReason bailout_reason) { CodeStubAssembler::Label match(this); CodeStubAssembler::Label no_match(this); + CodeStubAssembler::Label end(this); Node* condition = WordEqual(lhs, rhs); Branch(condition, &match, &no_match); Bind(&no_match); Abort(bailout_reason); + Goto(&end); Bind(&match); + Goto(&end); + Bind(&end); } void InterpreterAssembler::TraceBytecode(Runtime::FunctionId function_id) { CallRuntime(function_id, GetContext(), BytecodeArrayTaggedPointer(), - SmiTag(BytecodeOffset()), GetAccumulator()); + SmiTag(BytecodeOffset()), GetAccumulatorUnchecked()); } // static @@ -534,7 +679,8 @@ bool InterpreterAssembler::TargetSupportsUnalignedAccess() { return false; #elif V8_TARGET_ARCH_ARM || V8_TARGET_ARCH_ARM64 || V8_TARGET_ARCH_PPC return CpuFeatures::IsSupported(UNALIGNED_ACCESSES); -#elif V8_TARGET_ARCH_IA32 || V8_TARGET_ARCH_X64 || V8_TARGET_ARCH_X87 +#elif V8_TARGET_ARCH_IA32 || V8_TARGET_ARCH_X64 || V8_TARGET_ARCH_X87 || \ + V8_TARGET_ARCH_S390 return true; #else #error "Unknown Architecture" diff --git a/deps/v8/src/interpreter/interpreter-assembler.h b/deps/v8/src/interpreter/interpreter-assembler.h index 9600dfb6c5..86ecea54dd 100644 --- a/deps/v8/src/interpreter/interpreter-assembler.h +++ b/deps/v8/src/interpreter/interpreter-assembler.h @@ -19,12 +19,16 @@ namespace interpreter { class InterpreterAssembler : public compiler::CodeStubAssembler { public: - InterpreterAssembler(Isolate* isolate, Zone* zone, Bytecode bytecode); + InterpreterAssembler(Isolate* isolate, Zone* zone, Bytecode bytecode, + OperandScale operand_scale); virtual ~InterpreterAssembler(); // Returns the count immediate for bytecode operand |operand_index| in the // current bytecode. compiler::Node* BytecodeOperandCount(int operand_index); + // Returns the 8-bit flag for bytecode operand |operand_index| in the + // current bytecode. + compiler::Node* BytecodeOperandFlag(int operand_index); // Returns the index immediate for bytecode operand |operand_index| in the // current bytecode. compiler::Node* BytecodeOperandIdx(int operand_index); @@ -34,6 +38,9 @@ class InterpreterAssembler : public compiler::CodeStubAssembler { // Returns the register index for bytecode operand |operand_index| in the // current bytecode. compiler::Node* BytecodeOperandReg(int operand_index); + // Returns the runtime id immediate for bytecode operand + // |operand_index| in the current bytecode. + compiler::Node* BytecodeOperandRuntimeId(int operand_index); // Accumulator. compiler::Node* GetAccumulator(); @@ -62,9 +69,6 @@ class InterpreterAssembler : public compiler::CodeStubAssembler { // Load constant at |index| in the constant pool. compiler::Node* LoadConstantPoolEntry(compiler::Node* index); - // Load an element from a fixed array on the heap. - compiler::Node* LoadFixedArrayElement(compiler::Node* fixed_array, int index); - // Load a field from an object on the heap. compiler::Node* LoadObjectField(compiler::Node* object, int offset); @@ -139,10 +143,14 @@ class InterpreterAssembler : public compiler::CodeStubAssembler { DispatchToBytecodeHandler(handler, BytecodeOffset()); } + // Dispatch bytecode as wide operand variant. + void DispatchWide(OperandScale operand_scale); + // Abort with the given bailout reason. void Abort(BailoutReason bailout_reason); protected: + Bytecode bytecode() const { return bytecode_; } static bool TargetSupportsUnalignedAccess(); private: @@ -155,6 +163,11 @@ class InterpreterAssembler : public compiler::CodeStubAssembler { // Returns a raw pointer to first entry in the interpreter dispatch table. compiler::Node* DispatchTableRawPointer(); + // Returns the accumulator value without checking whether bytecode + // uses it. This is intended to be used only in dispatch and in + // tracing as these need to bypass accumulator use validity checks. + compiler::Node* GetAccumulatorUnchecked(); + // Saves and restores interpreter bytecode offset to the interpreter stack // frame when performing a call. void CallPrologue() override; @@ -170,10 +183,28 @@ class InterpreterAssembler : public compiler::CodeStubAssembler { // Returns the offset of register |index| relative to RegisterFilePointer(). compiler::Node* RegisterFrameOffset(compiler::Node* index); - compiler::Node* BytecodeOperand(int operand_index); - compiler::Node* BytecodeOperandSignExtended(int operand_index); - compiler::Node* BytecodeOperandShort(int operand_index); - compiler::Node* BytecodeOperandShortSignExtended(int operand_index); + // Returns the offset of an operand relative to the current bytecode offset. + compiler::Node* OperandOffset(int operand_index); + + // Returns a value built from an sequence of bytes in the bytecode + // array starting at |relative_offset| from the current bytecode. + // The |result_type| determines the size and signedness. of the + // value read. This method should only be used on architectures that + // do not support unaligned memory accesses. + compiler::Node* BytecodeOperandReadUnaligned(int relative_offset, + MachineType result_type); + + compiler::Node* BytecodeOperandUnsignedByte(int operand_index); + compiler::Node* BytecodeOperandSignedByte(int operand_index); + compiler::Node* BytecodeOperandUnsignedShort(int operand_index); + compiler::Node* BytecodeOperandSignedShort(int operand_index); + compiler::Node* BytecodeOperandUnsignedQuad(int operand_index); + compiler::Node* BytecodeOperandSignedQuad(int operand_index); + + compiler::Node* BytecodeSignedOperand(int operand_index, + OperandSize operand_size); + compiler::Node* BytecodeUnsignedOperand(int operand_index, + OperandSize operand_size); // Returns BytecodeOffset() advanced by delta bytecodes. Note: this does not // update BytecodeOffset() itself. @@ -187,8 +218,12 @@ class InterpreterAssembler : public compiler::CodeStubAssembler { void AbortIfWordNotEqual(compiler::Node* lhs, compiler::Node* rhs, BailoutReason bailout_reason); + OperandScale operand_scale() const { return operand_scale_; } + Bytecode bytecode_; + OperandScale operand_scale_; CodeStubAssembler::Variable accumulator_; + AccumulatorUse accumulator_use_; CodeStubAssembler::Variable context_; CodeStubAssembler::Variable bytecode_array_; diff --git a/deps/v8/src/interpreter/interpreter-intrinsics.cc b/deps/v8/src/interpreter/interpreter-intrinsics.cc new file mode 100644 index 0000000000..6d9917de4f --- /dev/null +++ b/deps/v8/src/interpreter/interpreter-intrinsics.cc @@ -0,0 +1,159 @@ +// Copyright 2015 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "src/interpreter/interpreter-intrinsics.h" + +namespace v8 { +namespace internal { +namespace interpreter { + +using compiler::Node; + +#define __ assembler_-> + +IntrinsicsHelper::IntrinsicsHelper(InterpreterAssembler* assembler) + : assembler_(assembler) {} + +bool IntrinsicsHelper::IsSupported(Runtime::FunctionId function_id) { + switch (function_id) { +#define SUPPORTED(name, lower_case, count) case Runtime::kInline##name: + INTRINSICS_LIST(SUPPORTED) + return true; +#undef SUPPORTED + default: + return false; + } +} + +Node* IntrinsicsHelper::InvokeIntrinsic(Node* function_id, Node* context, + Node* first_arg_reg, Node* arg_count) { + InterpreterAssembler::Label abort(assembler_), end(assembler_); + InterpreterAssembler::Variable result(assembler_, + MachineRepresentation::kTagged); + +#define MAKE_LABEL(name, lower_case, count) \ + InterpreterAssembler::Label lower_case(assembler_); + INTRINSICS_LIST(MAKE_LABEL) +#undef MAKE_LABEL + +#define LABEL_POINTER(name, lower_case, count) &lower_case, + InterpreterAssembler::Label* labels[] = {INTRINSICS_LIST(LABEL_POINTER)}; +#undef LABEL_POINTER + +#define CASE(name, lower_case, count) \ + static_cast<int32_t>(Runtime::kInline##name), + int32_t cases[] = {INTRINSICS_LIST(CASE)}; +#undef CASE + + __ Switch(function_id, &abort, cases, labels, arraysize(cases)); +#define HANDLE_CASE(name, lower_case, expected_arg_count) \ + __ Bind(&lower_case); \ + if (FLAG_debug_code) { \ + AbortIfArgCountMismatch(expected_arg_count, arg_count); \ + } \ + result.Bind(name(first_arg_reg)); \ + __ Goto(&end); + INTRINSICS_LIST(HANDLE_CASE) +#undef HANDLE_CASE + + __ Bind(&abort); + __ Abort(BailoutReason::kUnexpectedFunctionIDForInvokeIntrinsic); + result.Bind(__ UndefinedConstant()); + __ Goto(&end); + + __ Bind(&end); + return result.value(); +} + +Node* IntrinsicsHelper::CompareInstanceType(Node* map, int type, + InstanceTypeCompareMode mode) { + InterpreterAssembler::Variable return_value(assembler_, + MachineRepresentation::kTagged); + Node* instance_type = __ LoadInstanceType(map); + + InterpreterAssembler::Label if_true(assembler_), if_false(assembler_), + end(assembler_); + Node* condition; + if (mode == kInstanceTypeEqual) { + condition = __ Word32Equal(instance_type, __ Int32Constant(type)); + } else { + DCHECK(mode == kInstanceTypeGreaterThanOrEqual); + condition = + __ Int32GreaterThanOrEqual(instance_type, __ Int32Constant(type)); + } + __ Branch(condition, &if_true, &if_false); + + __ Bind(&if_true); + return_value.Bind(__ BooleanConstant(true)); + __ Goto(&end); + + __ Bind(&if_false); + return_value.Bind(__ BooleanConstant(false)); + __ Goto(&end); + + __ Bind(&end); + return return_value.value(); +} + +Node* IntrinsicsHelper::IsJSReceiver(Node* input) { + InterpreterAssembler::Variable return_value(assembler_, + MachineRepresentation::kTagged); + + InterpreterAssembler::Label if_smi(assembler_), if_not_smi(assembler_), + end(assembler_); + Node* arg = __ LoadRegister(input); + + __ Branch(__ WordIsSmi(arg), &if_smi, &if_not_smi); + __ Bind(&if_smi); + return_value.Bind(__ BooleanConstant(false)); + __ Goto(&end); + + __ Bind(&if_not_smi); + STATIC_ASSERT(LAST_TYPE == LAST_JS_RECEIVER_TYPE); + return_value.Bind(CompareInstanceType(arg, FIRST_JS_RECEIVER_TYPE, + kInstanceTypeGreaterThanOrEqual)); + __ Goto(&end); + + __ Bind(&end); + return return_value.value(); +} + +Node* IntrinsicsHelper::IsArray(Node* input) { + InterpreterAssembler::Variable return_value(assembler_, + MachineRepresentation::kTagged); + + InterpreterAssembler::Label if_smi(assembler_), if_not_smi(assembler_), + end(assembler_); + Node* arg = __ LoadRegister(input); + + __ Branch(__ WordIsSmi(arg), &if_smi, &if_not_smi); + __ Bind(&if_smi); + return_value.Bind(__ BooleanConstant(false)); + __ Goto(&end); + + __ Bind(&if_not_smi); + return_value.Bind( + CompareInstanceType(arg, JS_ARRAY_TYPE, kInstanceTypeEqual)); + __ Goto(&end); + + __ Bind(&end); + return return_value.value(); +} + +void IntrinsicsHelper::AbortIfArgCountMismatch(int expected, Node* actual) { + InterpreterAssembler::Label match(assembler_), mismatch(assembler_), + end(assembler_); + Node* comparison = __ Word32Equal(actual, __ Int32Constant(expected)); + __ Branch(comparison, &match, &mismatch); + __ Bind(&mismatch); + __ Abort(kWrongArgumentCountForInvokeIntrinsic); + __ Goto(&end); + __ Bind(&match); + __ Goto(&end); + __ Bind(&end); +} + +} // namespace interpreter +} // namespace internal +} // namespace v8 diff --git a/deps/v8/src/interpreter/interpreter-intrinsics.h b/deps/v8/src/interpreter/interpreter-intrinsics.h new file mode 100644 index 0000000000..e27c678e25 --- /dev/null +++ b/deps/v8/src/interpreter/interpreter-intrinsics.h @@ -0,0 +1,62 @@ +// Copyright 2015 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef V8_INTERPRETER_INTERPRETER_INTRINSICS_H_ +#define V8_INTERPRETER_INTERPRETER_INTRINSICS_H_ + +#include "src/allocation.h" +#include "src/base/smart-pointers.h" +#include "src/builtins.h" +#include "src/frames.h" +#include "src/interpreter/bytecodes.h" +#include "src/interpreter/interpreter-assembler.h" +#include "src/runtime/runtime.h" + +namespace v8 { +namespace internal { + +namespace compiler { +class Node; +} // namespace compiler + +#define INTRINSICS_LIST(V) \ + V(IsJSReceiver, is_js_receiver, 1) \ + V(IsArray, is_array, 1) + +namespace interpreter { + +class IntrinsicsHelper { + public: + explicit IntrinsicsHelper(InterpreterAssembler* assembler); + + compiler::Node* InvokeIntrinsic(compiler::Node* function_id, + compiler::Node* context, + compiler::Node* first_arg_reg, + compiler::Node* arg_count); + + static bool IsSupported(Runtime::FunctionId function_id); + + private: + enum InstanceTypeCompareMode { + kInstanceTypeEqual, + kInstanceTypeGreaterThanOrEqual + }; + compiler::Node* CompareInstanceType(compiler::Node* map, int type, + InstanceTypeCompareMode mode); + void AbortIfArgCountMismatch(int expected, compiler::Node* actual); + InterpreterAssembler* assembler_; + +#define DECLARE_INTRINSIC_HELPER(name, lower_case, count) \ + compiler::Node* name(compiler::Node* input); + INTRINSICS_LIST(DECLARE_INTRINSIC_HELPER) +#undef DECLARE_INTRINSIC_HELPER + + DISALLOW_COPY_AND_ASSIGN(IntrinsicsHelper); +}; + +} // namespace interpreter +} // namespace internal +} // namespace v8 + +#endif diff --git a/deps/v8/src/interpreter/interpreter.cc b/deps/v8/src/interpreter/interpreter.cc index eb883427bb..5084300dfe 100644 --- a/deps/v8/src/interpreter/interpreter.cc +++ b/deps/v8/src/interpreter/interpreter.cc @@ -11,6 +11,8 @@ #include "src/interpreter/bytecode-generator.h" #include "src/interpreter/bytecodes.h" #include "src/interpreter/interpreter-assembler.h" +#include "src/interpreter/interpreter-intrinsics.h" +#include "src/log.h" #include "src/zone.h" namespace v8 { @@ -22,30 +24,69 @@ using compiler::Node; #define __ assembler-> Interpreter::Interpreter(Isolate* isolate) : isolate_(isolate) { - memset(&dispatch_table_, 0, sizeof(dispatch_table_)); + memset(dispatch_table_, 0, sizeof(dispatch_table_)); } void Interpreter::Initialize() { DCHECK(FLAG_ignition); if (IsDispatchTableInitialized()) return; - Zone zone; + Zone zone(isolate_->allocator()); HandleScope scope(isolate_); -#define GENERATE_CODE(Name, ...) \ - { \ - InterpreterAssembler assembler(isolate_, &zone, Bytecode::k##Name); \ - Do##Name(&assembler); \ - Handle<Code> code = assembler.GenerateCode(); \ - TraceCodegen(code, #Name); \ - dispatch_table_[Bytecodes::ToByte(Bytecode::k##Name)] = *code; \ + // Generate bytecode handlers for all bytecodes and scales. + for (OperandScale operand_scale = OperandScale::kSingle; + operand_scale <= OperandScale::kMaxValid; + operand_scale = Bytecodes::NextOperandScale(operand_scale)) { +#define GENERATE_CODE(Name, ...) \ + { \ + if (Bytecodes::BytecodeHasHandler(Bytecode::k##Name, operand_scale)) { \ + InterpreterAssembler assembler(isolate_, &zone, Bytecode::k##Name, \ + operand_scale); \ + Do##Name(&assembler); \ + Handle<Code> code = assembler.GenerateCode(); \ + size_t index = GetDispatchTableIndex(Bytecode::k##Name, operand_scale); \ + dispatch_table_[index] = *code; \ + TraceCodegen(code); \ + LOG_CODE_EVENT( \ + isolate_, \ + CodeCreateEvent( \ + Logger::BYTECODE_HANDLER_TAG, AbstractCode::cast(*code), \ + Bytecodes::ToString(Bytecode::k##Name, operand_scale).c_str())); \ + } \ } - BYTECODE_LIST(GENERATE_CODE) + BYTECODE_LIST(GENERATE_CODE) #undef GENERATE_CODE + } + + // Fill unused entries will the illegal bytecode handler. + size_t illegal_index = + GetDispatchTableIndex(Bytecode::kIllegal, OperandScale::kSingle); + for (size_t index = 0; index < arraysize(dispatch_table_); ++index) { + if (dispatch_table_[index] == nullptr) { + dispatch_table_[index] = dispatch_table_[illegal_index]; + } + } } -Code* Interpreter::GetBytecodeHandler(Bytecode bytecode) { +Code* Interpreter::GetBytecodeHandler(Bytecode bytecode, + OperandScale operand_scale) { DCHECK(IsDispatchTableInitialized()); - return dispatch_table_[Bytecodes::ToByte(bytecode)]; + DCHECK(Bytecodes::BytecodeHasHandler(bytecode, operand_scale)); + size_t index = GetDispatchTableIndex(bytecode, operand_scale); + return dispatch_table_[index]; +} + +// static +size_t Interpreter::GetDispatchTableIndex(Bytecode bytecode, + OperandScale operand_scale) { + static const size_t kEntriesPerOperandScale = 1u << kBitsPerByte; + size_t index = static_cast<size_t>(bytecode); + OperandScale current_scale = OperandScale::kSingle; + while (current_scale != operand_scale) { + index += kEntriesPerOperandScale; + current_scale = Bytecodes::NextOperandScale(current_scale); + } + return index; } void Interpreter::IterateDispatchTable(ObjectVisitor* v) { @@ -62,6 +103,9 @@ int Interpreter::InterruptBudget() { } bool Interpreter::MakeBytecode(CompilationInfo* info) { + TimerEventScope<TimerEventCompileIgnition> timer(info->isolate()); + TRACE_EVENT0("v8", "V8.CompileIgnition"); + if (FLAG_print_bytecode || FLAG_print_source || FLAG_print_ast) { OFStream os(stdout); base::SmartArrayPointer<char> name = info->GetDebugName(); @@ -88,8 +132,10 @@ bool Interpreter::MakeBytecode(CompilationInfo* info) { #endif // DEBUG BytecodeGenerator generator(info->isolate(), info->zone()); - info->EnsureFeedbackVector(); Handle<BytecodeArray> bytecodes = generator.MakeBytecode(info); + + if (generator.HasStackOverflow()) return false; + if (FLAG_print_bytecode) { OFStream os(stdout); bytecodes->Print(os); @@ -102,23 +148,36 @@ bool Interpreter::MakeBytecode(CompilationInfo* info) { } bool Interpreter::IsDispatchTableInitialized() { - if (FLAG_trace_ignition) { - // Regenerate table to add bytecode tracing operations. + if (FLAG_trace_ignition || FLAG_trace_ignition_codegen) { + // Regenerate table to add bytecode tracing operations + // or to print the assembly code generated by TurboFan. return false; } return dispatch_table_[0] != nullptr; } -void Interpreter::TraceCodegen(Handle<Code> code, const char* name) { +void Interpreter::TraceCodegen(Handle<Code> code) { #ifdef ENABLE_DISASSEMBLER if (FLAG_trace_ignition_codegen) { OFStream os(stdout); - code->Disassemble(name, os); + code->Disassemble(nullptr, os); os << std::flush; } #endif // ENABLE_DISASSEMBLER } +const char* Interpreter::LookupNameOfBytecodeHandler(Code* code) { +#ifdef ENABLE_DISASSEMBLER +#define RETURN_NAME(Name, ...) \ + if (dispatch_table_[Bytecodes::ToByte(Bytecode::k##Name)] == code) { \ + return #Name; \ + } + BYTECODE_LIST(RETURN_NAME) +#undef RETURN_NAME +#endif // ENABLE_DISASSEMBLER + return nullptr; +} + // LdaZero // // Load literal '0' into the accumulator. @@ -128,11 +187,10 @@ void Interpreter::DoLdaZero(InterpreterAssembler* assembler) { __ Dispatch(); } - -// LdaSmi8 <imm8> +// LdaSmi <imm> // -// Load an 8-bit integer literal into the accumulator as a Smi. -void Interpreter::DoLdaSmi8(InterpreterAssembler* assembler) { +// Load an integer literal into the accumulator as a Smi. +void Interpreter::DoLdaSmi(InterpreterAssembler* assembler) { Node* raw_int = __ BytecodeOperandImm(0); Node* smi_int = __ SmiTag(raw_int); __ SetAccumulator(smi_int); @@ -154,15 +212,6 @@ void Interpreter::DoLdaConstant(InterpreterAssembler* assembler) { DoLoadConstant(assembler); } - -// LdaConstantWide <idx> -// -// Load constant literal at |idx| in the constant pool into the accumulator. -void Interpreter::DoLdaConstantWide(InterpreterAssembler* assembler) { - DoLoadConstant(assembler); -} - - // LdaUndefined // // Load Undefined into the accumulator. @@ -248,13 +297,6 @@ void Interpreter::DoMov(InterpreterAssembler* assembler) { } -// MovWide <src> <dst> -// -// Stores the value of register <src> to register <dst>. -void Interpreter::DoMovWide(InterpreterAssembler* assembler) { - DoMov(assembler); -} - void Interpreter::DoLoadGlobal(Callable ic, InterpreterAssembler* assembler) { // Get the global object. Node* context = __ GetContext(); @@ -295,27 +337,6 @@ void Interpreter::DoLdaGlobalInsideTypeof(InterpreterAssembler* assembler) { DoLoadGlobal(ic, assembler); } -// LdaGlobalWide <name_index> <slot> -// -// Load the global with name in constant pool entry <name_index> into the -// accumulator using FeedBackVector slot <slot> outside of a typeof. -void Interpreter::DoLdaGlobalWide(InterpreterAssembler* assembler) { - Callable ic = CodeFactory::LoadICInOptimizedCode(isolate_, NOT_INSIDE_TYPEOF, - UNINITIALIZED); - DoLoadGlobal(ic, assembler); -} - -// LdaGlobalInsideTypeofWide <name_index> <slot> -// -// Load the global with name in constant pool entry <name_index> into the -// accumulator using FeedBackVector slot <slot> inside of a typeof. -void Interpreter::DoLdaGlobalInsideTypeofWide(InterpreterAssembler* assembler) { - Callable ic = CodeFactory::LoadICInOptimizedCode(isolate_, INSIDE_TYPEOF, - UNINITIALIZED); - DoLoadGlobal(ic, assembler); -} - - void Interpreter::DoStoreGlobal(Callable ic, InterpreterAssembler* assembler) { // Get the global object. Node* context = __ GetContext(); @@ -333,7 +354,6 @@ void Interpreter::DoStoreGlobal(Callable ic, InterpreterAssembler* assembler) { Node* type_feedback_vector = __ LoadTypeFeedbackVector(); __ CallStub(ic.descriptor(), code_target, context, global, name, value, smi_slot, type_feedback_vector); - __ Dispatch(); } @@ -359,29 +379,6 @@ void Interpreter::DoStaGlobalStrict(InterpreterAssembler* assembler) { DoStoreGlobal(ic, assembler); } - -// StaGlobalSloppyWide <name_index> <slot> -// -// Store the value in the accumulator into the global with name in constant pool -// entry <name_index> using FeedBackVector slot <slot> in sloppy mode. -void Interpreter::DoStaGlobalSloppyWide(InterpreterAssembler* assembler) { - Callable ic = - CodeFactory::StoreICInOptimizedCode(isolate_, SLOPPY, UNINITIALIZED); - DoStoreGlobal(ic, assembler); -} - - -// StaGlobalStrictWide <name_index> <slot> -// -// Store the value in the accumulator into the global with name in constant pool -// entry <name_index> using FeedBackVector slot <slot> in strict mode. -void Interpreter::DoStaGlobalStrictWide(InterpreterAssembler* assembler) { - Callable ic = - CodeFactory::StoreICInOptimizedCode(isolate_, STRICT, UNINITIALIZED); - DoStoreGlobal(ic, assembler); -} - - // LdaContextSlot <context> <slot_index> // // Load the object in |slot_index| of |context| into the accumulator. @@ -394,15 +391,6 @@ void Interpreter::DoLdaContextSlot(InterpreterAssembler* assembler) { __ Dispatch(); } - -// LdaContextSlotWide <context> <slot_index> -// -// Load the object in |slot_index| of |context| into the accumulator. -void Interpreter::DoLdaContextSlotWide(InterpreterAssembler* assembler) { - DoLdaContextSlot(assembler); -} - - // StaContextSlot <context> <slot_index> // // Stores the object in the accumulator into |slot_index| of |context|. @@ -415,14 +403,6 @@ void Interpreter::DoStaContextSlot(InterpreterAssembler* assembler) { __ Dispatch(); } - -// StaContextSlot <context> <slot_index> -// -// Stores the object in the accumulator into |slot_index| of |context|. -void Interpreter::DoStaContextSlotWide(InterpreterAssembler* assembler) { - DoStaContextSlot(assembler); -} - void Interpreter::DoLoadLookupSlot(Runtime::FunctionId function_id, InterpreterAssembler* assembler) { Node* index = __ BytecodeOperandIdx(0); @@ -433,7 +413,6 @@ void Interpreter::DoLoadLookupSlot(Runtime::FunctionId function_id, __ Dispatch(); } - // LdaLookupSlot <name_index> // // Lookup the object with the name in constant pool entry |name_index| @@ -442,7 +421,6 @@ void Interpreter::DoLdaLookupSlot(InterpreterAssembler* assembler) { DoLoadLookupSlot(Runtime::kLoadLookupSlot, assembler); } - // LdaLookupSlotInsideTypeof <name_index> // // Lookup the object with the name in constant pool entry |name_index| @@ -451,25 +429,6 @@ void Interpreter::DoLdaLookupSlotInsideTypeof(InterpreterAssembler* assembler) { DoLoadLookupSlot(Runtime::kLoadLookupSlotInsideTypeof, assembler); } - -// LdaLookupSlotWide <name_index> -// -// Lookup the object with the name in constant pool entry |name_index| -// dynamically. -void Interpreter::DoLdaLookupSlotWide(InterpreterAssembler* assembler) { - DoLdaLookupSlot(assembler); -} - - -// LdaLookupSlotInsideTypeofWide <name_index> -// -// Lookup the object with the name in constant pool entry |name_index| -// dynamically without causing a NoReferenceError. -void Interpreter::DoLdaLookupSlotInsideTypeofWide( - InterpreterAssembler* assembler) { - DoLdaLookupSlotInsideTypeof(assembler); -} - void Interpreter::DoStoreLookupSlot(LanguageMode language_mode, InterpreterAssembler* assembler) { Node* value = __ GetAccumulator(); @@ -484,7 +443,6 @@ void Interpreter::DoStoreLookupSlot(LanguageMode language_mode, __ Dispatch(); } - // StaLookupSlotSloppy <name_index> // // Store the object in accumulator to the object with the name in constant @@ -502,24 +460,6 @@ void Interpreter::DoStaLookupSlotStrict(InterpreterAssembler* assembler) { DoStoreLookupSlot(LanguageMode::STRICT, assembler); } - -// StaLookupSlotSloppyWide <name_index> -// -// Store the object in accumulator to the object with the name in constant -// pool entry |name_index| in sloppy mode. -void Interpreter::DoStaLookupSlotSloppyWide(InterpreterAssembler* assembler) { - DoStaLookupSlotSloppy(assembler); -} - - -// StaLookupSlotStrictWide <name_index> -// -// Store the object in accumulator to the object with the name in constant -// pool entry |name_index| in strict mode. -void Interpreter::DoStaLookupSlotStrictWide(InterpreterAssembler* assembler) { - DoStaLookupSlotStrict(assembler); -} - void Interpreter::DoLoadIC(Callable ic, InterpreterAssembler* assembler) { Node* code_target = __ HeapConstant(ic.code()); Node* register_index = __ BytecodeOperandReg(0); @@ -546,17 +486,6 @@ void Interpreter::DoLoadIC(InterpreterAssembler* assembler) { DoLoadIC(ic, assembler); } -// LoadICWide <object> <name_index> <slot> -// -// Calls the LoadIC at FeedBackVector slot <slot> for <object> and the name at -// constant pool entry <name_index>. -void Interpreter::DoLoadICWide(InterpreterAssembler* assembler) { - Callable ic = CodeFactory::LoadICInOptimizedCode(isolate_, NOT_INSIDE_TYPEOF, - UNINITIALIZED); - DoLoadIC(ic, assembler); -} - - void Interpreter::DoKeyedLoadIC(Callable ic, InterpreterAssembler* assembler) { Node* code_target = __ HeapConstant(ic.code()); Node* reg_index = __ BytecodeOperandReg(0); @@ -582,17 +511,6 @@ void Interpreter::DoKeyedLoadIC(InterpreterAssembler* assembler) { DoKeyedLoadIC(ic, assembler); } -// KeyedLoadICWide <object> <slot> -// -// Calls the KeyedLoadIC at FeedBackVector slot <slot> for <object> and the key -// in the accumulator. -void Interpreter::DoKeyedLoadICWide(InterpreterAssembler* assembler) { - Callable ic = - CodeFactory::KeyedLoadICInOptimizedCode(isolate_, UNINITIALIZED); - DoKeyedLoadIC(ic, assembler); -} - - void Interpreter::DoStoreIC(Callable ic, InterpreterAssembler* assembler) { Node* code_target = __ HeapConstant(ic.code()); Node* object_reg_index = __ BytecodeOperandReg(0); @@ -633,30 +551,6 @@ void Interpreter::DoStoreICStrict(InterpreterAssembler* assembler) { DoStoreIC(ic, assembler); } - -// StoreICSloppyWide <object> <name_index> <slot> -// -// Calls the sloppy mode StoreIC at FeedBackVector slot <slot> for <object> and -// the name in constant pool entry <name_index> with the value in the -// accumulator. -void Interpreter::DoStoreICSloppyWide(InterpreterAssembler* assembler) { - Callable ic = - CodeFactory::StoreICInOptimizedCode(isolate_, SLOPPY, UNINITIALIZED); - DoStoreIC(ic, assembler); -} - - -// StoreICStrictWide <object> <name_index> <slot> -// -// Calls the strict mode StoreIC at FeedBackVector slot <slot> for <object> and -// the name in constant pool entry <name_index> with the value in the -// accumulator. -void Interpreter::DoStoreICStrictWide(InterpreterAssembler* assembler) { - Callable ic = - CodeFactory::StoreICInOptimizedCode(isolate_, STRICT, UNINITIALIZED); - DoStoreIC(ic, assembler); -} - void Interpreter::DoKeyedStoreIC(Callable ic, InterpreterAssembler* assembler) { Node* code_target = __ HeapConstant(ic.code()); Node* object_reg_index = __ BytecodeOperandReg(0); @@ -695,28 +589,6 @@ void Interpreter::DoKeyedStoreICStrict(InterpreterAssembler* assembler) { DoKeyedStoreIC(ic, assembler); } - -// KeyedStoreICSloppyWide <object> <key> <slot> -// -// Calls the sloppy mode KeyStoreIC at FeedBackVector slot <slot> for <object> -// and the key <key> with the value in the accumulator. -void Interpreter::DoKeyedStoreICSloppyWide(InterpreterAssembler* assembler) { - Callable ic = - CodeFactory::KeyedStoreICInOptimizedCode(isolate_, SLOPPY, UNINITIALIZED); - DoKeyedStoreIC(ic, assembler); -} - - -// KeyedStoreICStoreWide <object> <key> <slot> -// -// Calls the strict mode KeyStoreIC at FeedBackVector slot <slot> for <object> -// and the key <key> with the value in the accumulator. -void Interpreter::DoKeyedStoreICStrictWide(InterpreterAssembler* assembler) { - Callable ic = - CodeFactory::KeyedStoreICInOptimizedCode(isolate_, STRICT, UNINITIALIZED); - DoKeyedStoreIC(ic, assembler); -} - // PushContext <context> // // Saves the current context in <context>, and pushes the accumulator as the @@ -741,6 +613,20 @@ void Interpreter::DoPopContext(InterpreterAssembler* assembler) { __ Dispatch(); } +void Interpreter::DoBinaryOp(Callable callable, + InterpreterAssembler* assembler) { + // TODO(bmeurer): Collect definition side type feedback for various + // binary operations. + Node* target = __ HeapConstant(callable.code()); + Node* reg_index = __ BytecodeOperandReg(0); + Node* lhs = __ LoadRegister(reg_index); + Node* rhs = __ GetAccumulator(); + Node* context = __ GetContext(); + Node* result = __ CallStub(callable.descriptor(), target, context, lhs, rhs); + __ SetAccumulator(result); + __ Dispatch(); +} + void Interpreter::DoBinaryOp(Runtime::FunctionId function_id, InterpreterAssembler* assembler) { // TODO(rmcilroy): Call ICs which back-patch bytecode with type specialized @@ -759,7 +645,7 @@ void Interpreter::DoBinaryOp(Runtime::FunctionId function_id, // // Add register <src> to accumulator. void Interpreter::DoAdd(InterpreterAssembler* assembler) { - DoBinaryOp(Runtime::kAdd, assembler); + DoBinaryOp(CodeFactory::Add(isolate_), assembler); } @@ -767,7 +653,7 @@ void Interpreter::DoAdd(InterpreterAssembler* assembler) { // // Subtract register <src> from accumulator. void Interpreter::DoSub(InterpreterAssembler* assembler) { - DoBinaryOp(Runtime::kSubtract, assembler); + DoBinaryOp(CodeFactory::Subtract(isolate_), assembler); } @@ -799,7 +685,7 @@ void Interpreter::DoMod(InterpreterAssembler* assembler) { // // BitwiseOr register <src> to accumulator. void Interpreter::DoBitwiseOr(InterpreterAssembler* assembler) { - DoBinaryOp(Runtime::kBitwiseOr, assembler); + DoBinaryOp(CodeFactory::BitwiseOr(isolate_), assembler); } @@ -807,7 +693,7 @@ void Interpreter::DoBitwiseOr(InterpreterAssembler* assembler) { // // BitwiseXor register <src> to accumulator. void Interpreter::DoBitwiseXor(InterpreterAssembler* assembler) { - DoBinaryOp(Runtime::kBitwiseXor, assembler); + DoBinaryOp(CodeFactory::BitwiseXor(isolate_), assembler); } @@ -815,7 +701,7 @@ void Interpreter::DoBitwiseXor(InterpreterAssembler* assembler) { // // BitwiseAnd register <src> to accumulator. void Interpreter::DoBitwiseAnd(InterpreterAssembler* assembler) { - DoBinaryOp(Runtime::kBitwiseAnd, assembler); + DoBinaryOp(CodeFactory::BitwiseAnd(isolate_), assembler); } @@ -883,24 +769,40 @@ void Interpreter::DoDec(InterpreterAssembler* assembler) { // Perform logical-not on the accumulator, first casting the // accumulator to a boolean value if required. void Interpreter::DoLogicalNot(InterpreterAssembler* assembler) { + Callable callable = CodeFactory::ToBoolean(isolate_); + Node* target = __ HeapConstant(callable.code()); Node* accumulator = __ GetAccumulator(); Node* context = __ GetContext(); - Node* result = - __ CallRuntime(Runtime::kInterpreterLogicalNot, context, accumulator); - __ SetAccumulator(result); - __ Dispatch(); + Node* to_boolean_value = + __ CallStub(callable.descriptor(), target, context, accumulator); + InterpreterAssembler::Label if_true(assembler), if_false(assembler); + Node* true_value = __ BooleanConstant(true); + Node* false_value = __ BooleanConstant(false); + Node* condition = __ WordEqual(to_boolean_value, true_value); + __ Branch(condition, &if_true, &if_false); + __ Bind(&if_true); + { + __ SetAccumulator(false_value); + __ Dispatch(); + } + __ Bind(&if_false); + { + __ SetAccumulator(true_value); + __ Dispatch(); + } } - // TypeOf // // Load the accumulator with the string representating type of the // object in the accumulator. void Interpreter::DoTypeOf(InterpreterAssembler* assembler) { + Callable callable = CodeFactory::Typeof(isolate_); + Node* target = __ HeapConstant(callable.code()); Node* accumulator = __ GetAccumulator(); Node* context = __ GetContext(); Node* result = - __ CallRuntime(Runtime::kInterpreterTypeOf, context, accumulator); + __ CallStub(callable.descriptor(), target, context, accumulator); __ SetAccumulator(result); __ Dispatch(); } @@ -960,15 +862,6 @@ void Interpreter::DoCall(InterpreterAssembler* assembler) { DoJSCall(assembler, TailCallMode::kDisallow); } - -// CallWide <callable> <receiver> <arg_count> -// -// Call a JSfunction or Callable in |callable| with the |receiver| and -// |arg_count| arguments in subsequent registers. -void Interpreter::DoCallWide(InterpreterAssembler* assembler) { - DoJSCall(assembler, TailCallMode::kDisallow); -} - // TailCall <callable> <receiver> <arg_count> // // Tail call a JSfunction or Callable in |callable| with the |receiver| and @@ -977,16 +870,8 @@ void Interpreter::DoTailCall(InterpreterAssembler* assembler) { DoJSCall(assembler, TailCallMode::kAllow); } -// TailCallWide <callable> <receiver> <arg_count> -// -// Tail call a JSfunction or Callable in |callable| with the |receiver| and -// |arg_count| arguments in subsequent registers. -void Interpreter::DoTailCallWide(InterpreterAssembler* assembler) { - DoJSCall(assembler, TailCallMode::kAllow); -} - void Interpreter::DoCallRuntimeCommon(InterpreterAssembler* assembler) { - Node* function_id = __ BytecodeOperandIdx(0); + Node* function_id = __ BytecodeOperandRuntimeId(0); Node* first_arg_reg = __ BytecodeOperandReg(1); Node* first_arg = __ RegisterLocation(first_arg_reg); Node* args_count = __ BytecodeOperandCount(2); @@ -1006,19 +891,26 @@ void Interpreter::DoCallRuntime(InterpreterAssembler* assembler) { DoCallRuntimeCommon(assembler); } - -// CallRuntime <function_id> <first_arg> <arg_count> +// InvokeIntrinsic <function_id> <first_arg> <arg_count> // -// Call the runtime function |function_id| with the first argument in -// register |first_arg| and |arg_count| arguments in subsequent -// registers. -void Interpreter::DoCallRuntimeWide(InterpreterAssembler* assembler) { - DoCallRuntimeCommon(assembler); +// Implements the semantic equivalent of calling the runtime function +// |function_id| with the first argument in |first_arg| and |arg_count| +// arguments in subsequent registers. +void Interpreter::DoInvokeIntrinsic(InterpreterAssembler* assembler) { + Node* function_id = __ BytecodeOperandRuntimeId(0); + Node* first_arg_reg = __ BytecodeOperandReg(1); + Node* arg_count = __ BytecodeOperandCount(2); + Node* context = __ GetContext(); + IntrinsicsHelper helper(assembler); + Node* result = + helper.InvokeIntrinsic(function_id, context, first_arg_reg, arg_count); + __ SetAccumulator(result); + __ Dispatch(); } void Interpreter::DoCallRuntimeForPairCommon(InterpreterAssembler* assembler) { // Call the runtime function. - Node* function_id = __ BytecodeOperandIdx(0); + Node* function_id = __ BytecodeOperandRuntimeId(0); Node* first_arg_reg = __ BytecodeOperandReg(1); Node* first_arg = __ RegisterLocation(first_arg_reg); Node* args_count = __ BytecodeOperandCount(2); @@ -1047,17 +939,6 @@ void Interpreter::DoCallRuntimeForPair(InterpreterAssembler* assembler) { DoCallRuntimeForPairCommon(assembler); } - -// CallRuntimeForPairWide <function_id> <first_arg> <arg_count> <first_return> -// -// Call the runtime function |function_id| which returns a pair, with the -// first argument in register |first_arg| and |arg_count| arguments in -// subsequent registers. Returns the result in <first_return> and -// <first_return + 1> -void Interpreter::DoCallRuntimeForPairWide(InterpreterAssembler* assembler) { - DoCallRuntimeForPairCommon(assembler); -} - void Interpreter::DoCallJSRuntimeCommon(InterpreterAssembler* assembler) { Node* context_index = __ BytecodeOperandIdx(0); Node* receiver_reg = __ BytecodeOperandReg(1); @@ -1088,15 +969,6 @@ void Interpreter::DoCallJSRuntime(InterpreterAssembler* assembler) { DoCallJSRuntimeCommon(assembler); } - -// CallJSRuntimeWide <context_index> <receiver> <arg_count> -// -// Call the JS runtime function that has the |context_index| with the receiver -// in register |receiver| and |arg_count| arguments in subsequent registers. -void Interpreter::DoCallJSRuntimeWide(InterpreterAssembler* assembler) { - DoCallJSRuntimeCommon(assembler); -} - void Interpreter::DoCallConstruct(InterpreterAssembler* assembler) { Callable ic = CodeFactory::InterpreterPushArgsAndConstruct(isolate_); Node* new_target = __ GetAccumulator(); @@ -1123,23 +995,11 @@ void Interpreter::DoNew(InterpreterAssembler* assembler) { DoCallConstruct(assembler); } - -// NewWide <constructor> <first_arg> <arg_count> -// -// Call operator new with |constructor| and the first argument in -// register |first_arg| and |arg_count| arguments in subsequent -// registers. The new.target is in the accumulator. -// -void Interpreter::DoNewWide(InterpreterAssembler* assembler) { - DoCallConstruct(assembler); -} - - // TestEqual <src> // // Test if the value in the <src> register equals the accumulator. void Interpreter::DoTestEqual(InterpreterAssembler* assembler) { - DoBinaryOp(Runtime::kEqual, assembler); + DoBinaryOp(CodeFactory::Equal(isolate_), assembler); } @@ -1147,7 +1007,7 @@ void Interpreter::DoTestEqual(InterpreterAssembler* assembler) { // // Test if the value in the <src> register is not equal to the accumulator. void Interpreter::DoTestNotEqual(InterpreterAssembler* assembler) { - DoBinaryOp(Runtime::kNotEqual, assembler); + DoBinaryOp(CodeFactory::NotEqual(isolate_), assembler); } @@ -1155,16 +1015,7 @@ void Interpreter::DoTestNotEqual(InterpreterAssembler* assembler) { // // Test if the value in the <src> register is strictly equal to the accumulator. void Interpreter::DoTestEqualStrict(InterpreterAssembler* assembler) { - DoBinaryOp(Runtime::kStrictEqual, assembler); -} - - -// TestNotEqualStrict <src> -// -// Test if the value in the <src> register is not strictly equal to the -// accumulator. -void Interpreter::DoTestNotEqualStrict(InterpreterAssembler* assembler) { - DoBinaryOp(Runtime::kStrictNotEqual, assembler); + DoBinaryOp(CodeFactory::StrictEqual(isolate_), assembler); } @@ -1172,7 +1023,7 @@ void Interpreter::DoTestNotEqualStrict(InterpreterAssembler* assembler) { // // Test if the value in the <src> register is less than the accumulator. void Interpreter::DoTestLessThan(InterpreterAssembler* assembler) { - DoBinaryOp(Runtime::kLessThan, assembler); + DoBinaryOp(CodeFactory::LessThan(isolate_), assembler); } @@ -1180,7 +1031,7 @@ void Interpreter::DoTestLessThan(InterpreterAssembler* assembler) { // // Test if the value in the <src> register is greater than the accumulator. void Interpreter::DoTestGreaterThan(InterpreterAssembler* assembler) { - DoBinaryOp(Runtime::kGreaterThan, assembler); + DoBinaryOp(CodeFactory::GreaterThan(isolate_), assembler); } @@ -1189,7 +1040,7 @@ void Interpreter::DoTestGreaterThan(InterpreterAssembler* assembler) { // Test if the value in the <src> register is less than or equal to the // accumulator. void Interpreter::DoTestLessThanOrEqual(InterpreterAssembler* assembler) { - DoBinaryOp(Runtime::kLessThanOrEqual, assembler); + DoBinaryOp(CodeFactory::LessThanOrEqual(isolate_), assembler); } @@ -1198,7 +1049,7 @@ void Interpreter::DoTestLessThanOrEqual(InterpreterAssembler* assembler) { // Test if the value in the <src> register is greater than or equal to the // accumulator. void Interpreter::DoTestGreaterThanOrEqual(InterpreterAssembler* assembler) { - DoBinaryOp(Runtime::kGreaterThanOrEqual, assembler); + DoBinaryOp(CodeFactory::GreaterThanOrEqual(isolate_), assembler); } @@ -1219,16 +1070,22 @@ void Interpreter::DoTestInstanceOf(InterpreterAssembler* assembler) { DoBinaryOp(Runtime::kInstanceOf, assembler); } +void Interpreter::DoTypeConversionOp(Callable callable, + InterpreterAssembler* assembler) { + Node* target = __ HeapConstant(callable.code()); + Node* accumulator = __ GetAccumulator(); + Node* context = __ GetContext(); + Node* result = + __ CallStub(callable.descriptor(), target, context, accumulator); + __ SetAccumulator(result); + __ Dispatch(); +} // ToName // // Cast the object referenced by the accumulator to a name. void Interpreter::DoToName(InterpreterAssembler* assembler) { - Node* accumulator = __ GetAccumulator(); - Node* context = __ GetContext(); - Node* result = __ CallRuntime(Runtime::kToName, context, accumulator); - __ SetAccumulator(result); - __ Dispatch(); + DoTypeConversionOp(CodeFactory::ToName(isolate_), assembler); } @@ -1236,11 +1093,7 @@ void Interpreter::DoToName(InterpreterAssembler* assembler) { // // Cast the object referenced by the accumulator to a number. void Interpreter::DoToNumber(InterpreterAssembler* assembler) { - Node* accumulator = __ GetAccumulator(); - Node* context = __ GetContext(); - Node* result = __ CallRuntime(Runtime::kToNumber, context, accumulator); - __ SetAccumulator(result); - __ Dispatch(); + DoTypeConversionOp(CodeFactory::ToNumber(isolate_), assembler); } @@ -1248,26 +1101,20 @@ void Interpreter::DoToNumber(InterpreterAssembler* assembler) { // // Cast the object referenced by the accumulator to a JSObject. void Interpreter::DoToObject(InterpreterAssembler* assembler) { - Node* accumulator = __ GetAccumulator(); - Node* context = __ GetContext(); - Node* result = __ CallRuntime(Runtime::kToObject, context, accumulator); - __ SetAccumulator(result); - __ Dispatch(); + DoTypeConversionOp(CodeFactory::ToObject(isolate_), assembler); } - -// Jump <imm8> +// Jump <imm> // -// Jump by number of bytes represented by the immediate operand |imm8|. +// Jump by number of bytes represented by the immediate operand |imm|. void Interpreter::DoJump(InterpreterAssembler* assembler) { Node* relative_jump = __ BytecodeOperandImm(0); __ Jump(relative_jump); } - -// JumpConstant <idx8> +// JumpConstant <idx> // -// Jump by number of bytes in the Smi in the |idx8| entry in the constant pool. +// Jump by number of bytes in the Smi in the |idx| entry in the constant pool. void Interpreter::DoJumpConstant(InterpreterAssembler* assembler) { Node* index = __ BytecodeOperandIdx(0); Node* constant = __ LoadConstantPoolEntry(index); @@ -1275,17 +1122,7 @@ void Interpreter::DoJumpConstant(InterpreterAssembler* assembler) { __ Jump(relative_jump); } - -// JumpConstantWide <idx16> -// -// Jump by number of bytes in the Smi in the |idx16| entry in the -// constant pool. -void Interpreter::DoJumpConstantWide(InterpreterAssembler* assembler) { - DoJumpConstant(assembler); -} - - -// JumpIfTrue <imm8> +// JumpIfTrue <imm> // // Jump by number of bytes represented by an immediate operand if the // accumulator contains true. @@ -1296,10 +1133,9 @@ void Interpreter::DoJumpIfTrue(InterpreterAssembler* assembler) { __ JumpIfWordEqual(accumulator, true_value, relative_jump); } - -// JumpIfTrueConstant <idx8> +// JumpIfTrueConstant <idx> // -// Jump by number of bytes in the Smi in the |idx8| entry in the constant pool +// Jump by number of bytes in the Smi in the |idx| entry in the constant pool // if the accumulator contains true. void Interpreter::DoJumpIfTrueConstant(InterpreterAssembler* assembler) { Node* accumulator = __ GetAccumulator(); @@ -1310,17 +1146,7 @@ void Interpreter::DoJumpIfTrueConstant(InterpreterAssembler* assembler) { __ JumpIfWordEqual(accumulator, true_value, relative_jump); } - -// JumpIfTrueConstantWide <idx16> -// -// Jump by number of bytes in the Smi in the |idx16| entry in the constant pool -// if the accumulator contains true. -void Interpreter::DoJumpIfTrueConstantWide(InterpreterAssembler* assembler) { - DoJumpIfTrueConstant(assembler); -} - - -// JumpIfFalse <imm8> +// JumpIfFalse <imm> // // Jump by number of bytes represented by an immediate operand if the // accumulator contains false. @@ -1331,10 +1157,9 @@ void Interpreter::DoJumpIfFalse(InterpreterAssembler* assembler) { __ JumpIfWordEqual(accumulator, false_value, relative_jump); } - -// JumpIfFalseConstant <idx8> +// JumpIfFalseConstant <idx> // -// Jump by number of bytes in the Smi in the |idx8| entry in the constant pool +// Jump by number of bytes in the Smi in the |idx| entry in the constant pool // if the accumulator contains false. void Interpreter::DoJumpIfFalseConstant(InterpreterAssembler* assembler) { Node* accumulator = __ GetAccumulator(); @@ -1345,42 +1170,35 @@ void Interpreter::DoJumpIfFalseConstant(InterpreterAssembler* assembler) { __ JumpIfWordEqual(accumulator, false_value, relative_jump); } - -// JumpIfFalseConstant <idx16> -// -// Jump by number of bytes in the Smi in the |idx16| entry in the constant pool -// if the accumulator contains false. -void Interpreter::DoJumpIfFalseConstantWide(InterpreterAssembler* assembler) { - DoJumpIfFalseConstant(assembler); -} - - -// JumpIfToBooleanTrue <imm8> +// JumpIfToBooleanTrue <imm> // // Jump by number of bytes represented by an immediate operand if the object // referenced by the accumulator is true when the object is cast to boolean. void Interpreter::DoJumpIfToBooleanTrue(InterpreterAssembler* assembler) { + Callable callable = CodeFactory::ToBoolean(isolate_); + Node* target = __ HeapConstant(callable.code()); Node* accumulator = __ GetAccumulator(); Node* context = __ GetContext(); Node* to_boolean_value = - __ CallRuntime(Runtime::kInterpreterToBoolean, context, accumulator); + __ CallStub(callable.descriptor(), target, context, accumulator); Node* relative_jump = __ BytecodeOperandImm(0); Node* true_value = __ BooleanConstant(true); __ JumpIfWordEqual(to_boolean_value, true_value, relative_jump); } - -// JumpIfToBooleanTrueConstant <idx8> +// JumpIfToBooleanTrueConstant <idx> // -// Jump by number of bytes in the Smi in the |idx8| entry in the constant pool +// Jump by number of bytes in the Smi in the |idx| entry in the constant pool // if the object referenced by the accumulator is true when the object is cast // to boolean. void Interpreter::DoJumpIfToBooleanTrueConstant( InterpreterAssembler* assembler) { + Callable callable = CodeFactory::ToBoolean(isolate_); + Node* target = __ HeapConstant(callable.code()); Node* accumulator = __ GetAccumulator(); Node* context = __ GetContext(); Node* to_boolean_value = - __ CallRuntime(Runtime::kInterpreterToBoolean, context, accumulator); + __ CallStub(callable.descriptor(), target, context, accumulator); Node* index = __ BytecodeOperandIdx(0); Node* constant = __ LoadConstantPoolEntry(index); Node* relative_jump = __ SmiUntag(constant); @@ -1388,44 +1206,35 @@ void Interpreter::DoJumpIfToBooleanTrueConstant( __ JumpIfWordEqual(to_boolean_value, true_value, relative_jump); } - -// JumpIfToBooleanTrueConstantWide <idx16> -// -// Jump by number of bytes in the Smi in the |idx16| entry in the constant pool -// if the object referenced by the accumulator is true when the object is cast -// to boolean. -void Interpreter::DoJumpIfToBooleanTrueConstantWide( - InterpreterAssembler* assembler) { - DoJumpIfToBooleanTrueConstant(assembler); -} - - -// JumpIfToBooleanFalse <imm8> +// JumpIfToBooleanFalse <imm> // // Jump by number of bytes represented by an immediate operand if the object // referenced by the accumulator is false when the object is cast to boolean. void Interpreter::DoJumpIfToBooleanFalse(InterpreterAssembler* assembler) { + Callable callable = CodeFactory::ToBoolean(isolate_); + Node* target = __ HeapConstant(callable.code()); Node* accumulator = __ GetAccumulator(); Node* context = __ GetContext(); Node* to_boolean_value = - __ CallRuntime(Runtime::kInterpreterToBoolean, context, accumulator); + __ CallStub(callable.descriptor(), target, context, accumulator); Node* relative_jump = __ BytecodeOperandImm(0); Node* false_value = __ BooleanConstant(false); __ JumpIfWordEqual(to_boolean_value, false_value, relative_jump); } - -// JumpIfToBooleanFalseConstant <idx8> +// JumpIfToBooleanFalseConstant <idx> // -// Jump by number of bytes in the Smi in the |idx8| entry in the constant pool +// Jump by number of bytes in the Smi in the |idx| entry in the constant pool // if the object referenced by the accumulator is false when the object is cast // to boolean. void Interpreter::DoJumpIfToBooleanFalseConstant( InterpreterAssembler* assembler) { + Callable callable = CodeFactory::ToBoolean(isolate_); + Node* target = __ HeapConstant(callable.code()); Node* accumulator = __ GetAccumulator(); Node* context = __ GetContext(); Node* to_boolean_value = - __ CallRuntime(Runtime::kInterpreterToBoolean, context, accumulator); + __ CallStub(callable.descriptor(), target, context, accumulator); Node* index = __ BytecodeOperandIdx(0); Node* constant = __ LoadConstantPoolEntry(index); Node* relative_jump = __ SmiUntag(constant); @@ -1433,19 +1242,7 @@ void Interpreter::DoJumpIfToBooleanFalseConstant( __ JumpIfWordEqual(to_boolean_value, false_value, relative_jump); } - -// JumpIfToBooleanFalseConstantWide <idx16> -// -// Jump by number of bytes in the Smi in the |idx16| entry in the constant pool -// if the object referenced by the accumulator is false when the object is cast -// to boolean. -void Interpreter::DoJumpIfToBooleanFalseConstantWide( - InterpreterAssembler* assembler) { - DoJumpIfToBooleanFalseConstant(assembler); -} - - -// JumpIfNull <imm8> +// JumpIfNull <imm> // // Jump by number of bytes represented by an immediate operand if the object // referenced by the accumulator is the null constant. @@ -1456,10 +1253,9 @@ void Interpreter::DoJumpIfNull(InterpreterAssembler* assembler) { __ JumpIfWordEqual(accumulator, null_value, relative_jump); } - -// JumpIfNullConstant <idx8> +// JumpIfNullConstant <idx> // -// Jump by number of bytes in the Smi in the |idx8| entry in the constant pool +// Jump by number of bytes in the Smi in the |idx| entry in the constant pool // if the object referenced by the accumulator is the null constant. void Interpreter::DoJumpIfNullConstant(InterpreterAssembler* assembler) { Node* accumulator = __ GetAccumulator(); @@ -1470,16 +1266,7 @@ void Interpreter::DoJumpIfNullConstant(InterpreterAssembler* assembler) { __ JumpIfWordEqual(accumulator, null_value, relative_jump); } - -// JumpIfNullConstantWide <idx16> -// -// Jump by number of bytes in the Smi in the |idx16| entry in the constant pool -// if the object referenced by the accumulator is the null constant. -void Interpreter::DoJumpIfNullConstantWide(InterpreterAssembler* assembler) { - DoJumpIfNullConstant(assembler); -} - -// JumpIfUndefined <imm8> +// JumpIfUndefined <imm> // // Jump by number of bytes represented by an immediate operand if the object // referenced by the accumulator is the undefined constant. @@ -1491,10 +1278,9 @@ void Interpreter::DoJumpIfUndefined(InterpreterAssembler* assembler) { __ JumpIfWordEqual(accumulator, undefined_value, relative_jump); } - -// JumpIfUndefinedConstant <idx8> +// JumpIfUndefinedConstant <idx> // -// Jump by number of bytes in the Smi in the |idx8| entry in the constant pool +// Jump by number of bytes in the Smi in the |idx| entry in the constant pool // if the object referenced by the accumulator is the undefined constant. void Interpreter::DoJumpIfUndefinedConstant(InterpreterAssembler* assembler) { Node* accumulator = __ GetAccumulator(); @@ -1506,17 +1292,7 @@ void Interpreter::DoJumpIfUndefinedConstant(InterpreterAssembler* assembler) { __ JumpIfWordEqual(accumulator, undefined_value, relative_jump); } - -// JumpIfUndefinedConstantWide <idx16> -// -// Jump by number of bytes in the Smi in the |idx16| entry in the constant pool -// if the object referenced by the accumulator is the undefined constant. -void Interpreter::DoJumpIfUndefinedConstantWide( - InterpreterAssembler* assembler) { - DoJumpIfUndefinedConstant(assembler); -} - -// JumpIfNotHole <imm8> +// JumpIfNotHole <imm> // // Jump by number of bytes represented by an immediate operand if the object // referenced by the accumulator is the hole. @@ -1527,9 +1303,9 @@ void Interpreter::DoJumpIfNotHole(InterpreterAssembler* assembler) { __ JumpIfWordNotEqual(accumulator, the_hole_value, relative_jump); } -// JumpIfNotHoleConstant <idx8> +// JumpIfNotHoleConstant <idx> // -// Jump by number of bytes in the Smi in the |idx8| entry in the constant pool +// Jump by number of bytes in the Smi in the |idx| entry in the constant pool // if the object referenced by the accumulator is the hole constant. void Interpreter::DoJumpIfNotHoleConstant(InterpreterAssembler* assembler) { Node* accumulator = __ GetAccumulator(); @@ -1540,21 +1316,13 @@ void Interpreter::DoJumpIfNotHoleConstant(InterpreterAssembler* assembler) { __ JumpIfWordNotEqual(accumulator, the_hole_value, relative_jump); } -// JumpIfNotHoleConstantWide <idx16> -// -// Jump by number of bytes in the Smi in the |idx16| entry in the constant pool -// if the object referenced by the accumulator is the hole constant. -void Interpreter::DoJumpIfNotHoleConstantWide(InterpreterAssembler* assembler) { - DoJumpIfNotHoleConstant(assembler); -} - void Interpreter::DoCreateLiteral(Runtime::FunctionId function_id, InterpreterAssembler* assembler) { Node* index = __ BytecodeOperandIdx(0); Node* constant_elements = __ LoadConstantPoolEntry(index); Node* literal_index_raw = __ BytecodeOperandIdx(1); Node* literal_index = __ SmiTag(literal_index_raw); - Node* flags_raw = __ BytecodeOperandImm(2); + Node* flags_raw = __ BytecodeOperandFlag(2); Node* flags = __ SmiTag(flags_raw); Node* closure = __ LoadRegister(Register::function_closure()); Node* context = __ GetContext(); @@ -1570,19 +1338,22 @@ void Interpreter::DoCreateLiteral(Runtime::FunctionId function_id, // Creates a regular expression literal for literal index <literal_idx> with // <flags> and the pattern in <pattern_idx>. void Interpreter::DoCreateRegExpLiteral(InterpreterAssembler* assembler) { - DoCreateLiteral(Runtime::kCreateRegExpLiteral, assembler); -} - - -// CreateRegExpLiteralWide <pattern_idx> <literal_idx> <flags> -// -// Creates a regular expression literal for literal index <literal_idx> with -// <flags> and the pattern in <pattern_idx>. -void Interpreter::DoCreateRegExpLiteralWide(InterpreterAssembler* assembler) { - DoCreateLiteral(Runtime::kCreateRegExpLiteral, assembler); + Callable callable = CodeFactory::FastCloneRegExp(isolate_); + Node* target = __ HeapConstant(callable.code()); + Node* index = __ BytecodeOperandIdx(0); + Node* pattern = __ LoadConstantPoolEntry(index); + Node* literal_index_raw = __ BytecodeOperandIdx(1); + Node* literal_index = __ SmiTag(literal_index_raw); + Node* flags_raw = __ BytecodeOperandFlag(2); + Node* flags = __ SmiTag(flags_raw); + Node* closure = __ LoadRegister(Register::function_closure()); + Node* context = __ GetContext(); + Node* result = __ CallStub(callable.descriptor(), target, context, closure, + literal_index, pattern, flags); + __ SetAccumulator(result); + __ Dispatch(); } - // CreateArrayLiteral <element_idx> <literal_idx> <flags> // // Creates an array literal for literal index <literal_idx> with flags <flags> @@ -1591,16 +1362,6 @@ void Interpreter::DoCreateArrayLiteral(InterpreterAssembler* assembler) { DoCreateLiteral(Runtime::kCreateArrayLiteral, assembler); } - -// CreateArrayLiteralWide <element_idx> <literal_idx> <flags> -// -// Creates an array literal for literal index <literal_idx> with flags <flags> -// and constant elements in <element_idx>. -void Interpreter::DoCreateArrayLiteralWide(InterpreterAssembler* assembler) { - DoCreateLiteral(Runtime::kCreateArrayLiteral, assembler); -} - - // CreateObjectLiteral <element_idx> <literal_idx> <flags> // // Creates an object literal for literal index <literal_idx> with flags <flags> @@ -1609,16 +1370,6 @@ void Interpreter::DoCreateObjectLiteral(InterpreterAssembler* assembler) { DoCreateLiteral(Runtime::kCreateObjectLiteral, assembler); } - -// CreateObjectLiteralWide <element_idx> <literal_idx> <flags> -// -// Creates an object literal for literal index <literal_idx> with flags <flags> -// and constant elements in <element_idx>. -void Interpreter::DoCreateObjectLiteralWide(InterpreterAssembler* assembler) { - DoCreateLiteral(Runtime::kCreateObjectLiteral, assembler); -} - - // CreateClosure <index> <tenured> // // Creates a new closure for SharedFunctionInfo at position |index| in the @@ -1628,7 +1379,7 @@ void Interpreter::DoCreateClosure(InterpreterAssembler* assembler) { // calling into the runtime. Node* index = __ BytecodeOperandIdx(0); Node* shared = __ LoadConstantPoolEntry(index); - Node* tenured_raw = __ BytecodeOperandImm(1); + Node* tenured_raw = __ BytecodeOperandFlag(1); Node* tenured = __ SmiTag(tenured_raw); Node* context = __ GetContext(); Node* result = @@ -1637,16 +1388,6 @@ void Interpreter::DoCreateClosure(InterpreterAssembler* assembler) { __ Dispatch(); } - -// CreateClosureWide <index> <tenured> -// -// Creates a new closure for SharedFunctionInfo at position |index| in the -// constant pool and with the PretenureFlag <tenured>. -void Interpreter::DoCreateClosureWide(InterpreterAssembler* assembler) { - return DoCreateClosure(assembler); -} - - // CreateMappedArguments // // Creates a new mapped arguments object. @@ -1737,11 +1478,13 @@ void Interpreter::DoDebugger(InterpreterAssembler* assembler) { // DebugBreak // // Call runtime to handle a debug break. -#define DEBUG_BREAK(Name, ...) \ - void Interpreter::Do##Name(InterpreterAssembler* assembler) { \ - Node* context = __ GetContext(); \ - Node* original_handler = __ CallRuntime(Runtime::kDebugBreak, context); \ - __ DispatchToBytecodeHandler(original_handler); \ +#define DEBUG_BREAK(Name, ...) \ + void Interpreter::Do##Name(InterpreterAssembler* assembler) { \ + Node* context = __ GetContext(); \ + Node* accumulator = __ GetAccumulator(); \ + Node* original_handler = \ + __ CallRuntime(Runtime::kDebugBreakOnBytecode, context, accumulator); \ + __ DispatchToBytecodeHandler(original_handler); \ } DEBUG_BREAK_BYTECODE_LIST(DEBUG_BREAK); #undef DEBUG_BREAK @@ -1768,18 +1511,6 @@ void Interpreter::DoForInPrepare(InterpreterAssembler* assembler) { __ Dispatch(); } - -// ForInPrepareWide <cache_info_triple> -// -// Returns state for for..in loop execution based on the object in the -// accumulator. The result is output in registers |cache_info_triple| to -// |cache_info_triple + 2|, with the registers holding cache_type, cache_array, -// and cache_length respectively. -void Interpreter::DoForInPrepareWide(InterpreterAssembler* assembler) { - DoForInPrepare(assembler); -} - - // ForInNext <receiver> <index> <cache_info_pair> // // Returns the next enumerable property in the the accumulator. @@ -1792,53 +1523,101 @@ void Interpreter::DoForInNext(InterpreterAssembler* assembler) { Node* cache_type = __ LoadRegister(cache_type_reg); Node* cache_array_reg = __ NextRegister(cache_type_reg); Node* cache_array = __ LoadRegister(cache_array_reg); - Node* context = __ GetContext(); - Node* result = __ CallRuntime(Runtime::kForInNext, context, receiver, - cache_array, cache_type, index); - __ SetAccumulator(result); - __ Dispatch(); -} - -// ForInNextWide <receiver> <index> <cache_info_pair> -// -// Returns the next enumerable property in the the accumulator. -void Interpreter::DoForInNextWide(InterpreterAssembler* assembler) { - return DoForInNext(assembler); + // Load the next key from the enumeration array. + Node* key = __ LoadFixedArrayElementSmiIndex(cache_array, index); + + // Check if we can use the for-in fast path potentially using the enum cache. + InterpreterAssembler::Label if_fast(assembler), if_slow(assembler); + Node* receiver_map = __ LoadObjectField(receiver, HeapObject::kMapOffset); + Node* condition = __ WordEqual(receiver_map, cache_type); + __ Branch(condition, &if_fast, &if_slow); + __ Bind(&if_fast); + { + // Enum cache in use for {receiver}, the {key} is definitely valid. + __ SetAccumulator(key); + __ Dispatch(); + } + __ Bind(&if_slow); + { + // Record the fact that we hit the for-in slow path. + Node* vector_index = __ BytecodeOperandIdx(3); + Node* type_feedback_vector = __ LoadTypeFeedbackVector(); + Node* megamorphic_sentinel = + __ HeapConstant(TypeFeedbackVector::MegamorphicSentinel(isolate_)); + __ StoreFixedArrayElementNoWriteBarrier(type_feedback_vector, vector_index, + megamorphic_sentinel); + + // Need to filter the {key} for the {receiver}. + Node* context = __ GetContext(); + Node* result = + __ CallRuntime(Runtime::kForInFilter, context, receiver, key); + __ SetAccumulator(result); + __ Dispatch(); + } } - // ForInDone <index> <cache_length> // // Returns true if the end of the enumerable properties has been reached. void Interpreter::DoForInDone(InterpreterAssembler* assembler) { - // TODO(oth): Implement directly rather than making a runtime call. Node* index_reg = __ BytecodeOperandReg(0); Node* index = __ LoadRegister(index_reg); Node* cache_length_reg = __ BytecodeOperandReg(1); Node* cache_length = __ LoadRegister(cache_length_reg); - Node* context = __ GetContext(); - Node* result = - __ CallRuntime(Runtime::kForInDone, context, index, cache_length); - __ SetAccumulator(result); - __ Dispatch(); -} + // Check if {index} is at {cache_length} already. + InterpreterAssembler::Label if_true(assembler), if_false(assembler); + Node* condition = __ WordEqual(index, cache_length); + __ Branch(condition, &if_true, &if_false); + __ Bind(&if_true); + { + Node* result = __ BooleanConstant(true); + __ SetAccumulator(result); + __ Dispatch(); + } + __ Bind(&if_false); + { + Node* result = __ BooleanConstant(false); + __ SetAccumulator(result); + __ Dispatch(); + } +} // ForInStep <index> // // Increments the loop counter in register |index| and stores the result // in the accumulator. void Interpreter::DoForInStep(InterpreterAssembler* assembler) { - // TODO(oth): Implement directly rather than making a runtime call. Node* index_reg = __ BytecodeOperandReg(0); Node* index = __ LoadRegister(index_reg); - Node* context = __ GetContext(); - Node* result = __ CallRuntime(Runtime::kForInStep, context, index); + Node* one = __ SmiConstant(Smi::FromInt(1)); + Node* result = __ SmiAdd(index, one); __ SetAccumulator(result); __ Dispatch(); } +// Wide +// +// Prefix bytecode indicating next bytecode has wide (16-bit) operands. +void Interpreter::DoWide(InterpreterAssembler* assembler) { + __ DispatchWide(OperandScale::kDouble); +} + +// ExtraWide +// +// Prefix bytecode indicating next bytecode has extra-wide (32-bit) operands. +void Interpreter::DoExtraWide(InterpreterAssembler* assembler) { + __ DispatchWide(OperandScale::kQuadruple); +} + +// Illegal +// +// An invalid bytecode aborting execution if dispatched. +void Interpreter::DoIllegal(InterpreterAssembler* assembler) { + __ Abort(kInvalidBytecode); +} + } // namespace interpreter } // namespace internal } // namespace v8 diff --git a/deps/v8/src/interpreter/interpreter.h b/deps/v8/src/interpreter/interpreter.h index e02e9142b3..ea50faa02d 100644 --- a/deps/v8/src/interpreter/interpreter.h +++ b/deps/v8/src/interpreter/interpreter.h @@ -40,12 +40,14 @@ class Interpreter { static bool MakeBytecode(CompilationInfo* info); // Return bytecode handler for |bytecode|. - Code* GetBytecodeHandler(Bytecode bytecode); + Code* GetBytecodeHandler(Bytecode bytecode, OperandScale operand_scale); // GC support. void IterateDispatchTable(ObjectVisitor* v); - void TraceCodegen(Handle<Code> code, const char* name); + // Disassembler support (only useful with ENABLE_DISASSEMBLER defined). + void TraceCodegen(Handle<Code> code); + const char* LookupNameOfBytecodeHandler(Code* code); Address dispatch_table_address() { return reinterpret_cast<Address>(&dispatch_table_[0]); @@ -58,6 +60,9 @@ class Interpreter { BYTECODE_LIST(DECLARE_BYTECODE_HANDLER_GENERATOR) #undef DECLARE_BYTECODE_HANDLER_GENERATOR + // Generates code to perform the binary operations via |callable|. + void DoBinaryOp(Callable callable, InterpreterAssembler* assembler); + // Generates code to perform the binary operations via |function_id|. void DoBinaryOp(Runtime::FunctionId function_id, InterpreterAssembler* assembler); @@ -103,9 +108,12 @@ class Interpreter { // Generates code to perform a JS runtime call. void DoCallJSRuntimeCommon(InterpreterAssembler* assembler); - // Generates code to perform a constructor call.. + // Generates code to perform a constructor call. void DoCallConstruct(InterpreterAssembler* assembler); + // Generates code to perform a type conversion. + void DoTypeConversionOp(Callable callable, InterpreterAssembler* assembler); + // Generates code ro create a literal via |function_id|. void DoCreateLiteral(Runtime::FunctionId function_id, InterpreterAssembler* assembler); @@ -122,9 +130,14 @@ class Interpreter { void DoStoreLookupSlot(LanguageMode language_mode, InterpreterAssembler* assembler); + // Get dispatch table index of bytecode. + static size_t GetDispatchTableIndex(Bytecode bytecode, + OperandScale operand_scale); + bool IsDispatchTableInitialized(); - static const int kDispatchTableSize = static_cast<int>(Bytecode::kLast) + 1; + static const int kNumberOfWideVariants = 3; + static const int kDispatchTableSize = kNumberOfWideVariants * (kMaxUInt8 + 1); Isolate* isolate_; Code* dispatch_table_[kDispatchTableSize]; diff --git a/deps/v8/src/interpreter/register-translator.cc b/deps/v8/src/interpreter/register-translator.cc deleted file mode 100644 index 3eba42f0dc..0000000000 --- a/deps/v8/src/interpreter/register-translator.cc +++ /dev/null @@ -1,173 +0,0 @@ -// Copyright 2015 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "src/interpreter/register-translator.h" - -#include "src/interpreter/bytecode-array-builder.h" - -namespace v8 { -namespace internal { -namespace interpreter { - -RegisterTranslator::RegisterTranslator(RegisterMover* mover) - : mover_(mover), - emitting_moves_(false), - window_registers_count_(0), - output_moves_count_(0) {} - -void RegisterTranslator::TranslateInputRegisters(Bytecode bytecode, - uint32_t* raw_operands, - int raw_operand_count) { - DCHECK_EQ(Bytecodes::NumberOfOperands(bytecode), raw_operand_count); - if (!emitting_moves_) { - emitting_moves_ = true; - DCHECK_EQ(window_registers_count_, 0); - int register_bitmap = Bytecodes::GetRegisterOperandBitmap(bytecode); - for (int i = 0; i < raw_operand_count; i++) { - if ((register_bitmap & (1 << i)) == 0) { - continue; - } - Register in_reg = Register::FromRawOperand(raw_operands[i]); - Register out_reg = TranslateAndMove(bytecode, i, in_reg); - raw_operands[i] = out_reg.ToRawOperand(); - } - window_registers_count_ = 0; - emitting_moves_ = false; - } else { - // When the register translator is translating registers, it will - // cause the bytecode generator to emit moves on it's behalf. This - // path is reached by these moves. - DCHECK(bytecode == Bytecode::kMovWide && raw_operand_count == 2 && - Register::FromRawOperand(raw_operands[0]).is_valid() && - Register::FromRawOperand(raw_operands[1]).is_valid()); - } -} - -Register RegisterTranslator::TranslateAndMove(Bytecode bytecode, - int operand_index, Register reg) { - if (FitsInReg8Operand(reg)) { - return reg; - } - - OperandType operand_type = Bytecodes::GetOperandType(bytecode, operand_index); - OperandSize operand_size = Bytecodes::SizeOfOperand(operand_type); - if (operand_size == OperandSize::kShort) { - CHECK(FitsInReg16Operand(reg)); - return Translate(reg); - } - - CHECK((operand_type == OperandType::kReg8 || - operand_type == OperandType::kRegOut8) && - RegisterIsMovableToWindow(bytecode, operand_index)); - Register translated_reg = Translate(reg); - Register window_reg(kTranslationWindowStart + window_registers_count_); - window_registers_count_ += 1; - if (Bytecodes::IsRegisterInputOperandType(operand_type)) { - DCHECK(!Bytecodes::IsRegisterOutputOperandType(operand_type)); - mover()->MoveRegisterUntranslated(translated_reg, window_reg); - } else if (Bytecodes::IsRegisterOutputOperandType(operand_type)) { - DCHECK_LT(output_moves_count_, kTranslationWindowLength); - output_moves_[output_moves_count_] = - std::make_pair(window_reg, translated_reg); - output_moves_count_ += 1; - } else { - UNREACHABLE(); - } - return window_reg; -} - -// static -bool RegisterTranslator::RegisterIsMovableToWindow(Bytecode bytecode, - int operand_index) { - // By design, we only support moving individual registers. There - // should be wide variants of such bytecodes instead to avoid the - // need for a large translation window. - OperandType operand_type = Bytecodes::GetOperandType(bytecode, operand_index); - if (operand_type != OperandType::kReg8 && - operand_type != OperandType::kRegOut8) { - return false; - } else if (operand_index + 1 == Bytecodes::NumberOfOperands(bytecode)) { - return true; - } else { - OperandType next_operand_type = - Bytecodes::GetOperandType(bytecode, operand_index + 1); - return (next_operand_type != OperandType::kRegCount8 && - next_operand_type != OperandType::kRegCount16); - } -} - -void RegisterTranslator::TranslateOutputRegisters() { - if (!emitting_moves_) { - emitting_moves_ = true; - while (output_moves_count_ > 0) { - output_moves_count_ -= 1; - mover()->MoveRegisterUntranslated( - output_moves_[output_moves_count_].first, - output_moves_[output_moves_count_].second); - } - emitting_moves_ = false; - } -} - -// static -Register RegisterTranslator::Translate(Register reg) { - if (reg.index() >= kTranslationWindowStart) { - return Register(reg.index() + kTranslationWindowLength); - } else { - return reg; - } -} - -// static -bool RegisterTranslator::InTranslationWindow(Register reg) { - return (reg.index() >= kTranslationWindowStart && - reg.index() <= kTranslationWindowLimit); -} - -// static -Register RegisterTranslator::UntranslateRegister(Register reg) { - if (reg.index() >= kTranslationWindowStart) { - return Register(reg.index() - kTranslationWindowLength); - } else { - return reg; - } -} - -// static -int RegisterTranslator::DistanceToTranslationWindow(Register reg) { - return kTranslationWindowStart - reg.index(); -} - -// static -bool RegisterTranslator::FitsInReg8Operand(Register reg) { - return reg.is_byte_operand() && reg.index() < kTranslationWindowStart; -} - -// static -bool RegisterTranslator::FitsInReg16Operand(Register reg) { - int max_index = Register::MaxRegisterIndex() - kTranslationWindowLength + 1; - return reg.is_short_operand() && reg.index() < max_index; -} - -// static -int RegisterTranslator::RegisterCountAdjustment(int register_count, - int parameter_count) { - if (register_count > kTranslationWindowStart) { - return kTranslationWindowLength; - } else if (parameter_count > 0) { - Register param0 = Register::FromParameterIndex(0, parameter_count); - if (!param0.is_byte_operand()) { - // TODO(oth): Number of parameters means translation is - // required, but the translation window location is such that - // some space is wasted. Hopefully a rare corner case, but could - // relocate window to limit waste. - return kTranslationWindowLimit + 1 - register_count; - } - } - return 0; -} - -} // namespace interpreter -} // namespace internal -} // namespace v8 diff --git a/deps/v8/src/interpreter/register-translator.h b/deps/v8/src/interpreter/register-translator.h deleted file mode 100644 index b683a899e2..0000000000 --- a/deps/v8/src/interpreter/register-translator.h +++ /dev/null @@ -1,119 +0,0 @@ -// Copyright 2015 the V8 project authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef V8_INTERPRETER_REGISTER_TRANSLATOR_H_ -#define V8_INTERPRETER_REGISTER_TRANSLATOR_H_ - -#include "src/interpreter/bytecodes.h" - -namespace v8 { -namespace internal { -namespace interpreter { - -class RegisterMover; - -// A class that enables bytecodes having only byte sized register operands -// to access all registers in the two byte space. Most bytecode uses few -// registers so space can be saved if most bytecodes with register operands -// just take byte operands. -// -// To reach the wider register space, a translation window is reserved in -// the byte addressable space specifically for copying registers into and -// out of before a bytecode is emitted. The translation window occupies -// the last register slots at the top of the byte addressable range. -// -// Because of the translation window any registers which naturally lie -// at above the translation window have to have their register index -// incremented by the window width before they are emitted. -// -// This class does not support moving ranges of registers to and from -// the translation window. It would be straightforward to add support -// for constrained ranges, e.g. kRegPair8, kRegTriple8 operands, but -// these would have two negative effects. The translation window would -// need to be wider, further limiting the space for byte operands. And -// every register in a range would need to be moved consuming more -// space in the bytecode array. -class RegisterTranslator final { - public: - explicit RegisterTranslator(RegisterMover* mover); - - // Translate and re-write the register operands that are inputs - // to |bytecode| when it is about to be emitted. - void TranslateInputRegisters(Bytecode bytecode, uint32_t* raw_operands, - int raw_operand_count); - - // Translate and re-write the register operands that are outputs - // from |bytecode| when it has just been output. - void TranslateOutputRegisters(); - - // Returns true if |reg| is in the translation window. - static bool InTranslationWindow(Register reg); - - // Return register value as if it had been translated. - static Register UntranslateRegister(Register reg); - - // Returns the distance in registers between the translation window - // start and |reg|. The result is negative when |reg| is above the - // start of the translation window. - static int DistanceToTranslationWindow(Register reg); - - // Returns true if |reg| can be represented as an 8-bit operand - // after translation. - static bool FitsInReg8Operand(Register reg); - - // Returns true if |reg| can be represented as an 16-bit operand - // after translation. - static bool FitsInReg16Operand(Register reg); - - // Returns the increment to the register count necessary if the - // value indicates the translation window is required. - static int RegisterCountAdjustment(int register_count, int parameter_count); - - private: - static const int kTranslationWindowLength = 4; - static const int kTranslationWindowLimit = -kMinInt8; - static const int kTranslationWindowStart = - kTranslationWindowLimit - kTranslationWindowLength + 1; - - Register TranslateAndMove(Bytecode bytecode, int operand_index, Register reg); - static bool RegisterIsMovableToWindow(Bytecode bytecode, int operand_index); - - static Register Translate(Register reg); - - RegisterMover* mover() const { return mover_; } - - // Entity to perform register moves necessary to translate registers - // and ensure reachability. - RegisterMover* mover_; - - // Flag to avoid re-entrancy when emitting move bytecodes for - // translation. - bool emitting_moves_; - - // Number of window registers in use. - int window_registers_count_; - - // State for restoring register moves emitted by TranslateOutputRegisters. - std::pair<Register, Register> output_moves_[kTranslationWindowLength]; - int output_moves_count_; -}; - -// Interface for RegisterTranslator helper class that will emit -// register move bytecodes at the translator's behest. -class RegisterMover { - public: - virtual ~RegisterMover() {} - - // Move register |from| to register |to| with no translation. - // returns false if either register operand is invalid. Implementations - // of this method must be aware that register moves with bad - // register values are a security hole. - virtual void MoveRegisterUntranslated(Register from, Register to) = 0; -}; - -} // namespace interpreter -} // namespace internal -} // namespace v8 - -#endif // V8_INTERPRETER_REGISTER_TRANSLATOR_H_ diff --git a/deps/v8/src/interpreter/source-position-table.cc b/deps/v8/src/interpreter/source-position-table.cc index 0b7c44e2d9..99a865b84e 100644 --- a/deps/v8/src/interpreter/source-position-table.cc +++ b/deps/v8/src/interpreter/source-position-table.cc @@ -4,7 +4,6 @@ #include "src/interpreter/source-position-table.h" -#include "src/assembler.h" #include "src/objects-inl.h" #include "src/objects.h" @@ -12,71 +11,196 @@ namespace v8 { namespace internal { namespace interpreter { -class IsStatementField : public BitField<bool, 0, 1> {}; -class SourcePositionField : public BitField<int, 1, 30> {}; +// We'll use a simple encoding scheme to record the source positions. +// Conceptually, each position consists of: +// - bytecode_offset: An integer index into the BytecodeArray +// - source_position: An integer index into the source string. +// - position type: Each position is either a statement or an expression. +// +// The basic idea for the encoding is to use a variable-length integer coding, +// where each byte contains 7 bits of payload data, and 1 'more' bit that +// determines whether additional bytes follow. Additionally: +// - we record the difference from the previous position, +// - we just stuff one bit for the type into the bytecode offset, +// - we write least-significant bits first, +// - negative numbers occur only rarely, so we use a denormalized +// most-significant byte (a byte with all zeros, which normally wouldn't +// make any sense) to encode a negative sign, so that we 'pay' nothing for +// positive numbers, but have to pay a full byte for negative integers. + +namespace { + +// A zero-value in the most-significant byte is used to mark negative numbers. +const int kNegativeSignMarker = 0; + +// Each byte is encoded as MoreBit | ValueBits. +class MoreBit : public BitField8<bool, 7, 1> {}; +class ValueBits : public BitField8<int, 0, 7> {}; + +// Helper: Add the offsets from 'other' to 'value'. Also set is_statement. +void AddAndSetEntry(PositionTableEntry& value, + const PositionTableEntry& other) { + value.bytecode_offset += other.bytecode_offset; + value.source_position += other.source_position; + value.is_statement = other.is_statement; +} + +// Helper: Substract the offsets from 'other' from 'value'. +void SubtractFromEntry(PositionTableEntry& value, + const PositionTableEntry& other) { + value.bytecode_offset -= other.bytecode_offset; + value.source_position -= other.source_position; +} + +// Helper: Encode an integer. +void EncodeInt(ZoneVector<byte>& bytes, int value) { + bool sign = false; + if (value < 0) { + sign = true; + value = -value; + } + + bool more; + do { + more = value > ValueBits::kMax; + bytes.push_back(MoreBit::encode(more || sign) | + ValueBits::encode(value & ValueBits::kMax)); + value >>= ValueBits::kSize; + } while (more); + + if (sign) { + bytes.push_back(MoreBit::encode(false) | + ValueBits::encode(kNegativeSignMarker)); + } +} + +// Encode a PositionTableEntry. +void EncodeEntry(ZoneVector<byte>& bytes, const PositionTableEntry& entry) { + // 1 bit for sign + is_statement each, which leaves 30b for the value. + DCHECK(abs(entry.bytecode_offset) < (1 << 30)); + EncodeInt(bytes, (entry.is_statement ? 1 : 0) | (entry.bytecode_offset << 1)); + EncodeInt(bytes, entry.source_position); +} + +// Helper: Decode an integer. +void DecodeInt(ByteArray* bytes, int* index, int* v) { + byte current; + int n = 0; + int value = 0; + bool more; + do { + current = bytes->get((*index)++); + value |= ValueBits::decode(current) << (n * ValueBits::kSize); + n++; + more = MoreBit::decode(current); + } while (more); + + if (ValueBits::decode(current) == kNegativeSignMarker) { + value = -value; + } + *v = value; +} + +void DecodeEntry(ByteArray* bytes, int* index, PositionTableEntry* entry) { + int tmp; + DecodeInt(bytes, index, &tmp); + entry->is_statement = (tmp & 1); + + // Note that '>>' needs to be arithmetic shift in order to handle negative + // numbers properly. + entry->bytecode_offset = (tmp >> 1); + + DecodeInt(bytes, index, &entry->source_position); +} + +} // namespace void SourcePositionTableBuilder::AddStatementPosition(size_t bytecode_offset, int source_position) { int offset = static_cast<int>(bytecode_offset); - // If a position has already been assigned to this bytecode offset, - // do not reassign a new statement position. - if (CodeOffsetHasPosition(offset)) return; - uint32_t encoded = IsStatementField::encode(true) | - SourcePositionField::encode(source_position); - entries_.push_back({offset, encoded}); + AddEntry({offset, source_position, true}); } void SourcePositionTableBuilder::AddExpressionPosition(size_t bytecode_offset, int source_position) { int offset = static_cast<int>(bytecode_offset); - // If a position has already been assigned to this bytecode offset, - // do not reassign a new statement position. - if (CodeOffsetHasPosition(offset)) return; - uint32_t encoded = IsStatementField::encode(false) | - SourcePositionField::encode(source_position); - entries_.push_back({offset, encoded}); + AddEntry({offset, source_position, false}); } -void SourcePositionTableBuilder::RevertPosition(size_t bytecode_offset) { - int offset = static_cast<int>(bytecode_offset); - // If we already added a source position table entry, but the bytecode array - // builder ended up not outputting a bytecode for the corresponding bytecode - // offset, we have to remove that entry. - if (CodeOffsetHasPosition(offset)) entries_.pop_back(); +void SourcePositionTableBuilder::AddEntry(const PositionTableEntry& entry) { + // Don't encode a new entry if this bytecode already has a source position + // assigned. + if (candidate_.bytecode_offset == entry.bytecode_offset) { + if (entry.is_statement) candidate_ = entry; + return; + } + + CommitEntry(); + candidate_ = entry; } -Handle<FixedArray> SourcePositionTableBuilder::ToFixedArray() { - int length = static_cast<int>(entries_.size()); - Handle<FixedArray> table = - isolate_->factory()->NewFixedArray(length * 2, TENURED); - for (int i = 0; i < length; i++) { - table->set(i * 2, Smi::FromInt(entries_[i].bytecode_offset)); - table->set(i * 2 + 1, Smi::FromInt(entries_[i].source_position_and_type)); +void SourcePositionTableBuilder::CommitEntry() { + if (candidate_.bytecode_offset == kUninitializedCandidateOffset) return; + PositionTableEntry tmp(candidate_); + SubtractFromEntry(tmp, previous_); + EncodeEntry(bytes_, tmp); + previous_ = candidate_; + + if (candidate_.is_statement) { + LOG_CODE_EVENT(isolate_, CodeLinePosInfoAddStatementPositionEvent( + jit_handler_data_, candidate_.bytecode_offset, + candidate_.source_position)); } + LOG_CODE_EVENT(isolate_, CodeLinePosInfoAddPositionEvent( + jit_handler_data_, candidate_.bytecode_offset, + candidate_.source_position)); + +#ifdef ENABLE_SLOW_DCHECKS + raw_entries_.push_back(candidate_); +#endif +} + +Handle<ByteArray> SourcePositionTableBuilder::ToSourcePositionTable() { + CommitEntry(); + if (bytes_.empty()) return isolate_->factory()->empty_byte_array(); + + Handle<ByteArray> table = isolate_->factory()->NewByteArray( + static_cast<int>(bytes_.size()), TENURED); + + MemCopy(table->GetDataStartAddress(), &*bytes_.begin(), bytes_.size()); + +#ifdef ENABLE_SLOW_DCHECKS + // Brute force testing: Record all positions and decode + // the entire table to verify they are identical. + auto raw = raw_entries_.begin(); + for (SourcePositionTableIterator encoded(*table); !encoded.done(); + encoded.Advance(), raw++) { + DCHECK(raw != raw_entries_.end()); + DCHECK_EQ(encoded.bytecode_offset(), raw->bytecode_offset); + DCHECK_EQ(encoded.source_position(), raw->source_position); + DCHECK_EQ(encoded.is_statement(), raw->is_statement); + } + DCHECK(raw == raw_entries_.end()); +#endif + return table; } -SourcePositionTableIterator::SourcePositionTableIterator( - BytecodeArray* bytecode_array) - : table_(bytecode_array->source_position_table()), - index_(0), - length_(table_->length()) { - DCHECK(table_->length() % 2 == 0); +SourcePositionTableIterator::SourcePositionTableIterator(ByteArray* byte_array) + : table_(byte_array), index_(0), current_() { Advance(); } void SourcePositionTableIterator::Advance() { - if (index_ < length_) { - int new_bytecode_offset = Smi::cast(table_->get(index_))->value(); - // Bytecode offsets are in ascending order. - DCHECK(bytecode_offset_ < new_bytecode_offset || index_ == 0); - bytecode_offset_ = new_bytecode_offset; - uint32_t source_position_and_type = - static_cast<uint32_t>(Smi::cast(table_->get(index_ + 1))->value()); - is_statement_ = IsStatementField::decode(source_position_and_type); - source_position_ = SourcePositionField::decode(source_position_and_type); + DCHECK(!done()); + DCHECK(index_ >= 0 && index_ <= table_->length()); + if (index_ == table_->length()) { + index_ = kDone; + } else { + PositionTableEntry tmp; + DecodeEntry(table_, &index_, &tmp); + AddAndSetEntry(current_, tmp); } - index_ += 2; } } // namespace interpreter diff --git a/deps/v8/src/interpreter/source-position-table.h b/deps/v8/src/interpreter/source-position-table.h index 336cf42bc2..3ac58d6217 100644 --- a/deps/v8/src/interpreter/source-position-table.h +++ b/deps/v8/src/interpreter/source-position-table.h @@ -6,72 +6,90 @@ #define V8_INTERPRETER_SOURCE_POSITION_TABLE_H_ #include "src/assert-scope.h" +#include "src/checks.h" #include "src/handles.h" -#include "src/zone.h" +#include "src/log.h" #include "src/zone-containers.h" namespace v8 { namespace internal { class BytecodeArray; -class FixedArray; +class ByteArray; class Isolate; +class Zone; namespace interpreter { -class SourcePositionTableBuilder { +struct PositionTableEntry { + PositionTableEntry() + : bytecode_offset(0), source_position(0), is_statement(false) {} + PositionTableEntry(int bytecode, int source, bool statement) + : bytecode_offset(bytecode), + source_position(source), + is_statement(statement) {} + + int bytecode_offset; + int source_position; + bool is_statement; +}; + +class SourcePositionTableBuilder : public PositionsRecorder { public: - explicit SourcePositionTableBuilder(Isolate* isolate, Zone* zone) - : isolate_(isolate), entries_(zone) {} + SourcePositionTableBuilder(Isolate* isolate, Zone* zone) + : isolate_(isolate), + bytes_(zone), +#ifdef ENABLE_SLOW_DCHECKS + raw_entries_(zone), +#endif + candidate_(kUninitializedCandidateOffset, 0, false) { + } void AddStatementPosition(size_t bytecode_offset, int source_position); void AddExpressionPosition(size_t bytecode_offset, int source_position); - void RevertPosition(size_t bytecode_offset); - Handle<FixedArray> ToFixedArray(); + Handle<ByteArray> ToSourcePositionTable(); private: - struct Entry { - int bytecode_offset; - uint32_t source_position_and_type; - }; - - bool CodeOffsetHasPosition(int bytecode_offset) { - // Return whether bytecode offset already has a position assigned. - return entries_.size() > 0 && - entries_.back().bytecode_offset == bytecode_offset; - } + static const int kUninitializedCandidateOffset = -1; + + void AddEntry(const PositionTableEntry& entry); + void CommitEntry(); Isolate* isolate_; - ZoneVector<Entry> entries_; + ZoneVector<byte> bytes_; +#ifdef ENABLE_SLOW_DCHECKS + ZoneVector<PositionTableEntry> raw_entries_; +#endif + PositionTableEntry candidate_; // Next entry to be written, if initialized. + PositionTableEntry previous_; // Previously written entry, to compute delta. }; class SourcePositionTableIterator { public: - explicit SourcePositionTableIterator(BytecodeArray* bytecode_array); + explicit SourcePositionTableIterator(ByteArray* byte_array); void Advance(); int bytecode_offset() const { DCHECK(!done()); - return bytecode_offset_; + return current_.bytecode_offset; } int source_position() const { DCHECK(!done()); - return source_position_; + return current_.source_position; } bool is_statement() const { DCHECK(!done()); - return is_statement_; + return current_.is_statement; } - bool done() const { return index_ > length_; } + bool done() const { return index_ == kDone; } private: - FixedArray* table_; + static const int kDone = -1; + + ByteArray* table_; int index_; - int length_; - bool is_statement_; - int bytecode_offset_; - int source_position_; + PositionTableEntry current_; DisallowHeapAllocation no_gc; }; |