[Intepreter] Extend and move Register class.
Add methods for converting parameter index to a register and vice-versa. Move Register class into bytecodes.h. Update Bytecodes::Decode to pretty print parameters. BUG=v8:4280 LOG=NO Review URL: https://codereview.chromium.org/1325983002 Cr-Commit-Position: refs/heads/master@{#30549}
This commit is contained in:
parent
310f2ece0f
commit
22983f71f9
@ -37,10 +37,10 @@ void BytecodeArrayBuilder::set_parameter_count(int number_of_parameters) {
|
||||
int BytecodeArrayBuilder::parameter_count() const { return parameter_count_; }
|
||||
|
||||
|
||||
Register BytecodeArrayBuilder::Parameter(int param_index) {
|
||||
DCHECK_GE(param_index, 0);
|
||||
DCHECK_LT(param_index, parameter_count_);
|
||||
return Register(kLastParamRegisterIndex - parameter_count_ + param_index + 1);
|
||||
Register BytecodeArrayBuilder::Parameter(int parameter_index) {
|
||||
DCHECK_GE(parameter_index, 0);
|
||||
DCHECK_LT(parameter_index, parameter_count_);
|
||||
return Register::FromParameterIndex(parameter_index, parameter_count_);
|
||||
}
|
||||
|
||||
|
||||
@ -229,10 +229,13 @@ bool BytecodeArrayBuilder::OperandIsValid(Bytecode bytecode, int operand_index,
|
||||
case OperandType::kIdx:
|
||||
return true;
|
||||
case OperandType::kReg: {
|
||||
int reg_index = Register::FromOperand(operand_value).index();
|
||||
return (reg_index >= 0 && reg_index < temporary_register_next_) ||
|
||||
(reg_index <= kLastParamRegisterIndex &&
|
||||
reg_index > kLastParamRegisterIndex - parameter_count_);
|
||||
Register reg = Register::FromOperand(operand_value);
|
||||
if (reg.is_parameter()) {
|
||||
int parameter_index = reg.ToParameterIndex(parameter_count_);
|
||||
return parameter_index >= 0 && parameter_index < parameter_count_;
|
||||
} else {
|
||||
return (reg.index() >= 0 && reg.index() < temporary_register_next_);
|
||||
}
|
||||
}
|
||||
}
|
||||
UNREACHABLE();
|
||||
|
@ -8,7 +8,6 @@
|
||||
#include <vector>
|
||||
|
||||
#include "src/ast.h"
|
||||
#include "src/frames.h"
|
||||
#include "src/identity-map.h"
|
||||
#include "src/interpreter/bytecodes.h"
|
||||
#include "src/zone.h"
|
||||
@ -64,9 +63,6 @@ class BytecodeArrayBuilder {
|
||||
BytecodeArrayBuilder& Return();
|
||||
|
||||
private:
|
||||
static const int kLastParamRegisterIndex =
|
||||
-InterpreterFrameConstants::kLastParamFromRegisterPointer / kPointerSize;
|
||||
|
||||
static Bytecode BytecodeForBinaryOperation(Token::Value op);
|
||||
static bool FitsInByteOperand(int value);
|
||||
static bool FitsInByteOperand(size_t value);
|
||||
@ -100,32 +96,6 @@ class BytecodeArrayBuilder {
|
||||
DISALLOW_IMPLICIT_CONSTRUCTORS(BytecodeArrayBuilder);
|
||||
};
|
||||
|
||||
// An interpreter register which is located in the function's register file
|
||||
// in its stack-frame.
|
||||
class Register {
|
||||
public:
|
||||
static const int kMaxRegisterIndex = 128;
|
||||
static const int kMinRegisterIndex = -127;
|
||||
|
||||
explicit Register(int index) : index_(index) {
|
||||
DCHECK_LE(index_, kMaxRegisterIndex);
|
||||
DCHECK_GE(index_, kMinRegisterIndex);
|
||||
}
|
||||
|
||||
int index() { return index_; }
|
||||
|
||||
uint8_t ToOperand() { return static_cast<uint8_t>(-index_); }
|
||||
static Register FromOperand(uint8_t operand) {
|
||||
return Register(-static_cast<int8_t>(operand));
|
||||
}
|
||||
|
||||
private:
|
||||
void* operator new(size_t size);
|
||||
void operator delete(void* p);
|
||||
|
||||
int index_;
|
||||
};
|
||||
|
||||
// A stack-allocated class than allows the instantiator to allocate
|
||||
// temporary registers that are cleaned up when scope is closed.
|
||||
class TemporaryRegisterScope {
|
||||
|
@ -4,7 +4,7 @@
|
||||
|
||||
#include "src/interpreter/bytecodes.h"
|
||||
|
||||
#include "src/interpreter/bytecode-array-builder.h"
|
||||
#include "src/frames.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
@ -103,8 +103,8 @@ int Bytecodes::MaximumSize() { return 1 + kMaxOperands; }
|
||||
|
||||
|
||||
// static
|
||||
std::ostream& Bytecodes::Decode(std::ostream& os,
|
||||
const uint8_t* bytecode_start) {
|
||||
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]);
|
||||
@ -132,9 +132,20 @@ std::ostream& Bytecodes::Decode(std::ostream& os,
|
||||
case interpreter::OperandType::kImm8:
|
||||
os << "#" << static_cast<int>(operand);
|
||||
break;
|
||||
case interpreter::OperandType::kReg:
|
||||
os << "r" << Register::FromOperand(operand).index();
|
||||
case interpreter::OperandType::kReg: {
|
||||
Register reg = Register::FromOperand(operand);
|
||||
if (reg.is_parameter()) {
|
||||
int parameter_index = reg.ToParameterIndex(parameter_count);
|
||||
if (parameter_index == 0) {
|
||||
os << "<this>";
|
||||
} else {
|
||||
os << "a" << parameter_index - 1;
|
||||
}
|
||||
} else {
|
||||
os << "r" << reg.index();
|
||||
}
|
||||
break;
|
||||
}
|
||||
case interpreter::OperandType::kNone:
|
||||
UNREACHABLE();
|
||||
break;
|
||||
@ -156,6 +167,44 @@ std::ostream& operator<<(std::ostream& os, const OperandType& operand_type) {
|
||||
return os << Bytecodes::OperandTypeToString(operand_type);
|
||||
}
|
||||
|
||||
|
||||
static const int kLastParamRegisterIndex =
|
||||
-InterpreterFrameConstants::kLastParamFromRegisterPointer / kPointerSize;
|
||||
|
||||
|
||||
// Registers occupy range 0-127 in 8-bit value leaving 128 unused values.
|
||||
// Parameter indices are biased with the negative value kLastParamRegisterIndex
|
||||
// for ease of access in the interpreter.
|
||||
static const int kMaxParameterIndex = 128 + kLastParamRegisterIndex;
|
||||
|
||||
|
||||
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);
|
||||
DCHECK_GE(register_index, Register::kMinRegisterIndex);
|
||||
return Register(register_index);
|
||||
}
|
||||
|
||||
|
||||
int Register::ToParameterIndex(int parameter_count) const {
|
||||
DCHECK(is_parameter());
|
||||
return index() - kLastParamRegisterIndex + parameter_count - 1;
|
||||
}
|
||||
|
||||
|
||||
int Register::MaxParameterIndex() { return kMaxParameterIndex; }
|
||||
|
||||
|
||||
uint8_t Register::ToOperand() const { return static_cast<uint8_t>(-index_); }
|
||||
|
||||
|
||||
Register Register::FromOperand(uint8_t operand) {
|
||||
return Register(-static_cast<int8_t>(operand));
|
||||
}
|
||||
|
||||
} // namespace interpreter
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
@ -80,6 +80,36 @@ enum class Bytecode : uint8_t {
|
||||
};
|
||||
|
||||
|
||||
// An interpreter register which is located in the function's register file
|
||||
// in its stack-frame. Register hold parameters, this, and expression values.
|
||||
class Register {
|
||||
public:
|
||||
static const int kMaxRegisterIndex = 127;
|
||||
static const int kMinRegisterIndex = -128;
|
||||
|
||||
explicit Register(int index) : index_(index) {
|
||||
DCHECK_LE(index_, kMaxRegisterIndex);
|
||||
DCHECK_GE(index_, kMinRegisterIndex);
|
||||
}
|
||||
|
||||
int index() const { return index_; }
|
||||
bool is_parameter() const { return index_ < 0; }
|
||||
|
||||
static Register FromParameterIndex(int index, int parameter_count);
|
||||
int ToParameterIndex(int parameter_count) const;
|
||||
static int MaxParameterIndex();
|
||||
|
||||
static Register FromOperand(uint8_t operand);
|
||||
uint8_t ToOperand() const;
|
||||
|
||||
private:
|
||||
void* operator new(size_t size);
|
||||
void operator delete(void* p);
|
||||
|
||||
int index_;
|
||||
};
|
||||
|
||||
|
||||
class Bytecodes {
|
||||
public:
|
||||
// Returns string representation of |bytecode|.
|
||||
@ -110,7 +140,8 @@ class Bytecodes {
|
||||
static int MaximumSize();
|
||||
|
||||
// Decode a single bytecode and operands to |os|.
|
||||
static std::ostream& Decode(std::ostream& os, const uint8_t* bytecode_start);
|
||||
static std::ostream& Decode(std::ostream& os, const uint8_t* bytecode_start,
|
||||
int number_of_parameters);
|
||||
|
||||
private:
|
||||
DISALLOW_IMPLICIT_CONSTRUCTORS(Bytecodes);
|
||||
|
@ -11916,7 +11916,7 @@ void BytecodeArray::Disassemble(std::ostream& os) {
|
||||
|
||||
SNPrintF(buf, "%p", bytecode_start);
|
||||
os << buf.start() << " : ";
|
||||
interpreter::Bytecodes::Decode(os, bytecode_start);
|
||||
interpreter::Bytecodes::Decode(os, bytecode_start, parameter_count());
|
||||
os << "\n";
|
||||
}
|
||||
|
||||
|
63
test/unittests/interpreter/bytecodes-unittest.cc
Normal file
63
test/unittests/interpreter/bytecodes-unittest.cc
Normal file
@ -0,0 +1,63 @@
|
||||
// Copyright 2014 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 <vector>
|
||||
|
||||
#include "src/v8.h"
|
||||
|
||||
#include "src/interpreter/bytecodes.h"
|
||||
#include "test/unittests/test-utils.h"
|
||||
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
namespace interpreter {
|
||||
|
||||
TEST(OperandConversion, Registers) {
|
||||
for (int i = 0; i < 128; i++) {
|
||||
uint8_t operand_value = Register(i).ToOperand();
|
||||
Register r = Register::FromOperand(operand_value);
|
||||
CHECK_EQ(i, r.index());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST(OperandConversion, Parameters) {
|
||||
int parameter_counts[] = {7, 13, 99};
|
||||
|
||||
size_t count = sizeof(parameter_counts) / sizeof(parameter_counts[0]);
|
||||
for (size_t p = 0; p < count; p++) {
|
||||
int parameter_count = parameter_counts[p];
|
||||
for (int i = 0; i < parameter_count; i++) {
|
||||
Register r = Register::FromParameterIndex(i, parameter_count);
|
||||
uint8_t operand_value = r.ToOperand();
|
||||
Register s = Register::FromOperand(operand_value);
|
||||
CHECK_EQ(i, s.ToParameterIndex(parameter_count));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST(OperandConversion, RegistersParametersNoOverlap) {
|
||||
std::vector<uint8_t> operand_count(256);
|
||||
|
||||
for (int i = 0; i <= Register::kMaxRegisterIndex; i++) {
|
||||
Register r = Register(i);
|
||||
uint8_t operand = r.ToOperand();
|
||||
operand_count[operand] += 1;
|
||||
CHECK_EQ(operand_count[operand], 1);
|
||||
}
|
||||
|
||||
int parameter_count = Register::MaxParameterIndex() + 1;
|
||||
for (int i = 0; i < parameter_count; i++) {
|
||||
Register r = Register::FromParameterIndex(i, parameter_count);
|
||||
uint8_t operand = r.ToOperand();
|
||||
operand_count[operand] += 1;
|
||||
CHECK_EQ(operand_count[operand], 1);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace interpreter
|
||||
} // namespace internal
|
||||
} // namespace v8
|
@ -95,6 +95,7 @@
|
||||
'compiler/value-numbering-reducer-unittest.cc',
|
||||
'compiler/zone-pool-unittest.cc',
|
||||
'counters-unittest.cc',
|
||||
'interpreter/bytecodes-unittest.cc',
|
||||
'interpreter/bytecode-array-builder-unittest.cc',
|
||||
'libplatform/default-platform-unittest.cc',
|
||||
'libplatform/task-queue-unittest.cc',
|
||||
|
Loading…
Reference in New Issue
Block a user