[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:
oth 2016-01-19 08:06:10 -08:00 committed by Commit bot
parent 603acc3f49
commit 68654b6476
14 changed files with 536 additions and 380 deletions

View File

@ -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);

View File

@ -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);

View File

@ -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;
}

View File

@ -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_;

View File

@ -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);
};

View File

@ -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();
}

View File

@ -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()) {

View File

@ -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;

View File

@ -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.

View File

@ -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);

View File

@ -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,

View File

@ -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};

View File

@ -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;

View File

@ -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)