Commit 48d082af authored by oth's avatar oth Committed by Commit bot

[interpreter] Add support for scalable operands.

This change introduces wide prefix bytecodes to support wide (16-bit)
and extra-wide (32-bit) operands. It retires the previous
wide-bytecodes and reduces the number of operand types.

Operands are now either scalable or fixed size. Scalable operands
increase in width when a bytecode is prefixed with wide or extra-wide.

The bytecode handler table is extended to 256*3 entries. The
first 256 entries are used for bytecodes with 8-bit operands,
the second 256 entries are used for bytecodes with operands that
scale to 16-bits, and the third group of 256 entries are used for
bytecodes with operands that scale to 32-bits.

LOG=N
BUG=v8:4747,v8:4280

Review URL: https://codereview.chromium.org/1783483002

Cr-Commit-Position: refs/heads/master@{#34955}
parent d50d7e18
...@@ -1133,8 +1133,6 @@ source_set("v8_base") { ...@@ -1133,8 +1133,6 @@ source_set("v8_base") {
"src/interpreter/interpreter.h", "src/interpreter/interpreter.h",
"src/interpreter/interpreter-assembler.cc", "src/interpreter/interpreter-assembler.cc",
"src/interpreter/interpreter-assembler.h", "src/interpreter/interpreter-assembler.h",
"src/interpreter/register-translator.cc",
"src/interpreter/register-translator.h",
"src/interpreter/source-position-table.cc", "src/interpreter/source-position-table.cc",
"src/interpreter/source-position-table.h", "src/interpreter/source-position-table.h",
"src/isolate-inl.h", "src/isolate-inl.h",
......
...@@ -102,6 +102,7 @@ namespace internal { ...@@ -102,6 +102,7 @@ namespace internal {
V(kInputStringTooLong, "Input string too long") \ V(kInputStringTooLong, "Input string too long") \
V(kInteger32ToSmiFieldWritingToNonSmiLocation, \ V(kInteger32ToSmiFieldWritingToNonSmiLocation, \
"Integer32ToSmiField writing to non-smi location") \ "Integer32ToSmiField writing to non-smi location") \
V(kInvalidBytecode, "Invalid bytecode") \
V(kInvalidCaptureReferenced, "Invalid capture referenced") \ V(kInvalidCaptureReferenced, "Invalid capture referenced") \
V(kInvalidElementsKindForInternalArrayOrInternalPackedArray, \ V(kInvalidElementsKindForInternalArrayOrInternalPackedArray, \
"Invalid ElementsKind for InternalArray or InternalPackedArray") \ "Invalid ElementsKind for InternalArray or InternalPackedArray") \
......
This diff is collapsed.
...@@ -111,9 +111,6 @@ class BytecodeGraphBuilder { ...@@ -111,9 +111,6 @@ class BytecodeGraphBuilder {
size_t arity); size_t arity);
void BuildCreateLiteral(const Operator* op); void BuildCreateLiteral(const Operator* op);
void BuildCreateRegExpLiteral();
void BuildCreateArrayLiteral();
void BuildCreateObjectLiteral();
void BuildCreateArguments(CreateArgumentsType type); void BuildCreateArguments(CreateArgumentsType type);
void BuildLoadGlobal(TypeofMode typeof_mode); void BuildLoadGlobal(TypeofMode typeof_mode);
void BuildStoreGlobal(LanguageMode language_mode); void BuildStoreGlobal(LanguageMode language_mode);
...@@ -124,10 +121,6 @@ class BytecodeGraphBuilder { ...@@ -124,10 +121,6 @@ class BytecodeGraphBuilder {
void BuildLdaLookupSlot(TypeofMode typeof_mode); void BuildLdaLookupSlot(TypeofMode typeof_mode);
void BuildStaLookupSlot(LanguageMode language_mode); void BuildStaLookupSlot(LanguageMode language_mode);
void BuildCall(TailCallMode tail_call_mode); void BuildCall(TailCallMode tail_call_mode);
void BuildCallJSRuntime();
void BuildCallRuntime();
void BuildCallRuntimeForPair();
void BuildCallConstruct();
void BuildThrow(); void BuildThrow();
void BuildBinaryOp(const Operator* op); void BuildBinaryOp(const Operator* op);
void BuildCompareOp(const Operator* op); void BuildCompareOp(const Operator* op);
......
...@@ -1579,7 +1579,8 @@ Object* Debug::SetAfterBreakTarget(JavaScriptFrame* frame) { ...@@ -1579,7 +1579,8 @@ Object* Debug::SetAfterBreakTarget(JavaScriptFrame* frame) {
int bytecode_offset = interpreted_frame->GetBytecodeOffset(); int bytecode_offset = interpreted_frame->GetBytecodeOffset();
interpreter::Bytecode bytecode = interpreter::Bytecode bytecode =
interpreter::Bytecodes::FromByte(bytecode_array->get(bytecode_offset)); interpreter::Bytecodes::FromByte(bytecode_array->get(bytecode_offset));
return isolate_->interpreter()->GetBytecodeHandler(bytecode); return isolate_->interpreter()->GetBytecodeHandler(
bytecode, interpreter::OperandScale::kSingle);
} else { } else {
after_break_target_ = NULL; after_break_target_ = NULL;
if (!LiveEdit::SetAfterBreakTarget(this)) { if (!LiveEdit::SetAfterBreakTarget(this)) {
......
...@@ -113,6 +113,7 @@ const int kMaxUInt16 = (1 << 16) - 1; ...@@ -113,6 +113,7 @@ const int kMaxUInt16 = (1 << 16) - 1;
const int kMinUInt16 = 0; const int kMinUInt16 = 0;
const uint32_t kMaxUInt32 = 0xFFFFFFFFu; const uint32_t kMaxUInt32 = 0xFFFFFFFFu;
const int kMinUInt32 = 0;
const int kCharSize = sizeof(char); // NOLINT const int kCharSize = sizeof(char); // NOLINT
const int kShortSize = sizeof(short); // NOLINT const int kShortSize = sizeof(short); // NOLINT
......
This diff is collapsed.
...@@ -10,7 +10,6 @@ ...@@ -10,7 +10,6 @@
#include "src/interpreter/bytecodes.h" #include "src/interpreter/bytecodes.h"
#include "src/interpreter/constant-array-builder.h" #include "src/interpreter/constant-array-builder.h"
#include "src/interpreter/handler-table-builder.h" #include "src/interpreter/handler-table-builder.h"
#include "src/interpreter/register-translator.h"
#include "src/interpreter/source-position-table.h" #include "src/interpreter/source-position-table.h"
#include "src/zone-containers.h" #include "src/zone-containers.h"
...@@ -24,7 +23,7 @@ namespace interpreter { ...@@ -24,7 +23,7 @@ namespace interpreter {
class BytecodeLabel; class BytecodeLabel;
class Register; class Register;
class BytecodeArrayBuilder final : public ZoneObject, private RegisterMover { class BytecodeArrayBuilder final : public ZoneObject {
public: public:
BytecodeArrayBuilder(Isolate* isolate, Zone* zone, int parameter_count, BytecodeArrayBuilder(Isolate* isolate, Zone* zone, int parameter_count,
int context_count, int locals_count, int context_count, int locals_count,
...@@ -66,13 +65,6 @@ class BytecodeArrayBuilder final : public ZoneObject, private RegisterMover { ...@@ -66,13 +65,6 @@ class BytecodeArrayBuilder final : public ZoneObject, private RegisterMover {
return temporary_register_allocator()->allocation_count(); 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; Register Parameter(int parameter_index) const;
// Return true if the register |reg| represents a parameter or a // Return true if the register |reg| represents a parameter or a
...@@ -276,6 +268,22 @@ class BytecodeArrayBuilder final : public ZoneObject, private RegisterMover { ...@@ -276,6 +268,22 @@ class BytecodeArrayBuilder final : public ZoneObject, private RegisterMover {
void EnsureReturn(); 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: private:
class PreviousBytecodeHelper; class PreviousBytecodeHelper;
friend class BytecodeRegisterAllocator; friend class BytecodeRegisterAllocator;
...@@ -283,7 +291,6 @@ class BytecodeArrayBuilder final : public ZoneObject, private RegisterMover { ...@@ -283,7 +291,6 @@ class BytecodeArrayBuilder final : public ZoneObject, private RegisterMover {
static Bytecode BytecodeForBinaryOperation(Token::Value op); static Bytecode BytecodeForBinaryOperation(Token::Value op);
static Bytecode BytecodeForCountOperation(Token::Value op); static Bytecode BytecodeForCountOperation(Token::Value op);
static Bytecode BytecodeForCompareOperation(Token::Value op); static Bytecode BytecodeForCompareOperation(Token::Value op);
static Bytecode BytecodeForWideOperands(Bytecode bytecode);
static Bytecode BytecodeForStoreIC(LanguageMode language_mode); static Bytecode BytecodeForStoreIC(LanguageMode language_mode);
static Bytecode BytecodeForKeyedStoreIC(LanguageMode language_mode); static Bytecode BytecodeForKeyedStoreIC(LanguageMode language_mode);
static Bytecode BytecodeForLoadGlobal(TypeofMode typeof_mode); static Bytecode BytecodeForLoadGlobal(TypeofMode typeof_mode);
...@@ -293,32 +300,22 @@ class BytecodeArrayBuilder final : public ZoneObject, private RegisterMover { ...@@ -293,32 +300,22 @@ class BytecodeArrayBuilder final : public ZoneObject, private RegisterMover {
static Bytecode BytecodeForDelete(LanguageMode language_mode); static Bytecode BytecodeForDelete(LanguageMode language_mode);
static Bytecode BytecodeForCall(TailCallMode tail_call_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 GetJumpWithConstantOperand(Bytecode jump_smi8_operand);
static Bytecode GetJumpWithConstantWideOperand(Bytecode jump_smi8_operand);
static Bytecode GetJumpWithToBoolean(Bytecode jump_smi8_operand); static Bytecode GetJumpWithToBoolean(Bytecode jump_smi8_operand);
template <size_t N> template <size_t N>
INLINE(void Output(Bytecode bytecode, uint32_t(&operands)[N])); INLINE(void Output(Bytecode bytecode, uint32_t (&operands)[N],
void Output(Bytecode bytecode, uint32_t operand0, uint32_t operand1, OperandScale operand_scale = OperandScale::kSingle));
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);
void Output(Bytecode bytecode); 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, BytecodeArrayBuilder& OutputJump(Bytecode jump_bytecode,
BytecodeLabel* label); BytecodeLabel* label);
...@@ -328,12 +325,14 @@ class BytecodeArrayBuilder final : public ZoneObject, private RegisterMover { ...@@ -328,12 +325,14 @@ class BytecodeArrayBuilder final : public ZoneObject, private RegisterMover {
const ZoneVector<uint8_t>::iterator& jump_location, int delta); const ZoneVector<uint8_t>::iterator& jump_location, int delta);
void PatchIndirectJumpWith16BitOperand( void PatchIndirectJumpWith16BitOperand(
const ZoneVector<uint8_t>::iterator& jump_location, int delta); const ZoneVector<uint8_t>::iterator& jump_location, int delta);
void PatchIndirectJumpWith32BitOperand(
const ZoneVector<uint8_t>::iterator& jump_location, int delta);
void LeaveBasicBlock(); void LeaveBasicBlock();
bool OperandIsValid(Bytecode bytecode, int operand_index, bool OperandIsValid(Bytecode bytecode, OperandScale operand_scale,
uint32_t operand_value) const; int operand_index, uint32_t operand_value) const;
bool RegisterIsValid(Register reg, OperandType reg_type) const; bool RegisterIsValid(Register reg, OperandSize reg_size) const;
bool LastBytecodeInSameBlock() const; bool LastBytecodeInSameBlock() const;
bool NeedToBooleanCast(); bool NeedToBooleanCast();
...@@ -360,7 +359,6 @@ class BytecodeArrayBuilder final : public ZoneObject, private RegisterMover { ...@@ -360,7 +359,6 @@ class BytecodeArrayBuilder final : public ZoneObject, private RegisterMover {
SourcePositionTableBuilder* source_position_table_builder() { SourcePositionTableBuilder* source_position_table_builder() {
return &source_position_table_builder_; return &source_position_table_builder_;
} }
RegisterTranslator* register_translator() { return &register_translator_; }
Isolate* isolate_; Isolate* isolate_;
Zone* zone_; Zone* zone_;
...@@ -378,7 +376,6 @@ class BytecodeArrayBuilder final : public ZoneObject, private RegisterMover { ...@@ -378,7 +376,6 @@ class BytecodeArrayBuilder final : public ZoneObject, private RegisterMover {
int context_register_count_; int context_register_count_;
int return_position_; int return_position_;
TemporaryRegisterAllocator temporary_allocator_; TemporaryRegisterAllocator temporary_allocator_;
RegisterTranslator register_translator_;
DISALLOW_COPY_AND_ASSIGN(BytecodeArrayBuilder); DISALLOW_COPY_AND_ASSIGN(BytecodeArrayBuilder);
}; };
......
...@@ -12,103 +12,119 @@ namespace interpreter { ...@@ -12,103 +12,119 @@ namespace interpreter {
BytecodeArrayIterator::BytecodeArrayIterator( BytecodeArrayIterator::BytecodeArrayIterator(
Handle<BytecodeArray> bytecode_array) 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() { 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 { bool BytecodeArrayIterator::done() const {
return bytecode_offset_ >= bytecode_array()->length(); return bytecode_offset_ >= bytecode_array()->length();
} }
Bytecode BytecodeArrayIterator::current_bytecode() const { Bytecode BytecodeArrayIterator::current_bytecode() const {
DCHECK(!done()); DCHECK(!done());
uint8_t current_byte = bytecode_array()->get(bytecode_offset_); uint8_t current_byte =
return interpreter::Bytecodes::FromByte(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 { 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::GetUnsignedOperand(
uint32_t BytecodeArrayIterator::GetRawOperand(int operand_index, int operand_index, OperandType operand_type) const {
OperandType operand_type) const {
DCHECK_GE(operand_index, 0); DCHECK_GE(operand_index, 0);
DCHECK_LT(operand_index, Bytecodes::NumberOfOperands(current_bytecode())); DCHECK_LT(operand_index, Bytecodes::NumberOfOperands(current_bytecode()));
DCHECK_EQ(operand_type, DCHECK_EQ(operand_type,
Bytecodes::GetOperandType(current_bytecode(), operand_index)); 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_ + bytecode_array()->GetFirstBytecodeAddress() + bytecode_offset_ +
Bytecodes::GetOperandOffset(current_bytecode(), operand_index); current_prefix_offset() +
switch (Bytecodes::SizeOfOperand(operand_type)) { Bytecodes::GetOperandOffset(current_bytecode(), operand_index,
case OperandSize::kByte: current_operand_scale());
return static_cast<uint32_t>(*operand_start); return Bytecodes::DecodeUnsignedOperand(operand_start, operand_type,
case OperandSize::kShort: current_operand_scale());
return ReadUnalignedUInt16(operand_start);
case OperandSize::kNone:
UNREACHABLE();
}
return 0;
} }
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 BytecodeArrayIterator::GetFlagOperand(int operand_index) const {
uint32_t operand = GetRawOperand(operand_index, OperandType::kImm8); DCHECK_EQ(Bytecodes::GetOperandType(current_bytecode(), operand_index),
return static_cast<int8_t>(operand); OperandType::kFlag8);
return GetUnsignedOperand(operand_index, OperandType::kFlag8);
} }
int BytecodeArrayIterator::GetRegisterCountOperand(int operand_index) const { int32_t BytecodeArrayIterator::GetImmediateOperand(int operand_index) const {
OperandSize size = DCHECK_EQ(Bytecodes::GetOperandType(current_bytecode(), operand_index),
Bytecodes::GetOperandSize(current_bytecode(), operand_index); OperandType::kImm);
OperandType type = (size == OperandSize::kByte) ? OperandType::kRegCount8 return GetSignedOperand(operand_index, OperandType::kImm);
: OperandType::kRegCount16;
uint32_t operand = GetRawOperand(operand_index, type);
return static_cast<int>(operand);
} }
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 = OperandType operand_type =
Bytecodes::GetOperandType(current_bytecode(), operand_index); Bytecodes::GetOperandType(current_bytecode(), operand_index);
DCHECK(operand_type == OperandType::kIdx8 || DCHECK_EQ(operand_type, OperandType::kIdx);
operand_type == OperandType::kIdx16); return GetUnsignedOperand(operand_index, operand_type);
uint32_t operand = GetRawOperand(operand_index, operand_type);
return static_cast<int>(operand);
} }
Register BytecodeArrayIterator::GetRegisterOperand(int operand_index) const { Register BytecodeArrayIterator::GetRegisterOperand(int operand_index) const {
OperandType operand_type = OperandType operand_type =
Bytecodes::GetOperandType(current_bytecode(), operand_index); Bytecodes::GetOperandType(current_bytecode(), operand_index);
DCHECK(Bytecodes::IsRegisterOperandType(operand_type)); const uint8_t* operand_start =
uint32_t operand = GetRawOperand(operand_index, operand_type); bytecode_array()->GetFirstBytecodeAddress() + bytecode_offset_ +
Register reg; current_prefix_offset() +
switch (Bytecodes::GetOperandSize(current_bytecode(), operand_index)) { Bytecodes::GetOperandOffset(current_bytecode(), operand_index,
case OperandSize::kByte: current_operand_scale());
reg = Register::FromOperand(static_cast<uint8_t>(operand)); return Bytecodes::DecodeRegisterOperand(operand_start, operand_type,
break; current_operand_scale());
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;
} }
int BytecodeArrayIterator::GetRegisterOperandRange(int operand_index) const { int BytecodeArrayIterator::GetRegisterOperandRange(int operand_index) const {
...@@ -116,20 +132,17 @@ int BytecodeArrayIterator::GetRegisterOperandRange(int operand_index) const { ...@@ -116,20 +132,17 @@ int BytecodeArrayIterator::GetRegisterOperandRange(int operand_index) const {
Bytecodes::GetOperandType(current_bytecode(), operand_index); Bytecodes::GetOperandType(current_bytecode(), operand_index);
DCHECK(Bytecodes::IsRegisterOperandType(operand_type)); DCHECK(Bytecodes::IsRegisterOperandType(operand_type));
switch (operand_type) { switch (operand_type) {
case OperandType::kRegPair8: case OperandType::kRegPair:
case OperandType::kRegPair16: case OperandType::kRegOutPair:
case OperandType::kRegOutPair8:
case OperandType::kRegOutPair16:
return 2; return 2;
case OperandType::kRegOutTriple8: case OperandType::kRegOutTriple:
case OperandType::kRegOutTriple16:
return 3; return 3;
default: { default: {
if (operand_index + 1 != if (operand_index + 1 !=
Bytecodes::NumberOfOperands(current_bytecode())) { Bytecodes::NumberOfOperands(current_bytecode())) {
OperandType next_operand_type = OperandType next_operand_type =
Bytecodes::GetOperandType(current_bytecode(), operand_index + 1); Bytecodes::GetOperandType(current_bytecode(), operand_index + 1);
if (Bytecodes::IsRegisterCountOperandType(next_operand_type)) { if (OperandType::kRegCount == next_operand_type) {
return GetRegisterCountOperand(operand_index + 1); return GetRegisterCountOperand(operand_index + 1);
} }
} }
...@@ -138,6 +151,13 @@ int BytecodeArrayIterator::GetRegisterOperandRange(int operand_index) const { ...@@ -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( Handle<Object> BytecodeArrayIterator::GetConstantForIndexOperand(
int operand_index) const { int operand_index) const {
return FixedArray::get(bytecode_array()->constant_pool(), return FixedArray::get(bytecode_array()->constant_pool(),
...@@ -150,11 +170,10 @@ int BytecodeArrayIterator::GetJumpTargetOffset() const { ...@@ -150,11 +170,10 @@ int BytecodeArrayIterator::GetJumpTargetOffset() const {
Bytecode bytecode = current_bytecode(); Bytecode bytecode = current_bytecode();
if (interpreter::Bytecodes::IsJumpImmediate(bytecode)) { if (interpreter::Bytecodes::IsJumpImmediate(bytecode)) {
int relative_offset = GetImmediateOperand(0); int relative_offset = GetImmediateOperand(0);
return current_offset() + relative_offset; return current_offset() + relative_offset + current_prefix_offset();
} else if (interpreter::Bytecodes::IsJumpConstant(bytecode) || } else if (interpreter::Bytecodes::IsJumpConstant(bytecode)) {
interpreter::Bytecodes::IsJumpConstantWide(bytecode)) {
Smi* smi = Smi::cast(*GetConstantForIndexOperand(0)); Smi* smi = Smi::cast(*GetConstantForIndexOperand(0));
return current_offset() + smi->value(); return current_offset() + smi->value() + current_prefix_offset();
} else { } else {
UNREACHABLE(); UNREACHABLE();
return kMinInt; return kMinInt;
......
...@@ -21,31 +21,38 @@ class BytecodeArrayIterator { ...@@ -21,31 +21,38 @@ class BytecodeArrayIterator {
bool done() const; bool done() const;
Bytecode current_bytecode() const; Bytecode current_bytecode() const;
int current_bytecode_size() const; int current_bytecode_size() const;
void set_current_offset(int offset) { bytecode_offset_ = offset; }
int current_offset() const { return bytecode_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 { const Handle<BytecodeArray>& bytecode_array() const {
return bytecode_array_; return bytecode_array_;
} }
int8_t GetImmediateOperand(int operand_index) const; uint32_t GetFlagOperand(int operand_index) const;
int GetIndexOperand(int operand_index) const; int32_t GetImmediateOperand(int operand_index) const;
int GetRegisterCountOperand(int operand_index) const; uint32_t GetIndexOperand(int operand_index) const;
uint32_t GetRegisterCountOperand(int operand_index) const;
Register GetRegisterOperand(int operand_index) const; Register GetRegisterOperand(int operand_index) const;
int GetRegisterOperandRange(int operand_index) const; int GetRegisterOperandRange(int operand_index) const;
uint32_t GetRuntimeIdOperand(int operand_index) const;
Handle<Object> GetConstantForIndexOperand(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 // Returns the absolute offset of the branch target at the current
// bytecode. It is an error to call this method if the bytecode is // bytecode. It is an error to call this method if the bytecode is
// not for a jump or conditional jump. // not for a jump or conditional jump.
int GetJumpTargetOffset() const; int GetJumpTargetOffset() const;
private: 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_; Handle<BytecodeArray> bytecode_array_;
int bytecode_offset_; int bytecode_offset_;
OperandScale operand_scale_;
int prefix_offset_;
DISALLOW_COPY_AND_ASSIGN(BytecodeArrayIterator); DISALLOW_COPY_AND_ASSIGN(BytecodeArrayIterator);
}; };
......
...@@ -1133,7 +1133,7 @@ void BytecodeGenerator::VisitForInStatement(ForInStatement* stmt) { ...@@ -1133,7 +1133,7 @@ void BytecodeGenerator::VisitForInStatement(ForInStatement* stmt) {
Register cache_type = register_allocator()->NextConsecutiveRegister(); Register cache_type = register_allocator()->NextConsecutiveRegister();
Register cache_array = register_allocator()->NextConsecutiveRegister(); Register cache_array = register_allocator()->NextConsecutiveRegister();
Register cache_length = 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); USE(cache_array);
builder()->ForInPrepare(cache_type); builder()->ForInPrepare(cache_type);
......
...@@ -95,17 +95,6 @@ int TemporaryRegisterAllocator::PrepareForConsecutiveTemporaryRegisters( ...@@ -95,17 +95,6 @@ int TemporaryRegisterAllocator::PrepareForConsecutiveTemporaryRegisters(
start = run_end; start = run_end;
run_length = 0; 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) { if (++run_length == count) {
return *start; return *start;
} }
...@@ -121,16 +110,6 @@ int TemporaryRegisterAllocator::PrepareForConsecutiveTemporaryRegisters( ...@@ -121,16 +110,6 @@ int TemporaryRegisterAllocator::PrepareForConsecutiveTemporaryRegisters(
// Pad temporaries if extended run would cross translation boundary. // Pad temporaries if extended run would cross translation boundary.
Register reg_first(*start); Register reg_first(*start);
Register reg_last(*start + static_cast<int>(count) - 1); 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. // Ensure enough registers for run.
while (run_length++ < count) { while (run_length++ < count) {
...@@ -139,10 +118,6 @@ int TemporaryRegisterAllocator::PrepareForConsecutiveTemporaryRegisters( ...@@ -139,10 +118,6 @@ int TemporaryRegisterAllocator::PrepareForConsecutiveTemporaryRegisters(
int run_start = int run_start =
last_temporary_register().index() - static_cast<int>(count) + 1; 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; return run_start;
} }
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
...@@ -58,6 +58,8 @@ ConstantArrayBuilder::ConstantArrayBuilder(Isolate* isolate, Zone* zone) ...@@ -58,6 +58,8 @@ ConstantArrayBuilder::ConstantArrayBuilder(Isolate* isolate, Zone* zone)
new (zone) ConstantArraySlice(zone, 0, k8BitCapacity, OperandSize::kByte); new (zone) ConstantArraySlice(zone, 0, k8BitCapacity, OperandSize::kByte);
idx_slice_[1] = new (zone) ConstantArraySlice( idx_slice_[1] = new (zone) ConstantArraySlice(
zone, k8BitCapacity, k16BitCapacity, OperandSize::kShort); zone, k8BitCapacity, k16BitCapacity, OperandSize::kShort);
idx_slice_[2] = new (zone) ConstantArraySlice(
zone, k16BitCapacity, k32BitCapacity, OperandSize::kQuad);
} }
size_t ConstantArrayBuilder::size() const { size_t ConstantArrayBuilder::size() const {
...@@ -164,6 +166,9 @@ ConstantArrayBuilder::OperandSizeToSlice(OperandSize operand_size) const { ...@@ -164,6 +166,9 @@ ConstantArrayBuilder::OperandSizeToSlice(OperandSize operand_size) const {
case OperandSize::kShort: case OperandSize::kShort:
slice = idx_slice_[1]; slice = idx_slice_[1];
break; break;
case OperandSize::kQuad:
slice = idx_slice_[2];
break;
} }
DCHECK(slice->operand_size() == operand_size); DCHECK(slice->operand_size() == operand_size);
return slice; return slice;
......
...@@ -97,7 +97,7 @@ class ConstantArrayBuilder final BASE_EMBEDDED { ...@@ -97,7 +97,7 @@ class ConstantArrayBuilder final BASE_EMBEDDED {
IdentityMap<index_t>* constants_map() { return &constants_map_; } IdentityMap<index_t>* constants_map() { return &constants_map_; }
Isolate* isolate_; Isolate* isolate_;
ConstantArraySlice* idx_slice_[2]; ConstantArraySlice* idx_slice_[3];
IdentityMap<index_t> constants_map_; IdentityMap<index_t> constants_map_;
}; };
......
This diff is collapsed.
...@@ -19,12 +19,16 @@ namespace interpreter { ...@@ -19,12 +19,16 @@ namespace interpreter {
class InterpreterAssembler : public compiler::CodeStubAssembler { class InterpreterAssembler : public compiler::CodeStubAssembler {
public: public:
InterpreterAssembler(Isolate* isolate, Zone* zone, Bytecode bytecode); InterpreterAssembler(Isolate* isolate, Zone* zone, Bytecode bytecode,
OperandScale operand_scale);
virtual ~InterpreterAssembler(); virtual ~InterpreterAssembler();
// Returns the count immediate for bytecode operand |operand_index| in the // Returns the count immediate for bytecode operand |operand_index| in the
// current bytecode. // current bytecode.
compiler::Node* BytecodeOperandCount(int operand_index); 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 // Returns the index immediate for bytecode operand |operand_index| in the
// current bytecode. // current bytecode.
compiler::Node* BytecodeOperandIdx(int operand_index); compiler::Node* BytecodeOperandIdx(int operand_index);
...@@ -34,6 +38,9 @@ class InterpreterAssembler : public compiler::CodeStubAssembler { ...@@ -34,6 +38,9 @@ class InterpreterAssembler : public compiler::CodeStubAssembler {
// Returns the register index for bytecode operand |operand_index| in the // Returns the register index for bytecode operand |operand_index| in the
// current bytecode. // current bytecode.
compiler::Node* BytecodeOperandReg(int operand_index); 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. // Accumulator.
compiler::Node* GetAccumulator(); compiler::Node* GetAccumulator();
...@@ -136,6 +143,9 @@ class InterpreterAssembler : public compiler::CodeStubAssembler { ...@@ -136,6 +143,9 @@ class InterpreterAssembler : public compiler::CodeStubAssembler {
DispatchToBytecodeHandler(handler, BytecodeOffset()); DispatchToBytecodeHandler(handler, BytecodeOffset());
} }
// Dispatch bytecode as wide operand variant.
void DispatchWide(OperandScale operand_scale);
// Abort with the given bailout reason. // Abort with the given bailout reason.
void Abort(BailoutReason bailout_reason); void Abort(BailoutReason bailout_reason);
...@@ -167,10 +177,28 @@ class InterpreterAssembler : public compiler::CodeStubAssembler { ...@@ -167,10 +177,28 @@ class InterpreterAssembler : public compiler::CodeStubAssembler {
// Returns the offset of register |index| relative to RegisterFilePointer(). // Returns the offset of register |index| relative to RegisterFilePointer().
compiler::Node* RegisterFrameOffset(compiler::Node* index); compiler::Node* RegisterFrameOffset(compiler::Node* index);
compiler::Node* BytecodeOperand(int operand_index); // Returns the offset of an operand relative to the current bytecode offset.
compiler::Node* BytecodeOperandSignExtended(int operand_index); compiler::Node* OperandOffset(int operand_index);
compiler::Node* BytecodeOperandShort(int operand_index);
compiler::Node* BytecodeOperandShortSignExtended(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 // Returns BytecodeOffset() advanced by delta bytecodes. Note: this does not
// update BytecodeOffset() itself. // update BytecodeOffset() itself.
...@@ -184,7 +212,10 @@ class InterpreterAssembler : public compiler::CodeStubAssembler { ...@@ -184,7 +212,10 @@ class InterpreterAssembler : public compiler::CodeStubAssembler {
void AbortIfWordNotEqual(compiler::Node* lhs, compiler::Node* rhs, void AbortIfWordNotEqual(compiler::Node* lhs, compiler::Node* rhs,
BailoutReason bailout_reason); BailoutReason bailout_reason);
OperandScale operand_scale() const { return operand_scale_; }
Bytecode bytecode_; Bytecode bytecode_;
OperandScale operand_scale_;
CodeStubAssembler::Variable accumulator_; CodeStubAssembler::Variable accumulator_;
CodeStubAssembler::Variable context_; CodeStubAssembler::Variable context_;
CodeStubAssembler::Variable bytecode_array_; CodeStubAssembler::Variable bytecode_array_;
......
This diff is collapsed.
...@@ -40,7 +40,7 @@ class Interpreter { ...@@ -40,7 +40,7 @@ class Interpreter {
static bool MakeBytecode(CompilationInfo* info); static bool MakeBytecode(CompilationInfo* info);
// Return bytecode handler for |bytecode|. // Return bytecode handler for |bytecode|.
Code* GetBytecodeHandler(Bytecode bytecode); Code* GetBytecodeHandler(Bytecode bytecode, OperandScale operand_scale);
// GC support. // GC support.
void IterateDispatchTable(ObjectVisitor* v); void IterateDispatchTable(ObjectVisitor* v);
...@@ -53,6 +53,10 @@ class Interpreter { ...@@ -53,6 +53,10 @@ class Interpreter {
return reinterpret_cast<Address>(&dispatch_table_[0]); return reinterpret_cast<Address>(&dispatch_table_[0]);
} }
// Returns true if a handler is generated for a bytecode at a given
// operand scale.
static bool BytecodeHasHandler(Bytecode bytecode, OperandScale operand_scale);
private: private:
// Bytecode handler generator functions. // Bytecode handler generator functions.
#define DECLARE_BYTECODE_HANDLER_GENERATOR(Name, ...) \ #define DECLARE_BYTECODE_HANDLER_GENERATOR(Name, ...) \
...@@ -130,9 +134,14 @@ class Interpreter { ...@@ -130,9 +134,14 @@ class Interpreter {
void DoStoreLookupSlot(LanguageMode language_mode, void DoStoreLookupSlot(LanguageMode language_mode,
InterpreterAssembler* assembler); InterpreterAssembler* assembler);
// Get dispatch table index of bytecode.
static size_t GetDispatchTableIndex(Bytecode bytecode,
OperandScale operand_scale);
bool IsDispatchTableInitialized(); 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_; Isolate* isolate_;
Code* dispatch_table_[kDispatchTableSize]; Code* dispatch_table_[kDispatchTableSize];
......
// 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
// 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_
...@@ -1607,12 +1607,23 @@ void Logger::LogCodeObjects() { ...@@ -1607,12 +1607,23 @@ void Logger::LogCodeObjects() {
void Logger::LogBytecodeHandlers() { void Logger::LogBytecodeHandlers() {
if (!FLAG_ignition) return; if (!FLAG_ignition) return;
interpreter::Interpreter* interpreter = isolate_->interpreter();
const int last_index = static_cast<int>(interpreter::Bytecode::kLast); const int last_index = static_cast<int>(interpreter::Bytecode::kLast);
for (auto operand_scale = interpreter::OperandScale::kSingle;
operand_scale <= interpreter::OperandScale::kMaxValid;
operand_scale =
interpreter::Bytecodes::NextOperandScale(operand_scale)) {
for (int index = 0; index <= last_index; ++index) { for (int index = 0; index <= last_index; ++index) {
interpreter::Bytecode bytecode = interpreter::Bytecodes::FromByte(index); interpreter::Bytecode bytecode = interpreter::Bytecodes::FromByte(index);
Code* code = isolate_->interpreter()->GetBytecodeHandler(bytecode); if (interpreter::Interpreter::BytecodeHasHandler(bytecode,
operand_scale)) {
Code* code = interpreter->GetBytecodeHandler(bytecode, operand_scale);
std::string bytecode_name =
interpreter::Bytecodes::ToString(bytecode, operand_scale);
CodeCreateEvent(Logger::BYTECODE_HANDLER_TAG, AbstractCode::cast(code), CodeCreateEvent(Logger::BYTECODE_HANDLER_TAG, AbstractCode::cast(code),
interpreter::Bytecodes::ToString(bytecode)); bytecode_name.c_str());
}
}
} }
} }
......
...@@ -229,6 +229,10 @@ void ByteArray::ByteArrayVerify() { ...@@ -229,6 +229,10 @@ void ByteArray::ByteArrayVerify() {
void BytecodeArray::BytecodeArrayVerify() { void BytecodeArray::BytecodeArrayVerify() {
// TODO(oth): Walk bytecodes and immediate values to validate sanity. // TODO(oth): Walk bytecodes and immediate values to validate sanity.
// - All bytecodes are known and well formed.
// - Jumps must go to new instructions starts.
// - No Illegal bytecodes.
// - No consecutive sequences of prefix Wide / ExtraWide.
CHECK(IsBytecodeArray()); CHECK(IsBytecodeArray());
CHECK(constant_pool()->IsFixedArray()); CHECK(constant_pool()->IsFixedArray());
VerifyHeapPointer(constant_pool()); VerifyHeapPointer(constant_pool());
......
...@@ -14999,6 +14999,7 @@ void BytecodeArray::Disassemble(std::ostream& os) { ...@@ -14999,6 +14999,7 @@ void BytecodeArray::Disassemble(std::ostream& os) {
const uint8_t* base_address = GetFirstBytecodeAddress(); const uint8_t* base_address = GetFirstBytecodeAddress();
interpreter::SourcePositionTableIterator source_positions( interpreter::SourcePositionTableIterator source_positions(
source_position_table()); source_position_table());
interpreter::BytecodeArrayIterator iterator(handle(this)); interpreter::BytecodeArrayIterator iterator(handle(this));
while (!iterator.done()) { while (!iterator.done()) {
if (!source_positions.done() && if (!source_positions.done() &&
......
...@@ -28,8 +28,18 @@ RUNTIME_FUNCTION(Runtime_InterpreterNewClosure) { ...@@ -28,8 +28,18 @@ RUNTIME_FUNCTION(Runtime_InterpreterNewClosure) {
namespace { namespace {
void AdvanceToOffsetForTracing(
interpreter::BytecodeArrayIterator& bytecode_iterator, int offset) {
while (bytecode_iterator.current_offset() +
bytecode_iterator.current_bytecode_size() <=
offset) {
bytecode_iterator.Advance();
}
DCHECK_EQ(offset, bytecode_iterator.current_offset());
}
void PrintRegisters(std::ostream& os, bool is_input, void PrintRegisters(std::ostream& os, bool is_input,
Handle<BytecodeArray> bytecode_array, int bytecode_offset, interpreter::BytecodeArrayIterator& bytecode_iterator,
Handle<Object> accumulator) { Handle<Object> accumulator) {
static const int kRegFieldWidth = static_cast<int>(strlen("accumulator")); static const int kRegFieldWidth = static_cast<int>(strlen("accumulator"));
static const char* kInputColourCode = "\033[0;36m"; static const char* kInputColourCode = "\033[0;36m";
...@@ -46,15 +56,13 @@ void PrintRegisters(std::ostream& os, bool is_input, ...@@ -46,15 +56,13 @@ void PrintRegisters(std::ostream& os, bool is_input,
os << " ]" << std::endl; os << " ]" << std::endl;
// Find the location of the register file. // Find the location of the register file.
JavaScriptFrameIterator frame_iterator(bytecode_array->GetIsolate()); JavaScriptFrameIterator frame_iterator(
bytecode_iterator.bytecode_array()->GetIsolate());
JavaScriptFrame* frame = frame_iterator.frame(); JavaScriptFrame* frame = frame_iterator.frame();
Address register_file = Address register_file =
frame->fp() + InterpreterFrameConstants::kRegisterFilePointerFromFp; frame->fp() + InterpreterFrameConstants::kRegisterFilePointerFromFp;
// Print the registers. // Print the registers.
interpreter::BytecodeArrayIterator bytecode_iterator(bytecode_array);
bytecode_iterator.set_current_offset(
bytecode_offset - BytecodeArray::kHeaderSize + kHeapObjectTag);
interpreter::Bytecode bytecode = bytecode_iterator.current_bytecode(); interpreter::Bytecode bytecode = bytecode_iterator.current_bytecode();
int operand_count = interpreter::Bytecodes::NumberOfOperands(bytecode); int operand_count = interpreter::Bytecodes::NumberOfOperands(bytecode);
for (int operand_index = 0; operand_index < operand_count; operand_index++) { for (int operand_index = 0; operand_index < operand_count; operand_index++) {
...@@ -74,7 +82,7 @@ void PrintRegisters(std::ostream& os, bool is_input, ...@@ -74,7 +82,7 @@ void PrintRegisters(std::ostream& os, bool is_input,
Object* reg_object = Memory::Object_at(reg_location); Object* reg_object = Memory::Object_at(reg_location);
os << " [ " << std::setw(kRegFieldWidth) os << " [ " << std::setw(kRegFieldWidth)
<< interpreter::Register(reg_index).ToString( << interpreter::Register(reg_index).ToString(
bytecode_array->parameter_count()) bytecode_iterator.bytecode_array()->parameter_count())
<< kArrowDirection; << kArrowDirection;
reg_object->ShortPrint(os); reg_object->ShortPrint(os);
os << " ]" << std::endl; os << " ]" << std::endl;
...@@ -96,6 +104,10 @@ RUNTIME_FUNCTION(Runtime_InterpreterTraceBytecodeEntry) { ...@@ -96,6 +104,10 @@ RUNTIME_FUNCTION(Runtime_InterpreterTraceBytecodeEntry) {
CONVERT_ARG_HANDLE_CHECKED(Object, accumulator, 2); CONVERT_ARG_HANDLE_CHECKED(Object, accumulator, 2);
OFStream os(stdout); OFStream os(stdout);
int offset = bytecode_offset - BytecodeArray::kHeaderSize + kHeapObjectTag;
interpreter::BytecodeArrayIterator bytecode_iterator(bytecode_array);
AdvanceToOffsetForTracing(bytecode_iterator, offset);
if (offset == bytecode_iterator.current_offset()) {
// Print bytecode. // Print bytecode.
const uint8_t* bytecode_address = const uint8_t* bytecode_address =
reinterpret_cast<const uint8_t*>(*bytecode_array) + bytecode_offset; reinterpret_cast<const uint8_t*>(*bytecode_array) + bytecode_offset;
...@@ -105,11 +117,11 @@ RUNTIME_FUNCTION(Runtime_InterpreterTraceBytecodeEntry) { ...@@ -105,11 +117,11 @@ RUNTIME_FUNCTION(Runtime_InterpreterTraceBytecodeEntry) {
interpreter::Bytecodes::Decode(os, bytecode_address, interpreter::Bytecodes::Decode(os, bytecode_address,
bytecode_array->parameter_count()); bytecode_array->parameter_count());
os << std::endl; os << std::endl;
// Print all input registers and accumulator. // Print all input registers and accumulator.
PrintRegisters(os, true, bytecode_array, bytecode_offset, accumulator); PrintRegisters(os, true, bytecode_iterator, accumulator);
os << std::flush; os << std::flush;
}
return isolate->heap()->undefined_value(); return isolate->heap()->undefined_value();
} }
...@@ -119,11 +131,21 @@ RUNTIME_FUNCTION(Runtime_InterpreterTraceBytecodeExit) { ...@@ -119,11 +131,21 @@ RUNTIME_FUNCTION(Runtime_InterpreterTraceBytecodeExit) {
CONVERT_ARG_HANDLE_CHECKED(BytecodeArray, bytecode_array, 0); CONVERT_ARG_HANDLE_CHECKED(BytecodeArray, bytecode_array, 0);
CONVERT_SMI_ARG_CHECKED(bytecode_offset, 1); CONVERT_SMI_ARG_CHECKED(bytecode_offset, 1);
CONVERT_ARG_HANDLE_CHECKED(Object, accumulator, 2); CONVERT_ARG_HANDLE_CHECKED(Object, accumulator, 2);
OFStream os(stdout);
int offset = bytecode_offset - BytecodeArray::kHeaderSize + kHeapObjectTag;
interpreter::BytecodeArrayIterator bytecode_iterator(bytecode_array);
AdvanceToOffsetForTracing(bytecode_iterator, offset);
// The offset comparison here ensures registers only printed when the
// (potentially) widened bytecode has completed. The iterator reports
// the offset as the offset of the prefix bytecode.
if (bytecode_iterator.current_operand_scale() ==
interpreter::OperandScale::kSingle ||
offset > bytecode_iterator.current_offset()) {
OFStream os(stdout);
// Print all output registers and accumulator. // Print all output registers and accumulator.
PrintRegisters(os, false, bytecode_array, bytecode_offset, accumulator); PrintRegisters(os, false, bytecode_iterator, accumulator);
os << std::flush; os << std::flush;
}
return isolate->heap()->undefined_value(); return isolate->heap()->undefined_value();
} }
......
...@@ -96,7 +96,7 @@ void BytecodeExpectationsPrinter::PrintEscapedString( ...@@ -96,7 +96,7 @@ void BytecodeExpectationsPrinter::PrintEscapedString(
} }
namespace { namespace {
i::Runtime::FunctionId IndexToFunctionId(int index) { i::Runtime::FunctionId IndexToFunctionId(uint32_t index) {
return static_cast<i::Runtime::FunctionId>(index); return static_cast<i::Runtime::FunctionId>(index);
} }
} // namespace } // namespace
...@@ -105,7 +105,8 @@ void BytecodeExpectationsPrinter::PrintBytecodeOperand( ...@@ -105,7 +105,8 @@ void BytecodeExpectationsPrinter::PrintBytecodeOperand(
std::ostream& stream, const BytecodeArrayIterator& bytecode_iter, std::ostream& stream, const BytecodeArrayIterator& bytecode_iter,
const Bytecode& bytecode, int op_index, int parameter_count) const { const Bytecode& bytecode, int op_index, int parameter_count) const {
OperandType op_type = Bytecodes::GetOperandType(bytecode, op_index); OperandType op_type = Bytecodes::GetOperandType(bytecode, op_index);
OperandSize op_size = Bytecodes::GetOperandSize(bytecode, op_index); OperandSize op_size = Bytecodes::GetOperandSize(
bytecode, op_index, bytecode_iter.current_operand_scale());
const char* size_tag; const char* size_tag;
switch (op_size) { switch (op_size) {
...@@ -115,6 +116,9 @@ void BytecodeExpectationsPrinter::PrintBytecodeOperand( ...@@ -115,6 +116,9 @@ void BytecodeExpectationsPrinter::PrintBytecodeOperand(
case OperandSize::kShort: case OperandSize::kShort:
size_tag = "16"; size_tag = "16";
break; break;
case OperandSize::kQuad:
size_tag = "32";
break;
default: default:
UNREACHABLE(); UNREACHABLE();
return; return;
...@@ -143,19 +147,26 @@ void BytecodeExpectationsPrinter::PrintBytecodeOperand( ...@@ -143,19 +147,26 @@ void BytecodeExpectationsPrinter::PrintBytecodeOperand(
} else { } else {
stream << 'U' << size_tag << '('; stream << 'U' << size_tag << '(';
if (op_index == 0 && Bytecodes::IsCallRuntime(bytecode)) { switch (op_type) {
DCHECK_EQ(op_type, OperandType::kIdx16); case OperandType::kFlag8:
int operand = bytecode_iter.GetIndexOperand(op_index); stream << bytecode_iter.GetFlagOperand(op_index);
break;
case OperandType::kIdx:
stream << bytecode_iter.GetIndexOperand(op_index);
break;
case OperandType::kImm:
stream << bytecode_iter.GetImmediateOperand(op_index);
break;
case OperandType::kRegCount:
stream << bytecode_iter.GetRegisterCountOperand(op_index);
break;
case OperandType::kRuntimeId: {
uint32_t operand = bytecode_iter.GetRuntimeIdOperand(op_index);
stream << "Runtime::k" stream << "Runtime::k"
<< i::Runtime::FunctionForId(IndexToFunctionId(operand))->name; << i::Runtime::FunctionForId(IndexToFunctionId(operand))->name;
} else if (Bytecodes::IsImmediateOperandType(op_type)) { break;
// We need a cast, otherwise the result is printed as char. }
stream << static_cast<int>(bytecode_iter.GetImmediateOperand(op_index)); default:
} else if (Bytecodes::IsRegisterCountOperandType(op_type)) {
stream << bytecode_iter.GetRegisterCountOperand(op_index);
} else if (Bytecodes::IsIndexOperandType(op_type)) {
stream << bytecode_iter.GetIndexOperand(op_index);
} else {
UNREACHABLE(); UNREACHABLE();
} }
...@@ -167,9 +178,12 @@ void BytecodeExpectationsPrinter::PrintBytecode( ...@@ -167,9 +178,12 @@ void BytecodeExpectationsPrinter::PrintBytecode(
std::ostream& stream, const BytecodeArrayIterator& bytecode_iter, std::ostream& stream, const BytecodeArrayIterator& bytecode_iter,
int parameter_count) const { int parameter_count) const {
Bytecode bytecode = bytecode_iter.current_bytecode(); Bytecode bytecode = bytecode_iter.current_bytecode();
OperandScale operand_scale = bytecode_iter.current_operand_scale();
if (Bytecodes::OperandScaleRequiresPrefixBytecode(operand_scale)) {
Bytecode prefix = Bytecodes::OperandScaleToPrefixBytecode(operand_scale);
stream << "B(" << Bytecodes::ToString(prefix) << "), ";
}
stream << "B(" << Bytecodes::ToString(bytecode) << ')'; stream << "B(" << Bytecodes::ToString(bytecode) << ')';
int operands_count = Bytecodes::NumberOfOperands(bytecode); int operands_count = Bytecodes::NumberOfOperands(bytecode);
for (int op_index = 0; op_index < operands_count; ++op_index) { for (int op_index = 0; op_index < operands_count; ++op_index) {
stream << ", "; stream << ", ";
......
...@@ -270,7 +270,7 @@ snippet: " ...@@ -270,7 +270,7 @@ snippet: "
" "
frame size: 1 frame size: 1
parameter count: 1 parameter count: 1
bytecode array length: 1032 bytecode array length: 1033
bytecodes: [ bytecodes: [
B(StackCheck), B(StackCheck),
B(LdaConstant), U8(0), B(LdaConstant), U8(0),
...@@ -785,7 +785,7 @@ bytecodes: [ ...@@ -785,7 +785,7 @@ bytecodes: [
B(Star), R(0), B(Star), R(0),
B(LdaConstant), U8(255), B(LdaConstant), U8(255),
B(Star), R(0), B(Star), R(0),
B(CreateArrayLiteralWide), U16(256), U16(0), U8(3), B(Wide), B(CreateArrayLiteral), U16(256), U16(0), U8(3),
B(Return), B(Return),
] ]
constant pool: [ constant pool: [
......
...@@ -36,7 +36,7 @@ bytecodes: [ ...@@ -36,7 +36,7 @@ bytecodes: [
B(Mov), R(closure), R(6), B(Mov), R(closure), R(6),
B(LdaZero), B(LdaZero),
B(Star), R(7), B(Star), R(7),
B(LdaSmi8), U8(30), B(LdaSmi), U8(30),
B(Star), R(8), B(Star), R(8),
B(CallRuntime), U16(Runtime::kResolvePossiblyDirectEval), R(4), U8(5), B(CallRuntime), U16(Runtime::kResolvePossiblyDirectEval), R(4), U8(5),
B(Star), R(1), B(Star), R(1),
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment