Commit 03369ed2 authored by rmcilroy's avatar rmcilroy Committed by Commit bot

[Interpreter] Add support for short (16 bit) operands.

Adds support for short operands, starting with kIdx16. Introduces
BytecodeTraits to enable compile time determination of various traits for a
bytecode, such as size, operands, etc. Reworks BytecodeIterator,
BytecodeArrayBuilder and Bytecodes::Decode to support 16 bit operands. Adds
support to Interpreter to load 16 bit operands.

Also fixes a bug with ToBoolean where it wouldn't get emitted at the start
of a block, and added a test.

BytecodeTraits template magic inspired by oth@chromium.org.

BUG=v8:4280
LOG=N

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

Cr-Commit-Position: refs/heads/master@{#31058}
parent 924b0ecf
...@@ -1051,6 +1051,7 @@ source_set("v8_base") { ...@@ -1051,6 +1051,7 @@ source_set("v8_base") {
"src/interpreter/bytecode-array-iterator.h", "src/interpreter/bytecode-array-iterator.h",
"src/interpreter/bytecode-generator.cc", "src/interpreter/bytecode-generator.cc",
"src/interpreter/bytecode-generator.h", "src/interpreter/bytecode-generator.h",
"src/interpreter/bytecode-traits.h",
"src/interpreter/control-flow-builders.cc", "src/interpreter/control-flow-builders.cc",
"src/interpreter/control-flow-builders.h", "src/interpreter/control-flow-builders.h",
"src/interpreter/interpreter.cc", "src/interpreter/interpreter.cc",
......
...@@ -188,7 +188,7 @@ void BytecodeGraphBuilder::VisitLdaZero( ...@@ -188,7 +188,7 @@ void BytecodeGraphBuilder::VisitLdaZero(
void BytecodeGraphBuilder::VisitLdaSmi8( void BytecodeGraphBuilder::VisitLdaSmi8(
const interpreter::BytecodeArrayIterator& iterator) { const interpreter::BytecodeArrayIterator& iterator) {
Node* node = jsgraph()->Constant(iterator.GetSmi8Operand(0)); Node* node = jsgraph()->Constant(iterator.GetImmediateOperand(0));
environment()->BindAccumulator(node); environment()->BindAccumulator(node);
} }
......
...@@ -126,17 +126,25 @@ Node* InterpreterAssembler::StoreRegister(Node* value, Node* reg_index) { ...@@ -126,17 +126,25 @@ Node* InterpreterAssembler::StoreRegister(Node* value, Node* reg_index) {
Node* InterpreterAssembler::BytecodeOperand(int operand_index) { Node* InterpreterAssembler::BytecodeOperand(int operand_index) {
DCHECK_LT(operand_index, interpreter::Bytecodes::NumberOfOperands(bytecode_)); DCHECK_LT(operand_index, interpreter::Bytecodes::NumberOfOperands(bytecode_));
DCHECK_EQ(interpreter::OperandSize::kByte,
interpreter::Bytecodes::GetOperandSize(bytecode_, operand_index));
return raw_assembler_->Load( return raw_assembler_->Load(
kMachUint8, BytecodeArrayTaggedPointer(), kMachUint8, BytecodeArrayTaggedPointer(),
IntPtrAdd(BytecodeOffset(), Int32Constant(1 + operand_index))); IntPtrAdd(BytecodeOffset(),
Int32Constant(interpreter::Bytecodes::GetOperandOffset(
bytecode_, operand_index))));
} }
Node* InterpreterAssembler::BytecodeOperandSignExtended(int operand_index) { Node* InterpreterAssembler::BytecodeOperandSignExtended(int operand_index) {
DCHECK_LT(operand_index, interpreter::Bytecodes::NumberOfOperands(bytecode_)); DCHECK_LT(operand_index, interpreter::Bytecodes::NumberOfOperands(bytecode_));
DCHECK_EQ(interpreter::OperandSize::kByte,
interpreter::Bytecodes::GetOperandSize(bytecode_, operand_index));
Node* load = raw_assembler_->Load( Node* load = raw_assembler_->Load(
kMachInt8, BytecodeArrayTaggedPointer(), kMachInt8, BytecodeArrayTaggedPointer(),
IntPtrAdd(BytecodeOffset(), Int32Constant(1 + operand_index))); IntPtrAdd(BytecodeOffset(),
Int32Constant(interpreter::Bytecodes::GetOperandOffset(
bytecode_, operand_index))));
// Ensure that we sign extend to full pointer size // Ensure that we sign extend to full pointer size
if (kPointerSize == 8) { if (kPointerSize == 8) {
load = raw_assembler_->ChangeInt32ToInt64(load); load = raw_assembler_->ChangeInt32ToInt64(load);
...@@ -145,8 +153,40 @@ Node* InterpreterAssembler::BytecodeOperandSignExtended(int operand_index) { ...@@ -145,8 +153,40 @@ Node* InterpreterAssembler::BytecodeOperandSignExtended(int operand_index) {
} }
Node* InterpreterAssembler::BytecodeOperandCount(int operand_index) { Node* InterpreterAssembler::BytecodeOperandShort(int operand_index) {
DCHECK_EQ(interpreter::OperandType::kCount, DCHECK_LT(operand_index, interpreter::Bytecodes::NumberOfOperands(bytecode_));
DCHECK_EQ(interpreter::OperandSize::kShort,
interpreter::Bytecodes::GetOperandSize(bytecode_, operand_index));
if (TargetSupportsUnalignedAccess()) {
return raw_assembler_->Load(
kMachUint16, BytecodeArrayTaggedPointer(),
IntPtrAdd(BytecodeOffset(),
Int32Constant(interpreter::Bytecodes::GetOperandOffset(
bytecode_, operand_index))));
} else {
int offset =
interpreter::Bytecodes::GetOperandOffset(bytecode_, operand_index);
Node* first_byte = raw_assembler_->Load(
kMachUint8, BytecodeArrayTaggedPointer(),
IntPtrAdd(BytecodeOffset(), Int32Constant(offset)));
Node* second_byte = raw_assembler_->Load(
kMachUint8, BytecodeArrayTaggedPointer(),
IntPtrAdd(BytecodeOffset(), Int32Constant(offset + 1)));
#if V8_TARGET_LITTLE_ENDIAN
return raw_assembler_->WordOr(WordShl(second_byte, kBitsPerByte),
first_byte);
#elif V8_TARGET_BIG_ENDIAN
return raw_assembler_->WordOr(WordShl(first_byte, kBitsPerByte),
second_byte);
#else
#error "Unknown Architecture"
#endif
}
}
Node* InterpreterAssembler::BytecodeOperandCount8(int operand_index) {
DCHECK_EQ(interpreter::OperandType::kCount8,
interpreter::Bytecodes::GetOperandType(bytecode_, operand_index)); interpreter::Bytecodes::GetOperandType(bytecode_, operand_index));
return BytecodeOperand(operand_index); return BytecodeOperand(operand_index);
} }
...@@ -159,20 +199,27 @@ Node* InterpreterAssembler::BytecodeOperandImm8(int operand_index) { ...@@ -159,20 +199,27 @@ Node* InterpreterAssembler::BytecodeOperandImm8(int operand_index) {
} }
Node* InterpreterAssembler::BytecodeOperandIdx(int operand_index) { Node* InterpreterAssembler::BytecodeOperandIdx8(int operand_index) {
DCHECK_EQ(interpreter::OperandType::kIdx, DCHECK_EQ(interpreter::OperandType::kIdx8,
interpreter::Bytecodes::GetOperandType(bytecode_, operand_index)); interpreter::Bytecodes::GetOperandType(bytecode_, operand_index));
return BytecodeOperand(operand_index); return BytecodeOperand(operand_index);
} }
Node* InterpreterAssembler::BytecodeOperandReg(int operand_index) { Node* InterpreterAssembler::BytecodeOperandReg8(int operand_index) {
DCHECK_EQ(interpreter::OperandType::kReg, DCHECK_EQ(interpreter::OperandType::kReg8,
interpreter::Bytecodes::GetOperandType(bytecode_, operand_index)); interpreter::Bytecodes::GetOperandType(bytecode_, operand_index));
return BytecodeOperandSignExtended(operand_index); return BytecodeOperandSignExtended(operand_index);
} }
Node* InterpreterAssembler::BytecodeOperandIdx16(int operand_index) {
DCHECK_EQ(interpreter::OperandType::kIdx16,
interpreter::Bytecodes::GetOperandType(bytecode_, operand_index));
return BytecodeOperandShort(operand_index);
}
Node* InterpreterAssembler::Int32Constant(int value) { Node* InterpreterAssembler::Int32Constant(int value) {
return raw_assembler_->Int32Constant(value); return raw_assembler_->Int32Constant(value);
} }
...@@ -432,6 +479,20 @@ void InterpreterAssembler::End() { ...@@ -432,6 +479,20 @@ void InterpreterAssembler::End() {
} }
// static
bool InterpreterAssembler::TargetSupportsUnalignedAccess() {
#if V8_TARGET_ARCH_MIPS || V8_TARGET_ARCH_MIPS64
return false;
#elif V8_TARGET_ARCH_ARM || V8_TARGET_ARCH_ARM64 || V8_TARGET_ARCH_PPC
return CpuFeatures::IsSupported(UNALIGNED_ACCESSES);
#elif V8_TARGET_ARCH_IA32 || V8_TARGET_ARCH_X64 || V8_TARGET_ARCH_X87
return true;
#else
#error "Unknown Architecture"
#endif
}
// RawMachineAssembler delegate helpers: // RawMachineAssembler delegate helpers:
Isolate* InterpreterAssembler::isolate() { return raw_assembler_->isolate(); } Isolate* InterpreterAssembler::isolate() { return raw_assembler_->isolate(); }
......
...@@ -41,16 +41,20 @@ class InterpreterAssembler { ...@@ -41,16 +41,20 @@ class InterpreterAssembler {
// Returns the count immediate for bytecode operand |operand_index| in the // Returns the count immediate for bytecode operand |operand_index| in the
// current bytecode. // current bytecode.
Node* BytecodeOperandCount(int operand_index); Node* BytecodeOperandCount8(int operand_index);
// Returns the index immediate for bytecode operand |operand_index| in the // Returns the index immediate for bytecode operand |operand_index| in the
// current bytecode. // current bytecode.
Node* BytecodeOperandIdx(int operand_index); Node* BytecodeOperandIdx8(int operand_index);
// Returns the Imm8 immediate for bytecode operand |operand_index| in the // Returns the Imm8 immediate for bytecode operand |operand_index| in the
// current bytecode. // current bytecode.
Node* BytecodeOperandImm8(int operand_index); Node* BytecodeOperandImm8(int operand_index);
// Returns the register index for bytecode operand |operand_index| in the // Returns the register index for bytecode operand |operand_index| in the
// current bytecode. // current bytecode.
Node* BytecodeOperandReg(int operand_index); Node* BytecodeOperandReg8(int operand_index);
// Returns the index immediate for the short (16 bit) bytecode operand
// |operand_index| in the current bytecode.
Node* BytecodeOperandIdx16(int operand_index);
// Accumulator. // Accumulator.
Node* GetAccumulator(); Node* GetAccumulator();
...@@ -126,6 +130,8 @@ class InterpreterAssembler { ...@@ -126,6 +130,8 @@ class InterpreterAssembler {
// Close the graph. // Close the graph.
void End(); void End();
static bool TargetSupportsUnalignedAccess();
// Protected helpers (for testing) which delegate to RawMachineAssembler. // Protected helpers (for testing) which delegate to RawMachineAssembler.
CallDescriptor* call_descriptor() const; CallDescriptor* call_descriptor() const;
Graph* graph(); Graph* graph();
...@@ -148,6 +154,7 @@ class InterpreterAssembler { ...@@ -148,6 +154,7 @@ class InterpreterAssembler {
Node* SmiShiftBitsConstant(); Node* SmiShiftBitsConstant();
Node* BytecodeOperand(int operand_index); Node* BytecodeOperand(int operand_index);
Node* BytecodeOperandSignExtended(int operand_index); Node* BytecodeOperandSignExtended(int operand_index);
Node* BytecodeOperandShort(int operand_index);
Node* CallIC(CallInterfaceDescriptor descriptor, Node* target, Node** args); Node* CallIC(CallInterfaceDescriptor descriptor, Node* target, Node** args);
Node* CallJSBuiltin(int context_index, Node* receiver, Node** js_args, Node* CallJSBuiltin(int context_index, Node* receiver, Node** js_args,
......
...@@ -76,40 +76,54 @@ Handle<BytecodeArray> BytecodeArrayBuilder::ToBytecodeArray() { ...@@ -76,40 +76,54 @@ Handle<BytecodeArray> BytecodeArrayBuilder::ToBytecodeArray() {
template <size_t N> template <size_t N>
void BytecodeArrayBuilder::Output(uint8_t(&bytes)[N]) { void BytecodeArrayBuilder::Output(Bytecode bytecode, uint32_t(&operands)[N]) {
DCHECK_EQ(Bytecodes::NumberOfOperands(Bytecodes::FromByte(bytes[0])), DCHECK_EQ(Bytecodes::NumberOfOperands(bytecode), N);
static_cast<int>(N) - 1);
last_bytecode_start_ = bytecodes()->size(); last_bytecode_start_ = bytecodes()->size();
for (int i = 1; i < static_cast<int>(N); i++) { bytecodes()->push_back(Bytecodes::ToByte(bytecode));
DCHECK(OperandIsValid(Bytecodes::FromByte(bytes[0]), i - 1, bytes[i])); for (int i = 0; i < static_cast<int>(N); i++) {
DCHECK(OperandIsValid(bytecode, i, operands[i]));
switch (Bytecodes::GetOperandSize(bytecode, i)) {
case OperandSize::kNone:
UNREACHABLE();
case OperandSize::kByte:
bytecodes()->push_back(static_cast<uint8_t>(operands[i]));
break;
case OperandSize::kShort: {
uint8_t operand_bytes[2];
Bytecodes::ShortOperandToBytes(operands[i], operand_bytes);
bytecodes()->insert(bytecodes()->end(), operand_bytes,
operand_bytes + 2);
break;
}
}
} }
bytecodes()->insert(bytecodes()->end(), bytes, bytes + N);
} }
void BytecodeArrayBuilder::Output(Bytecode bytecode, uint8_t operand0, void BytecodeArrayBuilder::Output(Bytecode bytecode, uint32_t operand0,
uint8_t operand1, uint8_t operand2) { uint32_t operand1, uint32_t operand2) {
uint8_t bytes[] = {Bytecodes::ToByte(bytecode), operand0, operand1, operand2}; uint32_t operands[] = {operand0, operand1, operand2};
Output(bytes); Output(bytecode, operands);
} }
void BytecodeArrayBuilder::Output(Bytecode bytecode, uint8_t operand0, void BytecodeArrayBuilder::Output(Bytecode bytecode, uint32_t operand0,
uint8_t operand1) { uint32_t operand1) {
uint8_t bytes[] = {Bytecodes::ToByte(bytecode), operand0, operand1}; uint32_t operands[] = {operand0, operand1};
Output(bytes); Output(bytecode, operands);
} }
void BytecodeArrayBuilder::Output(Bytecode bytecode, uint8_t operand0) { void BytecodeArrayBuilder::Output(Bytecode bytecode, uint32_t operand0) {
uint8_t bytes[] = {Bytecodes::ToByte(bytecode), operand0}; uint32_t operands[] = {operand0};
Output(bytes); Output(bytecode, operands);
} }
void BytecodeArrayBuilder::Output(Bytecode bytecode) { void BytecodeArrayBuilder::Output(Bytecode bytecode) {
uint8_t bytes[] = {Bytecodes::ToByte(bytecode)}; DCHECK_EQ(Bytecodes::NumberOfOperands(bytecode), 0);
Output(bytes); last_bytecode_start_ = bytecodes()->size();
bytecodes()->push_back(Bytecodes::ToByte(bytecode));
} }
...@@ -295,11 +309,13 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::CastAccumulatorToBoolean() { ...@@ -295,11 +309,13 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::CastAccumulatorToBoolean() {
case Bytecode::kTestGreaterThanOrEqual: case Bytecode::kTestGreaterThanOrEqual:
case Bytecode::kTestInstanceOf: case Bytecode::kTestInstanceOf:
case Bytecode::kTestIn: case Bytecode::kTestIn:
break; return *this;
default: default:
Output(Bytecode::kToBoolean); // Fall through to output kToBoolean.
break;
} }
} }
Output(Bytecode::kToBoolean);
return *this; return *this;
} }
...@@ -499,17 +515,19 @@ void BytecodeArrayBuilder::ReturnTemporaryRegister(int reg_index) { ...@@ -499,17 +515,19 @@ void BytecodeArrayBuilder::ReturnTemporaryRegister(int reg_index) {
bool BytecodeArrayBuilder::OperandIsValid(Bytecode bytecode, int operand_index, bool BytecodeArrayBuilder::OperandIsValid(Bytecode bytecode, int operand_index,
uint8_t operand_value) const { uint32_t operand_value) const {
OperandType operand_type = Bytecodes::GetOperandType(bytecode, operand_index); OperandType operand_type = Bytecodes::GetOperandType(bytecode, operand_index);
switch (operand_type) { switch (operand_type) {
case OperandType::kNone: case OperandType::kNone:
return false; return false;
case OperandType::kCount: case OperandType::kIdx16:
return static_cast<uint16_t>(operand_value) == operand_value;
case OperandType::kCount8:
case OperandType::kImm8: case OperandType::kImm8:
case OperandType::kIdx: case OperandType::kIdx8:
return true; return static_cast<uint8_t>(operand_value) == operand_value;
case OperandType::kReg: { case OperandType::kReg8: {
Register reg = Register::FromOperand(operand_value); Register reg = Register::FromOperand(static_cast<uint8_t>(operand_value));
if (reg.is_parameter()) { if (reg.is_parameter()) {
int parameter_index = reg.ToParameterIndex(parameter_count_); int parameter_index = reg.ToParameterIndex(parameter_count_);
return parameter_index >= 0 && parameter_index < parameter_count_; return parameter_index >= 0 && parameter_index < parameter_count_;
......
...@@ -113,21 +113,21 @@ class BytecodeArrayBuilder { ...@@ -113,21 +113,21 @@ class BytecodeArrayBuilder {
static Bytecode GetJumpWithConstantOperand(Bytecode jump_with_smi8_operand); static Bytecode GetJumpWithConstantOperand(Bytecode jump_with_smi8_operand);
template <size_t N> template <size_t N>
INLINE(void Output(uint8_t(&bytes)[N])); INLINE(void Output(Bytecode bytecode, uint32_t(&oprands)[N]));
void Output(Bytecode bytecode, uint8_t operand0, uint8_t operand1, void Output(Bytecode bytecode, uint32_t operand0, uint32_t operand1,
uint8_t operand2); uint32_t operand2);
void Output(Bytecode bytecode, uint8_t operand0, uint8_t operand1); void Output(Bytecode bytecode, uint32_t operand0, uint32_t operand1);
void Output(Bytecode bytecode, uint8_t operand0); void Output(Bytecode bytecode, uint32_t operand0);
void Output(Bytecode bytecode); void Output(Bytecode bytecode);
void PatchJump(const ZoneVector<uint8_t>::iterator& jump_target,
ZoneVector<uint8_t>::iterator jump_location);
BytecodeArrayBuilder& OutputJump(Bytecode jump_bytecode, BytecodeArrayBuilder& OutputJump(Bytecode jump_bytecode,
BytecodeLabel* label); BytecodeLabel* label);
void PatchJump(const ZoneVector<uint8_t>::iterator& jump_target,
ZoneVector<uint8_t>::iterator jump_location);
void EnsureReturn(); void EnsureReturn();
bool OperandIsValid(Bytecode bytecode, int operand_index, bool OperandIsValid(Bytecode bytecode, int operand_index,
uint8_t operand_value) const; uint32_t operand_value) const;
bool LastBytecodeInSameBlock() const; bool LastBytecodeInSameBlock() const;
size_t GetConstantPoolEntry(Handle<Object> object); size_t GetConstantPoolEntry(Handle<Object> object);
......
...@@ -32,31 +32,45 @@ Bytecode BytecodeArrayIterator::current_bytecode() const { ...@@ -32,31 +32,45 @@ Bytecode BytecodeArrayIterator::current_bytecode() const {
} }
uint8_t BytecodeArrayIterator::GetRawOperand(int operand_index, uint32_t BytecodeArrayIterator::GetRawOperand(int operand_index,
OperandType operand_type) const { OperandType operand_type) const {
DCHECK_GE(operand_index, 0); DCHECK_GE(operand_index, 0);
DCHECK_LT(operand_index, Bytecodes::NumberOfOperands(current_bytecode())); DCHECK_LT(operand_index, Bytecodes::NumberOfOperands(current_bytecode()));
DCHECK_EQ(operand_type, DCHECK_EQ(operand_type,
Bytecodes::GetOperandType(current_bytecode(), operand_index)); Bytecodes::GetOperandType(current_bytecode(), operand_index));
int operands_start = bytecode_offset_ + 1; uint8_t* operand_start =
return bytecode_array()->get(operands_start + operand_index); bytecode_array()->GetFirstBytecodeAddress() + bytecode_offset_ +
Bytecodes::GetOperandOffset(current_bytecode(), operand_index);
switch (Bytecodes::SizeOfOperand(operand_type)) {
default:
case OperandSize::kNone:
UNREACHABLE();
case OperandSize::kByte:
return static_cast<uint32_t>(*operand_start);
case OperandSize::kShort:
return Bytecodes::ShortOperandFromBytes(operand_start);
}
} }
int8_t BytecodeArrayIterator::GetSmi8Operand(int operand_index) const { int8_t BytecodeArrayIterator::GetImmediateOperand(int operand_index) const {
uint8_t operand = GetRawOperand(operand_index, OperandType::kImm8); uint32_t operand = GetRawOperand(operand_index, OperandType::kImm8);
return static_cast<int8_t>(operand); return static_cast<int8_t>(operand);
} }
int BytecodeArrayIterator::GetIndexOperand(int operand_index) const { int BytecodeArrayIterator::GetIndexOperand(int operand_index) const {
uint8_t operand = GetRawOperand(operand_index, OperandType::kIdx); OperandSize size =
Bytecodes::GetOperandSize(current_bytecode(), operand_index);
OperandType type =
(size == OperandSize::kByte) ? OperandType::kIdx8 : OperandType::kIdx16;
uint32_t operand = GetRawOperand(operand_index, type);
return static_cast<int>(operand); return static_cast<int>(operand);
} }
Register BytecodeArrayIterator::GetRegisterOperand(int operand_index) const { Register BytecodeArrayIterator::GetRegisterOperand(int operand_index) const {
uint8_t operand = GetRawOperand(operand_index, OperandType::kReg); uint32_t operand = GetRawOperand(operand_index, OperandType::kReg8);
return Register::FromOperand(operand); return Register::FromOperand(operand);
} }
......
...@@ -25,14 +25,14 @@ class BytecodeArrayIterator { ...@@ -25,14 +25,14 @@ class BytecodeArrayIterator {
return bytecode_array_; return bytecode_array_;
} }
int8_t GetSmi8Operand(int operand_index) const; int8_t GetImmediateOperand(int operand_index) const;
int GetIndexOperand(int operand_index) const; int GetIndexOperand(int operand_index) const;
Register GetRegisterOperand(int operand_index) const; Register GetRegisterOperand(int operand_index) const;
Handle<Object> GetConstantForIndexOperand(int operand_index) const; Handle<Object> GetConstantForIndexOperand(int operand_index) const;
// Get the raw byte for the given operand. Note: you should prefer using the // Get the raw byte for the given operand. Note: you should prefer using the
// typed versions above which cast the return to an appropriate type. // typed versions above which cast the return to an appropriate type.
uint8_t GetRawOperand(int operand_index, OperandType operand_type) const; uint32_t GetRawOperand(int operand_index, OperandType operand_type) const;
private: private:
Handle<BytecodeArray> bytecode_array_; Handle<BytecodeArray> bytecode_array_;
......
// Copyright 2015 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef V8_INTERPRETER_BYTECODE_TRAITS_H_
#define V8_INTERPRETER_BYTECODE_TRAITS_H_
#include "src/interpreter/bytecodes.h"
namespace v8 {
namespace internal {
namespace interpreter {
// TODO(rmcilroy): consider simplifying this to avoid the template magic.
// Template helpers to deduce the number of operands each bytecode has.
#define OPERAND_TERM OperandType::kNone, OperandType::kNone, OperandType::kNone
template <OperandType>
struct OperandTraits {};
#define DECLARE_OPERAND_SIZE(Name, Size) \
template <> \
struct OperandTraits<OperandType::k##Name> { \
static const OperandSize kSizeType = Size; \
static const int kSize = static_cast<int>(Size); \
};
OPERAND_TYPE_LIST(DECLARE_OPERAND_SIZE)
#undef DECLARE_OPERAND_SIZE
template <OperandType... Args>
struct BytecodeTraits {};
template <OperandType operand_0, OperandType operand_1, OperandType operand_2,
OperandType operand_3>
struct BytecodeTraits<operand_0, operand_1, operand_2, operand_3,
OPERAND_TERM> {
static OperandType GetOperandType(int i) {
DCHECK(0 <= i && i < kOperandCount);
const OperandType kOperands[] = {operand_0, operand_1, operand_2,
operand_3};
return kOperands[i];
}
static inline OperandSize GetOperandSize(int i) {
DCHECK(0 <= i && i < kOperandCount);
const OperandSize kOperandSizes[] =
{OperandTraits<operand_0>::kSizeType,
OperandTraits<operand_1>::kSizeType,
OperandTraits<operand_2>::kSizeType,
OperandTraits<operand_3>::kSizeType};
return kOperandSizes[i];
}
static inline int GetOperandOffset(int i) {
DCHECK(0 <= i && i < kOperandCount);
const int kOffset0 = 1;
const int kOffset1 = kOffset0 + OperandTraits<operand_0>::kSize;
const int kOffset2 = kOffset1 + OperandTraits<operand_1>::kSize;
const int kOffset3 = kOffset2 + OperandTraits<operand_2>::kSize;
const int kOperandOffsets[] = {kOffset0, kOffset1, kOffset2, kOffset3};
return kOperandOffsets[i];
}
static const int kOperandCount = 4;
static const int kSize =
1 + OperandTraits<operand_0>::kSize + OperandTraits<operand_1>::kSize +
OperandTraits<operand_2>::kSize + OperandTraits<operand_3>::kSize;
};
template <OperandType operand_0, OperandType operand_1, OperandType operand_2>
struct BytecodeTraits<operand_0, operand_1, operand_2, OPERAND_TERM> {
static inline OperandType GetOperandType(int i) {
DCHECK(0 <= i && i <= 2);
const OperandType kOperands[] = {operand_0, operand_1, operand_2};
return kOperands[i];
}
static inline OperandSize GetOperandSize(int i) {
DCHECK(0 <= i && i < kOperandCount);
const OperandSize kOperandSizes[] =
{OperandTraits<operand_0>::kSizeType,
OperandTraits<operand_1>::kSizeType,
OperandTraits<operand_2>::kSizeType};
return kOperandSizes[i];
}
static inline int GetOperandOffset(int i) {
DCHECK(0 <= i && i < kOperandCount);
const int kOffset0 = 1;
const int kOffset1 = kOffset0 + OperandTraits<operand_0>::kSize;
const int kOffset2 = kOffset1 + OperandTraits<operand_1>::kSize;
const int kOperandOffsets[] = {kOffset0, kOffset1, kOffset2};
return kOperandOffsets[i];
}
static const int kOperandCount = 3;
static const int kSize =
1 + OperandTraits<operand_0>::kSize + OperandTraits<operand_1>::kSize +
OperandTraits<operand_2>::kSize;
};
template <OperandType operand_0, OperandType operand_1>
struct BytecodeTraits<operand_0, operand_1, OPERAND_TERM> {
static inline OperandType GetOperandType(int i) {
DCHECK(0 <= i && i < kOperandCount);
const OperandType kOperands[] = {operand_0, operand_1};
return kOperands[i];
}
static inline OperandSize GetOperandSize(int i) {
DCHECK(0 <= i && i < kOperandCount);
const OperandSize kOperandSizes[] =
{OperandTraits<operand_0>::kSizeType,
OperandTraits<operand_1>::kSizeType};
return kOperandSizes[i];
}
static inline int GetOperandOffset(int i) {
DCHECK(0 <= i && i < kOperandCount);
const int kOffset0 = 1;
const int kOffset1 = kOffset0 + OperandTraits<operand_0>::kSize;
const int kOperandOffsets[] = {kOffset0, kOffset1};
return kOperandOffsets[i];
}
static const int kOperandCount = 2;
static const int kSize =
1 + OperandTraits<operand_0>::kSize + OperandTraits<operand_1>::kSize;
};
template <OperandType operand_0>
struct BytecodeTraits<operand_0, OPERAND_TERM> {
static inline OperandType GetOperandType(int i) {
DCHECK(i == 0);
return operand_0;
}
static inline OperandSize GetOperandSize(int i) {
DCHECK(i == 0);
return OperandTraits<operand_0>::kSizeType;
}
static inline int GetOperandOffset(int i) {
DCHECK(i == 0);
return 1;
}
static const int kOperandCount = 1;
static const int kSize = 1 + OperandTraits<operand_0>::kSize;
};
template <>
struct BytecodeTraits<OperandType::kNone, OPERAND_TERM> {
static inline OperandType GetOperandType(int i) {
UNREACHABLE();
return OperandType::kNone;
}
static inline OperandSize GetOperandSize(int i) {
UNREACHABLE();
return OperandSize::kNone;
}
static inline int GetOperandOffset(int i) {
UNREACHABLE();
return 1;
}
static const int kOperandCount = 0;
static const int kSize = 1 + OperandTraits<OperandType::kNone>::kSize;
};
} // namespace interpreter
} // namespace internal
} // namespace v8
#endif // V8_INTERPRETER_BYTECODE_TRAITS_H_
...@@ -5,25 +5,12 @@ ...@@ -5,25 +5,12 @@
#include "src/interpreter/bytecodes.h" #include "src/interpreter/bytecodes.h"
#include "src/frames.h" #include "src/frames.h"
#include "src/interpreter/bytecode-traits.h"
namespace v8 { namespace v8 {
namespace internal { namespace internal {
namespace interpreter { namespace interpreter {
// Maximum number of operands a bytecode may have.
static const int kMaxOperands = 3;
// kBytecodeTable relies on kNone being the same as zero to detect length.
STATIC_ASSERT(static_cast<int>(OperandType::kNone) == 0);
static const OperandType kBytecodeTable[][kMaxOperands] = {
#define DECLARE_OPERAND(_, ...) \
{ __VA_ARGS__ } \
,
BYTECODE_LIST(DECLARE_OPERAND)
#undef DECLARE_OPERAND
};
// static // static
const char* Bytecodes::ToString(Bytecode bytecode) { const char* Bytecodes::ToString(Bytecode bytecode) {
...@@ -42,7 +29,7 @@ const char* Bytecodes::ToString(Bytecode bytecode) { ...@@ -42,7 +29,7 @@ const char* Bytecodes::ToString(Bytecode bytecode) {
// static // static
const char* Bytecodes::OperandTypeToString(OperandType operand_type) { const char* Bytecodes::OperandTypeToString(OperandType operand_type) {
switch (operand_type) { switch (operand_type) {
#define CASE(Name) \ #define CASE(Name, _) \
case OperandType::k##Name: \ case OperandType::k##Name: \
return #Name; return #Name;
OPERAND_TYPE_LIST(CASE) OPERAND_TYPE_LIST(CASE)
...@@ -53,6 +40,21 @@ const char* Bytecodes::OperandTypeToString(OperandType operand_type) { ...@@ -53,6 +40,21 @@ const char* Bytecodes::OperandTypeToString(OperandType operand_type) {
} }
// static
const char* Bytecodes::OperandSizeToString(OperandSize operand_size) {
switch (operand_size) {
case OperandSize::kNone:
return "None";
case OperandSize::kByte:
return "Byte";
case OperandSize::kShort:
return "Short";
}
UNREACHABLE();
return "";
}
// static // static
uint8_t Bytecodes::ToByte(Bytecode bytecode) { uint8_t Bytecodes::ToByte(Bytecode bytecode) {
return static_cast<uint8_t>(bytecode); return static_cast<uint8_t>(bytecode);
...@@ -67,39 +69,93 @@ Bytecode Bytecodes::FromByte(uint8_t value) { ...@@ -67,39 +69,93 @@ Bytecode Bytecodes::FromByte(uint8_t value) {
} }
// static
int Bytecodes::Size(Bytecode bytecode) {
DCHECK(bytecode <= Bytecode::kLast);
switch (bytecode) {
#define CASE(Name, ...) \
case Bytecode::k##Name: \
return BytecodeTraits<__VA_ARGS__, OPERAND_TERM>::kSize;
BYTECODE_LIST(CASE)
#undef CASE
}
UNREACHABLE();
return 0;
}
// static // static
int Bytecodes::NumberOfOperands(Bytecode bytecode) { int Bytecodes::NumberOfOperands(Bytecode bytecode) {
DCHECK(bytecode <= Bytecode::kLast); DCHECK(bytecode <= Bytecode::kLast);
int count; switch (bytecode) {
uint8_t row = ToByte(bytecode); #define CASE(Name, ...) \
for (count = 0; count < kMaxOperands; count++) { case Bytecode::k##Name: \
if (kBytecodeTable[row][count] == OperandType::kNone) { return BytecodeTraits<__VA_ARGS__, OPERAND_TERM>::kOperandCount;
break; BYTECODE_LIST(CASE)
} #undef CASE
} }
return count; UNREACHABLE();
return 0;
} }
// static // static
OperandType Bytecodes::GetOperandType(Bytecode bytecode, int i) { OperandType Bytecodes::GetOperandType(Bytecode bytecode, int i) {
DCHECK(bytecode <= Bytecode::kLast && i < NumberOfOperands(bytecode)); DCHECK(bytecode <= Bytecode::kLast);
return kBytecodeTable[ToByte(bytecode)][i]; switch (bytecode) {
#define CASE(Name, ...) \
case Bytecode::k##Name: \
return BytecodeTraits<__VA_ARGS__, OPERAND_TERM>::GetOperandType(i);
BYTECODE_LIST(CASE)
#undef CASE
}
UNREACHABLE();
return OperandType::kNone;
} }
// static // static
int Bytecodes::Size(Bytecode bytecode) { OperandSize Bytecodes::GetOperandSize(Bytecode bytecode, int i) {
return 1 + NumberOfOperands(bytecode); DCHECK(bytecode <= Bytecode::kLast);
switch (bytecode) {
#define CASE(Name, ...) \
case Bytecode::k##Name: \
return BytecodeTraits<__VA_ARGS__, OPERAND_TERM>::GetOperandSize(i);
BYTECODE_LIST(CASE)
#undef CASE
}
UNREACHABLE();
return OperandSize::kNone;
} }
// static // static
int Bytecodes::MaximumNumberOfOperands() { return kMaxOperands; } int Bytecodes::GetOperandOffset(Bytecode bytecode, int i) {
DCHECK(bytecode <= Bytecode::kLast);
switch (bytecode) {
#define CASE(Name, ...) \
case Bytecode::k##Name: \
return BytecodeTraits<__VA_ARGS__, OPERAND_TERM>::GetOperandOffset(i);
BYTECODE_LIST(CASE)
#undef CASE
}
UNREACHABLE();
return 0;
}
// static // static
int Bytecodes::MaximumSize() { return 1 + kMaxOperands; } OperandSize Bytecodes::SizeOfOperand(OperandType operand_type) {
switch (operand_type) {
#define CASE(Name, Size) \
case OperandType::k##Name: \
return Size;
OPERAND_TYPE_LIST(CASE)
#undef CASE
}
UNREACHABLE();
return OperandSize::kNone;
}
// static // static
...@@ -117,6 +173,18 @@ bool Bytecodes::IsJumpConstant(Bytecode bytecode) { ...@@ -117,6 +173,18 @@ bool Bytecodes::IsJumpConstant(Bytecode bytecode) {
} }
// static
uint16_t Bytecodes::ShortOperandFromBytes(const uint8_t* bytes) {
return *reinterpret_cast<const uint16_t*>(bytes);
}
// static
void Bytecodes::ShortOperandToBytes(uint16_t operand, uint8_t* bytes_out) {
*reinterpret_cast<uint16_t*>(bytes_out) = operand;
}
// static // static
std::ostream& Bytecodes::Decode(std::ostream& os, const uint8_t* bytecode_start, std::ostream& Bytecodes::Decode(std::ostream& os, const uint8_t* bytecode_start,
int parameter_count) { int parameter_count) {
...@@ -129,29 +197,34 @@ std::ostream& Bytecodes::Decode(std::ostream& os, const uint8_t* bytecode_start, ...@@ -129,29 +197,34 @@ std::ostream& Bytecodes::Decode(std::ostream& os, const uint8_t* bytecode_start,
SNPrintF(buf, "%02x ", bytecode_start[i]); SNPrintF(buf, "%02x ", bytecode_start[i]);
os << buf.start(); os << buf.start();
} }
for (int i = bytecode_size; i < Bytecodes::MaximumSize(); i++) { const int kBytecodeColumnSize = 6;
for (int i = bytecode_size; i < kBytecodeColumnSize; i++) {
os << " "; os << " ";
} }
os << bytecode << " "; os << bytecode << " ";
const uint8_t* operands_start = bytecode_start + 1; int number_of_operands = NumberOfOperands(bytecode);
int operands_size = bytecode_size - 1; for (int i = 0; i < number_of_operands; i++) {
for (int i = 0; i < operands_size; i++) {
OperandType op_type = GetOperandType(bytecode, i); OperandType op_type = GetOperandType(bytecode, i);
uint8_t operand = operands_start[i]; const uint8_t* operand_start =
&bytecode_start[GetOperandOffset(bytecode, i)];
switch (op_type) { switch (op_type) {
case interpreter::OperandType::kCount: case interpreter::OperandType::kCount8:
os << "#" << static_cast<unsigned int>(operand); os << "#" << static_cast<unsigned int>(*operand_start);
break;
case interpreter::OperandType::kIdx8:
os << "[" << static_cast<unsigned int>(*operand_start) << "]";
break; break;
case interpreter::OperandType::kIdx: case interpreter::OperandType::kIdx16: {
os << "[" << static_cast<unsigned int>(operand) << "]"; os << "[" << Bytecodes::ShortOperandFromBytes(operand_start) << "]";
break; break;
}
case interpreter::OperandType::kImm8: case interpreter::OperandType::kImm8:
os << "#" << static_cast<int>(static_cast<int8_t>(operand)); os << "#" << static_cast<int>(static_cast<int8_t>(*operand_start));
break; break;
case interpreter::OperandType::kReg: { case interpreter::OperandType::kReg8: {
Register reg = Register::FromOperand(operand); Register reg = Register::FromOperand(*operand_start);
if (reg.is_parameter()) { if (reg.is_parameter()) {
int parameter_index = reg.ToParameterIndex(parameter_count); int parameter_index = reg.ToParameterIndex(parameter_count);
if (parameter_index == 0) { if (parameter_index == 0) {
...@@ -168,7 +241,7 @@ std::ostream& Bytecodes::Decode(std::ostream& os, const uint8_t* bytecode_start, ...@@ -168,7 +241,7 @@ std::ostream& Bytecodes::Decode(std::ostream& os, const uint8_t* bytecode_start,
UNREACHABLE(); UNREACHABLE();
break; break;
} }
if (i != operands_size - 1) { if (i != number_of_operands - 1) {
os << ", "; os << ", ";
} }
} }
...@@ -186,6 +259,11 @@ std::ostream& operator<<(std::ostream& os, const OperandType& operand_type) { ...@@ -186,6 +259,11 @@ std::ostream& operator<<(std::ostream& os, const OperandType& operand_type) {
} }
std::ostream& operator<<(std::ostream& os, const OperandSize& operand_size) {
return os << Bytecodes::OperandSizeToString(operand_size);
}
static const int kLastParamRegisterIndex = static const int kLastParamRegisterIndex =
-InterpreterFrameConstants::kLastParamFromRegisterPointer / kPointerSize; -InterpreterFrameConstants::kLastParamFromRegisterPointer / kPointerSize;
......
This diff is collapsed.
...@@ -111,7 +111,7 @@ void Interpreter::DoLdaSmi8(compiler::InterpreterAssembler* assembler) { ...@@ -111,7 +111,7 @@ void Interpreter::DoLdaSmi8(compiler::InterpreterAssembler* assembler) {
// //
// Load constant literal at |idx| in the constant pool into the accumulator. // Load constant literal at |idx| in the constant pool into the accumulator.
void Interpreter::DoLdaConstant(compiler::InterpreterAssembler* assembler) { void Interpreter::DoLdaConstant(compiler::InterpreterAssembler* assembler) {
Node* index = __ BytecodeOperandIdx(0); Node* index = __ BytecodeOperandIdx8(0);
Node* constant = __ LoadConstantPoolEntry(index); Node* constant = __ LoadConstantPoolEntry(index);
__ SetAccumulator(constant); __ SetAccumulator(constant);
__ Dispatch(); __ Dispatch();
...@@ -173,7 +173,7 @@ void Interpreter::DoLdaFalse(compiler::InterpreterAssembler* assembler) { ...@@ -173,7 +173,7 @@ void Interpreter::DoLdaFalse(compiler::InterpreterAssembler* assembler) {
// //
// Load accumulator with value from register <src>. // Load accumulator with value from register <src>.
void Interpreter::DoLdar(compiler::InterpreterAssembler* assembler) { void Interpreter::DoLdar(compiler::InterpreterAssembler* assembler) {
Node* reg_index = __ BytecodeOperandReg(0); Node* reg_index = __ BytecodeOperandReg8(0);
Node* value = __ LoadRegister(reg_index); Node* value = __ LoadRegister(reg_index);
__ SetAccumulator(value); __ SetAccumulator(value);
__ Dispatch(); __ Dispatch();
...@@ -184,7 +184,7 @@ void Interpreter::DoLdar(compiler::InterpreterAssembler* assembler) { ...@@ -184,7 +184,7 @@ void Interpreter::DoLdar(compiler::InterpreterAssembler* assembler) {
// //
// Store accumulator to register <dst>. // Store accumulator to register <dst>.
void Interpreter::DoStar(compiler::InterpreterAssembler* assembler) { void Interpreter::DoStar(compiler::InterpreterAssembler* assembler) {
Node* reg_index = __ BytecodeOperandReg(0); Node* reg_index = __ BytecodeOperandReg8(0);
Node* accumulator = __ GetAccumulator(); Node* accumulator = __ GetAccumulator();
__ StoreRegister(accumulator, reg_index); __ StoreRegister(accumulator, reg_index);
__ Dispatch(); __ Dispatch();
...@@ -195,7 +195,7 @@ void Interpreter::DoStar(compiler::InterpreterAssembler* assembler) { ...@@ -195,7 +195,7 @@ void Interpreter::DoStar(compiler::InterpreterAssembler* assembler) {
// //
// Load the global at |slot_index| into the accumulator. // Load the global at |slot_index| into the accumulator.
void Interpreter::DoLdaGlobal(compiler::InterpreterAssembler* assembler) { void Interpreter::DoLdaGlobal(compiler::InterpreterAssembler* assembler) {
Node* slot_index = __ BytecodeOperandIdx(0); Node* slot_index = __ BytecodeOperandIdx8(0);
Node* smi_slot_index = __ SmiTag(slot_index); Node* smi_slot_index = __ SmiTag(slot_index);
Node* result = __ CallRuntime(Runtime::kLoadGlobalViaContext, smi_slot_index); Node* result = __ CallRuntime(Runtime::kLoadGlobalViaContext, smi_slot_index);
__ SetAccumulator(result); __ SetAccumulator(result);
...@@ -206,10 +206,10 @@ void Interpreter::DoLdaGlobal(compiler::InterpreterAssembler* assembler) { ...@@ -206,10 +206,10 @@ void Interpreter::DoLdaGlobal(compiler::InterpreterAssembler* assembler) {
void Interpreter::DoPropertyLoadIC(Callable ic, void Interpreter::DoPropertyLoadIC(Callable ic,
compiler::InterpreterAssembler* assembler) { compiler::InterpreterAssembler* assembler) {
Node* code_target = __ HeapConstant(ic.code()); Node* code_target = __ HeapConstant(ic.code());
Node* reg_index = __ BytecodeOperandReg(0); Node* reg_index = __ BytecodeOperandReg8(0);
Node* object = __ LoadRegister(reg_index); Node* object = __ LoadRegister(reg_index);
Node* name = __ GetAccumulator(); Node* name = __ GetAccumulator();
Node* raw_slot = __ BytecodeOperandIdx(1); Node* raw_slot = __ BytecodeOperandIdx8(1);
Node* smi_slot = __ SmiTag(raw_slot); Node* smi_slot = __ SmiTag(raw_slot);
Node* type_feedback_vector = __ LoadTypeFeedbackVector(); Node* type_feedback_vector = __ LoadTypeFeedbackVector();
Node* result = __ CallIC(ic.descriptor(), code_target, object, name, smi_slot, Node* result = __ CallIC(ic.descriptor(), code_target, object, name, smi_slot,
...@@ -244,12 +244,12 @@ void Interpreter::DoKeyedLoadIC(compiler::InterpreterAssembler* assembler) { ...@@ -244,12 +244,12 @@ void Interpreter::DoKeyedLoadIC(compiler::InterpreterAssembler* assembler) {
void Interpreter::DoPropertyStoreIC(Callable ic, void Interpreter::DoPropertyStoreIC(Callable ic,
compiler::InterpreterAssembler* assembler) { compiler::InterpreterAssembler* assembler) {
Node* code_target = __ HeapConstant(ic.code()); Node* code_target = __ HeapConstant(ic.code());
Node* object_reg_index = __ BytecodeOperandReg(0); Node* object_reg_index = __ BytecodeOperandReg8(0);
Node* object = __ LoadRegister(object_reg_index); Node* object = __ LoadRegister(object_reg_index);
Node* name_reg_index = __ BytecodeOperandReg(1); Node* name_reg_index = __ BytecodeOperandReg8(1);
Node* name = __ LoadRegister(name_reg_index); Node* name = __ LoadRegister(name_reg_index);
Node* value = __ GetAccumulator(); Node* value = __ GetAccumulator();
Node* raw_slot = __ BytecodeOperandIdx(2); Node* raw_slot = __ BytecodeOperandIdx8(2);
Node* smi_slot = __ SmiTag(raw_slot); Node* smi_slot = __ SmiTag(raw_slot);
Node* type_feedback_vector = __ LoadTypeFeedbackVector(); Node* type_feedback_vector = __ LoadTypeFeedbackVector();
Node* result = __ CallIC(ic.descriptor(), code_target, object, name, value, Node* result = __ CallIC(ic.descriptor(), code_target, object, name, value,
...@@ -285,7 +285,7 @@ void Interpreter::DoBinaryOp(Runtime::FunctionId function_id, ...@@ -285,7 +285,7 @@ void Interpreter::DoBinaryOp(Runtime::FunctionId function_id,
compiler::InterpreterAssembler* assembler) { compiler::InterpreterAssembler* assembler) {
// TODO(rmcilroy): Call ICs which back-patch bytecode with type specialized // TODO(rmcilroy): Call ICs which back-patch bytecode with type specialized
// operations, instead of calling builtins directly. // operations, instead of calling builtins directly.
Node* reg_index = __ BytecodeOperandReg(0); Node* reg_index = __ BytecodeOperandReg8(0);
Node* lhs = __ LoadRegister(reg_index); Node* lhs = __ LoadRegister(reg_index);
Node* rhs = __ GetAccumulator(); Node* rhs = __ GetAccumulator();
Node* result = __ CallRuntime(function_id, lhs, rhs); Node* result = __ CallRuntime(function_id, lhs, rhs);
...@@ -339,11 +339,11 @@ void Interpreter::DoMod(compiler::InterpreterAssembler* assembler) { ...@@ -339,11 +339,11 @@ void Interpreter::DoMod(compiler::InterpreterAssembler* assembler) {
// Call a JS function with receiver and |arg_count| arguments in subsequent // Call a JS function with receiver and |arg_count| arguments in subsequent
// registers. The JSfunction or Callable to call is in the accumulator. // registers. The JSfunction or Callable to call is in the accumulator.
void Interpreter::DoCall(compiler::InterpreterAssembler* assembler) { void Interpreter::DoCall(compiler::InterpreterAssembler* assembler) {
Node* function_reg = __ BytecodeOperandReg(0); Node* function_reg = __ BytecodeOperandReg8(0);
Node* function = __ LoadRegister(function_reg); Node* function = __ LoadRegister(function_reg);
Node* receiver_reg = __ BytecodeOperandReg(1); Node* receiver_reg = __ BytecodeOperandReg8(1);
Node* first_arg = __ RegisterLocation(receiver_reg); Node* first_arg = __ RegisterLocation(receiver_reg);
Node* args_count = __ BytecodeOperandCount(2); Node* args_count = __ BytecodeOperandCount8(2);
Node* result = __ CallJS(function, first_arg, args_count); Node* result = __ CallJS(function, first_arg, args_count);
__ SetAccumulator(result); __ SetAccumulator(result);
__ Dispatch(); __ Dispatch();
...@@ -461,7 +461,7 @@ void Interpreter::DoJump(compiler::InterpreterAssembler* assembler) { ...@@ -461,7 +461,7 @@ void Interpreter::DoJump(compiler::InterpreterAssembler* assembler) {
// //
// Jump by number of bytes in the Smi in the |idx| entry in the constant pool. // Jump by number of bytes in the Smi in the |idx| entry in the constant pool.
void Interpreter::DoJumpConstant(compiler::InterpreterAssembler* assembler) { void Interpreter::DoJumpConstant(compiler::InterpreterAssembler* assembler) {
Node* index = __ BytecodeOperandIdx(0); Node* index = __ BytecodeOperandIdx8(0);
Node* constant = __ LoadConstantPoolEntry(index); Node* constant = __ LoadConstantPoolEntry(index);
Node* relative_jump = __ SmiUntag(constant); Node* relative_jump = __ SmiUntag(constant);
__ Jump(relative_jump); __ Jump(relative_jump);
...@@ -487,7 +487,7 @@ void Interpreter::DoJumpIfTrue(compiler::InterpreterAssembler* assembler) { ...@@ -487,7 +487,7 @@ void Interpreter::DoJumpIfTrue(compiler::InterpreterAssembler* assembler) {
void Interpreter::DoJumpIfTrueConstant( void Interpreter::DoJumpIfTrueConstant(
compiler::InterpreterAssembler* assembler) { compiler::InterpreterAssembler* assembler) {
Node* accumulator = __ GetAccumulator(); Node* accumulator = __ GetAccumulator();
Node* index = __ BytecodeOperandIdx(0); Node* index = __ BytecodeOperandIdx8(0);
Node* constant = __ LoadConstantPoolEntry(index); Node* constant = __ LoadConstantPoolEntry(index);
Node* relative_jump = __ SmiUntag(constant); Node* relative_jump = __ SmiUntag(constant);
Node* true_value = __ BooleanConstant(true); Node* true_value = __ BooleanConstant(true);
...@@ -514,7 +514,7 @@ void Interpreter::DoJumpIfFalse(compiler::InterpreterAssembler* assembler) { ...@@ -514,7 +514,7 @@ void Interpreter::DoJumpIfFalse(compiler::InterpreterAssembler* assembler) {
void Interpreter::DoJumpIfFalseConstant( void Interpreter::DoJumpIfFalseConstant(
compiler::InterpreterAssembler* assembler) { compiler::InterpreterAssembler* assembler) {
Node* accumulator = __ GetAccumulator(); Node* accumulator = __ GetAccumulator();
Node* index = __ BytecodeOperandIdx(0); Node* index = __ BytecodeOperandIdx8(0);
Node* constant = __ LoadConstantPoolEntry(index); Node* constant = __ LoadConstantPoolEntry(index);
Node* relative_jump = __ SmiUntag(constant); Node* relative_jump = __ SmiUntag(constant);
Node* false_value = __ BooleanConstant(false); Node* false_value = __ BooleanConstant(false);
......
...@@ -130,22 +130,37 @@ static void CheckBytecodeArrayEqual(struct ExpectedSnippet<T> expected, ...@@ -130,22 +130,37 @@ static void CheckBytecodeArrayEqual(struct ExpectedSnippet<T> expected,
<< " but got " << Bytecodes::ToString(bytecode); << " but got " << Bytecodes::ToString(bytecode);
FATAL(stream.str().c_str()); FATAL(stream.str().c_str());
} }
for (int j = 0; j < Bytecodes::NumberOfOperands(bytecode); ++j, ++i) { for (int j = 0; j < Bytecodes::NumberOfOperands(bytecode); ++j) {
uint8_t raw_operand = OperandType operand_type = Bytecodes::GetOperandType(bytecode, j);
iterator.GetRawOperand(j, Bytecodes::GetOperandType(bytecode, j)); int operand_index = i;
i += static_cast<int>(Bytecodes::SizeOfOperand(operand_type));
uint32_t raw_operand = iterator.GetRawOperand(j, operand_type);
if (has_unknown) { if (has_unknown) {
// Check actual bytecode array doesn't have the same byte as the // Check actual bytecode array doesn't have the same byte as the
// one we use to specify an unknown byte. // one we use to specify an unknown byte.
CHECK_NE(raw_operand, _); CHECK_NE(raw_operand, _);
if (expected.bytecode[i] == _) { if (expected.bytecode[operand_index] == _) {
continue; continue;
} }
} }
if (raw_operand != expected.bytecode[i]) { uint32_t expected_operand;
switch (Bytecodes::SizeOfOperand(operand_type)) {
case OperandSize::kNone:
UNREACHABLE();
case OperandSize::kByte:
expected_operand =
static_cast<uint32_t>(expected.bytecode[operand_index]);
break;
case OperandSize::kShort:
expected_operand = Bytecodes::ShortOperandFromBytes(
&expected.bytecode[operand_index]);
break;
}
if (raw_operand != expected_operand) {
std::ostringstream stream; std::ostringstream stream;
stream << "Check failed: expected operand [" << j << "] for bytecode [" stream << "Check failed: expected operand [" << j << "] for bytecode ["
<< bytecode_index << "] to be " << bytecode_index << "] to be "
<< static_cast<unsigned int>(expected.bytecode[i]) << " but got " << static_cast<unsigned int>(expected_operand) << " but got "
<< static_cast<unsigned int>(raw_operand); << static_cast<unsigned int>(raw_operand);
FATAL(stream.str().c_str()); FATAL(stream.str().c_str());
} }
......
...@@ -59,6 +59,13 @@ Matcher<Node*> IsWordSar(const Matcher<Node*>& lhs_matcher, ...@@ -59,6 +59,13 @@ Matcher<Node*> IsWordSar(const Matcher<Node*>& lhs_matcher,
} }
Matcher<Node*> IsWordOr(const Matcher<Node*>& lhs_matcher,
const Matcher<Node*>& rhs_matcher) {
return kPointerSize == 8 ? IsWord64Or(lhs_matcher, rhs_matcher)
: IsWord32Or(lhs_matcher, rhs_matcher);
}
Matcher<Node*> InterpreterAssemblerTest::InterpreterAssemblerForTest::IsLoad( Matcher<Node*> InterpreterAssemblerTest::InterpreterAssemblerForTest::IsLoad(
const Matcher<LoadRepresentation>& rep_matcher, const Matcher<LoadRepresentation>& rep_matcher,
const Matcher<Node*>& base_matcher, const Matcher<Node*>& index_matcher) { const Matcher<Node*>& base_matcher, const Matcher<Node*>& index_matcher) {
...@@ -87,20 +94,20 @@ Matcher<Node*> InterpreterAssemblerTest::InterpreterAssemblerForTest::IsCall( ...@@ -87,20 +94,20 @@ Matcher<Node*> InterpreterAssemblerTest::InterpreterAssemblerForTest::IsCall(
Matcher<Node*> Matcher<Node*>
InterpreterAssemblerTest::InterpreterAssemblerForTest::IsBytecodeOperand( InterpreterAssemblerTest::InterpreterAssemblerForTest::IsBytecodeOperand(
int operand) { int offset) {
return IsLoad( return IsLoad(
kMachUint8, IsParameter(Linkage::kInterpreterBytecodeArrayParameter), kMachUint8, IsParameter(Linkage::kInterpreterBytecodeArrayParameter),
IsIntPtrAdd(IsParameter(Linkage::kInterpreterBytecodeOffsetParameter), IsIntPtrAdd(IsParameter(Linkage::kInterpreterBytecodeOffsetParameter),
IsInt32Constant(1 + operand))); IsInt32Constant(offset)));
} }
Matcher<Node*> InterpreterAssemblerTest::InterpreterAssemblerForTest:: Matcher<Node*> InterpreterAssemblerTest::InterpreterAssemblerForTest::
IsBytecodeOperandSignExtended(int operand) { IsBytecodeOperandSignExtended(int offset) {
Matcher<Node*> load_matcher = IsLoad( Matcher<Node*> load_matcher = IsLoad(
kMachInt8, IsParameter(Linkage::kInterpreterBytecodeArrayParameter), kMachInt8, IsParameter(Linkage::kInterpreterBytecodeArrayParameter),
IsIntPtrAdd(IsParameter(Linkage::kInterpreterBytecodeOffsetParameter), IsIntPtrAdd(IsParameter(Linkage::kInterpreterBytecodeOffsetParameter),
IsInt32Constant(1 + operand))); IsInt32Constant(offset)));
if (kPointerSize == 8) { if (kPointerSize == 8) {
load_matcher = IsChangeInt32ToInt64(load_matcher); load_matcher = IsChangeInt32ToInt64(load_matcher);
} }
...@@ -108,6 +115,36 @@ Matcher<Node*> InterpreterAssemblerTest::InterpreterAssemblerForTest:: ...@@ -108,6 +115,36 @@ Matcher<Node*> InterpreterAssemblerTest::InterpreterAssemblerForTest::
} }
Matcher<Node*>
InterpreterAssemblerTest::InterpreterAssemblerForTest::IsBytecodeOperandShort(
int offset) {
if (TargetSupportsUnalignedAccess()) {
return IsLoad(
kMachUint16, IsParameter(Linkage::kInterpreterBytecodeArrayParameter),
IsIntPtrAdd(IsParameter(Linkage::kInterpreterBytecodeOffsetParameter),
IsInt32Constant(offset)));
} else {
Matcher<Node*> first_byte = IsLoad(
kMachUint8, IsParameter(Linkage::kInterpreterBytecodeArrayParameter),
IsIntPtrAdd(IsParameter(Linkage::kInterpreterBytecodeOffsetParameter),
IsInt32Constant(offset)));
Matcher<Node*> second_byte = IsLoad(
kMachUint8, IsParameter(Linkage::kInterpreterBytecodeArrayParameter),
IsIntPtrAdd(IsParameter(Linkage::kInterpreterBytecodeOffsetParameter),
IsInt32Constant(offset + 1)));
#if V8_TARGET_LITTLE_ENDIAN
return IsWordOr(IsWordShl(second_byte, IsInt32Constant(kBitsPerByte)),
first_byte);
#elif V8_TARGET_BIG_ENDIAN
return IsWordOr(IsWordShl(first_byte, IsInt32Constant(kBitsPerByte)),
second_byte);
#else
#error "Unknown Architecture"
#endif
}
}
Graph* Graph*
InterpreterAssemblerTest::InterpreterAssemblerForTest::GetCompletedGraph() { InterpreterAssemblerTest::InterpreterAssemblerForTest::GetCompletedGraph() {
End(); End();
...@@ -268,20 +305,25 @@ TARGET_TEST_F(InterpreterAssemblerTest, BytecodeOperand) { ...@@ -268,20 +305,25 @@ TARGET_TEST_F(InterpreterAssemblerTest, BytecodeOperand) {
InterpreterAssemblerForTest m(this, bytecode); InterpreterAssemblerForTest m(this, bytecode);
int number_of_operands = interpreter::Bytecodes::NumberOfOperands(bytecode); int number_of_operands = interpreter::Bytecodes::NumberOfOperands(bytecode);
for (int i = 0; i < number_of_operands; i++) { for (int i = 0; i < number_of_operands; i++) {
int offset = interpreter::Bytecodes::GetOperandOffset(bytecode, i);
switch (interpreter::Bytecodes::GetOperandType(bytecode, i)) { switch (interpreter::Bytecodes::GetOperandType(bytecode, i)) {
case interpreter::OperandType::kCount: case interpreter::OperandType::kCount8:
EXPECT_THAT(m.BytecodeOperandCount(i), m.IsBytecodeOperand(i)); EXPECT_THAT(m.BytecodeOperandCount8(i), m.IsBytecodeOperand(offset));
break; break;
case interpreter::OperandType::kIdx: case interpreter::OperandType::kIdx8:
EXPECT_THAT(m.BytecodeOperandIdx(i), m.IsBytecodeOperand(i)); EXPECT_THAT(m.BytecodeOperandIdx8(i), m.IsBytecodeOperand(offset));
break; break;
case interpreter::OperandType::kImm8: case interpreter::OperandType::kImm8:
EXPECT_THAT(m.BytecodeOperandImm8(i), EXPECT_THAT(m.BytecodeOperandImm8(i),
m.IsBytecodeOperandSignExtended(i)); m.IsBytecodeOperandSignExtended(offset));
break;
case interpreter::OperandType::kReg8:
EXPECT_THAT(m.BytecodeOperandReg8(i),
m.IsBytecodeOperandSignExtended(offset));
break; break;
case interpreter::OperandType::kReg: case interpreter::OperandType::kIdx16:
EXPECT_THAT(m.BytecodeOperandReg(i), EXPECT_THAT(m.BytecodeOperandIdx16(i),
m.IsBytecodeOperandSignExtended(i)); m.IsBytecodeOperandShort(offset));
break; break;
case interpreter::OperandType::kNone: case interpreter::OperandType::kNone:
UNREACHABLE(); UNREACHABLE();
......
...@@ -43,8 +43,9 @@ class InterpreterAssemblerTest : public TestWithIsolateAndZone { ...@@ -43,8 +43,9 @@ class InterpreterAssemblerTest : public TestWithIsolateAndZone {
const Matcher<const CallDescriptor*>& descriptor_matcher, const Matcher<const CallDescriptor*>& descriptor_matcher,
A... args); A... args);
Matcher<Node*> IsBytecodeOperand(int operand); Matcher<Node*> IsBytecodeOperand(int offset);
Matcher<Node*> IsBytecodeOperandSignExtended(int operand); Matcher<Node*> IsBytecodeOperandSignExtended(int offset);
Matcher<Node*> IsBytecodeOperandShort(int offset);
using InterpreterAssembler::call_descriptor; using InterpreterAssembler::call_descriptor;
using InterpreterAssembler::graph; using InterpreterAssembler::graph;
......
...@@ -1989,12 +1989,14 @@ IS_BINOP_MATCHER(NumberShiftLeft) ...@@ -1989,12 +1989,14 @@ IS_BINOP_MATCHER(NumberShiftLeft)
IS_BINOP_MATCHER(NumberShiftRight) IS_BINOP_MATCHER(NumberShiftRight)
IS_BINOP_MATCHER(NumberShiftRightLogical) IS_BINOP_MATCHER(NumberShiftRightLogical)
IS_BINOP_MATCHER(Word32And) IS_BINOP_MATCHER(Word32And)
IS_BINOP_MATCHER(Word32Or)
IS_BINOP_MATCHER(Word32Sar) IS_BINOP_MATCHER(Word32Sar)
IS_BINOP_MATCHER(Word32Shl) IS_BINOP_MATCHER(Word32Shl)
IS_BINOP_MATCHER(Word32Shr) IS_BINOP_MATCHER(Word32Shr)
IS_BINOP_MATCHER(Word32Ror) IS_BINOP_MATCHER(Word32Ror)
IS_BINOP_MATCHER(Word32Equal) IS_BINOP_MATCHER(Word32Equal)
IS_BINOP_MATCHER(Word64And) IS_BINOP_MATCHER(Word64And)
IS_BINOP_MATCHER(Word64Or)
IS_BINOP_MATCHER(Word64Sar) IS_BINOP_MATCHER(Word64Sar)
IS_BINOP_MATCHER(Word64Shl) IS_BINOP_MATCHER(Word64Shl)
IS_BINOP_MATCHER(Word64Equal) IS_BINOP_MATCHER(Word64Equal)
......
...@@ -256,6 +256,8 @@ Matcher<Node*> IsStore(const Matcher<StoreRepresentation>& rep_matcher, ...@@ -256,6 +256,8 @@ Matcher<Node*> IsStore(const Matcher<StoreRepresentation>& rep_matcher,
const Matcher<Node*>& control_matcher); const Matcher<Node*>& control_matcher);
Matcher<Node*> IsWord32And(const Matcher<Node*>& lhs_matcher, Matcher<Node*> IsWord32And(const Matcher<Node*>& lhs_matcher,
const Matcher<Node*>& rhs_matcher); const Matcher<Node*>& rhs_matcher);
Matcher<Node*> IsWord32Or(const Matcher<Node*>& lhs_matcher,
const Matcher<Node*>& rhs_matcher);
Matcher<Node*> IsWord32Sar(const Matcher<Node*>& lhs_matcher, Matcher<Node*> IsWord32Sar(const Matcher<Node*>& lhs_matcher,
const Matcher<Node*>& rhs_matcher); const Matcher<Node*>& rhs_matcher);
Matcher<Node*> IsWord32Shl(const Matcher<Node*>& lhs_matcher, Matcher<Node*> IsWord32Shl(const Matcher<Node*>& lhs_matcher,
...@@ -269,6 +271,8 @@ Matcher<Node*> IsWord32Equal(const Matcher<Node*>& lhs_matcher, ...@@ -269,6 +271,8 @@ Matcher<Node*> IsWord32Equal(const Matcher<Node*>& lhs_matcher,
Matcher<Node*> IsWord32Clz(const Matcher<Node*>& value_matcher); Matcher<Node*> IsWord32Clz(const Matcher<Node*>& value_matcher);
Matcher<Node*> IsWord64And(const Matcher<Node*>& lhs_matcher, Matcher<Node*> IsWord64And(const Matcher<Node*>& lhs_matcher,
const Matcher<Node*>& rhs_matcher); const Matcher<Node*>& rhs_matcher);
Matcher<Node*> IsWord64Or(const Matcher<Node*>& lhs_matcher,
const Matcher<Node*>& rhs_matcher);
Matcher<Node*> IsWord64Shl(const Matcher<Node*>& lhs_matcher, Matcher<Node*> IsWord64Shl(const Matcher<Node*>& lhs_matcher,
const Matcher<Node*>& rhs_matcher); const Matcher<Node*>& rhs_matcher);
Matcher<Node*> IsWord64Sar(const Matcher<Node*>& lhs_matcher, Matcher<Node*> IsWord64Sar(const Matcher<Node*>& lhs_matcher,
......
...@@ -94,13 +94,12 @@ TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) { ...@@ -94,13 +94,12 @@ TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) {
// Build scorecard of bytecodes encountered in the BytecodeArray. // Build scorecard of bytecodes encountered in the BytecodeArray.
std::vector<int> scorecard(Bytecodes::ToByte(Bytecode::kLast) + 1); std::vector<int> scorecard(Bytecodes::ToByte(Bytecode::kLast) + 1);
Bytecode final_bytecode = Bytecode::kLdaZero; Bytecode final_bytecode = Bytecode::kLdaZero;
for (int i = 0; i < the_array->length(); i++) { int i = 0;
while (i < the_array->length()) {
uint8_t code = the_array->get(i); uint8_t code = the_array->get(i);
scorecard[code] += 1; scorecard[code] += 1;
int operands = Bytecodes::NumberOfOperands(Bytecodes::FromByte(code));
CHECK_LE(operands, Bytecodes::MaximumNumberOfOperands());
final_bytecode = Bytecodes::FromByte(code); final_bytecode = Bytecodes::FromByte(code);
i += operands; i += Bytecodes::Size(Bytecodes::FromByte(code));
} }
// Check return occurs at the end and only once in the BytecodeArray. // Check return occurs at the end and only once in the BytecodeArray.
...@@ -240,15 +239,15 @@ TEST_F(BytecodeArrayBuilderTest, ForwardJumps) { ...@@ -240,15 +239,15 @@ TEST_F(BytecodeArrayBuilderTest, ForwardJumps) {
BytecodeArrayIterator iterator(array); BytecodeArrayIterator iterator(array);
CHECK_EQ(iterator.current_bytecode(), Bytecode::kJump); CHECK_EQ(iterator.current_bytecode(), Bytecode::kJump);
CHECK_EQ(iterator.GetSmi8Operand(0), 6); CHECK_EQ(iterator.GetImmediateOperand(0), 6);
iterator.Advance(); iterator.Advance();
CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpIfTrue); CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpIfTrue);
CHECK_EQ(iterator.GetSmi8Operand(0), 4); CHECK_EQ(iterator.GetImmediateOperand(0), 4);
iterator.Advance(); iterator.Advance();
CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpIfFalse); CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpIfFalse);
CHECK_EQ(iterator.GetSmi8Operand(0), 2); CHECK_EQ(iterator.GetImmediateOperand(0), 2);
iterator.Advance(); iterator.Advance();
CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpConstant); CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpConstant);
...@@ -303,17 +302,17 @@ TEST_F(BytecodeArrayBuilderTest, BackwardJumps) { ...@@ -303,17 +302,17 @@ TEST_F(BytecodeArrayBuilderTest, BackwardJumps) {
Handle<BytecodeArray> array = builder.ToBytecodeArray(); Handle<BytecodeArray> array = builder.ToBytecodeArray();
BytecodeArrayIterator iterator(array); BytecodeArrayIterator iterator(array);
CHECK_EQ(iterator.current_bytecode(), Bytecode::kJump); CHECK_EQ(iterator.current_bytecode(), Bytecode::kJump);
CHECK_EQ(iterator.GetSmi8Operand(0), 0); CHECK_EQ(iterator.GetImmediateOperand(0), 0);
iterator.Advance(); iterator.Advance();
CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpIfTrue); CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpIfTrue);
CHECK_EQ(iterator.GetSmi8Operand(0), 0); CHECK_EQ(iterator.GetImmediateOperand(0), 0);
iterator.Advance(); iterator.Advance();
CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpIfFalse); CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpIfFalse);
CHECK_EQ(iterator.GetSmi8Operand(0), 0); CHECK_EQ(iterator.GetImmediateOperand(0), 0);
iterator.Advance(); iterator.Advance();
for (int i = 0; i < 64; i++) { for (int i = 0; i < 64; i++) {
CHECK_EQ(iterator.current_bytecode(), Bytecode::kJump); CHECK_EQ(iterator.current_bytecode(), Bytecode::kJump);
CHECK_EQ(iterator.GetSmi8Operand(0), -i * 2 - 2); CHECK_EQ(iterator.GetImmediateOperand(0), -i * 2 - 2);
iterator.Advance(); iterator.Advance();
} }
CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpIfFalseConstant); CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpIfFalseConstant);
...@@ -345,13 +344,13 @@ TEST_F(BytecodeArrayBuilderTest, LabelReuse) { ...@@ -345,13 +344,13 @@ TEST_F(BytecodeArrayBuilderTest, LabelReuse) {
Handle<BytecodeArray> array = builder.ToBytecodeArray(); Handle<BytecodeArray> array = builder.ToBytecodeArray();
BytecodeArrayIterator iterator(array); BytecodeArrayIterator iterator(array);
CHECK_EQ(iterator.current_bytecode(), Bytecode::kJump); CHECK_EQ(iterator.current_bytecode(), Bytecode::kJump);
CHECK_EQ(iterator.GetSmi8Operand(0), 2); CHECK_EQ(iterator.GetImmediateOperand(0), 2);
iterator.Advance(); iterator.Advance();
CHECK_EQ(iterator.current_bytecode(), Bytecode::kJump); CHECK_EQ(iterator.current_bytecode(), Bytecode::kJump);
CHECK_EQ(iterator.GetSmi8Operand(0), 0); CHECK_EQ(iterator.GetImmediateOperand(0), 0);
iterator.Advance(); iterator.Advance();
CHECK_EQ(iterator.current_bytecode(), Bytecode::kJump); CHECK_EQ(iterator.current_bytecode(), Bytecode::kJump);
CHECK_EQ(iterator.GetSmi8Operand(0), -2); CHECK_EQ(iterator.GetImmediateOperand(0), -2);
iterator.Advance(); iterator.Advance();
CHECK_EQ(iterator.current_bytecode(), Bytecode::kReturn); CHECK_EQ(iterator.current_bytecode(), Bytecode::kReturn);
iterator.Advance(); iterator.Advance();
...@@ -377,13 +376,13 @@ TEST_F(BytecodeArrayBuilderTest, LabelAddressReuse) { ...@@ -377,13 +376,13 @@ TEST_F(BytecodeArrayBuilderTest, LabelAddressReuse) {
BytecodeArrayIterator iterator(array); BytecodeArrayIterator iterator(array);
for (int i = 0; i < kRepeats; i++) { for (int i = 0; i < kRepeats; i++) {
CHECK_EQ(iterator.current_bytecode(), Bytecode::kJump); CHECK_EQ(iterator.current_bytecode(), Bytecode::kJump);
CHECK_EQ(iterator.GetSmi8Operand(0), 2); CHECK_EQ(iterator.GetImmediateOperand(0), 2);
iterator.Advance(); iterator.Advance();
CHECK_EQ(iterator.current_bytecode(), Bytecode::kJump); CHECK_EQ(iterator.current_bytecode(), Bytecode::kJump);
CHECK_EQ(iterator.GetSmi8Operand(0), 0); CHECK_EQ(iterator.GetImmediateOperand(0), 0);
iterator.Advance(); iterator.Advance();
CHECK_EQ(iterator.current_bytecode(), Bytecode::kJump); CHECK_EQ(iterator.current_bytecode(), Bytecode::kJump);
CHECK_EQ(iterator.GetSmi8Operand(0), -2); CHECK_EQ(iterator.GetImmediateOperand(0), -2);
iterator.Advance(); iterator.Advance();
} }
CHECK_EQ(iterator.current_bytecode(), Bytecode::kReturn); CHECK_EQ(iterator.current_bytecode(), Bytecode::kReturn);
...@@ -392,6 +391,53 @@ TEST_F(BytecodeArrayBuilderTest, LabelAddressReuse) { ...@@ -392,6 +391,53 @@ TEST_F(BytecodeArrayBuilderTest, LabelAddressReuse) {
} }
TEST_F(BytecodeArrayBuilderTest, ToBoolean) {
BytecodeArrayBuilder builder(isolate(), zone());
builder.set_parameter_count(0);
builder.set_locals_count(0);
// Check ToBoolean emitted at start of block.
builder.EnterBlock().CastAccumulatorToBoolean();
// Check ToBoolean emitted preceding bytecode is non-boolean.
builder.LoadNull().CastAccumulatorToBoolean();
// Check ToBoolean omitted if preceding bytecode is boolean.
builder.LoadFalse().CastAccumulatorToBoolean();
// Check ToBoolean emitted if it is at the start of the next block.
builder.LoadFalse()
.LeaveBlock()
.EnterBlock()
.CastAccumulatorToBoolean()
.LeaveBlock();
builder.Return();
Handle<BytecodeArray> array = builder.ToBytecodeArray();
BytecodeArrayIterator iterator(array);
CHECK_EQ(iterator.current_bytecode(), Bytecode::kToBoolean);
iterator.Advance();
CHECK_EQ(iterator.current_bytecode(), Bytecode::kLdaNull);
iterator.Advance();
CHECK_EQ(iterator.current_bytecode(), Bytecode::kToBoolean);
iterator.Advance();
CHECK_EQ(iterator.current_bytecode(), Bytecode::kLdaFalse);
iterator.Advance();
CHECK_EQ(iterator.current_bytecode(), Bytecode::kLdaFalse);
iterator.Advance();
CHECK_EQ(iterator.current_bytecode(), Bytecode::kToBoolean);
iterator.Advance();
CHECK_EQ(iterator.current_bytecode(), Bytecode::kReturn);
iterator.Advance();
CHECK(iterator.done());
}
} // namespace interpreter } // namespace interpreter
} // namespace internal } // namespace internal
} // namespace v8 } // namespace v8
...@@ -37,6 +37,9 @@ TEST_F(BytecodeArrayIteratorTest, IteratesBytecodeArray) { ...@@ -37,6 +37,9 @@ TEST_F(BytecodeArrayIteratorTest, IteratesBytecodeArray) {
Register reg_2 = Register::FromParameterIndex(2, builder.parameter_count()); Register reg_2 = Register::FromParameterIndex(2, builder.parameter_count());
int feedback_slot = 97; int feedback_slot = 97;
// TODO(rmcilroy): Add a test for a bytecode with a short operand when
// the CallRuntime bytecode is landed.
builder.LoadLiteral(heap_num_0) builder.LoadLiteral(heap_num_0)
.LoadLiteral(heap_num_1) .LoadLiteral(heap_num_1)
.LoadLiteral(zero) .LoadLiteral(zero)
...@@ -64,7 +67,7 @@ TEST_F(BytecodeArrayIteratorTest, IteratesBytecodeArray) { ...@@ -64,7 +67,7 @@ TEST_F(BytecodeArrayIteratorTest, IteratesBytecodeArray) {
iterator.Advance(); iterator.Advance();
CHECK_EQ(iterator.current_bytecode(), Bytecode::kLdaSmi8); CHECK_EQ(iterator.current_bytecode(), Bytecode::kLdaSmi8);
CHECK_EQ(Smi::FromInt(iterator.GetSmi8Operand(0)), smi_0); CHECK_EQ(Smi::FromInt(iterator.GetImmediateOperand(0)), smi_0);
CHECK(!iterator.done()); CHECK(!iterator.done());
iterator.Advance(); iterator.Advance();
......
...@@ -810,12 +810,13 @@ ...@@ -810,12 +810,13 @@
'../../src/interface-descriptors.h', '../../src/interface-descriptors.h',
'../../src/interpreter/bytecodes.cc', '../../src/interpreter/bytecodes.cc',
'../../src/interpreter/bytecodes.h', '../../src/interpreter/bytecodes.h',
'../../src/interpreter/bytecode-generator.cc',
'../../src/interpreter/bytecode-generator.h',
'../../src/interpreter/bytecode-array-builder.cc', '../../src/interpreter/bytecode-array-builder.cc',
'../../src/interpreter/bytecode-array-builder.h', '../../src/interpreter/bytecode-array-builder.h',
'../../src/interpreter/bytecode-array-iterator.cc', '../../src/interpreter/bytecode-array-iterator.cc',
'../../src/interpreter/bytecode-array-iterator.h', '../../src/interpreter/bytecode-array-iterator.h',
'../../src/interpreter/bytecode-generator.cc',
'../../src/interpreter/bytecode-generator.h',
'../../src/interpreter/bytecode-traits.h',
'../../src/interpreter/control-flow-builders.cc', '../../src/interpreter/control-flow-builders.cc',
'../../src/interpreter/control-flow-builders.h', '../../src/interpreter/control-flow-builders.h',
'../../src/interpreter/interpreter.cc', '../../src/interpreter/interpreter.cc',
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment