[Interpreter] Preparation for wide registers.
o Adds wide variants of bytecodes that have operands describing ranges of registers. The upcoming wide register support does not suppport re-mapping ranges. o Adds kRegPair16 and kRegTriple16 operands required for new wide bytecodes and renames Count8/Count16 operands to RegCount8/RegCount16. o Removes Exchange bytecodes BUG=v8:4675 LOG=NO Review URL: https://codereview.chromium.org/1595103006 Cr-Commit-Position: refs/heads/master@{#33389}
This commit is contained in:
parent
603acc3f49
commit
68654b6476
@ -630,17 +630,9 @@ void BytecodeGraphBuilder::VisitMov(
|
||||
}
|
||||
|
||||
|
||||
void BytecodeGraphBuilder::VisitExchange(
|
||||
void BytecodeGraphBuilder::VisitMovWide(
|
||||
const interpreter::BytecodeArrayIterator& iterator) {
|
||||
environment()->ExchangeRegisters(iterator.GetRegisterOperand(0),
|
||||
iterator.GetRegisterOperand(1));
|
||||
}
|
||||
|
||||
|
||||
void BytecodeGraphBuilder::VisitExchangeWide(
|
||||
const interpreter::BytecodeArrayIterator& iterator) {
|
||||
environment()->ExchangeRegisters(iterator.GetRegisterOperand(0),
|
||||
iterator.GetRegisterOperand(1));
|
||||
VisitMov(iterator);
|
||||
}
|
||||
|
||||
|
||||
@ -1223,7 +1215,7 @@ void BytecodeGraphBuilder::VisitCallWide(
|
||||
}
|
||||
|
||||
|
||||
void BytecodeGraphBuilder::VisitCallJSRuntime(
|
||||
void BytecodeGraphBuilder::BuildCallJSRuntime(
|
||||
const interpreter::BytecodeArrayIterator& iterator) {
|
||||
FrameStateBeforeAndAfter states(this, iterator);
|
||||
Node* callee = BuildLoadNativeContextField(iterator.GetIndexOperand(0));
|
||||
@ -1238,6 +1230,18 @@ void BytecodeGraphBuilder::VisitCallJSRuntime(
|
||||
}
|
||||
|
||||
|
||||
void BytecodeGraphBuilder::VisitCallJSRuntime(
|
||||
const interpreter::BytecodeArrayIterator& iterator) {
|
||||
BuildCallJSRuntime(iterator);
|
||||
}
|
||||
|
||||
|
||||
void BytecodeGraphBuilder::VisitCallJSRuntimeWide(
|
||||
const interpreter::BytecodeArrayIterator& iterator) {
|
||||
BuildCallJSRuntime(iterator);
|
||||
}
|
||||
|
||||
|
||||
Node* BytecodeGraphBuilder::ProcessCallRuntimeArguments(
|
||||
const Operator* call_runtime_op, interpreter::Register first_arg,
|
||||
size_t arity) {
|
||||
@ -1252,7 +1256,7 @@ Node* BytecodeGraphBuilder::ProcessCallRuntimeArguments(
|
||||
}
|
||||
|
||||
|
||||
void BytecodeGraphBuilder::VisitCallRuntime(
|
||||
void BytecodeGraphBuilder::BuildCallRuntime(
|
||||
const interpreter::BytecodeArrayIterator& iterator) {
|
||||
FrameStateBeforeAndAfter states(this, iterator);
|
||||
Runtime::FunctionId functionId =
|
||||
@ -1267,7 +1271,19 @@ void BytecodeGraphBuilder::VisitCallRuntime(
|
||||
}
|
||||
|
||||
|
||||
void BytecodeGraphBuilder::VisitCallRuntimeForPair(
|
||||
void BytecodeGraphBuilder::VisitCallRuntime(
|
||||
const interpreter::BytecodeArrayIterator& iterator) {
|
||||
BuildCallRuntime(iterator);
|
||||
}
|
||||
|
||||
|
||||
void BytecodeGraphBuilder::VisitCallRuntimeWide(
|
||||
const interpreter::BytecodeArrayIterator& iterator) {
|
||||
BuildCallRuntime(iterator);
|
||||
}
|
||||
|
||||
|
||||
void BytecodeGraphBuilder::BuildCallRuntimeForPair(
|
||||
const interpreter::BytecodeArrayIterator& iterator) {
|
||||
FrameStateBeforeAndAfter states(this, iterator);
|
||||
Runtime::FunctionId functionId =
|
||||
@ -1283,6 +1299,18 @@ void BytecodeGraphBuilder::VisitCallRuntimeForPair(
|
||||
}
|
||||
|
||||
|
||||
void BytecodeGraphBuilder::VisitCallRuntimeForPair(
|
||||
const interpreter::BytecodeArrayIterator& iterator) {
|
||||
BuildCallRuntimeForPair(iterator);
|
||||
}
|
||||
|
||||
|
||||
void BytecodeGraphBuilder::VisitCallRuntimeForPairWide(
|
||||
const interpreter::BytecodeArrayIterator& iterator) {
|
||||
BuildCallRuntimeForPair(iterator);
|
||||
}
|
||||
|
||||
|
||||
Node* BytecodeGraphBuilder::ProcessCallNewArguments(
|
||||
const Operator* call_new_op, interpreter::Register callee,
|
||||
interpreter::Register first_arg, size_t arity) {
|
||||
@ -1300,7 +1328,7 @@ Node* BytecodeGraphBuilder::ProcessCallNewArguments(
|
||||
}
|
||||
|
||||
|
||||
void BytecodeGraphBuilder::VisitNew(
|
||||
void BytecodeGraphBuilder::BuildCallConstruct(
|
||||
const interpreter::BytecodeArrayIterator& iterator) {
|
||||
FrameStateBeforeAndAfter states(this, iterator);
|
||||
interpreter::Register callee = iterator.GetRegisterOperand(0);
|
||||
@ -1315,6 +1343,18 @@ void BytecodeGraphBuilder::VisitNew(
|
||||
}
|
||||
|
||||
|
||||
void BytecodeGraphBuilder::VisitNew(
|
||||
const interpreter::BytecodeArrayIterator& iterator) {
|
||||
BuildCallConstruct(iterator);
|
||||
}
|
||||
|
||||
|
||||
void BytecodeGraphBuilder::VisitNewWide(
|
||||
const interpreter::BytecodeArrayIterator& iterator) {
|
||||
BuildCallConstruct(iterator);
|
||||
}
|
||||
|
||||
|
||||
void BytecodeGraphBuilder::VisitThrow(
|
||||
const interpreter::BytecodeArrayIterator& iterator) {
|
||||
FrameStateBeforeAndAfter states(this, iterator);
|
||||
@ -1722,7 +1762,7 @@ void BytecodeGraphBuilder::VisitReturn(
|
||||
}
|
||||
|
||||
|
||||
void BytecodeGraphBuilder::VisitForInPrepare(
|
||||
void BytecodeGraphBuilder::BuildForInPrepare(
|
||||
const interpreter::BytecodeArrayIterator& iterator) {
|
||||
FrameStateBeforeAndAfter states(this, iterator);
|
||||
Node* receiver = environment()->LookupAccumulator();
|
||||
@ -1732,6 +1772,18 @@ void BytecodeGraphBuilder::VisitForInPrepare(
|
||||
}
|
||||
|
||||
|
||||
void BytecodeGraphBuilder::VisitForInPrepare(
|
||||
const interpreter::BytecodeArrayIterator& iterator) {
|
||||
BuildForInPrepare(iterator);
|
||||
}
|
||||
|
||||
|
||||
void BytecodeGraphBuilder::VisitForInPrepareWide(
|
||||
const interpreter::BytecodeArrayIterator& iterator) {
|
||||
BuildForInPrepare(iterator);
|
||||
}
|
||||
|
||||
|
||||
void BytecodeGraphBuilder::VisitForInDone(
|
||||
const interpreter::BytecodeArrayIterator& iterator) {
|
||||
FrameStateBeforeAndAfter states(this, iterator);
|
||||
@ -1743,7 +1795,7 @@ void BytecodeGraphBuilder::VisitForInDone(
|
||||
}
|
||||
|
||||
|
||||
void BytecodeGraphBuilder::VisitForInNext(
|
||||
void BytecodeGraphBuilder::BuildForInNext(
|
||||
const interpreter::BytecodeArrayIterator& iterator) {
|
||||
FrameStateBeforeAndAfter states(this, iterator);
|
||||
Node* receiver =
|
||||
@ -1761,6 +1813,18 @@ void BytecodeGraphBuilder::VisitForInNext(
|
||||
}
|
||||
|
||||
|
||||
void BytecodeGraphBuilder::VisitForInNext(
|
||||
const interpreter::BytecodeArrayIterator& iterator) {
|
||||
BuildForInNext(iterator);
|
||||
}
|
||||
|
||||
|
||||
void BytecodeGraphBuilder::VisitForInNextWide(
|
||||
const interpreter::BytecodeArrayIterator& iterator) {
|
||||
BuildForInNext(iterator);
|
||||
}
|
||||
|
||||
|
||||
void BytecodeGraphBuilder::VisitForInStep(
|
||||
const interpreter::BytecodeArrayIterator& iterator) {
|
||||
FrameStateBeforeAndAfter states(this, iterator);
|
||||
|
@ -147,6 +147,11 @@ class BytecodeGraphBuilder {
|
||||
void BuildStaLookupSlot(LanguageMode language_mode,
|
||||
const interpreter::BytecodeArrayIterator& iterator);
|
||||
void BuildCall(const interpreter::BytecodeArrayIterator& iterator);
|
||||
void BuildCallJSRuntime(const interpreter::BytecodeArrayIterator& iterator);
|
||||
void BuildCallRuntime(const interpreter::BytecodeArrayIterator& iterator);
|
||||
void BuildCallRuntimeForPair(
|
||||
const interpreter::BytecodeArrayIterator& iterator);
|
||||
void BuildCallConstruct(const interpreter::BytecodeArrayIterator& iterator);
|
||||
void BuildBinaryOp(const Operator* op,
|
||||
const interpreter::BytecodeArrayIterator& iterator);
|
||||
void BuildCompareOp(const Operator* op,
|
||||
@ -154,6 +159,8 @@ class BytecodeGraphBuilder {
|
||||
void BuildDelete(const interpreter::BytecodeArrayIterator& iterator);
|
||||
void BuildCastOperator(const Operator* js_op,
|
||||
const interpreter::BytecodeArrayIterator& iterator);
|
||||
void BuildForInPrepare(const interpreter::BytecodeArrayIterator& iterator);
|
||||
void BuildForInNext(const interpreter::BytecodeArrayIterator& iterator);
|
||||
|
||||
// Control flow plumbing.
|
||||
void BuildJump(int source_offset, int target_offset);
|
||||
|
@ -259,18 +259,18 @@ Node* InterpreterAssembler::BytecodeOperandCount(int operand_index) {
|
||||
switch (interpreter::Bytecodes::GetOperandSize(bytecode_, operand_index)) {
|
||||
case interpreter::OperandSize::kByte:
|
||||
DCHECK_EQ(
|
||||
interpreter::OperandType::kCount8,
|
||||
interpreter::OperandType::kRegCount8,
|
||||
interpreter::Bytecodes::GetOperandType(bytecode_, operand_index));
|
||||
return BytecodeOperand(operand_index);
|
||||
case interpreter::OperandSize::kShort:
|
||||
DCHECK_EQ(
|
||||
interpreter::OperandType::kCount16,
|
||||
interpreter::OperandType::kRegCount16,
|
||||
interpreter::Bytecodes::GetOperandType(bytecode_, operand_index));
|
||||
return BytecodeOperandShort(operand_index);
|
||||
default:
|
||||
case interpreter::OperandSize::kNone:
|
||||
UNREACHABLE();
|
||||
return nullptr;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
@ -293,32 +293,40 @@ Node* InterpreterAssembler::BytecodeOperandIdx(int operand_index) {
|
||||
interpreter::OperandType::kIdx16,
|
||||
interpreter::Bytecodes::GetOperandType(bytecode_, operand_index));
|
||||
return BytecodeOperandShort(operand_index);
|
||||
default:
|
||||
case interpreter::OperandSize::kNone:
|
||||
UNREACHABLE();
|
||||
return nullptr;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
Node* InterpreterAssembler::BytecodeOperandReg(int operand_index) {
|
||||
switch (interpreter::Bytecodes::GetOperandType(bytecode_, operand_index)) {
|
||||
case interpreter::OperandType::kMaybeReg8:
|
||||
case interpreter::OperandType::kReg8:
|
||||
case interpreter::OperandType::kRegPair8:
|
||||
case interpreter::OperandType::kRegTriple8:
|
||||
case interpreter::OperandType::kMaybeReg8:
|
||||
DCHECK_EQ(
|
||||
interpreter::OperandSize::kByte,
|
||||
interpreter::Bytecodes::GetOperandSize(bytecode_, operand_index));
|
||||
return BytecodeOperandSignExtended(operand_index);
|
||||
case interpreter::OperandType::kMaybeReg16:
|
||||
case interpreter::OperandType::kReg16:
|
||||
case interpreter::OperandType::kRegPair16:
|
||||
case interpreter::OperandType::kRegTriple16:
|
||||
DCHECK_EQ(
|
||||
interpreter::OperandSize::kShort,
|
||||
interpreter::Bytecodes::GetOperandSize(bytecode_, operand_index));
|
||||
return BytecodeOperandShortSignExtended(operand_index);
|
||||
default:
|
||||
case interpreter::OperandType::kNone:
|
||||
case interpreter::OperandType::kIdx8:
|
||||
case interpreter::OperandType::kIdx16:
|
||||
case interpreter::OperandType::kImm8:
|
||||
case interpreter::OperandType::kRegCount8:
|
||||
case interpreter::OperandType::kRegCount16:
|
||||
UNREACHABLE();
|
||||
return nullptr;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
|
@ -233,7 +233,7 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::BinaryOperation(Token::Value op,
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
Output(BytecodeForBinaryOperation(op), reg.ToOperand());
|
||||
Output(BytecodeForBinaryOperation(op), reg.ToRawOperand());
|
||||
return *this;
|
||||
}
|
||||
|
||||
@ -267,7 +267,7 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::CompareOperation(
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
Output(BytecodeForCompareOperation(op), reg.ToOperand());
|
||||
Output(BytecodeForCompareOperation(op), reg.ToRawOperand());
|
||||
return *this;
|
||||
}
|
||||
|
||||
@ -342,7 +342,7 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::LoadBooleanConstant(bool value) {
|
||||
BytecodeArrayBuilder& BytecodeArrayBuilder::LoadAccumulatorWithRegister(
|
||||
Register reg) {
|
||||
if (!IsRegisterInAccumulator(reg)) {
|
||||
Output(Bytecode::kLdar, reg.ToOperand());
|
||||
Output(Bytecode::kLdar, reg.ToRawOperand());
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
@ -350,15 +350,8 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::LoadAccumulatorWithRegister(
|
||||
|
||||
BytecodeArrayBuilder& BytecodeArrayBuilder::StoreAccumulatorInRegister(
|
||||
Register reg) {
|
||||
// TODO(oth): Avoid storing the accumulator in the register if the
|
||||
// previous bytecode loaded the accumulator with the same register.
|
||||
//
|
||||
// TODO(oth): If the previous bytecode is a MOV into this register,
|
||||
// the previous instruction can be removed. The logic for determining
|
||||
// these redundant MOVs appears complex.
|
||||
Output(Bytecode::kStar, reg.ToOperand());
|
||||
if (!IsRegisterInAccumulator(reg)) {
|
||||
Output(Bytecode::kStar, reg.ToOperand());
|
||||
Output(Bytecode::kStar, reg.ToRawOperand());
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
@ -367,20 +360,12 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::StoreAccumulatorInRegister(
|
||||
BytecodeArrayBuilder& BytecodeArrayBuilder::MoveRegister(Register from,
|
||||
Register to) {
|
||||
DCHECK(from != to);
|
||||
Output(Bytecode::kMov, from.ToOperand(), to.ToOperand());
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
BytecodeArrayBuilder& BytecodeArrayBuilder::ExchangeRegisters(Register reg0,
|
||||
Register reg1) {
|
||||
DCHECK(reg0 != reg1);
|
||||
if (FitsInReg8Operand(reg0)) {
|
||||
Output(Bytecode::kExchange, reg0.ToOperand(), reg1.ToWideOperand());
|
||||
} else if (FitsInReg8Operand(reg1)) {
|
||||
Output(Bytecode::kExchange, reg1.ToOperand(), reg0.ToWideOperand());
|
||||
if (FitsInReg8Operand(to) && FitsInReg8Operand(from)) {
|
||||
Output(Bytecode::kMov, from.ToRawOperand(), to.ToRawOperand());
|
||||
} else if (FitsInReg16Operand(to) && FitsInReg16Operand(from)) {
|
||||
Output(Bytecode::kMovWide, from.ToRawOperand(), to.ToRawOperand());
|
||||
} else {
|
||||
Output(Bytecode::kExchangeWide, reg0.ToWideOperand(), reg1.ToWideOperand());
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
@ -429,10 +414,10 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::LoadContextSlot(Register context,
|
||||
int slot_index) {
|
||||
DCHECK(slot_index >= 0);
|
||||
if (FitsInIdx8Operand(slot_index)) {
|
||||
Output(Bytecode::kLdaContextSlot, context.ToOperand(),
|
||||
Output(Bytecode::kLdaContextSlot, context.ToRawOperand(),
|
||||
static_cast<uint8_t>(slot_index));
|
||||
} else if (FitsInIdx16Operand(slot_index)) {
|
||||
Output(Bytecode::kLdaContextSlotWide, context.ToOperand(),
|
||||
Output(Bytecode::kLdaContextSlotWide, context.ToRawOperand(),
|
||||
static_cast<uint16_t>(slot_index));
|
||||
} else {
|
||||
UNIMPLEMENTED();
|
||||
@ -445,10 +430,10 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::StoreContextSlot(Register context,
|
||||
int slot_index) {
|
||||
DCHECK(slot_index >= 0);
|
||||
if (FitsInIdx8Operand(slot_index)) {
|
||||
Output(Bytecode::kStaContextSlot, context.ToOperand(),
|
||||
Output(Bytecode::kStaContextSlot, context.ToRawOperand(),
|
||||
static_cast<uint8_t>(slot_index));
|
||||
} else if (FitsInIdx16Operand(slot_index)) {
|
||||
Output(Bytecode::kStaContextSlotWide, context.ToOperand(),
|
||||
Output(Bytecode::kStaContextSlotWide, context.ToRawOperand(),
|
||||
static_cast<uint16_t>(slot_index));
|
||||
} else {
|
||||
UNIMPLEMENTED();
|
||||
@ -497,11 +482,11 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::LoadNamedProperty(
|
||||
Bytecode bytecode = BytecodeForLoadIC(language_mode);
|
||||
size_t name_index = GetConstantPoolEntry(name);
|
||||
if (FitsInIdx8Operand(name_index) && FitsInIdx8Operand(feedback_slot)) {
|
||||
Output(bytecode, object.ToOperand(), static_cast<uint8_t>(name_index),
|
||||
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.ToOperand(),
|
||||
Output(BytecodeForWideOperands(bytecode), object.ToRawOperand(),
|
||||
static_cast<uint16_t>(name_index),
|
||||
static_cast<uint16_t>(feedback_slot));
|
||||
} else {
|
||||
@ -515,9 +500,10 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::LoadKeyedProperty(
|
||||
Register object, int feedback_slot, LanguageMode language_mode) {
|
||||
Bytecode bytecode = BytecodeForKeyedLoadIC(language_mode);
|
||||
if (FitsInIdx8Operand(feedback_slot)) {
|
||||
Output(bytecode, object.ToOperand(), static_cast<uint8_t>(feedback_slot));
|
||||
Output(bytecode, object.ToRawOperand(),
|
||||
static_cast<uint8_t>(feedback_slot));
|
||||
} else if (FitsInIdx16Operand(feedback_slot)) {
|
||||
Output(BytecodeForWideOperands(bytecode), object.ToOperand(),
|
||||
Output(BytecodeForWideOperands(bytecode), object.ToRawOperand(),
|
||||
static_cast<uint16_t>(feedback_slot));
|
||||
} else {
|
||||
UNIMPLEMENTED();
|
||||
@ -532,11 +518,11 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::StoreNamedProperty(
|
||||
Bytecode bytecode = BytecodeForStoreIC(language_mode);
|
||||
size_t name_index = GetConstantPoolEntry(name);
|
||||
if (FitsInIdx8Operand(name_index) && FitsInIdx8Operand(feedback_slot)) {
|
||||
Output(bytecode, object.ToOperand(), static_cast<uint8_t>(name_index),
|
||||
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.ToOperand(),
|
||||
Output(BytecodeForWideOperands(bytecode), object.ToRawOperand(),
|
||||
static_cast<uint16_t>(name_index),
|
||||
static_cast<uint16_t>(feedback_slot));
|
||||
} else {
|
||||
@ -551,11 +537,11 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::StoreKeyedProperty(
|
||||
LanguageMode language_mode) {
|
||||
Bytecode bytecode = BytecodeForKeyedStoreIC(language_mode);
|
||||
if (FitsInIdx8Operand(feedback_slot)) {
|
||||
Output(bytecode, object.ToOperand(), key.ToOperand(),
|
||||
Output(bytecode, object.ToRawOperand(), key.ToRawOperand(),
|
||||
static_cast<uint8_t>(feedback_slot));
|
||||
} else if (FitsInIdx16Operand(feedback_slot)) {
|
||||
Output(BytecodeForWideOperands(bytecode), object.ToOperand(),
|
||||
key.ToOperand(), static_cast<uint16_t>(feedback_slot));
|
||||
Output(BytecodeForWideOperands(bytecode), object.ToRawOperand(),
|
||||
key.ToRawOperand(), static_cast<uint16_t>(feedback_slot));
|
||||
} else {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
@ -653,13 +639,13 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::CreateObjectLiteral(
|
||||
|
||||
|
||||
BytecodeArrayBuilder& BytecodeArrayBuilder::PushContext(Register context) {
|
||||
Output(Bytecode::kPushContext, context.ToOperand());
|
||||
Output(Bytecode::kPushContext, context.ToRawOperand());
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
BytecodeArrayBuilder& BytecodeArrayBuilder::PopContext(Register context) {
|
||||
Output(Bytecode::kPopContext, context.ToOperand());
|
||||
Output(Bytecode::kPopContext, context.ToRawOperand());
|
||||
return *this;
|
||||
}
|
||||
|
||||
@ -982,28 +968,44 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::Return() {
|
||||
|
||||
BytecodeArrayBuilder& BytecodeArrayBuilder::ForInPrepare(
|
||||
Register cache_info_triple) {
|
||||
Output(Bytecode::kForInPrepare, cache_info_triple.ToOperand());
|
||||
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();
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
BytecodeArrayBuilder& BytecodeArrayBuilder::ForInDone(Register index,
|
||||
Register cache_length) {
|
||||
Output(Bytecode::kForInDone, index.ToOperand(), cache_length.ToOperand());
|
||||
Output(Bytecode::kForInDone, index.ToRawOperand(),
|
||||
cache_length.ToRawOperand());
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
BytecodeArrayBuilder& BytecodeArrayBuilder::ForInNext(
|
||||
Register receiver, Register index, Register cache_type_array_pair) {
|
||||
Output(Bytecode::kForInNext, receiver.ToOperand(), index.ToOperand(),
|
||||
cache_type_array_pair.ToOperand());
|
||||
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();
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
BytecodeArrayBuilder& BytecodeArrayBuilder::ForInStep(Register index) {
|
||||
Output(Bytecode::kForInStep, index.ToOperand());
|
||||
Output(Bytecode::kForInStep, index.ToRawOperand());
|
||||
return *this;
|
||||
}
|
||||
|
||||
@ -1026,14 +1028,16 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::Call(Register callable,
|
||||
Register receiver,
|
||||
size_t arg_count,
|
||||
int feedback_slot) {
|
||||
if (FitsInIdx8Operand(arg_count) && FitsInIdx8Operand(feedback_slot)) {
|
||||
Output(Bytecode::kCall, callable.ToOperand(), receiver.ToOperand(),
|
||||
if (FitsInReg8Operand(callable) && FitsInReg8Operand(receiver) &&
|
||||
FitsInIdx8Operand(arg_count) && FitsInIdx8Operand(feedback_slot)) {
|
||||
Output(Bytecode::kCall, callable.ToRawOperand(), receiver.ToRawOperand(),
|
||||
static_cast<uint8_t>(arg_count),
|
||||
static_cast<uint8_t>(feedback_slot));
|
||||
} else if (FitsInIdx16Operand(arg_count) &&
|
||||
} else if (FitsInReg16Operand(callable) && FitsInReg16Operand(receiver) &&
|
||||
FitsInIdx16Operand(arg_count) &&
|
||||
FitsInIdx16Operand(feedback_slot)) {
|
||||
Output(Bytecode::kCallWide, callable.ToOperand(), receiver.ToOperand(),
|
||||
static_cast<uint16_t>(arg_count),
|
||||
Output(Bytecode::kCallWide, callable.ToRawOperand(),
|
||||
receiver.ToRawOperand(), static_cast<uint16_t>(arg_count),
|
||||
static_cast<uint16_t>(feedback_slot));
|
||||
} else {
|
||||
UNIMPLEMENTED();
|
||||
@ -1049,9 +1053,18 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::New(Register constructor,
|
||||
DCHECK_EQ(0u, arg_count);
|
||||
first_arg = Register(0);
|
||||
}
|
||||
DCHECK(FitsInIdx8Operand(arg_count));
|
||||
Output(Bytecode::kNew, constructor.ToOperand(), first_arg.ToOperand(),
|
||||
static_cast<uint8_t>(arg_count));
|
||||
|
||||
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();
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
@ -1060,13 +1073,19 @@ 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(FitsInIdx8Operand(arg_count));
|
||||
if (!first_arg.is_valid()) {
|
||||
DCHECK_EQ(0u, arg_count);
|
||||
first_arg = Register(0);
|
||||
}
|
||||
Output(Bytecode::kCallRuntime, static_cast<uint16_t>(function_id),
|
||||
first_arg.ToOperand(), static_cast<uint8_t>(arg_count));
|
||||
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();
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
@ -1076,14 +1095,23 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::CallRuntimeForPair(
|
||||
Register first_return) {
|
||||
DCHECK_EQ(2, Runtime::FunctionForId(function_id)->result_size);
|
||||
DCHECK(FitsInIdx16Operand(function_id));
|
||||
DCHECK(FitsInIdx8Operand(arg_count));
|
||||
if (!first_arg.is_valid()) {
|
||||
DCHECK_EQ(0u, arg_count);
|
||||
first_arg = Register(0);
|
||||
}
|
||||
Output(Bytecode::kCallRuntimeForPair, static_cast<uint16_t>(function_id),
|
||||
first_arg.ToOperand(), static_cast<uint8_t>(arg_count),
|
||||
first_return.ToOperand());
|
||||
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();
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
@ -1092,16 +1120,22 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::CallJSRuntime(int context_index,
|
||||
Register receiver,
|
||||
size_t arg_count) {
|
||||
DCHECK(FitsInIdx16Operand(context_index));
|
||||
DCHECK(FitsInIdx8Operand(arg_count));
|
||||
Output(Bytecode::kCallJSRuntime, static_cast<uint16_t>(context_index),
|
||||
receiver.ToOperand(), static_cast<uint8_t>(arg_count));
|
||||
if (FitsInReg8Operand(receiver) && FitsInIdx8Operand(arg_count)) {
|
||||
Output(Bytecode::kCallJSRuntime, static_cast<uint16_t>(context_index),
|
||||
receiver.ToRawOperand(), static_cast<uint8_t>(arg_count));
|
||||
} else if (FitsInReg16Operand(receiver) && FitsInIdx16Operand(arg_count)) {
|
||||
Output(Bytecode::kCallJSRuntimeWide, static_cast<uint16_t>(context_index),
|
||||
receiver.ToRawOperand(), static_cast<uint16_t>(arg_count));
|
||||
} else {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
BytecodeArrayBuilder& BytecodeArrayBuilder::Delete(Register object,
|
||||
LanguageMode language_mode) {
|
||||
Output(BytecodeForDelete(language_mode), object.ToOperand());
|
||||
Output(BytecodeForDelete(language_mode), object.ToRawOperand());
|
||||
return *this;
|
||||
}
|
||||
|
||||
@ -1211,7 +1245,72 @@ bool BytecodeArrayBuilder::TemporaryRegisterIsLive(Register reg) const {
|
||||
}
|
||||
|
||||
|
||||
bool BytecodeArrayBuilder::RegisterIsValid(Register reg) const {
|
||||
bool BytecodeArrayBuilder::OperandIsValid(Bytecode bytecode, int operand_index,
|
||||
uint32_t operand_value) const {
|
||||
OperandType operand_type = Bytecodes::GetOperandType(bytecode, operand_index);
|
||||
switch (operand_type) {
|
||||
case OperandType::kNone:
|
||||
return false;
|
||||
case OperandType::kRegCount16:
|
||||
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;
|
||||
case OperandType::kMaybeReg8:
|
||||
if (operand_value == 0) {
|
||||
return true;
|
||||
}
|
||||
// Fall-through to kReg8 case.
|
||||
case OperandType::kReg8:
|
||||
return RegisterIsValid(Register::FromRawOperand(operand_value),
|
||||
operand_type);
|
||||
case OperandType::kRegPair8:
|
||||
case OperandType::kRegPair16: {
|
||||
Register reg0 = Register::FromRawOperand(operand_value);
|
||||
Register reg1 = Register(reg0.index() + 1);
|
||||
return RegisterIsValid(reg0, operand_type) &&
|
||||
RegisterIsValid(reg1, operand_type);
|
||||
}
|
||||
case OperandType::kRegTriple8:
|
||||
case OperandType::kRegTriple16: {
|
||||
Register reg0 = Register::FromRawOperand(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: {
|
||||
Register reg = Register::FromRawOperand(operand_value);
|
||||
return RegisterIsValid(reg, operand_type);
|
||||
}
|
||||
}
|
||||
UNREACHABLE();
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool BytecodeArrayBuilder::RegisterIsValid(Register reg,
|
||||
OperandType reg_type) const {
|
||||
switch (Bytecodes::SizeOfOperand(reg_type)) {
|
||||
case OperandSize::kByte:
|
||||
if (!FitsInReg8Operand(reg)) { return false; }
|
||||
break;
|
||||
case OperandSize::kShort:
|
||||
if (!FitsInReg16Operand(reg)) { return false; }
|
||||
break;
|
||||
case OperandSize::kNone:
|
||||
UNREACHABLE();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (reg.is_function_context() || reg.is_function_closure() ||
|
||||
reg.is_new_target()) {
|
||||
return true;
|
||||
@ -1226,54 +1325,6 @@ bool BytecodeArrayBuilder::RegisterIsValid(Register reg) const {
|
||||
}
|
||||
|
||||
|
||||
bool BytecodeArrayBuilder::OperandIsValid(Bytecode bytecode, int operand_index,
|
||||
uint32_t operand_value) const {
|
||||
OperandType operand_type = Bytecodes::GetOperandType(bytecode, operand_index);
|
||||
switch (operand_type) {
|
||||
case OperandType::kNone:
|
||||
return false;
|
||||
case OperandType::kCount16:
|
||||
case OperandType::kIdx16:
|
||||
return static_cast<uint16_t>(operand_value) == operand_value;
|
||||
case OperandType::kCount8:
|
||||
case OperandType::kImm8:
|
||||
case OperandType::kIdx8:
|
||||
return static_cast<uint8_t>(operand_value) == operand_value;
|
||||
case OperandType::kMaybeReg8:
|
||||
if (operand_value == 0) {
|
||||
return true;
|
||||
}
|
||||
// Fall-through to kReg8 case.
|
||||
case OperandType::kReg8:
|
||||
return RegisterIsValid(
|
||||
Register::FromOperand(static_cast<uint8_t>(operand_value)));
|
||||
case OperandType::kRegPair8: {
|
||||
Register reg0 =
|
||||
Register::FromOperand(static_cast<uint8_t>(operand_value));
|
||||
Register reg1 = Register(reg0.index() + 1);
|
||||
return RegisterIsValid(reg0) && RegisterIsValid(reg1);
|
||||
}
|
||||
case OperandType::kRegTriple8: {
|
||||
Register reg0 =
|
||||
Register::FromOperand(static_cast<uint8_t>(operand_value));
|
||||
Register reg1 = Register(reg0.index() + 1);
|
||||
Register reg2 = Register(reg0.index() + 2);
|
||||
return RegisterIsValid(reg0) && RegisterIsValid(reg1) &&
|
||||
RegisterIsValid(reg2);
|
||||
}
|
||||
case OperandType::kReg16:
|
||||
if (bytecode != Bytecode::kExchange &&
|
||||
bytecode != Bytecode::kExchangeWide) {
|
||||
return false;
|
||||
}
|
||||
return RegisterIsValid(
|
||||
Register::FromWideOperand(static_cast<uint16_t>(operand_value)));
|
||||
}
|
||||
UNREACHABLE();
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool BytecodeArrayBuilder::LastBytecodeInSameBlock() const {
|
||||
return last_bytecode_start_ < bytecodes()->size() &&
|
||||
last_bytecode_start_ >= last_block_end_;
|
||||
|
@ -18,7 +18,6 @@ class Isolate;
|
||||
namespace interpreter {
|
||||
|
||||
class BytecodeLabel;
|
||||
class ConstantArrayBuilder;
|
||||
class Register;
|
||||
|
||||
// TODO(rmcilroy): Unify this with CreateArgumentsParameters::Type in Turbofan
|
||||
@ -98,7 +97,6 @@ class BytecodeArrayBuilder final {
|
||||
|
||||
// Register-register transfer.
|
||||
BytecodeArrayBuilder& MoveRegister(Register from, Register to);
|
||||
BytecodeArrayBuilder& ExchangeRegisters(Register reg0, Register reg1);
|
||||
|
||||
// Named load property.
|
||||
BytecodeArrayBuilder& LoadNamedProperty(Register object,
|
||||
@ -231,15 +229,8 @@ class BytecodeArrayBuilder final {
|
||||
Zone* zone() const { return zone_; }
|
||||
|
||||
private:
|
||||
ZoneVector<uint8_t>* bytecodes() { return &bytecodes_; }
|
||||
const ZoneVector<uint8_t>* bytecodes() const { return &bytecodes_; }
|
||||
Isolate* isolate() const { return isolate_; }
|
||||
ConstantArrayBuilder* constant_array_builder() {
|
||||
return &constant_array_builder_;
|
||||
}
|
||||
const ConstantArrayBuilder* constant_array_builder() const {
|
||||
return &constant_array_builder_;
|
||||
}
|
||||
class PreviousBytecodeHelper;
|
||||
friend class BytecodeRegisterAllocator;
|
||||
|
||||
static Bytecode BytecodeForBinaryOperation(Token::Value op);
|
||||
static Bytecode BytecodeForCountOperation(Token::Value op);
|
||||
@ -296,12 +287,11 @@ class BytecodeArrayBuilder final {
|
||||
bool OperandIsValid(Bytecode bytecode, int operand_index,
|
||||
uint32_t operand_value) const;
|
||||
bool LastBytecodeInSameBlock() const;
|
||||
bool RegisterIsValid(Register reg, OperandType reg_type) const;
|
||||
|
||||
bool NeedToBooleanCast();
|
||||
bool IsRegisterInAccumulator(Register reg);
|
||||
|
||||
bool RegisterIsValid(Register reg) const;
|
||||
|
||||
// Temporary register management.
|
||||
int BorrowTemporaryRegister();
|
||||
int BorrowTemporaryRegisterNotInRange(int start_index, int end_index);
|
||||
@ -316,6 +306,16 @@ class BytecodeArrayBuilder final {
|
||||
// Gets a constant pool entry for the |object|.
|
||||
size_t GetConstantPoolEntry(Handle<Object> object);
|
||||
|
||||
ZoneVector<uint8_t>* bytecodes() { return &bytecodes_; }
|
||||
const ZoneVector<uint8_t>* bytecodes() const { return &bytecodes_; }
|
||||
Isolate* isolate() const { return isolate_; }
|
||||
ConstantArrayBuilder* constant_array_builder() {
|
||||
return &constant_array_builder_;
|
||||
}
|
||||
const ConstantArrayBuilder* constant_array_builder() const {
|
||||
return &constant_array_builder_;
|
||||
}
|
||||
|
||||
Isolate* isolate_;
|
||||
Zone* zone_;
|
||||
ZoneVector<uint8_t> bytecodes_;
|
||||
@ -332,9 +332,6 @@ class BytecodeArrayBuilder final {
|
||||
int temporary_register_count_;
|
||||
ZoneSet<int> free_temporaries_;
|
||||
|
||||
class PreviousBytecodeHelper;
|
||||
friend class BytecodeRegisterAllocator;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(BytecodeArrayBuilder);
|
||||
};
|
||||
|
||||
|
@ -67,8 +67,8 @@ int8_t BytecodeArrayIterator::GetImmediateOperand(int operand_index) const {
|
||||
int BytecodeArrayIterator::GetCountOperand(int operand_index) const {
|
||||
OperandSize size =
|
||||
Bytecodes::GetOperandSize(current_bytecode(), operand_index);
|
||||
OperandType type = (size == OperandSize::kByte) ? OperandType::kCount8
|
||||
: OperandType::kCount16;
|
||||
OperandType type = (size == OperandSize::kByte) ? OperandType::kRegCount8
|
||||
: OperandType::kRegCount16;
|
||||
uint32_t operand = GetRawOperand(operand_index, type);
|
||||
return static_cast<int>(operand);
|
||||
}
|
||||
@ -93,7 +93,15 @@ Register BytecodeArrayIterator::GetRegisterOperand(int operand_index) const {
|
||||
operand_type == OperandType::kMaybeReg8 ||
|
||||
operand_type == OperandType::kReg16);
|
||||
uint32_t operand = GetRawOperand(operand_index, operand_type);
|
||||
return Register::FromOperand(operand);
|
||||
switch (Bytecodes::GetOperandSize(current_bytecode(), operand_index)) {
|
||||
case OperandSize::kByte:
|
||||
return Register::FromOperand(static_cast<uint8_t>(operand));
|
||||
case OperandSize::kShort:
|
||||
return Register::FromWideOperand(static_cast<uint16_t>(operand));
|
||||
case OperandSize::kNone:
|
||||
UNREACHABLE();
|
||||
}
|
||||
return Register();
|
||||
}
|
||||
|
||||
|
||||
|
@ -232,6 +232,23 @@ bool Bytecodes::IsJumpOrReturn(Bytecode bytecode) {
|
||||
}
|
||||
|
||||
|
||||
namespace {
|
||||
static Register DecodeRegister(const uint8_t* operand_start,
|
||||
OperandType operand_type) {
|
||||
switch (Bytecodes::SizeOfOperand(operand_type)) {
|
||||
case OperandSize::kByte:
|
||||
return Register::FromOperand(*operand_start);
|
||||
case OperandSize::kShort:
|
||||
return Register::FromWideOperand(ReadUnalignedUInt16(operand_start));
|
||||
case OperandSize::kNone: {
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
return Register();
|
||||
}
|
||||
} // namespace
|
||||
|
||||
|
||||
// static
|
||||
std::ostream& Bytecodes::Decode(std::ostream& os, const uint8_t* bytecode_start,
|
||||
int parameter_count) {
|
||||
@ -257,10 +274,10 @@ std::ostream& Bytecodes::Decode(std::ostream& os, const uint8_t* bytecode_start,
|
||||
const uint8_t* operand_start =
|
||||
&bytecode_start[GetOperandOffset(bytecode, i)];
|
||||
switch (op_type) {
|
||||
case interpreter::OperandType::kCount8:
|
||||
case interpreter::OperandType::kRegCount8:
|
||||
os << "#" << static_cast<unsigned int>(*operand_start);
|
||||
break;
|
||||
case interpreter::OperandType::kCount16:
|
||||
case interpreter::OperandType::kRegCount16:
|
||||
os << '#' << ReadUnalignedUInt16(operand_start);
|
||||
break;
|
||||
case interpreter::OperandType::kIdx8:
|
||||
@ -272,9 +289,11 @@ std::ostream& Bytecodes::Decode(std::ostream& os, const uint8_t* bytecode_start,
|
||||
case interpreter::OperandType::kImm8:
|
||||
os << "#" << static_cast<int>(static_cast<int8_t>(*operand_start));
|
||||
break;
|
||||
case interpreter::OperandType::kMaybeReg8:
|
||||
case interpreter::OperandType::kMaybeReg16:
|
||||
case interpreter::OperandType::kReg8:
|
||||
case interpreter::OperandType::kMaybeReg8: {
|
||||
Register reg = Register::FromOperand(*operand_start);
|
||||
case interpreter::OperandType::kReg16: {
|
||||
Register reg = DecodeRegister(operand_start, op_type);
|
||||
if (reg.is_function_context()) {
|
||||
os << "<context>";
|
||||
} else if (reg.is_function_closure()) {
|
||||
@ -294,30 +313,20 @@ std::ostream& Bytecodes::Decode(std::ostream& os, const uint8_t* bytecode_start,
|
||||
break;
|
||||
}
|
||||
case interpreter::OperandType::kRegPair8:
|
||||
case interpreter::OperandType::kRegTriple8: {
|
||||
Register reg = Register::FromOperand(*operand_start);
|
||||
case interpreter::OperandType::kRegTriple8:
|
||||
case interpreter::OperandType::kRegPair16:
|
||||
case interpreter::OperandType::kRegTriple16: {
|
||||
Register reg = DecodeRegister(operand_start, op_type);
|
||||
int range = op_type == interpreter::OperandType::kRegPair8 ? 1 : 2;
|
||||
if (reg.is_parameter()) {
|
||||
int parameter_index = reg.ToParameterIndex(parameter_count);
|
||||
DCHECK_NE(parameter_index, 0);
|
||||
DCHECK_GT(parameter_index, 0);
|
||||
os << "a" << parameter_index - range << "-" << parameter_index;
|
||||
} else {
|
||||
os << "r" << reg.index() << "-" << reg.index() + range;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case interpreter::OperandType::kReg16: {
|
||||
Register reg =
|
||||
Register::FromWideOperand(ReadUnalignedUInt16(operand_start));
|
||||
if (reg.is_parameter()) {
|
||||
int parameter_index = reg.ToParameterIndex(parameter_count);
|
||||
DCHECK_NE(parameter_index, 0);
|
||||
os << "a" << parameter_index - 1;
|
||||
} else {
|
||||
os << "r" << reg.index();
|
||||
}
|
||||
break;
|
||||
}
|
||||
case interpreter::OperandType::kNone:
|
||||
UNREACHABLE();
|
||||
break;
|
||||
@ -433,6 +442,16 @@ Register Register::FromWideOperand(uint16_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()) {
|
||||
|
@ -15,25 +15,35 @@ namespace v8 {
|
||||
namespace internal {
|
||||
namespace interpreter {
|
||||
|
||||
// The list of operand types used by bytecodes.
|
||||
#define OPERAND_TYPE_LIST(V) \
|
||||
\
|
||||
/* None operand. */ \
|
||||
V(None, OperandSize::kNone) \
|
||||
\
|
||||
#define INVALID_OPERAND_TYPE_LIST(V) \
|
||||
V(None, OperandSize::kNone)
|
||||
|
||||
#define REGISTER_OPERAND_TYPE_LIST(V) \
|
||||
/* Byte operands. */ \
|
||||
V(MaybeReg8, OperandSize::kByte) \
|
||||
V(Reg8, OperandSize::kByte) \
|
||||
V(RegPair8, OperandSize::kByte) \
|
||||
V(RegTriple8, OperandSize::kByte) \
|
||||
/* Short operands. */ \
|
||||
V(MaybeReg16, OperandSize::kShort) \
|
||||
V(Reg16, OperandSize::kShort) \
|
||||
V(RegPair16, OperandSize::kShort) \
|
||||
V(RegTriple16, OperandSize::kShort)
|
||||
|
||||
#define SCALAR_OPERAND_TYPE_LIST(V) \
|
||||
/* Byte operands. */ \
|
||||
V(Count8, OperandSize::kByte) \
|
||||
V(Imm8, OperandSize::kByte) \
|
||||
V(Idx8, OperandSize::kByte) \
|
||||
V(MaybeReg8, OperandSize::kByte) \
|
||||
V(Reg8, OperandSize::kByte) \
|
||||
V(RegPair8, OperandSize::kByte) \
|
||||
V(RegTriple8, OperandSize::kByte) \
|
||||
\
|
||||
V(Imm8, OperandSize::kByte) \
|
||||
V(RegCount8, OperandSize::kByte) \
|
||||
/* Short operands. */ \
|
||||
V(Count16, OperandSize::kShort) \
|
||||
V(Idx16, OperandSize::kShort) \
|
||||
V(Reg16, OperandSize::kShort)
|
||||
V(RegCount16, OperandSize::kShort)
|
||||
|
||||
// The list of operand types used by bytecodes.
|
||||
#define OPERAND_TYPE_LIST(V) \
|
||||
INVALID_OPERAND_TYPE_LIST(V) \
|
||||
REGISTER_OPERAND_TYPE_LIST(V) \
|
||||
SCALAR_OPERAND_TYPE_LIST(V)
|
||||
|
||||
// The list of bytecodes which are interpreted by the interpreter.
|
||||
#define BYTECODE_LIST(V) \
|
||||
@ -87,8 +97,7 @@ namespace interpreter {
|
||||
\
|
||||
/* Register-register transfers */ \
|
||||
V(Mov, OperandType::kReg8, OperandType::kReg8) \
|
||||
V(Exchange, OperandType::kReg8, OperandType::kReg16) \
|
||||
V(ExchangeWide, OperandType::kReg16, OperandType::kReg16) \
|
||||
V(MovWide, OperandType::kReg16, OperandType::kReg16) \
|
||||
\
|
||||
/* LoadIC operations */ \
|
||||
V(LoadICSloppy, OperandType::kReg8, OperandType::kIdx8, OperandType::kIdx8) \
|
||||
@ -143,19 +152,27 @@ namespace interpreter {
|
||||
V(DeleteLookupSlot, OperandType::kNone) \
|
||||
\
|
||||
/* Call operations */ \
|
||||
V(Call, OperandType::kReg8, OperandType::kReg8, OperandType::kCount8, \
|
||||
V(Call, OperandType::kReg8, OperandType::kReg8, OperandType::kRegCount8, \
|
||||
OperandType::kIdx8) \
|
||||
V(CallWide, OperandType::kReg8, OperandType::kReg8, OperandType::kCount16, \
|
||||
OperandType::kIdx16) \
|
||||
V(CallWide, OperandType::kReg16, OperandType::kReg16, \
|
||||
OperandType::kRegCount16, OperandType::kIdx16) \
|
||||
V(CallRuntime, OperandType::kIdx16, OperandType::kMaybeReg8, \
|
||||
OperandType::kCount8) \
|
||||
OperandType::kRegCount8) \
|
||||
V(CallRuntimeWide, OperandType::kIdx16, OperandType::kMaybeReg16, \
|
||||
OperandType::kRegCount8) \
|
||||
V(CallRuntimeForPair, OperandType::kIdx16, OperandType::kMaybeReg8, \
|
||||
OperandType::kCount8, OperandType::kRegPair8) \
|
||||
OperandType::kRegCount8, OperandType::kRegPair8) \
|
||||
V(CallRuntimeForPairWide, OperandType::kIdx16, OperandType::kMaybeReg16, \
|
||||
OperandType::kRegCount8, OperandType::kRegPair16) \
|
||||
V(CallJSRuntime, OperandType::kIdx16, OperandType::kReg8, \
|
||||
OperandType::kCount8) \
|
||||
OperandType::kRegCount8) \
|
||||
V(CallJSRuntimeWide, OperandType::kIdx16, OperandType::kReg16, \
|
||||
OperandType::kRegCount16) \
|
||||
\
|
||||
/* New operator */ \
|
||||
V(New, OperandType::kReg8, OperandType::kMaybeReg8, OperandType::kCount8) \
|
||||
V(New, OperandType::kReg8, OperandType::kMaybeReg8, OperandType::kRegCount8) \
|
||||
V(NewWide, OperandType::kReg16, OperandType::kMaybeReg16, \
|
||||
OperandType::kRegCount16) \
|
||||
\
|
||||
/* Test Operators */ \
|
||||
V(TestEqual, OperandType::kReg8) \
|
||||
@ -221,8 +238,11 @@ namespace interpreter {
|
||||
\
|
||||
/* Complex flow control For..in */ \
|
||||
V(ForInPrepare, OperandType::kRegTriple8) \
|
||||
V(ForInPrepareWide, OperandType::kRegTriple16) \
|
||||
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) \
|
||||
\
|
||||
/* Non-local flow control */ \
|
||||
@ -301,6 +321,9 @@ class Register {
|
||||
static Register FromWideOperand(uint16_t operand);
|
||||
uint16_t ToWideOperand() const;
|
||||
|
||||
static Register FromRawOperand(uint32_t raw_operand);
|
||||
uint32_t ToRawOperand() const;
|
||||
|
||||
static bool AreContiguous(Register reg1, Register reg2,
|
||||
Register reg3 = Register(),
|
||||
Register reg4 = Register(),
|
||||
@ -318,6 +341,12 @@ class Register {
|
||||
bool operator<=(const Register& other) const {
|
||||
return index() <= other.index();
|
||||
}
|
||||
bool operator>(const Register& other) const {
|
||||
return index() > other.index();
|
||||
}
|
||||
bool operator>=(const Register& other) const {
|
||||
return index() >= other.index();
|
||||
}
|
||||
|
||||
private:
|
||||
static const int kIllegalIndex = kMaxInt;
|
||||
|
@ -201,28 +201,6 @@ void Interpreter::DoStar(compiler::InterpreterAssembler* assembler) {
|
||||
}
|
||||
|
||||
|
||||
// Exchange <reg8> <reg16>
|
||||
//
|
||||
// Exchange two registers.
|
||||
void Interpreter::DoExchange(compiler::InterpreterAssembler* assembler) {
|
||||
Node* reg0_index = __ BytecodeOperandReg(0);
|
||||
Node* reg1_index = __ BytecodeOperandReg(1);
|
||||
Node* reg0_value = __ LoadRegister(reg0_index);
|
||||
Node* reg1_value = __ LoadRegister(reg1_index);
|
||||
__ StoreRegister(reg1_value, reg0_index);
|
||||
__ StoreRegister(reg0_value, reg1_index);
|
||||
__ Dispatch();
|
||||
}
|
||||
|
||||
|
||||
// ExchangeWide <reg16> <reg16>
|
||||
//
|
||||
// Exchange two registers.
|
||||
void Interpreter::DoExchangeWide(compiler::InterpreterAssembler* assembler) {
|
||||
return DoExchange(assembler);
|
||||
}
|
||||
|
||||
|
||||
// Mov <src> <dst>
|
||||
//
|
||||
// Stores the value of register <src> to register <dst>.
|
||||
@ -235,6 +213,14 @@ void Interpreter::DoMov(compiler::InterpreterAssembler* assembler) {
|
||||
}
|
||||
|
||||
|
||||
// MovWide <src> <dst>
|
||||
//
|
||||
// Stores the value of register <src> to register <dst>.
|
||||
void Interpreter::DoMovWide(compiler::InterpreterAssembler* assembler) {
|
||||
DoMov(assembler);
|
||||
}
|
||||
|
||||
|
||||
void Interpreter::DoLoadGlobal(Callable ic,
|
||||
compiler::InterpreterAssembler* assembler) {
|
||||
// Get the global object.
|
||||
@ -1088,12 +1074,8 @@ void Interpreter::DoCallWide(compiler::InterpreterAssembler* assembler) {
|
||||
}
|
||||
|
||||
|
||||
// CallRuntime <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::DoCallRuntime(compiler::InterpreterAssembler* assembler) {
|
||||
void Interpreter::DoCallRuntimeCommon(
|
||||
compiler::InterpreterAssembler* assembler) {
|
||||
Node* function_id = __ BytecodeOperandIdx(0);
|
||||
Node* first_arg_reg = __ BytecodeOperandReg(1);
|
||||
Node* first_arg = __ RegisterLocation(first_arg_reg);
|
||||
@ -1104,13 +1086,27 @@ void Interpreter::DoCallRuntime(compiler::InterpreterAssembler* assembler) {
|
||||
}
|
||||
|
||||
|
||||
// CallRuntimeForPair <function_id> <first_arg> <arg_count> <first_return>
|
||||
// CallRuntime <function_id> <first_arg> <arg_count>
|
||||
//
|
||||
// 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::DoCallRuntimeForPair(
|
||||
// Call the runtime function |function_id| with the first argument in
|
||||
// register |first_arg| and |arg_count| arguments in subsequent
|
||||
// registers.
|
||||
void Interpreter::DoCallRuntime(compiler::InterpreterAssembler* assembler) {
|
||||
DoCallRuntimeCommon(assembler);
|
||||
}
|
||||
|
||||
|
||||
// CallRuntime <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(compiler::InterpreterAssembler* assembler) {
|
||||
DoCallRuntimeCommon(assembler);
|
||||
}
|
||||
|
||||
|
||||
void Interpreter::DoCallRuntimeForPairCommon(
|
||||
compiler::InterpreterAssembler* assembler) {
|
||||
// Call the runtime function.
|
||||
Node* function_id = __ BytecodeOperandIdx(0);
|
||||
@ -1126,16 +1122,36 @@ void Interpreter::DoCallRuntimeForPair(
|
||||
Node* result1 = __ Projection(1, result_pair);
|
||||
__ StoreRegister(result0, first_return_reg);
|
||||
__ StoreRegister(result1, second_return_reg);
|
||||
|
||||
__ Dispatch();
|
||||
}
|
||||
|
||||
|
||||
// CallJSRuntime <context_index> <receiver> <arg_count>
|
||||
// CallRuntimeForPair <function_id> <first_arg> <arg_count> <first_return>
|
||||
//
|
||||
// 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::DoCallJSRuntime(compiler::InterpreterAssembler* assembler) {
|
||||
// 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::DoCallRuntimeForPair(
|
||||
compiler::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(
|
||||
compiler::InterpreterAssembler* assembler) {
|
||||
DoCallRuntimeForPairCommon(assembler);
|
||||
}
|
||||
|
||||
|
||||
void Interpreter::DoCallJSRuntimeCommon(
|
||||
compiler::InterpreterAssembler* assembler) {
|
||||
Node* context_index = __ BytecodeOperandIdx(0);
|
||||
Node* receiver_reg = __ BytecodeOperandReg(1);
|
||||
Node* first_arg = __ RegisterLocation(receiver_reg);
|
||||
@ -1154,12 +1170,26 @@ void Interpreter::DoCallJSRuntime(compiler::InterpreterAssembler* assembler) {
|
||||
}
|
||||
|
||||
|
||||
// New <constructor> <first_arg> <arg_count>
|
||||
// CallJSRuntime <context_index> <receiver> <arg_count>
|
||||
//
|
||||
// Call operator new with |constructor| and the first argument in
|
||||
// register |first_arg| and |arg_count| arguments in subsequent
|
||||
// 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::DoCallJSRuntime(compiler::InterpreterAssembler* assembler) {
|
||||
DoCallJSRuntimeCommon(assembler);
|
||||
}
|
||||
|
||||
|
||||
// CallJSRuntimeWide <context_index> <receiver> <arg_count>
|
||||
//
|
||||
void Interpreter::DoNew(compiler::InterpreterAssembler* assembler) {
|
||||
// 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(
|
||||
compiler::InterpreterAssembler* assembler) {
|
||||
DoCallJSRuntimeCommon(assembler);
|
||||
}
|
||||
|
||||
|
||||
void Interpreter::DoCallConstruct(compiler::InterpreterAssembler* assembler) {
|
||||
Callable ic = CodeFactory::InterpreterPushArgsAndConstruct(isolate_);
|
||||
Node* constructor_reg = __ BytecodeOperandReg(0);
|
||||
Node* constructor = __ LoadRegister(constructor_reg);
|
||||
@ -1173,6 +1203,26 @@ void Interpreter::DoNew(compiler::InterpreterAssembler* assembler) {
|
||||
}
|
||||
|
||||
|
||||
// New <constructor> <first_arg> <arg_count>
|
||||
//
|
||||
// Call operator new with |constructor| and the first argument in
|
||||
// register |first_arg| and |arg_count| arguments in subsequent
|
||||
//
|
||||
void Interpreter::DoNew(compiler::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
|
||||
//
|
||||
void Interpreter::DoNewWide(compiler::InterpreterAssembler* assembler) {
|
||||
DoCallConstruct(assembler);
|
||||
}
|
||||
|
||||
|
||||
// TestEqual <src>
|
||||
//
|
||||
// Test if the value in the <src> register equals the accumulator.
|
||||
@ -1727,11 +1777,22 @@ void Interpreter::DoForInPrepare(compiler::InterpreterAssembler* assembler) {
|
||||
__ StoreRegister(cache_info, output_register);
|
||||
output_register = __ NextRegister(output_register);
|
||||
}
|
||||
|
||||
__ 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(
|
||||
compiler::InterpreterAssembler* assembler) {
|
||||
DoForInPrepare(assembler);
|
||||
}
|
||||
|
||||
|
||||
// ForInNext <receiver> <index> <cache_info_pair>
|
||||
//
|
||||
// Returns the next enumerable property in the the accumulator.
|
||||
@ -1751,6 +1812,14 @@ void Interpreter::DoForInNext(compiler::InterpreterAssembler* assembler) {
|
||||
}
|
||||
|
||||
|
||||
// ForInNextWide <receiver> <index> <cache_info_pair>
|
||||
//
|
||||
// Returns the next enumerable property in the the accumulator.
|
||||
void Interpreter::DoForInNextWide(compiler::InterpreterAssembler* assembler) {
|
||||
return DoForInNext(assembler);
|
||||
}
|
||||
|
||||
|
||||
// ForInDone <index> <cache_length>
|
||||
//
|
||||
// Returns true if the end of the enumerable properties has been reached.
|
||||
|
@ -87,6 +87,18 @@ class Interpreter {
|
||||
// Generates code to perform a JS call.
|
||||
void DoJSCall(compiler::InterpreterAssembler* assembler);
|
||||
|
||||
// Generates code to perform a runtime call.
|
||||
void DoCallRuntimeCommon(compiler::InterpreterAssembler* assembler);
|
||||
|
||||
// Generates code to perform a runtime call returning a pair.
|
||||
void DoCallRuntimeForPairCommon(compiler::InterpreterAssembler* assembler);
|
||||
|
||||
// Generates code to perform a JS runtime call.
|
||||
void DoCallJSRuntimeCommon(compiler::InterpreterAssembler* assembler);
|
||||
|
||||
// Generates code to perform a constructor call..
|
||||
void DoCallConstruct(compiler::InterpreterAssembler* assembler);
|
||||
|
||||
// Generates code ro create a literal via |function_id|.
|
||||
void DoCreateLiteral(Runtime::FunctionId function_id,
|
||||
compiler::InterpreterAssembler* assembler);
|
||||
|
@ -94,6 +94,7 @@ class BytecodeGeneratorHelper {
|
||||
#define B(x) static_cast<uint8_t>(Bytecode::k##x)
|
||||
#define U8(x) static_cast<uint8_t>((x) & 0xff)
|
||||
#define R(x) static_cast<uint8_t>(-(x) & 0xff)
|
||||
#define R16(x) U16(-(x))
|
||||
#define A(x, n) R(helper.kLastParamIndex - (n) + 1 + (x))
|
||||
#define THIS(n) A(0, n)
|
||||
#if defined(V8_TARGET_LITTLE_ENDIAN)
|
||||
@ -1440,7 +1441,7 @@ TEST(PropertyCall) {
|
||||
" return a.func(); }\nf(" FUNC_ARG ")",
|
||||
2 * kPointerSize,
|
||||
2,
|
||||
1044,
|
||||
1046,
|
||||
{
|
||||
B(Ldar), A(1, 2), //
|
||||
B(Star), R(0), //
|
||||
@ -1453,7 +1454,7 @@ TEST(PropertyCall) {
|
||||
B(Star), R(1), //
|
||||
B(LoadICSloppyWide), R(1), U16(0), U16(wide_idx + 4), //
|
||||
B(Star), R(0), //
|
||||
B(CallWide), R(0), R(1), U16(0), U16(wide_idx + 2), //
|
||||
B(CallWide), R16(0), R16(1), U16(0), U16(wide_idx + 2), //
|
||||
B(Return), //
|
||||
},
|
||||
1,
|
||||
|
@ -362,117 +362,6 @@ TEST(InterpreterLoadStoreRegisters) {
|
||||
}
|
||||
|
||||
|
||||
TEST(InterpreterExchangeRegisters) {
|
||||
for (int locals_count = 2; locals_count < 300; locals_count += 126) {
|
||||
HandleAndZoneScope handles;
|
||||
for (int exchanges = 1; exchanges < 4; exchanges++) {
|
||||
BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone());
|
||||
builder.set_locals_count(locals_count);
|
||||
builder.set_context_count(0);
|
||||
builder.set_parameter_count(0);
|
||||
|
||||
Register r0(0);
|
||||
Register r1(locals_count - 1);
|
||||
builder.LoadTrue();
|
||||
builder.StoreAccumulatorInRegister(r0);
|
||||
builder.ExchangeRegisters(r0, r1);
|
||||
builder.LoadFalse();
|
||||
builder.StoreAccumulatorInRegister(r0);
|
||||
|
||||
bool expected = false;
|
||||
for (int i = 0; i < exchanges; i++) {
|
||||
builder.ExchangeRegisters(r0, r1);
|
||||
expected = !expected;
|
||||
}
|
||||
builder.LoadAccumulatorWithRegister(r0);
|
||||
builder.Return();
|
||||
Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray();
|
||||
InterpreterTester tester(handles.main_isolate(), bytecode_array);
|
||||
auto callable = tester.GetCallable<>();
|
||||
Handle<Object> return_val = callable().ToHandleChecked();
|
||||
Handle<Object> expected_val =
|
||||
handles.main_isolate()->factory()->ToBoolean(expected);
|
||||
CHECK(return_val.is_identical_to(expected_val));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST(InterpreterExchangeRegistersWithParameter) {
|
||||
for (int locals_count = 2; locals_count < 300; locals_count += 126) {
|
||||
HandleAndZoneScope handles;
|
||||
for (int exchanges = 1; exchanges < 4; exchanges++) {
|
||||
BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone());
|
||||
builder.set_locals_count(locals_count);
|
||||
builder.set_context_count(0);
|
||||
builder.set_parameter_count(3);
|
||||
|
||||
Register r0 = Register::FromParameterIndex(2, 3);
|
||||
Register r1(locals_count - 1);
|
||||
builder.LoadTrue();
|
||||
builder.StoreAccumulatorInRegister(r0);
|
||||
builder.ExchangeRegisters(r0, r1);
|
||||
builder.LoadFalse();
|
||||
builder.StoreAccumulatorInRegister(r0);
|
||||
|
||||
bool expected = false;
|
||||
for (int i = 0; i < exchanges; i++) {
|
||||
builder.ExchangeRegisters(r0, r1);
|
||||
expected = !expected;
|
||||
}
|
||||
builder.LoadAccumulatorWithRegister(r0);
|
||||
builder.Return();
|
||||
Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray();
|
||||
InterpreterTester tester(handles.main_isolate(), bytecode_array);
|
||||
auto callable = tester.GetCallable<>();
|
||||
Handle<Object> return_val = callable().ToHandleChecked();
|
||||
Handle<Object> expected_val =
|
||||
handles.main_isolate()->factory()->ToBoolean(expected);
|
||||
CHECK(return_val.is_identical_to(expected_val));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST(InterpreterExchangeWideRegisters) {
|
||||
for (int locals_count = 3; locals_count < 300; locals_count += 126) {
|
||||
HandleAndZoneScope handles;
|
||||
for (int exchanges = 0; exchanges < 7; exchanges++) {
|
||||
BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone());
|
||||
builder.set_locals_count(locals_count);
|
||||
builder.set_context_count(0);
|
||||
builder.set_parameter_count(0);
|
||||
|
||||
Register r0(0);
|
||||
Register r1(locals_count - 1);
|
||||
Register r2(locals_count - 2);
|
||||
builder.LoadLiteral(Smi::FromInt(200));
|
||||
builder.StoreAccumulatorInRegister(r0);
|
||||
builder.ExchangeRegisters(r0, r1);
|
||||
builder.LoadLiteral(Smi::FromInt(100));
|
||||
builder.StoreAccumulatorInRegister(r0);
|
||||
builder.ExchangeRegisters(r0, r2);
|
||||
builder.LoadLiteral(Smi::FromInt(0));
|
||||
builder.StoreAccumulatorInRegister(r0);
|
||||
for (int i = 0; i < exchanges; i++) {
|
||||
builder.ExchangeRegisters(r1, r2);
|
||||
builder.ExchangeRegisters(r0, r1);
|
||||
}
|
||||
builder.LoadAccumulatorWithRegister(r0);
|
||||
builder.Return();
|
||||
Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray();
|
||||
InterpreterTester tester(handles.main_isolate(), bytecode_array);
|
||||
auto callable = tester.GetCallable<>();
|
||||
Handle<Object> return_val = callable().ToHandleChecked();
|
||||
Handle<Object> expected_val =
|
||||
handles.main_isolate()->factory()->NewNumberFromInt(100 *
|
||||
(exchanges % 3));
|
||||
CHECK(return_val.is_identical_to(expected_val));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static const Token::Value kShiftOperators[] = {
|
||||
Token::Value::SHL, Token::Value::SAR, Token::Value::SHR};
|
||||
|
||||
|
@ -338,7 +338,7 @@ TARGET_TEST_F(InterpreterAssemblerTest, BytecodeOperand) {
|
||||
for (int i = 0; i < number_of_operands; i++) {
|
||||
int offset = interpreter::Bytecodes::GetOperandOffset(bytecode, i);
|
||||
switch (interpreter::Bytecodes::GetOperandType(bytecode, i)) {
|
||||
case interpreter::OperandType::kCount8:
|
||||
case interpreter::OperandType::kRegCount8:
|
||||
EXPECT_THAT(m.BytecodeOperandCount(i), m.IsBytecodeOperand(offset));
|
||||
break;
|
||||
case interpreter::OperandType::kIdx8:
|
||||
@ -355,7 +355,7 @@ TARGET_TEST_F(InterpreterAssemblerTest, BytecodeOperand) {
|
||||
EXPECT_THAT(m.BytecodeOperandReg(i),
|
||||
m.IsBytecodeOperandSignExtended(offset));
|
||||
break;
|
||||
case interpreter::OperandType::kCount16:
|
||||
case interpreter::OperandType::kRegCount16:
|
||||
EXPECT_THAT(m.BytecodeOperandCount(i),
|
||||
m.IsBytecodeOperandShort(offset));
|
||||
break;
|
||||
@ -363,7 +363,10 @@ TARGET_TEST_F(InterpreterAssemblerTest, BytecodeOperand) {
|
||||
EXPECT_THAT(m.BytecodeOperandIdx(i),
|
||||
m.IsBytecodeOperandShort(offset));
|
||||
break;
|
||||
case interpreter::OperandType::kMaybeReg16:
|
||||
case interpreter::OperandType::kReg16:
|
||||
case interpreter::OperandType::kRegPair16:
|
||||
case interpreter::OperandType::kRegTriple16:
|
||||
EXPECT_THAT(m.BytecodeOperandReg(i),
|
||||
m.IsBytecodeOperandShortSignExtended(offset));
|
||||
break;
|
||||
|
@ -23,12 +23,12 @@ class BytecodeArrayBuilderTest : public TestWithIsolateAndZone {
|
||||
TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) {
|
||||
BytecodeArrayBuilder builder(isolate(), zone());
|
||||
|
||||
builder.set_locals_count(200);
|
||||
builder.set_locals_count(131);
|
||||
builder.set_context_count(1);
|
||||
builder.set_parameter_count(0);
|
||||
CHECK_EQ(builder.locals_count(), 200);
|
||||
CHECK_EQ(builder.locals_count(), 131);
|
||||
CHECK_EQ(builder.context_count(), 1);
|
||||
CHECK_EQ(builder.fixed_register_count(), 201);
|
||||
CHECK_EQ(builder.fixed_register_count(), 132);
|
||||
|
||||
// Emit constant loads.
|
||||
builder.LoadLiteral(Smi::FromInt(0))
|
||||
@ -40,23 +40,17 @@ TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) {
|
||||
.LoadTrue()
|
||||
.LoadFalse();
|
||||
|
||||
// Emit accumulator transfers. Stores followed by loads to the same register
|
||||
// are not generated. Hence, a dummy instruction in between.
|
||||
Register reg(0);
|
||||
Register other(reg.index() + 1);
|
||||
Register wide(128);
|
||||
|
||||
builder.LoadAccumulatorWithRegister(reg)
|
||||
.LoadNull()
|
||||
.StoreAccumulatorInRegister(reg);
|
||||
|
||||
// Emit register-register transfer.
|
||||
Register other(1);
|
||||
builder.MoveRegister(reg, other);
|
||||
|
||||
// Emit register-register exchanges.
|
||||
Register wide(150);
|
||||
builder.ExchangeRegisters(reg, wide);
|
||||
builder.ExchangeRegisters(wide, reg);
|
||||
Register wider(151);
|
||||
builder.ExchangeRegisters(wide, wider);
|
||||
builder.MoveRegister(reg, wide);
|
||||
|
||||
// Emit global load / store operations.
|
||||
Factory* factory = isolate()->factory();
|
||||
@ -107,11 +101,14 @@ TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) {
|
||||
.CreateObjectLiteral(factory->NewFixedArray(1), 0, 0);
|
||||
|
||||
// Call operations.
|
||||
builder.Call(reg, reg, 0, 0)
|
||||
.Call(reg, reg, 0, 1024)
|
||||
builder.Call(reg, other, 1, 0)
|
||||
.Call(reg, wide, 1, 0)
|
||||
.CallRuntime(Runtime::kIsArray, reg, 1)
|
||||
.CallRuntimeForPair(Runtime::kLoadLookupSlot, reg, 1, reg)
|
||||
.CallJSRuntime(Context::SPREAD_ITERABLE_INDEX, reg, 1);
|
||||
.CallRuntime(Runtime::kIsArray, wide, 1)
|
||||
.CallRuntimeForPair(Runtime::kLoadLookupSlot, reg, 1, other)
|
||||
.CallRuntimeForPair(Runtime::kLoadLookupSlot, wide, 1, other)
|
||||
.CallJSRuntime(Context::SPREAD_ITERABLE_INDEX, reg, 1)
|
||||
.CallJSRuntime(Context::SPREAD_ITERABLE_INDEX, wide, 1);
|
||||
|
||||
// Emit binary operator invocations.
|
||||
builder.BinaryOperation(Token::Value::ADD, reg, Strength::WEAK)
|
||||
@ -144,6 +141,7 @@ TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) {
|
||||
|
||||
// Emit new.
|
||||
builder.New(reg, reg, 0);
|
||||
builder.New(wide, wide, 0);
|
||||
|
||||
// Emit test operator invocations.
|
||||
builder.CompareOperation(Token::Value::EQ, reg, Strength::WEAK)
|
||||
@ -205,14 +203,16 @@ TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) {
|
||||
// Emit throw in it's own basic block so that the rest of the code isn't
|
||||
// omitted due to being dead.
|
||||
BytecodeLabel after_throw;
|
||||
builder.Jump(&after_throw)
|
||||
.Throw()
|
||||
.Bind(&after_throw);
|
||||
builder.Jump(&after_throw).Throw().Bind(&after_throw);
|
||||
|
||||
builder.ForInPrepare(reg)
|
||||
.ForInDone(reg, reg)
|
||||
.ForInNext(reg, reg, reg)
|
||||
.ForInStep(reg);
|
||||
builder.ForInPrepare(wide)
|
||||
.ForInDone(reg, other)
|
||||
.ForInNext(wide, wide, wide)
|
||||
.ForInStep(reg);
|
||||
|
||||
// Wide constant pool loads
|
||||
for (int i = 0; i < 256; i++) {
|
||||
@ -243,8 +243,7 @@ TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) {
|
||||
.StoreKeyedProperty(reg, reg, 2056, LanguageMode::STRICT);
|
||||
|
||||
// Emit wide context operations.
|
||||
builder.LoadContextSlot(reg, 1024)
|
||||
.StoreContextSlot(reg, 1024);
|
||||
builder.LoadContextSlot(reg, 1024).StoreContextSlot(reg, 1024);
|
||||
|
||||
// Emit wide load / store lookup slots.
|
||||
builder.LoadLookupSlot(wide_name, TypeofMode::NOT_INSIDE_TYPEOF)
|
||||
|
Loading…
Reference in New Issue
Block a user