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") {
"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.h",
"src/interpreter/interpreter.cc",
......
......@@ -188,7 +188,7 @@ void BytecodeGraphBuilder::VisitLdaZero(
void BytecodeGraphBuilder::VisitLdaSmi8(
const interpreter::BytecodeArrayIterator& iterator) {
Node* node = jsgraph()->Constant(iterator.GetSmi8Operand(0));
Node* node = jsgraph()->Constant(iterator.GetImmediateOperand(0));
environment()->BindAccumulator(node);
}
......
......@@ -126,17 +126,25 @@ Node* InterpreterAssembler::StoreRegister(Node* value, Node* reg_index) {
Node* InterpreterAssembler::BytecodeOperand(int operand_index) {
DCHECK_LT(operand_index, interpreter::Bytecodes::NumberOfOperands(bytecode_));
DCHECK_EQ(interpreter::OperandSize::kByte,
interpreter::Bytecodes::GetOperandSize(bytecode_, operand_index));
return raw_assembler_->Load(
kMachUint8, BytecodeArrayTaggedPointer(),
IntPtrAdd(BytecodeOffset(), Int32Constant(1 + operand_index)));
IntPtrAdd(BytecodeOffset(),
Int32Constant(interpreter::Bytecodes::GetOperandOffset(
bytecode_, operand_index))));
}
Node* InterpreterAssembler::BytecodeOperandSignExtended(int operand_index) {
DCHECK_LT(operand_index, interpreter::Bytecodes::NumberOfOperands(bytecode_));
DCHECK_EQ(interpreter::OperandSize::kByte,
interpreter::Bytecodes::GetOperandSize(bytecode_, operand_index));
Node* load = raw_assembler_->Load(
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
if (kPointerSize == 8) {
load = raw_assembler_->ChangeInt32ToInt64(load);
......@@ -145,8 +153,40 @@ Node* InterpreterAssembler::BytecodeOperandSignExtended(int operand_index) {
}
Node* InterpreterAssembler::BytecodeOperandCount(int operand_index) {
DCHECK_EQ(interpreter::OperandType::kCount,
Node* InterpreterAssembler::BytecodeOperandShort(int operand_index) {
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));
return BytecodeOperand(operand_index);
}
......@@ -159,20 +199,27 @@ Node* InterpreterAssembler::BytecodeOperandImm8(int operand_index) {
}
Node* InterpreterAssembler::BytecodeOperandIdx(int operand_index) {
DCHECK_EQ(interpreter::OperandType::kIdx,
Node* InterpreterAssembler::BytecodeOperandIdx8(int operand_index) {
DCHECK_EQ(interpreter::OperandType::kIdx8,
interpreter::Bytecodes::GetOperandType(bytecode_, operand_index));
return BytecodeOperand(operand_index);
}
Node* InterpreterAssembler::BytecodeOperandReg(int operand_index) {
DCHECK_EQ(interpreter::OperandType::kReg,
Node* InterpreterAssembler::BytecodeOperandReg8(int operand_index) {
DCHECK_EQ(interpreter::OperandType::kReg8,
interpreter::Bytecodes::GetOperandType(bytecode_, 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) {
return raw_assembler_->Int32Constant(value);
}
......@@ -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:
Isolate* InterpreterAssembler::isolate() { return raw_assembler_->isolate(); }
......
......@@ -41,16 +41,20 @@ class InterpreterAssembler {
// Returns the count immediate for bytecode operand |operand_index| in the
// current bytecode.
Node* BytecodeOperandCount(int operand_index);
Node* BytecodeOperandCount8(int operand_index);
// Returns the index immediate for bytecode operand |operand_index| in the
// current bytecode.
Node* BytecodeOperandIdx(int operand_index);
Node* BytecodeOperandIdx8(int operand_index);
// Returns the Imm8 immediate for bytecode operand |operand_index| in the
// current bytecode.
Node* BytecodeOperandImm8(int operand_index);
// Returns the register index for bytecode operand |operand_index| in the
// 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.
Node* GetAccumulator();
......@@ -126,6 +130,8 @@ class InterpreterAssembler {
// Close the graph.
void End();
static bool TargetSupportsUnalignedAccess();
// Protected helpers (for testing) which delegate to RawMachineAssembler.
CallDescriptor* call_descriptor() const;
Graph* graph();
......@@ -148,6 +154,7 @@ class InterpreterAssembler {
Node* SmiShiftBitsConstant();
Node* BytecodeOperand(int operand_index);
Node* BytecodeOperandSignExtended(int operand_index);
Node* BytecodeOperandShort(int operand_index);
Node* CallIC(CallInterfaceDescriptor descriptor, Node* target, Node** args);
Node* CallJSBuiltin(int context_index, Node* receiver, Node** js_args,
......
......@@ -76,40 +76,54 @@ Handle<BytecodeArray> BytecodeArrayBuilder::ToBytecodeArray() {
template <size_t N>
void BytecodeArrayBuilder::Output(uint8_t(&bytes)[N]) {
DCHECK_EQ(Bytecodes::NumberOfOperands(Bytecodes::FromByte(bytes[0])),
static_cast<int>(N) - 1);
void BytecodeArrayBuilder::Output(Bytecode bytecode, uint32_t(&operands)[N]) {
DCHECK_EQ(Bytecodes::NumberOfOperands(bytecode), N);
last_bytecode_start_ = bytecodes()->size();
for (int i = 1; i < static_cast<int>(N); i++) {
DCHECK(OperandIsValid(Bytecodes::FromByte(bytes[0]), i - 1, bytes[i]));
bytecodes()->push_back(Bytecodes::ToByte(bytecode));
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,
uint8_t operand1, uint8_t operand2) {
uint8_t bytes[] = {Bytecodes::ToByte(bytecode), operand0, operand1, operand2};
Output(bytes);
void BytecodeArrayBuilder::Output(Bytecode bytecode, uint32_t operand0,
uint32_t operand1, uint32_t operand2) {
uint32_t operands[] = {operand0, operand1, operand2};
Output(bytecode, operands);
}
void BytecodeArrayBuilder::Output(Bytecode bytecode, uint8_t operand0,
uint8_t operand1) {
uint8_t bytes[] = {Bytecodes::ToByte(bytecode), operand0, operand1};
Output(bytes);
void BytecodeArrayBuilder::Output(Bytecode bytecode, uint32_t operand0,
uint32_t operand1) {
uint32_t operands[] = {operand0, operand1};
Output(bytecode, operands);
}
void BytecodeArrayBuilder::Output(Bytecode bytecode, uint8_t operand0) {
uint8_t bytes[] = {Bytecodes::ToByte(bytecode), operand0};
Output(bytes);
void BytecodeArrayBuilder::Output(Bytecode bytecode, uint32_t operand0) {
uint32_t operands[] = {operand0};
Output(bytecode, operands);
}
void BytecodeArrayBuilder::Output(Bytecode bytecode) {
uint8_t bytes[] = {Bytecodes::ToByte(bytecode)};
Output(bytes);
DCHECK_EQ(Bytecodes::NumberOfOperands(bytecode), 0);
last_bytecode_start_ = bytecodes()->size();
bytecodes()->push_back(Bytecodes::ToByte(bytecode));
}
......@@ -295,11 +309,13 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::CastAccumulatorToBoolean() {
case Bytecode::kTestGreaterThanOrEqual:
case Bytecode::kTestInstanceOf:
case Bytecode::kTestIn:
break;
return *this;
default:
Output(Bytecode::kToBoolean);
// Fall through to output kToBoolean.
break;
}
}
Output(Bytecode::kToBoolean);
return *this;
}
......@@ -499,17 +515,19 @@ void BytecodeArrayBuilder::ReturnTemporaryRegister(int reg_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);
switch (operand_type) {
case OperandType::kNone:
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::kIdx:
return true;
case OperandType::kReg: {
Register reg = Register::FromOperand(operand_value);
case OperandType::kIdx8:
return static_cast<uint8_t>(operand_value) == operand_value;
case OperandType::kReg8: {
Register reg = Register::FromOperand(static_cast<uint8_t>(operand_value));
if (reg.is_parameter()) {
int parameter_index = reg.ToParameterIndex(parameter_count_);
return parameter_index >= 0 && parameter_index < parameter_count_;
......
......@@ -113,21 +113,21 @@ class BytecodeArrayBuilder {
static Bytecode GetJumpWithConstantOperand(Bytecode jump_with_smi8_operand);
template <size_t N>
INLINE(void Output(uint8_t(&bytes)[N]));
void Output(Bytecode bytecode, uint8_t operand0, uint8_t operand1,
uint8_t operand2);
void Output(Bytecode bytecode, uint8_t operand0, uint8_t operand1);
void Output(Bytecode bytecode, uint8_t operand0);
INLINE(void Output(Bytecode bytecode, uint32_t(&oprands)[N]));
void Output(Bytecode bytecode, uint32_t operand0, uint32_t operand1,
uint32_t operand2);
void Output(Bytecode bytecode, uint32_t operand0, uint32_t operand1);
void Output(Bytecode bytecode, uint32_t operand0);
void Output(Bytecode bytecode);
void PatchJump(const ZoneVector<uint8_t>::iterator& jump_target,
ZoneVector<uint8_t>::iterator jump_location);
BytecodeArrayBuilder& OutputJump(Bytecode jump_bytecode,
BytecodeLabel* label);
void PatchJump(const ZoneVector<uint8_t>::iterator& jump_target,
ZoneVector<uint8_t>::iterator jump_location);
void EnsureReturn();
bool OperandIsValid(Bytecode bytecode, int operand_index,
uint8_t operand_value) const;
uint32_t operand_value) const;
bool LastBytecodeInSameBlock() const;
size_t GetConstantPoolEntry(Handle<Object> object);
......
......@@ -32,31 +32,45 @@ Bytecode BytecodeArrayIterator::current_bytecode() const {
}
uint8_t BytecodeArrayIterator::GetRawOperand(int operand_index,
OperandType operand_type) const {
uint32_t BytecodeArrayIterator::GetRawOperand(int operand_index,
OperandType operand_type) const {
DCHECK_GE(operand_index, 0);
DCHECK_LT(operand_index, Bytecodes::NumberOfOperands(current_bytecode()));
DCHECK_EQ(operand_type,
Bytecodes::GetOperandType(current_bytecode(), operand_index));
int operands_start = bytecode_offset_ + 1;
return bytecode_array()->get(operands_start + operand_index);
uint8_t* operand_start =
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 {
uint8_t operand = GetRawOperand(operand_index, OperandType::kImm8);
int8_t BytecodeArrayIterator::GetImmediateOperand(int operand_index) const {
uint32_t operand = GetRawOperand(operand_index, OperandType::kImm8);
return static_cast<int8_t>(operand);
}
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);
}
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);
}
......
......@@ -25,14 +25,14 @@ class BytecodeArrayIterator {
return bytecode_array_;
}
int8_t GetSmi8Operand(int operand_index) const;
int8_t GetImmediateOperand(int operand_index) const;
int GetIndexOperand(int operand_index) const;
Register GetRegisterOperand(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
// 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:
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 @@
#include "src/interpreter/bytecodes.h"
#include "src/frames.h"
#include "src/interpreter/bytecode-traits.h"
namespace v8 {
namespace internal {
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
const char* Bytecodes::ToString(Bytecode bytecode) {
......@@ -42,7 +29,7 @@ const char* Bytecodes::ToString(Bytecode bytecode) {
// static
const char* Bytecodes::OperandTypeToString(OperandType operand_type) {
switch (operand_type) {
#define CASE(Name) \
#define CASE(Name, _) \
case OperandType::k##Name: \
return #Name;
OPERAND_TYPE_LIST(CASE)
......@@ -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
uint8_t Bytecodes::ToByte(Bytecode bytecode) {
return static_cast<uint8_t>(bytecode);
......@@ -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
int Bytecodes::NumberOfOperands(Bytecode bytecode) {
DCHECK(bytecode <= Bytecode::kLast);
int count;
uint8_t row = ToByte(bytecode);
for (count = 0; count < kMaxOperands; count++) {
if (kBytecodeTable[row][count] == OperandType::kNone) {
break;
}
switch (bytecode) {
#define CASE(Name, ...) \
case Bytecode::k##Name: \
return BytecodeTraits<__VA_ARGS__, OPERAND_TERM>::kOperandCount;
BYTECODE_LIST(CASE)
#undef CASE
}
return count;
UNREACHABLE();
return 0;
}
// static
OperandType Bytecodes::GetOperandType(Bytecode bytecode, int i) {
DCHECK(bytecode <= Bytecode::kLast && i < NumberOfOperands(bytecode));
return kBytecodeTable[ToByte(bytecode)][i];
DCHECK(bytecode <= Bytecode::kLast);
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
int Bytecodes::Size(Bytecode bytecode) {
return 1 + NumberOfOperands(bytecode);
OperandSize Bytecodes::GetOperandSize(Bytecode bytecode, int i) {
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
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
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
......@@ -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
std::ostream& Bytecodes::Decode(std::ostream& os, const uint8_t* bytecode_start,
int parameter_count) {
......@@ -129,29 +197,34 @@ std::ostream& Bytecodes::Decode(std::ostream& os, const uint8_t* bytecode_start,
SNPrintF(buf, "%02x ", bytecode_start[i]);
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 << bytecode << " ";
const uint8_t* operands_start = bytecode_start + 1;
int operands_size = bytecode_size - 1;
for (int i = 0; i < operands_size; i++) {
int number_of_operands = NumberOfOperands(bytecode);
for (int i = 0; i < number_of_operands; 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) {
case interpreter::OperandType::kCount:
os << "#" << static_cast<unsigned int>(operand);
case interpreter::OperandType::kCount8:
os << "#" << static_cast<unsigned int>(*operand_start);
break;
case interpreter::OperandType::kIdx8:
os << "[" << static_cast<unsigned int>(*operand_start) << "]";
break;
case interpreter::OperandType::kIdx:
os << "[" << static_cast<unsigned int>(operand) << "]";
case interpreter::OperandType::kIdx16: {
os << "[" << Bytecodes::ShortOperandFromBytes(operand_start) << "]";
break;
}
case interpreter::OperandType::kImm8:
os << "#" << static_cast<int>(static_cast<int8_t>(operand));
os << "#" << static_cast<int>(static_cast<int8_t>(*operand_start));
break;
case interpreter::OperandType::kReg: {
Register reg = Register::FromOperand(operand);
case interpreter::OperandType::kReg8: {
Register reg = Register::FromOperand(*operand_start);
if (reg.is_parameter()) {
int parameter_index = reg.ToParameterIndex(parameter_count);
if (parameter_index == 0) {
......@@ -168,7 +241,7 @@ std::ostream& Bytecodes::Decode(std::ostream& os, const uint8_t* bytecode_start,
UNREACHABLE();
break;
}
if (i != operands_size - 1) {
if (i != number_of_operands - 1) {
os << ", ";
}
}
......@@ -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 =
-InterpreterFrameConstants::kLastParamFromRegisterPointer / kPointerSize;
......
This diff is collapsed.
......@@ -111,7 +111,7 @@ void Interpreter::DoLdaSmi8(compiler::InterpreterAssembler* assembler) {
//
// Load constant literal at |idx| in the constant pool into the accumulator.
void Interpreter::DoLdaConstant(compiler::InterpreterAssembler* assembler) {
Node* index = __ BytecodeOperandIdx(0);
Node* index = __ BytecodeOperandIdx8(0);
Node* constant = __ LoadConstantPoolEntry(index);
__ SetAccumulator(constant);
__ Dispatch();
......@@ -173,7 +173,7 @@ void Interpreter::DoLdaFalse(compiler::InterpreterAssembler* assembler) {
//
// Load accumulator with value from register <src>.
void Interpreter::DoLdar(compiler::InterpreterAssembler* assembler) {
Node* reg_index = __ BytecodeOperandReg(0);
Node* reg_index = __ BytecodeOperandReg8(0);
Node* value = __ LoadRegister(reg_index);
__ SetAccumulator(value);
__ Dispatch();
......@@ -184,7 +184,7 @@ void Interpreter::DoLdar(compiler::InterpreterAssembler* assembler) {
//
// Store accumulator to register <dst>.
void Interpreter::DoStar(compiler::InterpreterAssembler* assembler) {
Node* reg_index = __ BytecodeOperandReg(0);
Node* reg_index = __ BytecodeOperandReg8(0);
Node* accumulator = __ GetAccumulator();
__ StoreRegister(accumulator, reg_index);
__ Dispatch();
......@@ -195,7 +195,7 @@ void Interpreter::DoStar(compiler::InterpreterAssembler* assembler) {
//
// Load the global at |slot_index| into the accumulator.
void Interpreter::DoLdaGlobal(compiler::InterpreterAssembler* assembler) {
Node* slot_index = __ BytecodeOperandIdx(0);
Node* slot_index = __ BytecodeOperandIdx8(0);
Node* smi_slot_index = __ SmiTag(slot_index);
Node* result = __ CallRuntime(Runtime::kLoadGlobalViaContext, smi_slot_index);
__ SetAccumulator(result);
......@@ -206,10 +206,10 @@ void Interpreter::DoLdaGlobal(compiler::InterpreterAssembler* assembler) {
void Interpreter::DoPropertyLoadIC(Callable ic,
compiler::InterpreterAssembler* assembler) {
Node* code_target = __ HeapConstant(ic.code());
Node* reg_index = __ BytecodeOperandReg(0);
Node* reg_index = __ BytecodeOperandReg8(0);
Node* object = __ LoadRegister(reg_index);
Node* name = __ GetAccumulator();
Node* raw_slot = __ BytecodeOperandIdx(1);
Node* raw_slot = __ BytecodeOperandIdx8(1);
Node* smi_slot = __ SmiTag(raw_slot);
Node* type_feedback_vector = __ LoadTypeFeedbackVector();
Node* result = __ CallIC(ic.descriptor(), code_target, object, name, smi_slot,
......@@ -244,12 +244,12 @@ void Interpreter::DoKeyedLoadIC(compiler::InterpreterAssembler* assembler) {
void Interpreter::DoPropertyStoreIC(Callable ic,
compiler::InterpreterAssembler* assembler) {
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* name_reg_index = __ BytecodeOperandReg(1);
Node* name_reg_index = __ BytecodeOperandReg8(1);
Node* name = __ LoadRegister(name_reg_index);
Node* value = __ GetAccumulator();
Node* raw_slot = __ BytecodeOperandIdx(2);
Node* raw_slot = __ BytecodeOperandIdx8(2);
Node* smi_slot = __ SmiTag(raw_slot);
Node* type_feedback_vector = __ LoadTypeFeedbackVector();
Node* result = __ CallIC(ic.descriptor(), code_target, object, name, value,
......@@ -285,7 +285,7 @@ void Interpreter::DoBinaryOp(Runtime::FunctionId function_id,
compiler::InterpreterAssembler* assembler) {
// TODO(rmcilroy): Call ICs which back-patch bytecode with type specialized
// operations, instead of calling builtins directly.
Node* reg_index = __ BytecodeOperandReg(0);
Node* reg_index = __ BytecodeOperandReg8(0);
Node* lhs = __ LoadRegister(reg_index);
Node* rhs = __ GetAccumulator();
Node* result = __ CallRuntime(function_id, lhs, rhs);
......@@ -339,11 +339,11 @@ void Interpreter::DoMod(compiler::InterpreterAssembler* assembler) {
// Call a JS function with receiver and |arg_count| arguments in subsequent
// registers. The JSfunction or Callable to call is in the accumulator.
void Interpreter::DoCall(compiler::InterpreterAssembler* assembler) {
Node* function_reg = __ BytecodeOperandReg(0);
Node* function_reg = __ BytecodeOperandReg8(0);
Node* function = __ LoadRegister(function_reg);
Node* receiver_reg = __ BytecodeOperandReg(1);
Node* receiver_reg = __ BytecodeOperandReg8(1);
Node* first_arg = __ RegisterLocation(receiver_reg);
Node* args_count = __ BytecodeOperandCount(2);
Node* args_count = __ BytecodeOperandCount8(2);
Node* result = __ CallJS(function, first_arg, args_count);
__ SetAccumulator(result);
__ Dispatch();
......@@ -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.
void Interpreter::DoJumpConstant(compiler::InterpreterAssembler* assembler) {
Node* index = __ BytecodeOperandIdx(0);
Node* index = __ BytecodeOperandIdx8(0);
Node* constant = __ LoadConstantPoolEntry(index);
Node* relative_jump = __ SmiUntag(constant);
__ Jump(relative_jump);
......@@ -487,7 +487,7 @@ void Interpreter::DoJumpIfTrue(compiler::InterpreterAssembler* assembler) {
void Interpreter::DoJumpIfTrueConstant(
compiler::InterpreterAssembler* assembler) {
Node* accumulator = __ GetAccumulator();
Node* index = __ BytecodeOperandIdx(0);
Node* index = __ BytecodeOperandIdx8(0);
Node* constant = __ LoadConstantPoolEntry(index);
Node* relative_jump = __ SmiUntag(constant);
Node* true_value = __ BooleanConstant(true);
......@@ -514,7 +514,7 @@ void Interpreter::DoJumpIfFalse(compiler::InterpreterAssembler* assembler) {
void Interpreter::DoJumpIfFalseConstant(
compiler::InterpreterAssembler* assembler) {
Node* accumulator = __ GetAccumulator();
Node* index = __ BytecodeOperandIdx(0);
Node* index = __ BytecodeOperandIdx8(0);
Node* constant = __ LoadConstantPoolEntry(index);
Node* relative_jump = __ SmiUntag(constant);
Node* false_value = __ BooleanConstant(false);
......
......@@ -130,22 +130,37 @@ static void CheckBytecodeArrayEqual(struct ExpectedSnippet<T> expected,
<< " but got " << Bytecodes::ToString(bytecode);
FATAL(stream.str().c_str());
}
for (int j = 0; j < Bytecodes::NumberOfOperands(bytecode); ++j, ++i) {
uint8_t raw_operand =
iterator.GetRawOperand(j, Bytecodes::GetOperandType(bytecode, j));
for (int j = 0; j < Bytecodes::NumberOfOperands(bytecode); ++j) {
OperandType operand_type = 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) {
// Check actual bytecode array doesn't have the same byte as the
// one we use to specify an unknown byte.
CHECK_NE(raw_operand, _);
if (expected.bytecode[i] == _) {
if (expected.bytecode[operand_index] == _) {
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;
stream << "Check failed: expected operand [" << j << "] for bytecode ["
<< 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);
FATAL(stream.str().c_str());
}
......
......@@ -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(
const Matcher<LoadRepresentation>& rep_matcher,
const Matcher<Node*>& base_matcher, const Matcher<Node*>& index_matcher) {
......@@ -87,20 +94,20 @@ Matcher<Node*> InterpreterAssemblerTest::InterpreterAssemblerForTest::IsCall(
Matcher<Node*>
InterpreterAssemblerTest::InterpreterAssemblerForTest::IsBytecodeOperand(
int operand) {
int offset) {
return IsLoad(
kMachUint8, IsParameter(Linkage::kInterpreterBytecodeArrayParameter),
IsIntPtrAdd(IsParameter(Linkage::kInterpreterBytecodeOffsetParameter),
IsInt32Constant(1 + operand)));
IsInt32Constant(offset)));
}
Matcher<Node*> InterpreterAssemblerTest::InterpreterAssemblerForTest::
IsBytecodeOperandSignExtended(int operand) {
IsBytecodeOperandSignExtended(int offset) {
Matcher<Node*> load_matcher = IsLoad(
kMachInt8, IsParameter(Linkage::kInterpreterBytecodeArrayParameter),
IsIntPtrAdd(IsParameter(Linkage::kInterpreterBytecodeOffsetParameter),
IsInt32Constant(1 + operand)));
IsInt32Constant(offset)));
if (kPointerSize == 8) {
load_matcher = IsChangeInt32ToInt64(load_matcher);
}
......@@ -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*
InterpreterAssemblerTest::InterpreterAssemblerForTest::GetCompletedGraph() {
End();
......@@ -268,20 +305,25 @@ TARGET_TEST_F(InterpreterAssemblerTest, BytecodeOperand) {
InterpreterAssemblerForTest m(this, bytecode);
int number_of_operands = interpreter::Bytecodes::NumberOfOperands(bytecode);
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::kCount:
EXPECT_THAT(m.BytecodeOperandCount(i), m.IsBytecodeOperand(i));
case interpreter::OperandType::kCount8:
EXPECT_THAT(m.BytecodeOperandCount8(i), m.IsBytecodeOperand(offset));
break;
case interpreter::OperandType::kIdx:
EXPECT_THAT(m.BytecodeOperandIdx(i), m.IsBytecodeOperand(i));
case interpreter::OperandType::kIdx8:
EXPECT_THAT(m.BytecodeOperandIdx8(i), m.IsBytecodeOperand(offset));
break;
case interpreter::OperandType::kImm8:
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;
case interpreter::OperandType::kReg:
EXPECT_THAT(m.BytecodeOperandReg(i),
m.IsBytecodeOperandSignExtended(i));
case interpreter::OperandType::kIdx16:
EXPECT_THAT(m.BytecodeOperandIdx16(i),
m.IsBytecodeOperandShort(offset));
break;
case interpreter::OperandType::kNone:
UNREACHABLE();
......
......@@ -43,8 +43,9 @@ class InterpreterAssemblerTest : public TestWithIsolateAndZone {
const Matcher<const CallDescriptor*>& descriptor_matcher,
A... args);
Matcher<Node*> IsBytecodeOperand(int operand);
Matcher<Node*> IsBytecodeOperandSignExtended(int operand);
Matcher<Node*> IsBytecodeOperand(int offset);
Matcher<Node*> IsBytecodeOperandSignExtended(int offset);
Matcher<Node*> IsBytecodeOperandShort(int offset);
using InterpreterAssembler::call_descriptor;
using InterpreterAssembler::graph;
......
......@@ -1989,12 +1989,14 @@ IS_BINOP_MATCHER(NumberShiftLeft)
IS_BINOP_MATCHER(NumberShiftRight)
IS_BINOP_MATCHER(NumberShiftRightLogical)
IS_BINOP_MATCHER(Word32And)
IS_BINOP_MATCHER(Word32Or)
IS_BINOP_MATCHER(Word32Sar)
IS_BINOP_MATCHER(Word32Shl)
IS_BINOP_MATCHER(Word32Shr)
IS_BINOP_MATCHER(Word32Ror)
IS_BINOP_MATCHER(Word32Equal)
IS_BINOP_MATCHER(Word64And)
IS_BINOP_MATCHER(Word64Or)
IS_BINOP_MATCHER(Word64Sar)
IS_BINOP_MATCHER(Word64Shl)
IS_BINOP_MATCHER(Word64Equal)
......
......@@ -256,6 +256,8 @@ Matcher<Node*> IsStore(const Matcher<StoreRepresentation>& rep_matcher,
const Matcher<Node*>& control_matcher);
Matcher<Node*> IsWord32And(const Matcher<Node*>& lhs_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,
const Matcher<Node*>& rhs_matcher);
Matcher<Node*> IsWord32Shl(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*> IsWord64And(const Matcher<Node*>& lhs_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,
const Matcher<Node*>& rhs_matcher);
Matcher<Node*> IsWord64Sar(const Matcher<Node*>& lhs_matcher,
......
......@@ -94,13 +94,12 @@ TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) {
// Build scorecard of bytecodes encountered in the BytecodeArray.
std::vector<int> scorecard(Bytecodes::ToByte(Bytecode::kLast) + 1);
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);
scorecard[code] += 1;
int operands = Bytecodes::NumberOfOperands(Bytecodes::FromByte(code));
CHECK_LE(operands, Bytecodes::MaximumNumberOfOperands());
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.
......@@ -240,15 +239,15 @@ TEST_F(BytecodeArrayBuilderTest, ForwardJumps) {
BytecodeArrayIterator iterator(array);
CHECK_EQ(iterator.current_bytecode(), Bytecode::kJump);
CHECK_EQ(iterator.GetSmi8Operand(0), 6);
CHECK_EQ(iterator.GetImmediateOperand(0), 6);
iterator.Advance();
CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpIfTrue);
CHECK_EQ(iterator.GetSmi8Operand(0), 4);
CHECK_EQ(iterator.GetImmediateOperand(0), 4);
iterator.Advance();
CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpIfFalse);
CHECK_EQ(iterator.GetSmi8Operand(0), 2);
CHECK_EQ(iterator.GetImmediateOperand(0), 2);
iterator.Advance();
CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpConstant);
......@@ -303,17 +302,17 @@ TEST_F(BytecodeArrayBuilderTest, BackwardJumps) {
Handle<BytecodeArray> array = builder.ToBytecodeArray();
BytecodeArrayIterator iterator(array);
CHECK_EQ(iterator.current_bytecode(), Bytecode::kJump);
CHECK_EQ(iterator.GetSmi8Operand(0), 0);
CHECK_EQ(iterator.GetImmediateOperand(0), 0);
iterator.Advance();
CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpIfTrue);
CHECK_EQ(iterator.GetSmi8Operand(0), 0);
CHECK_EQ(iterator.GetImmediateOperand(0), 0);
iterator.Advance();
CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpIfFalse);
CHECK_EQ(iterator.GetSmi8Operand(0), 0);
CHECK_EQ(iterator.GetImmediateOperand(0), 0);
iterator.Advance();
for (int i = 0; i < 64; i++) {
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();
}
CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpIfFalseConstant);
......@@ -345,13 +344,13 @@ TEST_F(BytecodeArrayBuilderTest, LabelReuse) {
Handle<BytecodeArray> array = builder.ToBytecodeArray();
BytecodeArrayIterator iterator(array);
CHECK_EQ(iterator.current_bytecode(), Bytecode::kJump);
CHECK_EQ(iterator.GetSmi8Operand(0), 2);
CHECK_EQ(iterator.GetImmediateOperand(0), 2);
iterator.Advance();
CHECK_EQ(iterator.current_bytecode(), Bytecode::kJump);
CHECK_EQ(iterator.GetSmi8Operand(0), 0);
CHECK_EQ(iterator.GetImmediateOperand(0), 0);
iterator.Advance();
CHECK_EQ(iterator.current_bytecode(), Bytecode::kJump);
CHECK_EQ(iterator.GetSmi8Operand(0), -2);
CHECK_EQ(iterator.GetImmediateOperand(0), -2);
iterator.Advance();
CHECK_EQ(iterator.current_bytecode(), Bytecode::kReturn);
iterator.Advance();
......@@ -377,13 +376,13 @@ TEST_F(BytecodeArrayBuilderTest, LabelAddressReuse) {
BytecodeArrayIterator iterator(array);
for (int i = 0; i < kRepeats; i++) {
CHECK_EQ(iterator.current_bytecode(), Bytecode::kJump);
CHECK_EQ(iterator.GetSmi8Operand(0), 2);
CHECK_EQ(iterator.GetImmediateOperand(0), 2);
iterator.Advance();
CHECK_EQ(iterator.current_bytecode(), Bytecode::kJump);
CHECK_EQ(iterator.GetSmi8Operand(0), 0);
CHECK_EQ(iterator.GetImmediateOperand(0), 0);
iterator.Advance();
CHECK_EQ(iterator.current_bytecode(), Bytecode::kJump);
CHECK_EQ(iterator.GetSmi8Operand(0), -2);
CHECK_EQ(iterator.GetImmediateOperand(0), -2);
iterator.Advance();
}
CHECK_EQ(iterator.current_bytecode(), Bytecode::kReturn);
......@@ -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 internal
} // namespace v8
......@@ -37,6 +37,9 @@ TEST_F(BytecodeArrayIteratorTest, IteratesBytecodeArray) {
Register reg_2 = Register::FromParameterIndex(2, builder.parameter_count());
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)
.LoadLiteral(heap_num_1)
.LoadLiteral(zero)
......@@ -64,7 +67,7 @@ TEST_F(BytecodeArrayIteratorTest, IteratesBytecodeArray) {
iterator.Advance();
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());
iterator.Advance();
......
......@@ -810,12 +810,13 @@
'../../src/interface-descriptors.h',
'../../src/interpreter/bytecodes.cc',
'../../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.h',
'../../src/interpreter/bytecode-array-iterator.cc',
'../../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.h',
'../../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