| Index: src/interpreter/bytecode-array-builder.cc
|
| diff --git a/src/interpreter/bytecode-array-builder.cc b/src/interpreter/bytecode-array-builder.cc
|
| index c513663a2f97e06d713ae2c418227d597dcf2218..56cdfb9d82d9873fba68eb3914601cd4d8c54698 100644
|
| --- a/src/interpreter/bytecode-array-builder.cc
|
| +++ b/src/interpreter/bytecode-array-builder.cc
|
| @@ -8,7 +8,7 @@ namespace v8 {
|
| namespace internal {
|
| namespace interpreter {
|
|
|
| -class BytecodeArrayBuilder::PreviousBytecodeHelper {
|
| +class BytecodeArrayBuilder::PreviousBytecodeHelper BASE_EMBEDDED {
|
| public:
|
| explicit PreviousBytecodeHelper(const BytecodeArrayBuilder& array_builder)
|
| : array_builder_(array_builder),
|
| @@ -37,9 +37,9 @@ class BytecodeArrayBuilder::PreviousBytecodeHelper {
|
| Bytecodes::GetOperandOffset(bytecode, operand_index);
|
| OperandSize size = Bytecodes::GetOperandSize(bytecode, operand_index);
|
| switch (size) {
|
| - default:
|
| case OperandSize::kNone:
|
| UNREACHABLE();
|
| + break;
|
| case OperandSize::kByte:
|
| return static_cast<uint32_t>(
|
| array_builder_.bytecodes()->at(operand_offset));
|
| @@ -49,6 +49,7 @@ class BytecodeArrayBuilder::PreviousBytecodeHelper {
|
| array_builder_.bytecodes()->at(operand_offset + 1);
|
| return static_cast<uint32_t>(operand);
|
| }
|
| + return 0;
|
| }
|
|
|
| Handle<Object> GetConstantForIndexOperand(int operand_index) const {
|
| @@ -63,7 +64,6 @@ class BytecodeArrayBuilder::PreviousBytecodeHelper {
|
| DISALLOW_COPY_AND_ASSIGN(PreviousBytecodeHelper);
|
| };
|
|
|
| -
|
| BytecodeArrayBuilder::BytecodeArrayBuilder(Isolate* isolate, Zone* zone)
|
| : isolate_(isolate),
|
| zone_(zone),
|
| @@ -79,8 +79,8 @@ BytecodeArrayBuilder::BytecodeArrayBuilder(Isolate* isolate, Zone* zone)
|
| local_register_count_(-1),
|
| context_register_count_(-1),
|
| temporary_register_count_(0),
|
| - free_temporaries_(zone) {}
|
| -
|
| + free_temporaries_(zone),
|
| + register_translator_(this) {}
|
|
|
| BytecodeArrayBuilder::~BytecodeArrayBuilder() { DCHECK_EQ(0, unbound_jumps_); }
|
|
|
| @@ -148,7 +148,8 @@ Handle<BytecodeArray> BytecodeArrayBuilder::ToBytecodeArray() {
|
| EnsureReturn();
|
|
|
| int bytecode_size = static_cast<int>(bytecodes_.size());
|
| - int register_count = fixed_register_count() + temporary_register_count_;
|
| + int register_count =
|
| + fixed_and_temporary_register_count() + translation_register_count();
|
| int frame_size = register_count * kPointerSize;
|
| Handle<FixedArray> constant_pool = constant_array_builder()->ToFixedArray();
|
| Handle<FixedArray> handler_table = handler_table_builder()->ToHandlerTable();
|
| @@ -166,14 +167,23 @@ void BytecodeArrayBuilder::Output(Bytecode bytecode, uint32_t(&operands)[N]) {
|
| // Don't output dead code.
|
| if (exit_seen_in_block_) return;
|
|
|
| - DCHECK_EQ(Bytecodes::NumberOfOperands(bytecode), static_cast<int>(N));
|
| + 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();
|
| bytecodes()->push_back(Bytecodes::ToByte(bytecode));
|
| - for (int i = 0; i < static_cast<int>(N); i++) {
|
| + for (int i = 0; i < operand_count; i++) {
|
| DCHECK(OperandIsValid(bytecode, i, operands[i]));
|
| switch (Bytecodes::GetOperandSize(bytecode, i)) {
|
| case OperandSize::kNone:
|
| UNREACHABLE();
|
| + break;
|
| case OperandSize::kByte:
|
| bytecodes()->push_back(static_cast<uint8_t>(operands[i]));
|
| break;
|
| @@ -186,6 +196,10 @@ void BytecodeArrayBuilder::Output(Bytecode bytecode, uint32_t(&operands)[N]) {
|
| }
|
| }
|
| }
|
| +
|
| + if (register_operand_count > 0) {
|
| + register_translator()->TranslateOutputRegisters();
|
| + }
|
| }
|
|
|
|
|
| @@ -361,9 +375,9 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::StoreAccumulatorInRegister(
|
| BytecodeArrayBuilder& BytecodeArrayBuilder::MoveRegister(Register from,
|
| Register to) {
|
| DCHECK(from != to);
|
| - if (FitsInReg8Operand(to) && FitsInReg8Operand(from)) {
|
| + if (FitsInReg8Operand(from) && FitsInReg8Operand(to)) {
|
| Output(Bytecode::kMov, from.ToRawOperand(), to.ToRawOperand());
|
| - } else if (FitsInReg16Operand(to) && FitsInReg16Operand(from)) {
|
| + } else if (FitsInReg16Operand(from) && FitsInReg16Operand(to)) {
|
| Output(Bytecode::kMovWide, from.ToRawOperand(), to.ToRawOperand());
|
| } else {
|
| UNIMPLEMENTED();
|
| @@ -371,6 +385,40 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::MoveRegister(Register from,
|
| 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());
|
| +}
|
| +
|
| +bool BytecodeArrayBuilder::RegisterOperandIsMovable(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::kReg16) {
|
| + 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);
|
| + }
|
| +}
|
|
|
| BytecodeArrayBuilder& BytecodeArrayBuilder::LoadGlobal(
|
| const Handle<String> name, int feedback_slot, LanguageMode language_mode,
|
| @@ -1083,7 +1131,6 @@ 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(),
|
| @@ -1180,10 +1227,13 @@ size_t BytecodeArrayBuilder::GetConstantPoolEntry(Handle<Object> object) {
|
| return constant_array_builder()->Insert(object);
|
| }
|
|
|
| +void BytecodeArrayBuilder::ForgeTemporaryRegister() {
|
| + temporary_register_count_++;
|
| +}
|
|
|
| int BytecodeArrayBuilder::BorrowTemporaryRegister() {
|
| if (free_temporaries_.empty()) {
|
| - temporary_register_count_ += 1;
|
| + ForgeTemporaryRegister();
|
| return last_temporary_register().index();
|
| } else {
|
| auto pos = free_temporaries_.begin();
|
| @@ -1202,7 +1252,7 @@ int BytecodeArrayBuilder::BorrowTemporaryRegisterNotInRange(int start_index,
|
| // greater than end_index.
|
| index = free_temporaries_.upper_bound(end_index);
|
| if (index == free_temporaries_.end()) {
|
| - temporary_register_count_ += 1;
|
| + ForgeTemporaryRegister();
|
| return last_temporary_register().index();
|
| }
|
| } else {
|
| @@ -1234,11 +1284,33 @@ int BytecodeArrayBuilder::PrepareForConsecutiveTemporaryRegisters(
|
| return -1;
|
| }
|
|
|
| + // TODO(oth): replace use of set<> here for free_temporaries with a
|
| + // more efficient structure. And/or partition into two searches -
|
| + // one before the translation window and one after.
|
| +
|
| + // A run will require at least |count| free temporaries.
|
| + while (free_temporaries_.size() < count) {
|
| + ForgeTemporaryRegister();
|
| + free_temporaries_.insert(last_temporary_register().index());
|
| + }
|
| +
|
| // Search within existing temporaries for a run.
|
| auto start = free_temporaries_.begin();
|
| size_t run_length = 0;
|
| for (auto run_end = start; run_end != free_temporaries_.end(); run_end++) {
|
| - if (*run_end != *start + static_cast<int>(run_length)) {
|
| + int expected = *start + static_cast<int>(run_length);
|
| + if (*run_end != expected) {
|
| + 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;
|
| }
|
| @@ -1255,12 +1327,34 @@ int BytecodeArrayBuilder::PrepareForConsecutiveTemporaryRegisters(
|
| run_length = 0;
|
| }
|
|
|
| + // 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) {
|
| + ForgeTemporaryRegister();
|
| + free_temporaries_.insert(last_temporary_register().index());
|
| + start = --free_temporaries_.end();
|
| + reg_first = Register(*start);
|
| + reg_last = Register(*start + static_cast<int>(count) - 1);
|
| + run_length = 0;
|
| + }
|
| +
|
| // Ensure enough registers for run.
|
| while (run_length++ < count) {
|
| - temporary_register_count_++;
|
| + ForgeTemporaryRegister();
|
| free_temporaries_.insert(last_temporary_register().index());
|
| }
|
| - return last_temporary_register().index() - static_cast<int>(count) + 1;
|
| +
|
| + 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;
|
| }
|
|
|
|
|
| @@ -1281,10 +1375,35 @@ bool BytecodeArrayBuilder::OperandIsValid(Bytecode bytecode, int operand_index,
|
| switch (operand_type) {
|
| case OperandType::kNone:
|
| return false;
|
| - case OperandType::kRegCount16:
|
| + 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.
|
| + 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;
|
| + }
|
| + }
|
| case OperandType::kIdx16:
|
| return static_cast<uint16_t>(operand_value) == operand_value;
|
| - case OperandType::kRegCount8:
|
| case OperandType::kImm8:
|
| case OperandType::kIdx8:
|
| return static_cast<uint8_t>(operand_value) == operand_value;
|
| @@ -1329,12 +1448,20 @@ bool BytecodeArrayBuilder::OperandIsValid(Bytecode bytecode, int operand_index,
|
|
|
| bool BytecodeArrayBuilder::RegisterIsValid(Register reg,
|
| OperandType reg_type) const {
|
| + if (!reg.is_valid()) {
|
| + return false;
|
| + }
|
| +
|
| switch (Bytecodes::SizeOfOperand(reg_type)) {
|
| case OperandSize::kByte:
|
| - if (!FitsInReg8Operand(reg)) { return false; }
|
| + if (!FitsInReg8OperandUntranslated(reg)) {
|
| + return false;
|
| + }
|
| break;
|
| case OperandSize::kShort:
|
| - if (!FitsInReg16Operand(reg)) { return false; }
|
| + if (!FitsInReg16OperandUntranslated(reg)) {
|
| + return false;
|
| + }
|
| break;
|
| case OperandSize::kNone:
|
| UNREACHABLE();
|
| @@ -1345,12 +1472,17 @@ bool BytecodeArrayBuilder::RegisterIsValid(Register reg,
|
| reg.is_new_target()) {
|
| return true;
|
| } else if (reg.is_parameter()) {
|
| - int parameter_index = reg.ToParameterIndex(parameter_count_);
|
| - return parameter_index >= 0 && parameter_index < parameter_count_;
|
| - } else if (reg.index() < fixed_register_count()) {
|
| - return true;
|
| + 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 {
|
| - return TemporaryRegisterIsLive(reg);
|
| + reg = RegisterTranslator::UntranslateRegister(reg);
|
| + if (reg.index() < fixed_register_count()) {
|
| + return true;
|
| + } else {
|
| + return TemporaryRegisterIsLive(reg);
|
| + }
|
| }
|
| }
|
|
|
| @@ -1365,9 +1497,10 @@ bool BytecodeArrayBuilder::IsRegisterInAccumulator(Register reg) {
|
| if (LastBytecodeInSameBlock()) {
|
| PreviousBytecodeHelper previous_bytecode(*this);
|
| Bytecode bytecode = previous_bytecode.GetBytecode();
|
| - if ((bytecode == Bytecode::kLdar || bytecode == Bytecode::kStar) &&
|
| - (reg == Register::FromOperand(previous_bytecode.GetOperand(0)))) {
|
| - return true;
|
| + if (bytecode == Bytecode::kLdar || bytecode == Bytecode::kStar) {
|
| + Register previous_reg =
|
| + Register::FromOperand(previous_bytecode.GetOperand(0));
|
| + return previous_reg == reg;
|
| }
|
| }
|
| return false;
|
| @@ -1680,13 +1813,23 @@ bool BytecodeArrayBuilder::FitsInIdx16Operand(size_t value) {
|
|
|
| // static
|
| bool BytecodeArrayBuilder::FitsInReg8Operand(Register value) {
|
| - return kMinInt8 <= value.index() && value.index() <= kMaxInt8;
|
| + return RegisterTranslator::FitsInReg8Operand(value);
|
| +}
|
| +
|
| +// static
|
| +bool BytecodeArrayBuilder::FitsInReg8OperandUntranslated(Register value) {
|
| + return value.is_byte_operand();
|
| }
|
|
|
|
|
| // static
|
| bool BytecodeArrayBuilder::FitsInReg16Operand(Register value) {
|
| - return kMinInt16 <= value.index() && value.index() <= kMaxInt16;
|
| + return RegisterTranslator::FitsInReg16Operand(value);
|
| +}
|
| +
|
| +// static
|
| +bool BytecodeArrayBuilder::FitsInReg16OperandUntranslated(Register value) {
|
| + return value.is_short_operand();
|
| }
|
|
|
| } // namespace interpreter
|
|
|