Commit 7f344213 authored by oth's avatar oth Committed by Commit bot

[interpreter] Add accumulator use description to bytecodes.

Anotates bytecodes with a description of how each uses the accumulator.

Validates annotations and uses of accumulator when generating bytecode
handlers.

Only prints the accumulator during tracing where used.

BUG=v8:4280
LOG=N

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

Cr-Commit-Position: refs/heads/master@{#35281}
parent 10027372
...@@ -11,11 +11,6 @@ namespace v8 { ...@@ -11,11 +11,6 @@ namespace v8 {
namespace internal { namespace internal {
namespace interpreter { 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 <OperandTypeInfo> template <OperandTypeInfo>
struct OperandTypeInfoTraits { struct OperandTypeInfoTraits {
static const bool kIsScalable = false; static const bool kIsScalable = false;
...@@ -59,13 +54,13 @@ struct RegisterOperandTraits { ...@@ -59,13 +54,13 @@ struct RegisterOperandTraits {
REGISTER_OPERAND_TYPE_LIST(DECLARE_REGISTER_OPERAND) REGISTER_OPERAND_TYPE_LIST(DECLARE_REGISTER_OPERAND)
#undef DECLARE_REGISTER_OPERAND #undef DECLARE_REGISTER_OPERAND
template <OperandType... Args> template <AccumulatorUse, OperandType...>
struct BytecodeTraits {}; struct BytecodeTraits {};
template <OperandType operand_0, OperandType operand_1, OperandType operand_2, template <AccumulatorUse accumulator_use, OperandType operand_0,
OperandType operand_3> OperandType operand_1, OperandType operand_2, OperandType operand_3>
struct BytecodeTraits<operand_0, operand_1, operand_2, operand_3, struct BytecodeTraits<accumulator_use, operand_0, operand_1, operand_2,
OPERAND_TERM> { operand_3> {
static OperandType GetOperandType(int i) { static OperandType GetOperandType(int i) {
DCHECK(0 <= i && i < kOperandCount); DCHECK(0 <= i && i < kOperandCount);
const OperandType kOperands[] = {operand_0, operand_1, operand_2, const OperandType kOperands[] = {operand_0, operand_1, operand_2,
...@@ -86,6 +81,7 @@ struct BytecodeTraits<operand_0, operand_1, operand_2, operand_3, ...@@ -86,6 +81,7 @@ struct BytecodeTraits<operand_0, operand_1, operand_2, operand_3,
OperandTraits<operand_3>::TypeInfo::kIsScalable); OperandTraits<operand_3>::TypeInfo::kIsScalable);
} }
static const AccumulatorUse kAccumulatorUse = accumulator_use;
static const int kOperandCount = 4; static const int kOperandCount = 4;
static const int kRegisterOperandCount = static const int kRegisterOperandCount =
RegisterOperandTraits<operand_0>::kIsRegisterOperand + RegisterOperandTraits<operand_0>::kIsRegisterOperand +
...@@ -99,8 +95,9 @@ struct BytecodeTraits<operand_0, operand_1, operand_2, operand_3, ...@@ -99,8 +95,9 @@ struct BytecodeTraits<operand_0, operand_1, operand_2, operand_3,
(RegisterOperandTraits<operand_3>::kIsRegisterOperand << 3); (RegisterOperandTraits<operand_3>::kIsRegisterOperand << 3);
}; };
template <OperandType operand_0, OperandType operand_1, OperandType operand_2> template <AccumulatorUse accumulator_use, OperandType operand_0,
struct BytecodeTraits<operand_0, operand_1, operand_2, OPERAND_TERM> { OperandType operand_1, OperandType operand_2>
struct BytecodeTraits<accumulator_use, operand_0, operand_1, operand_2> {
static inline OperandType GetOperandType(int i) { static inline OperandType GetOperandType(int i) {
DCHECK(0 <= i && i <= 2); DCHECK(0 <= i && i <= 2);
const OperandType kOperands[] = {operand_0, operand_1, operand_2}; const OperandType kOperands[] = {operand_0, operand_1, operand_2};
...@@ -118,6 +115,7 @@ struct BytecodeTraits<operand_0, operand_1, operand_2, OPERAND_TERM> { ...@@ -118,6 +115,7 @@ struct BytecodeTraits<operand_0, operand_1, operand_2, OPERAND_TERM> {
OperandTraits<operand_2>::TypeInfo::kIsScalable); OperandTraits<operand_2>::TypeInfo::kIsScalable);
} }
static const AccumulatorUse kAccumulatorUse = accumulator_use;
static const int kOperandCount = 3; static const int kOperandCount = 3;
static const int kRegisterOperandCount = static const int kRegisterOperandCount =
RegisterOperandTraits<operand_0>::kIsRegisterOperand + RegisterOperandTraits<operand_0>::kIsRegisterOperand +
...@@ -129,8 +127,9 @@ struct BytecodeTraits<operand_0, operand_1, operand_2, OPERAND_TERM> { ...@@ -129,8 +127,9 @@ struct BytecodeTraits<operand_0, operand_1, operand_2, OPERAND_TERM> {
(RegisterOperandTraits<operand_2>::kIsRegisterOperand << 2); (RegisterOperandTraits<operand_2>::kIsRegisterOperand << 2);
}; };
template <OperandType operand_0, OperandType operand_1> template <AccumulatorUse accumulator_use, OperandType operand_0,
struct BytecodeTraits<operand_0, operand_1, OPERAND_TERM> { OperandType operand_1>
struct BytecodeTraits<accumulator_use, operand_0, operand_1> {
static inline OperandType GetOperandType(int i) { static inline OperandType GetOperandType(int i) {
DCHECK(0 <= i && i < kOperandCount); DCHECK(0 <= i && i < kOperandCount);
const OperandType kOperands[] = {operand_0, operand_1}; const OperandType kOperands[] = {operand_0, operand_1};
...@@ -147,6 +146,7 @@ struct BytecodeTraits<operand_0, operand_1, OPERAND_TERM> { ...@@ -147,6 +146,7 @@ struct BytecodeTraits<operand_0, operand_1, OPERAND_TERM> {
OperandTraits<operand_1>::TypeInfo::kIsScalable); OperandTraits<operand_1>::TypeInfo::kIsScalable);
} }
static const AccumulatorUse kAccumulatorUse = accumulator_use;
static const int kOperandCount = 2; static const int kOperandCount = 2;
static const int kRegisterOperandCount = static const int kRegisterOperandCount =
RegisterOperandTraits<operand_0>::kIsRegisterOperand + RegisterOperandTraits<operand_0>::kIsRegisterOperand +
...@@ -156,8 +156,8 @@ struct BytecodeTraits<operand_0, operand_1, OPERAND_TERM> { ...@@ -156,8 +156,8 @@ struct BytecodeTraits<operand_0, operand_1, OPERAND_TERM> {
(RegisterOperandTraits<operand_1>::kIsRegisterOperand << 1); (RegisterOperandTraits<operand_1>::kIsRegisterOperand << 1);
}; };
template <OperandType operand_0> template <AccumulatorUse accumulator_use, OperandType operand_0>
struct BytecodeTraits<operand_0, OPERAND_TERM> { struct BytecodeTraits<accumulator_use, operand_0> {
static inline OperandType GetOperandType(int i) { static inline OperandType GetOperandType(int i) {
DCHECK(i == 0); DCHECK(i == 0);
return operand_0; return operand_0;
...@@ -172,6 +172,7 @@ struct BytecodeTraits<operand_0, OPERAND_TERM> { ...@@ -172,6 +172,7 @@ struct BytecodeTraits<operand_0, OPERAND_TERM> {
return OperandTraits<operand_0>::TypeInfo::kIsScalable; return OperandTraits<operand_0>::TypeInfo::kIsScalable;
} }
static const AccumulatorUse kAccumulatorUse = accumulator_use;
static const int kOperandCount = 1; static const int kOperandCount = 1;
static const int kRegisterOperandCount = static const int kRegisterOperandCount =
RegisterOperandTraits<operand_0>::kIsRegisterOperand; RegisterOperandTraits<operand_0>::kIsRegisterOperand;
...@@ -179,8 +180,8 @@ struct BytecodeTraits<operand_0, OPERAND_TERM> { ...@@ -179,8 +180,8 @@ struct BytecodeTraits<operand_0, OPERAND_TERM> {
RegisterOperandTraits<operand_0>::kIsRegisterOperand; RegisterOperandTraits<operand_0>::kIsRegisterOperand;
}; };
template <> template <AccumulatorUse accumulator_use>
struct BytecodeTraits<OperandType::kNone, OPERAND_TERM> { struct BytecodeTraits<accumulator_use> {
static inline OperandType GetOperandType(int i) { static inline OperandType GetOperandType(int i) {
UNREACHABLE(); UNREACHABLE();
return OperandType::kNone; return OperandType::kNone;
...@@ -193,6 +194,7 @@ struct BytecodeTraits<OperandType::kNone, OPERAND_TERM> { ...@@ -193,6 +194,7 @@ struct BytecodeTraits<OperandType::kNone, OPERAND_TERM> {
static inline bool IsScalable() { return false; } static inline bool IsScalable() { return false; }
static const AccumulatorUse kAccumulatorUse = accumulator_use;
static const int kOperandCount = 0; static const int kOperandCount = 0;
static const int kRegisterOperandCount = 0; static const int kRegisterOperandCount = 0;
static const int kRegisterOperandBitmap = 0; static const int kRegisterOperandBitmap = 0;
......
...@@ -42,6 +42,22 @@ std::string Bytecodes::ToString(Bytecode bytecode, OperandScale operand_scale) { ...@@ -42,6 +42,22 @@ std::string Bytecodes::ToString(Bytecode bytecode, OperandScale operand_scale) {
} }
} }
// static
const char* Bytecodes::AccumulatorUseToString(AccumulatorUse accumulator_use) {
switch (accumulator_use) {
case AccumulatorUse::kNone:
return "None";
case AccumulatorUse::kRead:
return "Read";
case AccumulatorUse::kWrite:
return "Write";
case AccumulatorUse::kReadWrite:
return "ReadWrite";
}
UNREACHABLE();
return "";
}
// static // static
const char* Bytecodes::OperandTypeToString(OperandType operand_type) { const char* Bytecodes::OperandTypeToString(OperandType operand_type) {
switch (operand_type) { switch (operand_type) {
...@@ -141,7 +157,7 @@ int Bytecodes::NumberOfOperands(Bytecode bytecode) { ...@@ -141,7 +157,7 @@ int Bytecodes::NumberOfOperands(Bytecode bytecode) {
switch (bytecode) { switch (bytecode) {
#define CASE(Name, ...) \ #define CASE(Name, ...) \
case Bytecode::k##Name: \ case Bytecode::k##Name: \
return BytecodeTraits<__VA_ARGS__, OPERAND_TERM>::kOperandCount; return BytecodeTraits<__VA_ARGS__>::kOperandCount;
BYTECODE_LIST(CASE) BYTECODE_LIST(CASE)
#undef CASE #undef CASE
} }
...@@ -156,7 +172,7 @@ int Bytecodes::NumberOfRegisterOperands(Bytecode bytecode) { ...@@ -156,7 +172,7 @@ int Bytecodes::NumberOfRegisterOperands(Bytecode bytecode) {
switch (bytecode) { switch (bytecode) {
#define CASE(Name, ...) \ #define CASE(Name, ...) \
case Bytecode::k##Name: \ case Bytecode::k##Name: \
typedef BytecodeTraits<__VA_ARGS__, OPERAND_TERM> Name##Trait; \ typedef BytecodeTraits<__VA_ARGS__> Name##Trait; \
return Name##Trait::kRegisterOperandCount; return Name##Trait::kRegisterOperandCount;
BYTECODE_LIST(CASE) BYTECODE_LIST(CASE)
#undef CASE #undef CASE
...@@ -198,13 +214,39 @@ OperandScale Bytecodes::PrefixBytecodeToOperandScale(Bytecode bytecode) { ...@@ -198,13 +214,39 @@ OperandScale Bytecodes::PrefixBytecodeToOperandScale(Bytecode bytecode) {
} }
} }
// static
AccumulatorUse Bytecodes::GetAccumulatorUse(Bytecode bytecode) {
DCHECK(bytecode <= Bytecode::kLast);
switch (bytecode) {
#define CASE(Name, ...) \
case Bytecode::k##Name: \
return BytecodeTraits<__VA_ARGS__>::kAccumulatorUse;
BYTECODE_LIST(CASE)
#undef CASE
}
UNREACHABLE();
return AccumulatorUse::kNone;
}
// static
bool Bytecodes::ReadsAccumulator(Bytecode bytecode) {
return (GetAccumulatorUse(bytecode) & AccumulatorUse::kRead) ==
AccumulatorUse::kRead;
}
// static
bool Bytecodes::WritesAccumulator(Bytecode bytecode) {
return (GetAccumulatorUse(bytecode) & AccumulatorUse::kWrite) ==
AccumulatorUse::kWrite;
}
// static // static
OperandType Bytecodes::GetOperandType(Bytecode bytecode, int i) { OperandType Bytecodes::GetOperandType(Bytecode bytecode, int i) {
DCHECK(bytecode <= Bytecode::kLast); DCHECK(bytecode <= Bytecode::kLast);
switch (bytecode) { switch (bytecode) {
#define CASE(Name, ...) \ #define CASE(Name, ...) \
case Bytecode::k##Name: \ case Bytecode::k##Name: \
return BytecodeTraits<__VA_ARGS__, OPERAND_TERM>::GetOperandType(i); return BytecodeTraits<__VA_ARGS__>::GetOperandType(i);
BYTECODE_LIST(CASE) BYTECODE_LIST(CASE)
#undef CASE #undef CASE
} }
...@@ -225,7 +267,7 @@ int Bytecodes::GetRegisterOperandBitmap(Bytecode bytecode) { ...@@ -225,7 +267,7 @@ int Bytecodes::GetRegisterOperandBitmap(Bytecode bytecode) {
switch (bytecode) { switch (bytecode) {
#define CASE(Name, ...) \ #define CASE(Name, ...) \
case Bytecode::k##Name: \ case Bytecode::k##Name: \
typedef BytecodeTraits<__VA_ARGS__, OPERAND_TERM> Name##Trait; \ typedef BytecodeTraits<__VA_ARGS__> Name##Trait; \
return Name##Trait::kRegisterOperandBitmap; return Name##Trait::kRegisterOperandBitmap;
BYTECODE_LIST(CASE) BYTECODE_LIST(CASE)
#undef CASE #undef CASE
...@@ -333,7 +375,7 @@ bool Bytecodes::IsBytecodeWithScalableOperands(Bytecode bytecode) { ...@@ -333,7 +375,7 @@ bool Bytecodes::IsBytecodeWithScalableOperands(Bytecode bytecode) {
switch (bytecode) { switch (bytecode) {
#define CASE(Name, ...) \ #define CASE(Name, ...) \
case Bytecode::k##Name: \ case Bytecode::k##Name: \
typedef BytecodeTraits<__VA_ARGS__, OPERAND_TERM> Name##Trait; \ typedef BytecodeTraits<__VA_ARGS__> Name##Trait; \
return Name##Trait::IsScalable(); return Name##Trait::IsScalable();
BYTECODE_LIST(CASE) BYTECODE_LIST(CASE)
#undef CASE #undef CASE
...@@ -586,6 +628,10 @@ std::ostream& operator<<(std::ostream& os, const Bytecode& bytecode) { ...@@ -586,6 +628,10 @@ std::ostream& operator<<(std::ostream& os, const Bytecode& bytecode) {
return os << Bytecodes::ToString(bytecode); return os << Bytecodes::ToString(bytecode);
} }
std::ostream& operator<<(std::ostream& os, const AccumulatorUse& use) {
return os << Bytecodes::AccumulatorUseToString(use);
}
std::ostream& operator<<(std::ostream& os, const OperandSize& operand_size) { std::ostream& operator<<(std::ostream& os, const OperandSize& operand_size) {
return os << Bytecodes::OperandSizeToString(operand_size); return os << Bytecodes::OperandSizeToString(operand_size);
} }
......
...@@ -48,23 +48,24 @@ namespace interpreter { ...@@ -48,23 +48,24 @@ namespace interpreter {
REGISTER_OPERAND_TYPE_LIST(V) REGISTER_OPERAND_TYPE_LIST(V)
// Define one debug break bytecode for each possible size of unscaled // Define one debug break bytecode for each possible size of unscaled
// bytecodes. // bytecodes. Format is V(<bytecode>, <accumulator_use>, <operands>).
#define DEBUG_BREAK_PLAIN_BYTECODE_LIST(V) \ #define DEBUG_BREAK_PLAIN_BYTECODE_LIST(V) \
V(DebugBreak0, OperandType::kNone) \ V(DebugBreak0, AccumulatorUse::kRead) \
V(DebugBreak1, OperandType::kReg) \ V(DebugBreak1, AccumulatorUse::kRead, OperandType::kReg) \
V(DebugBreak2, OperandType::kReg, OperandType::kReg) \ V(DebugBreak2, AccumulatorUse::kRead, OperandType::kReg, OperandType::kReg) \
V(DebugBreak3, OperandType::kReg, OperandType::kReg, OperandType::kReg) \ V(DebugBreak3, AccumulatorUse::kRead, OperandType::kReg, OperandType::kReg, \
V(DebugBreak4, OperandType::kReg, OperandType::kReg, OperandType::kReg, \
OperandType::kReg) \ OperandType::kReg) \
V(DebugBreak5, OperandType::kRuntimeId, OperandType::kReg, \ V(DebugBreak4, AccumulatorUse::kRead, OperandType::kReg, OperandType::kReg, \
OperandType::kReg) \ OperandType::kReg, OperandType::kReg) \
V(DebugBreak6, OperandType::kRuntimeId, OperandType::kReg, \ V(DebugBreak5, AccumulatorUse::kRead, OperandType::kRuntimeId, \
OperandType::kReg, OperandType::kReg) OperandType::kReg, OperandType::kReg) \
V(DebugBreak6, AccumulatorUse::kRead, OperandType::kRuntimeId, \
OperandType::kReg, OperandType::kReg, OperandType::kReg)
// Define one debug break for each widening prefix. // Define one debug break for each widening prefix.
#define DEBUG_BREAK_PREFIX_BYTECODE_LIST(V) \ #define DEBUG_BREAK_PREFIX_BYTECODE_LIST(V) \
V(DebugBreakWide, OperandType::kNone) \ V(DebugBreakWide, AccumulatorUse::kRead) \
V(DebugBreakExtraWide, OperandType::kNone) V(DebugBreakExtraWide, AccumulatorUse::kRead)
#define DEBUG_BREAK_BYTECODE_LIST(V) \ #define DEBUG_BREAK_BYTECODE_LIST(V) \
DEBUG_BREAK_PLAIN_BYTECODE_LIST(V) \ DEBUG_BREAK_PLAIN_BYTECODE_LIST(V) \
...@@ -73,167 +74,195 @@ namespace interpreter { ...@@ -73,167 +74,195 @@ namespace interpreter {
// The list of bytecodes which are interpreted by the interpreter. // The list of bytecodes which are interpreted by the interpreter.
#define BYTECODE_LIST(V) \ #define BYTECODE_LIST(V) \
/* Extended width operands */ \ /* Extended width operands */ \
V(Wide, OperandType::kNone) \ V(Wide, AccumulatorUse::kNone) \
V(ExtraWide, OperandType::kNone) \ V(ExtraWide, AccumulatorUse::kNone) \
\ \
/* Loading the accumulator */ \ /* Loading the accumulator */ \
V(LdaZero, OperandType::kNone) \ V(LdaZero, AccumulatorUse::kWrite) \
V(LdaSmi, OperandType::kImm) \ V(LdaSmi, AccumulatorUse::kWrite, OperandType::kImm) \
V(LdaUndefined, OperandType::kNone) \ V(LdaUndefined, AccumulatorUse::kWrite) \
V(LdaNull, OperandType::kNone) \ V(LdaNull, AccumulatorUse::kWrite) \
V(LdaTheHole, OperandType::kNone) \ V(LdaTheHole, AccumulatorUse::kWrite) \
V(LdaTrue, OperandType::kNone) \ V(LdaTrue, AccumulatorUse::kWrite) \
V(LdaFalse, OperandType::kNone) \ V(LdaFalse, AccumulatorUse::kWrite) \
V(LdaConstant, OperandType::kIdx) \ V(LdaConstant, AccumulatorUse::kWrite, OperandType::kIdx) \
\ \
/* Globals */ \ /* Globals */ \
V(LdaGlobal, OperandType::kIdx, OperandType::kIdx) \ V(LdaGlobal, AccumulatorUse::kWrite, OperandType::kIdx, OperandType::kIdx) \
V(LdaGlobalInsideTypeof, OperandType::kIdx, OperandType::kIdx) \ V(LdaGlobalInsideTypeof, AccumulatorUse::kWrite, OperandType::kIdx, \
V(StaGlobalSloppy, OperandType::kIdx, OperandType::kIdx) \ OperandType::kIdx) \
V(StaGlobalStrict, OperandType::kIdx, OperandType::kIdx) \ V(StaGlobalSloppy, AccumulatorUse::kRead, OperandType::kIdx, \
OperandType::kIdx) \
V(StaGlobalStrict, AccumulatorUse::kRead, OperandType::kIdx, \
OperandType::kIdx) \
\ \
/* Context operations */ \ /* Context operations */ \
V(PushContext, OperandType::kReg) \ V(PushContext, AccumulatorUse::kRead, OperandType::kReg) \
V(PopContext, OperandType::kReg) \ V(PopContext, AccumulatorUse::kNone, OperandType::kReg) \
V(LdaContextSlot, OperandType::kReg, OperandType::kIdx) \ V(LdaContextSlot, AccumulatorUse::kWrite, OperandType::kReg, \
V(StaContextSlot, OperandType::kReg, OperandType::kIdx) \ OperandType::kIdx) \
V(StaContextSlot, AccumulatorUse::kRead, OperandType::kReg, \
OperandType::kIdx) \
\ \
/* Load-Store lookup slots */ \ /* Load-Store lookup slots */ \
V(LdaLookupSlot, OperandType::kIdx) \ V(LdaLookupSlot, AccumulatorUse::kWrite, OperandType::kIdx) \
V(LdaLookupSlotInsideTypeof, OperandType::kIdx) \ V(LdaLookupSlotInsideTypeof, AccumulatorUse::kWrite, OperandType::kIdx) \
V(StaLookupSlotSloppy, OperandType::kIdx) \ V(StaLookupSlotSloppy, AccumulatorUse::kReadWrite, OperandType::kIdx) \
V(StaLookupSlotStrict, OperandType::kIdx) \ V(StaLookupSlotStrict, AccumulatorUse::kReadWrite, OperandType::kIdx) \
\ \
/* Register-accumulator transfers */ \ /* Register-accumulator transfers */ \
V(Ldar, OperandType::kReg) \ V(Ldar, AccumulatorUse::kWrite, OperandType::kReg) \
V(Star, OperandType::kRegOut) \ V(Star, AccumulatorUse::kRead, OperandType::kRegOut) \
\ \
/* Register-register transfers */ \ /* Register-register transfers */ \
V(Mov, OperandType::kReg, OperandType::kRegOut) \ V(Mov, AccumulatorUse::kNone, OperandType::kReg, OperandType::kRegOut) \
\ \
/* LoadIC operations */ \ /* LoadIC operations */ \
V(LoadIC, OperandType::kReg, OperandType::kIdx, OperandType::kIdx) \ V(LoadIC, AccumulatorUse::kWrite, OperandType::kReg, OperandType::kIdx, \
V(KeyedLoadIC, OperandType::kReg, OperandType::kIdx) \
\
/* StoreIC operations */ \
V(StoreICSloppy, OperandType::kReg, OperandType::kIdx, OperandType::kIdx) \
V(StoreICStrict, OperandType::kReg, OperandType::kIdx, OperandType::kIdx) \
V(KeyedStoreICSloppy, OperandType::kReg, OperandType::kReg, \
OperandType::kIdx) \ OperandType::kIdx) \
V(KeyedStoreICStrict, OperandType::kReg, OperandType::kReg, \ V(KeyedLoadIC, AccumulatorUse::kReadWrite, OperandType::kReg, \
OperandType::kIdx) \ OperandType::kIdx) \
\ \
/* StoreIC operations */ \
V(StoreICSloppy, AccumulatorUse::kRead, OperandType::kReg, \
OperandType::kIdx, OperandType::kIdx) \
V(StoreICStrict, AccumulatorUse::kRead, OperandType::kReg, \
OperandType::kIdx, OperandType::kIdx) \
V(KeyedStoreICSloppy, AccumulatorUse::kRead, OperandType::kReg, \
OperandType::kReg, OperandType::kIdx) \
V(KeyedStoreICStrict, AccumulatorUse::kRead, OperandType::kReg, \
OperandType::kReg, OperandType::kIdx) \
\
/* Binary Operators */ \ /* Binary Operators */ \
V(Add, OperandType::kReg) \ V(Add, AccumulatorUse::kReadWrite, OperandType::kReg) \
V(Sub, OperandType::kReg) \ V(Sub, AccumulatorUse::kReadWrite, OperandType::kReg) \
V(Mul, OperandType::kReg) \ V(Mul, AccumulatorUse::kReadWrite, OperandType::kReg) \
V(Div, OperandType::kReg) \ V(Div, AccumulatorUse::kReadWrite, OperandType::kReg) \
V(Mod, OperandType::kReg) \ V(Mod, AccumulatorUse::kReadWrite, OperandType::kReg) \
V(BitwiseOr, OperandType::kReg) \ V(BitwiseOr, AccumulatorUse::kReadWrite, OperandType::kReg) \
V(BitwiseXor, OperandType::kReg) \ V(BitwiseXor, AccumulatorUse::kReadWrite, OperandType::kReg) \
V(BitwiseAnd, OperandType::kReg) \ V(BitwiseAnd, AccumulatorUse::kReadWrite, OperandType::kReg) \
V(ShiftLeft, OperandType::kReg) \ V(ShiftLeft, AccumulatorUse::kReadWrite, OperandType::kReg) \
V(ShiftRight, OperandType::kReg) \ V(ShiftRight, AccumulatorUse::kReadWrite, OperandType::kReg) \
V(ShiftRightLogical, OperandType::kReg) \ V(ShiftRightLogical, AccumulatorUse::kReadWrite, OperandType::kReg) \
\ \
/* Unary Operators */ \ /* Unary Operators */ \
V(Inc, OperandType::kNone) \ V(Inc, AccumulatorUse::kReadWrite) \
V(Dec, OperandType::kNone) \ V(Dec, AccumulatorUse::kReadWrite) \
V(LogicalNot, OperandType::kNone) \ V(LogicalNot, AccumulatorUse::kReadWrite) \
V(TypeOf, OperandType::kNone) \ V(TypeOf, AccumulatorUse::kReadWrite) \
V(DeletePropertyStrict, OperandType::kReg) \ V(DeletePropertyStrict, AccumulatorUse::kReadWrite, OperandType::kReg) \
V(DeletePropertySloppy, OperandType::kReg) \ V(DeletePropertySloppy, AccumulatorUse::kReadWrite, OperandType::kReg) \
\ \
/* Call operations */ \ /* Call operations */ \
V(Call, OperandType::kReg, OperandType::kReg, OperandType::kRegCount, \ V(Call, AccumulatorUse::kWrite, OperandType::kReg, OperandType::kReg, \
OperandType::kIdx) \ OperandType::kRegCount, OperandType::kIdx) \
V(TailCall, OperandType::kReg, OperandType::kReg, OperandType::kRegCount, \ V(TailCall, AccumulatorUse::kWrite, OperandType::kReg, OperandType::kReg, \
OperandType::kIdx) \ OperandType::kRegCount, OperandType::kIdx) \
V(CallRuntime, OperandType::kRuntimeId, OperandType::kMaybeReg, \ V(CallRuntime, AccumulatorUse::kWrite, OperandType::kRuntimeId, \
OperandType::kRegCount) \ OperandType::kMaybeReg, OperandType::kRegCount) \
V(CallRuntimeForPair, OperandType::kRuntimeId, OperandType::kMaybeReg, \ V(CallRuntimeForPair, AccumulatorUse::kNone, OperandType::kRuntimeId, \
OperandType::kRegCount, OperandType::kRegOutPair) \ OperandType::kMaybeReg, OperandType::kRegCount, OperandType::kRegOutPair) \
V(CallJSRuntime, OperandType::kIdx, OperandType::kReg, \ V(CallJSRuntime, AccumulatorUse::kWrite, OperandType::kIdx, \
OperandType::kRegCount) \ OperandType::kReg, OperandType::kRegCount) \
\ \
/* Intrinsics */ \ /* Intrinsics */ \
V(InvokeIntrinsic, OperandType::kRuntimeId, OperandType::kMaybeReg, \ V(InvokeIntrinsic, AccumulatorUse::kWrite, OperandType::kRuntimeId, \
OperandType::kRegCount) \ OperandType::kMaybeReg, OperandType::kRegCount) \
\ \
/* New operator */ \ /* New operator */ \
V(New, OperandType::kReg, OperandType::kMaybeReg, OperandType::kRegCount) \ V(New, AccumulatorUse::kReadWrite, OperandType::kReg, \
OperandType::kMaybeReg, OperandType::kRegCount) \
\ \
/* Test Operators */ \ /* Test Operators */ \
V(TestEqual, OperandType::kReg) \ V(TestEqual, AccumulatorUse::kReadWrite, OperandType::kReg) \
V(TestNotEqual, OperandType::kReg) \ V(TestNotEqual, AccumulatorUse::kReadWrite, OperandType::kReg) \
V(TestEqualStrict, OperandType::kReg) \ V(TestEqualStrict, AccumulatorUse::kReadWrite, OperandType::kReg) \
V(TestLessThan, OperandType::kReg) \ V(TestLessThan, AccumulatorUse::kReadWrite, OperandType::kReg) \
V(TestGreaterThan, OperandType::kReg) \ V(TestGreaterThan, AccumulatorUse::kReadWrite, OperandType::kReg) \
V(TestLessThanOrEqual, OperandType::kReg) \ V(TestLessThanOrEqual, AccumulatorUse::kReadWrite, OperandType::kReg) \
V(TestGreaterThanOrEqual, OperandType::kReg) \ V(TestGreaterThanOrEqual, AccumulatorUse::kReadWrite, OperandType::kReg) \
V(TestInstanceOf, OperandType::kReg) \ V(TestInstanceOf, AccumulatorUse::kReadWrite, OperandType::kReg) \
V(TestIn, OperandType::kReg) \ V(TestIn, AccumulatorUse::kReadWrite, OperandType::kReg) \
\ \
/* Cast operators */ \ /* Cast operators */ \
V(ToName, OperandType::kNone) \ V(ToName, AccumulatorUse::kReadWrite) \
V(ToNumber, OperandType::kNone) \ V(ToNumber, AccumulatorUse::kReadWrite) \
V(ToObject, OperandType::kNone) \ V(ToObject, AccumulatorUse::kReadWrite) \
\ \
/* Literals */ \ /* Literals */ \
V(CreateRegExpLiteral, OperandType::kIdx, OperandType::kIdx, \ V(CreateRegExpLiteral, AccumulatorUse::kWrite, OperandType::kIdx, \
OperandType::kFlag8) \ OperandType::kIdx, OperandType::kFlag8) \
V(CreateArrayLiteral, OperandType::kIdx, OperandType::kIdx, \ V(CreateArrayLiteral, AccumulatorUse::kWrite, OperandType::kIdx, \
OperandType::kFlag8) \ OperandType::kIdx, OperandType::kFlag8) \
V(CreateObjectLiteral, OperandType::kIdx, OperandType::kIdx, \ V(CreateObjectLiteral, AccumulatorUse::kWrite, OperandType::kIdx, \
OperandType::kFlag8) \ OperandType::kIdx, OperandType::kFlag8) \
\ \
/* Closure allocation */ \ /* Closure allocation */ \
V(CreateClosure, OperandType::kIdx, OperandType::kFlag8) \ V(CreateClosure, AccumulatorUse::kWrite, OperandType::kIdx, \
OperandType::kFlag8) \
\ \
/* Arguments allocation */ \ /* Arguments allocation */ \
V(CreateMappedArguments, OperandType::kNone) \ V(CreateMappedArguments, AccumulatorUse::kWrite) \
V(CreateUnmappedArguments, OperandType::kNone) \ V(CreateUnmappedArguments, AccumulatorUse::kWrite) \
V(CreateRestParameter, OperandType::kNone) \ V(CreateRestParameter, AccumulatorUse::kWrite) \
\ \
/* Control Flow */ \ /* Control Flow */ \
V(Jump, OperandType::kImm) \ V(Jump, AccumulatorUse::kNone, OperandType::kImm) \
V(JumpConstant, OperandType::kIdx) \ V(JumpConstant, AccumulatorUse::kNone, OperandType::kIdx) \
V(JumpIfTrue, OperandType::kImm) \ V(JumpIfTrue, AccumulatorUse::kRead, OperandType::kImm) \
V(JumpIfTrueConstant, OperandType::kIdx) \ V(JumpIfTrueConstant, AccumulatorUse::kRead, OperandType::kIdx) \
V(JumpIfFalse, OperandType::kImm) \ V(JumpIfFalse, AccumulatorUse::kRead, OperandType::kImm) \
V(JumpIfFalseConstant, OperandType::kIdx) \ V(JumpIfFalseConstant, AccumulatorUse::kRead, OperandType::kIdx) \
V(JumpIfToBooleanTrue, OperandType::kImm) \ V(JumpIfToBooleanTrue, AccumulatorUse::kRead, OperandType::kImm) \
V(JumpIfToBooleanTrueConstant, OperandType::kIdx) \ V(JumpIfToBooleanTrueConstant, AccumulatorUse::kRead, OperandType::kIdx) \
V(JumpIfToBooleanFalse, OperandType::kImm) \ V(JumpIfToBooleanFalse, AccumulatorUse::kRead, OperandType::kImm) \
V(JumpIfToBooleanFalseConstant, OperandType::kIdx) \ V(JumpIfToBooleanFalseConstant, AccumulatorUse::kRead, OperandType::kIdx) \
V(JumpIfNull, OperandType::kImm) \ V(JumpIfNull, AccumulatorUse::kRead, OperandType::kImm) \
V(JumpIfNullConstant, OperandType::kIdx) \ V(JumpIfNullConstant, AccumulatorUse::kRead, OperandType::kIdx) \
V(JumpIfUndefined, OperandType::kImm) \ V(JumpIfUndefined, AccumulatorUse::kRead, OperandType::kImm) \
V(JumpIfUndefinedConstant, OperandType::kIdx) \ V(JumpIfUndefinedConstant, AccumulatorUse::kRead, OperandType::kIdx) \
V(JumpIfNotHole, OperandType::kImm) \ V(JumpIfNotHole, AccumulatorUse::kRead, OperandType::kImm) \
V(JumpIfNotHoleConstant, OperandType::kIdx) \ V(JumpIfNotHoleConstant, AccumulatorUse::kRead, OperandType::kIdx) \
\ \
/* Complex flow control For..in */ \ /* Complex flow control For..in */ \
V(ForInPrepare, OperandType::kRegOutTriple) \ V(ForInPrepare, AccumulatorUse::kRead, OperandType::kRegOutTriple) \
V(ForInDone, OperandType::kReg, OperandType::kReg) \ V(ForInDone, AccumulatorUse::kWrite, OperandType::kReg, OperandType::kReg) \
V(ForInNext, OperandType::kReg, OperandType::kReg, OperandType::kRegPair, \ V(ForInNext, AccumulatorUse::kWrite, OperandType::kReg, OperandType::kReg, \
OperandType::kIdx) \ OperandType::kRegPair, OperandType::kIdx) \
V(ForInStep, OperandType::kReg) \ V(ForInStep, AccumulatorUse::kWrite, OperandType::kReg) \
\ \
/* Perform a stack guard check */ \ /* Perform a stack guard check */ \
V(StackCheck, OperandType::kNone) \ V(StackCheck, AccumulatorUse::kNone) \
\ \
/* Non-local flow control */ \ /* Non-local flow control */ \
V(Throw, OperandType::kNone) \ V(Throw, AccumulatorUse::kRead) \
V(ReThrow, OperandType::kNone) \ V(ReThrow, AccumulatorUse::kRead) \
V(Return, OperandType::kNone) \ V(Return, AccumulatorUse::kNone) \
\ \
/* Debugger */ \ /* Debugger */ \
V(Debugger, OperandType::kNone) \ V(Debugger, AccumulatorUse::kNone) \
DEBUG_BREAK_BYTECODE_LIST(V) \ DEBUG_BREAK_BYTECODE_LIST(V) \
\ \
/* Illegal bytecode (terminates execution) */ \ /* Illegal bytecode (terminates execution) */ \
V(Illegal, OperandType::kNone) V(Illegal, AccumulatorUse::kNone)
enum class AccumulatorUse : uint8_t {
kNone = 0,
kRead = 1 << 0,
kWrite = 1 << 1,
kReadWrite = kRead | kWrite
};
V8_INLINE AccumulatorUse operator&(AccumulatorUse lhs, AccumulatorUse rhs) {
int result = static_cast<int>(lhs) & static_cast<int>(rhs);
return static_cast<AccumulatorUse>(result);
}
V8_INLINE AccumulatorUse operator|(AccumulatorUse lhs, AccumulatorUse rhs) {
int result = static_cast<int>(lhs) | static_cast<int>(rhs);
return static_cast<AccumulatorUse>(result);
}
// Enumeration of scaling factors applicable to scalable operands. Code // Enumeration of scaling factors applicable to scalable operands. Code
// relies on being able to cast values to integer scaling values. // relies on being able to cast values to integer scaling values.
...@@ -374,6 +403,9 @@ class Bytecodes { ...@@ -374,6 +403,9 @@ class Bytecodes {
// Returns string representation of |bytecode|. // Returns string representation of |bytecode|.
static std::string ToString(Bytecode bytecode, OperandScale operand_scale); static std::string ToString(Bytecode bytecode, OperandScale operand_scale);
// Returns string representation of |accumulator_use|.
static const char* AccumulatorUseToString(AccumulatorUse accumulator_use);
// Returns string representation of |operand_type|. // Returns string representation of |operand_type|.
static const char* OperandTypeToString(OperandType operand_type); static const char* OperandTypeToString(OperandType operand_type);
...@@ -406,6 +438,15 @@ class Bytecodes { ...@@ -406,6 +438,15 @@ class Bytecodes {
// is a scaling prefix. // is a scaling prefix.
static OperandScale PrefixBytecodeToOperandScale(Bytecode bytecode); static OperandScale PrefixBytecodeToOperandScale(Bytecode bytecode);
// Returns how accumulator is used by |bytecode|.
static AccumulatorUse GetAccumulatorUse(Bytecode bytecode);
// Returns true if |bytecode| reads the accumulator.
static bool ReadsAccumulator(Bytecode bytecode);
// Returns true if |bytecode| writes the accumulator.
static bool WritesAccumulator(Bytecode bytecode);
// Returns the i-th operand of |bytecode|. // Returns the i-th operand of |bytecode|.
static OperandType GetOperandType(Bytecode bytecode, int i); static OperandType GetOperandType(Bytecode bytecode, int i);
...@@ -526,6 +567,7 @@ class Bytecodes { ...@@ -526,6 +567,7 @@ class Bytecodes {
}; };
std::ostream& operator<<(std::ostream& os, const Bytecode& bytecode); std::ostream& operator<<(std::ostream& os, const Bytecode& bytecode);
std::ostream& operator<<(std::ostream& os, const AccumulatorUse& use);
std::ostream& operator<<(std::ostream& os, const OperandScale& operand_scale); std::ostream& operator<<(std::ostream& os, const OperandScale& operand_scale);
std::ostream& operator<<(std::ostream& os, const OperandSize& operand_size); std::ostream& operator<<(std::ostream& os, const OperandSize& operand_size);
std::ostream& operator<<(std::ostream& os, const OperandType& operand_type); std::ostream& operator<<(std::ostream& os, const OperandType& operand_type);
......
...@@ -31,6 +31,7 @@ InterpreterAssembler::InterpreterAssembler(Isolate* isolate, Zone* zone, ...@@ -31,6 +31,7 @@ InterpreterAssembler::InterpreterAssembler(Isolate* isolate, Zone* zone,
bytecode_(bytecode), bytecode_(bytecode),
operand_scale_(operand_scale), operand_scale_(operand_scale),
accumulator_(this, MachineRepresentation::kTagged), accumulator_(this, MachineRepresentation::kTagged),
accumulator_use_(AccumulatorUse::kNone),
context_(this, MachineRepresentation::kTagged), context_(this, MachineRepresentation::kTagged),
bytecode_array_(this, MachineRepresentation::kTagged), bytecode_array_(this, MachineRepresentation::kTagged),
disable_stack_check_across_call_(false), disable_stack_check_across_call_(false),
...@@ -45,11 +46,26 @@ InterpreterAssembler::InterpreterAssembler(Isolate* isolate, Zone* zone, ...@@ -45,11 +46,26 @@ InterpreterAssembler::InterpreterAssembler(Isolate* isolate, Zone* zone,
} }
} }
InterpreterAssembler::~InterpreterAssembler() {} InterpreterAssembler::~InterpreterAssembler() {
// If the following check fails the handler does not use the
// accumulator in the way described in the bytecode definitions in
// bytecodes.h.
DCHECK_EQ(accumulator_use_, Bytecodes::GetAccumulatorUse(bytecode_));
}
Node* InterpreterAssembler::GetAccumulatorUnchecked() {
return accumulator_.value();
}
Node* InterpreterAssembler::GetAccumulator() { return accumulator_.value(); } Node* InterpreterAssembler::GetAccumulator() {
DCHECK(Bytecodes::ReadsAccumulator(bytecode_));
accumulator_use_ = accumulator_use_ | AccumulatorUse::kRead;
return GetAccumulatorUnchecked();
}
void InterpreterAssembler::SetAccumulator(Node* value) { void InterpreterAssembler::SetAccumulator(Node* value) {
DCHECK(Bytecodes::WritesAccumulator(bytecode_));
accumulator_use_ = accumulator_use_ | AccumulatorUse::kWrite;
accumulator_.Bind(value); accumulator_.Bind(value);
} }
...@@ -554,7 +570,7 @@ void InterpreterAssembler::DispatchToBytecodeHandler(Node* handler, ...@@ -554,7 +570,7 @@ void InterpreterAssembler::DispatchToBytecodeHandler(Node* handler,
} }
InterpreterDispatchDescriptor descriptor(isolate()); InterpreterDispatchDescriptor descriptor(isolate());
Node* args[] = {GetAccumulator(), RegisterFileRawPointer(), Node* args[] = {GetAccumulatorUnchecked(), RegisterFileRawPointer(),
bytecode_offset, BytecodeArrayTaggedPointer(), bytecode_offset, BytecodeArrayTaggedPointer(),
DispatchTableRawPointer(), GetContext()}; DispatchTableRawPointer(), GetContext()};
TailCall(descriptor, handler, args, 0); TailCall(descriptor, handler, args, 0);
...@@ -654,7 +670,7 @@ void InterpreterAssembler::AbortIfWordNotEqual(Node* lhs, Node* rhs, ...@@ -654,7 +670,7 @@ void InterpreterAssembler::AbortIfWordNotEqual(Node* lhs, Node* rhs,
void InterpreterAssembler::TraceBytecode(Runtime::FunctionId function_id) { void InterpreterAssembler::TraceBytecode(Runtime::FunctionId function_id) {
CallRuntime(function_id, GetContext(), BytecodeArrayTaggedPointer(), CallRuntime(function_id, GetContext(), BytecodeArrayTaggedPointer(),
SmiTag(BytecodeOffset()), GetAccumulator()); SmiTag(BytecodeOffset()), GetAccumulatorUnchecked());
} }
// static // static
......
...@@ -150,6 +150,7 @@ class InterpreterAssembler : public compiler::CodeStubAssembler { ...@@ -150,6 +150,7 @@ class InterpreterAssembler : public compiler::CodeStubAssembler {
void Abort(BailoutReason bailout_reason); void Abort(BailoutReason bailout_reason);
protected: protected:
Bytecode bytecode() const { return bytecode_; }
static bool TargetSupportsUnalignedAccess(); static bool TargetSupportsUnalignedAccess();
private: private:
...@@ -162,6 +163,11 @@ class InterpreterAssembler : public compiler::CodeStubAssembler { ...@@ -162,6 +163,11 @@ class InterpreterAssembler : public compiler::CodeStubAssembler {
// Returns a raw pointer to first entry in the interpreter dispatch table. // Returns a raw pointer to first entry in the interpreter dispatch table.
compiler::Node* DispatchTableRawPointer(); compiler::Node* DispatchTableRawPointer();
// Returns the accumulator value without checking whether bytecode
// uses it. This is intended to be used only in dispatch and in
// tracing as these need to bypass accumulator use validity checks.
compiler::Node* GetAccumulatorUnchecked();
// Saves and restores interpreter bytecode offset to the interpreter stack // Saves and restores interpreter bytecode offset to the interpreter stack
// frame when performing a call. // frame when performing a call.
void CallPrologue() override; void CallPrologue() override;
...@@ -217,6 +223,7 @@ class InterpreterAssembler : public compiler::CodeStubAssembler { ...@@ -217,6 +223,7 @@ class InterpreterAssembler : public compiler::CodeStubAssembler {
Bytecode bytecode_; Bytecode bytecode_;
OperandScale operand_scale_; OperandScale operand_scale_;
CodeStubAssembler::Variable accumulator_; CodeStubAssembler::Variable accumulator_;
AccumulatorUse accumulator_use_;
CodeStubAssembler::Variable context_; CodeStubAssembler::Variable context_;
CodeStubAssembler::Variable bytecode_array_; CodeStubAssembler::Variable bytecode_array_;
......
...@@ -44,7 +44,8 @@ void AdvanceToOffsetForTracing( ...@@ -44,7 +44,8 @@ void AdvanceToOffsetForTracing(
void PrintRegisters(std::ostream& os, bool is_input, void PrintRegisters(std::ostream& os, bool is_input,
interpreter::BytecodeArrayIterator& bytecode_iterator, interpreter::BytecodeArrayIterator& bytecode_iterator,
Handle<Object> accumulator) { Handle<Object> accumulator) {
static const int kRegFieldWidth = static_cast<int>(strlen("accumulator")); static const char kAccumulator[] = "accumulator";
static const int kRegFieldWidth = static_cast<int>(sizeof(kAccumulator) - 1);
static const char* kInputColourCode = "\033[0;36m"; static const char* kInputColourCode = "\033[0;36m";
static const char* kOutputColourCode = "\033[0;35m"; static const char* kOutputColourCode = "\033[0;35m";
static const char* kNormalColourCode = "\033[0;m"; static const char* kNormalColourCode = "\033[0;m";
...@@ -53,10 +54,15 @@ void PrintRegisters(std::ostream& os, bool is_input, ...@@ -53,10 +54,15 @@ void PrintRegisters(std::ostream& os, bool is_input,
os << (is_input ? kInputColourCode : kOutputColourCode); os << (is_input ? kInputColourCode : kOutputColourCode);
} }
interpreter::Bytecode bytecode = bytecode_iterator.current_bytecode();
// Print accumulator. // Print accumulator.
os << " [ accumulator" << kArrowDirection; if ((is_input && interpreter::Bytecodes::ReadsAccumulator(bytecode)) ||
(!is_input && interpreter::Bytecodes::WritesAccumulator(bytecode))) {
os << " [ " << kAccumulator << kArrowDirection;
accumulator->ShortPrint(); accumulator->ShortPrint();
os << " ]" << std::endl; os << " ]" << std::endl;
}
// Find the location of the register file. // Find the location of the register file.
JavaScriptFrameIterator frame_iterator( JavaScriptFrameIterator frame_iterator(
...@@ -66,7 +72,6 @@ void PrintRegisters(std::ostream& os, bool is_input, ...@@ -66,7 +72,6 @@ void PrintRegisters(std::ostream& os, bool is_input,
frame->fp() + InterpreterFrameConstants::kRegisterFilePointerFromFp; frame->fp() + InterpreterFrameConstants::kRegisterFilePointerFromFp;
// Print the registers. // Print the registers.
interpreter::Bytecode bytecode = bytecode_iterator.current_bytecode();
int operand_count = interpreter::Bytecodes::NumberOfOperands(bytecode); int operand_count = interpreter::Bytecodes::NumberOfOperands(bytecode);
for (int operand_index = 0; operand_index < operand_count; operand_index++) { for (int operand_index = 0; operand_index < operand_count; operand_index++) {
interpreter::OperandType operand_type = interpreter::OperandType operand_type =
......
...@@ -280,6 +280,41 @@ TEST(OperandScale, PrefixesRequired) { ...@@ -280,6 +280,41 @@ TEST(OperandScale, PrefixesRequired) {
Bytecode::kExtraWide); Bytecode::kExtraWide);
} }
TEST(AccumulatorUse, LogicalOperators) {
CHECK_EQ(AccumulatorUse::kNone | AccumulatorUse::kRead,
AccumulatorUse::kRead);
CHECK_EQ(AccumulatorUse::kRead | AccumulatorUse::kWrite,
AccumulatorUse::kReadWrite);
CHECK_EQ(AccumulatorUse::kRead & AccumulatorUse::kReadWrite,
AccumulatorUse::kRead);
CHECK_EQ(AccumulatorUse::kRead & AccumulatorUse::kWrite,
AccumulatorUse::kNone);
}
TEST(AccumulatorUse, SampleBytecodes) {
CHECK(Bytecodes::ReadsAccumulator(Bytecode::kStar));
CHECK(!Bytecodes::WritesAccumulator(Bytecode::kStar));
CHECK_EQ(Bytecodes::GetAccumulatorUse(Bytecode::kStar),
AccumulatorUse::kRead);
CHECK(!Bytecodes::ReadsAccumulator(Bytecode::kLdar));
CHECK(Bytecodes::WritesAccumulator(Bytecode::kLdar));
CHECK_EQ(Bytecodes::GetAccumulatorUse(Bytecode::kLdar),
AccumulatorUse::kWrite);
CHECK(Bytecodes::ReadsAccumulator(Bytecode::kAdd));
CHECK(Bytecodes::WritesAccumulator(Bytecode::kAdd));
CHECK_EQ(Bytecodes::GetAccumulatorUse(Bytecode::kAdd),
AccumulatorUse::kReadWrite);
}
TEST(AccumulatorUse, AccumulatorUseToString) {
std::set<std::string> names;
names.insert(Bytecodes::AccumulatorUseToString(AccumulatorUse::kNone));
names.insert(Bytecodes::AccumulatorUseToString(AccumulatorUse::kRead));
names.insert(Bytecodes::AccumulatorUseToString(AccumulatorUse::kWrite));
names.insert(Bytecodes::AccumulatorUseToString(AccumulatorUse::kReadWrite));
CHECK_EQ(names.size(), 4);
}
} // namespace interpreter } // namespace interpreter
} // namespace internal } // namespace internal
} // namespace v8 } // namespace v8
...@@ -62,6 +62,18 @@ Matcher<Node*> IsWordOr(const Matcher<Node*>& lhs_matcher, ...@@ -62,6 +62,18 @@ Matcher<Node*> IsWordOr(const Matcher<Node*>& lhs_matcher,
: IsWord32Or(lhs_matcher, rhs_matcher); : IsWord32Or(lhs_matcher, rhs_matcher);
} }
InterpreterAssemblerTest::InterpreterAssemblerForTest::
~InterpreterAssemblerForTest() {
// Tests don't necessarily read and write accumulator but
// InterpreterAssembler checks accumulator uses.
if (Bytecodes::ReadsAccumulator(bytecode())) {
GetAccumulator();
}
if (Bytecodes::WritesAccumulator(bytecode())) {
SetAccumulator(nullptr);
}
}
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) {
...@@ -524,12 +536,16 @@ TARGET_TEST_F(InterpreterAssemblerTest, BytecodeOperand) { ...@@ -524,12 +536,16 @@ TARGET_TEST_F(InterpreterAssemblerTest, BytecodeOperand) {
TARGET_TEST_F(InterpreterAssemblerTest, GetSetAccumulator) { TARGET_TEST_F(InterpreterAssemblerTest, GetSetAccumulator) {
TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) { TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) {
if (!interpreter::Bytecodes::ReadsAccumulator(bytecode) ||
!interpreter::Bytecodes::WritesAccumulator(bytecode)) {
continue;
}
InterpreterAssemblerForTest m(this, bytecode); InterpreterAssemblerForTest m(this, bytecode);
// Should be incoming accumulator if not set. // Should be incoming accumulator if not set.
EXPECT_THAT( EXPECT_THAT(
m.GetAccumulator(), m.GetAccumulator(),
IsParameter(InterpreterDispatchDescriptor::kAccumulatorParameter)); IsParameter(InterpreterDispatchDescriptor::kAccumulatorParameter));
// Should be set by SetAccumulator. // Should be set by SetAccumulator.
Node* accumulator_value_1 = m.Int32Constant(0xdeadbeef); Node* accumulator_value_1 = m.Int32Constant(0xdeadbeef);
m.SetAccumulator(accumulator_value_1); m.SetAccumulator(accumulator_value_1);
......
...@@ -28,7 +28,7 @@ class InterpreterAssemblerTest : public TestWithIsolateAndZone { ...@@ -28,7 +28,7 @@ class InterpreterAssemblerTest : public TestWithIsolateAndZone {
OperandScale operand_scale = OperandScale::kSingle) OperandScale operand_scale = OperandScale::kSingle)
: InterpreterAssembler(test->isolate(), test->zone(), bytecode, : InterpreterAssembler(test->isolate(), test->zone(), bytecode,
operand_scale) {} operand_scale) {}
~InterpreterAssemblerForTest() override {} ~InterpreterAssemblerForTest() override;
Matcher<compiler::Node*> IsLoad( Matcher<compiler::Node*> IsLoad(
const Matcher<compiler::LoadRepresentation>& rep_matcher, const Matcher<compiler::LoadRepresentation>& rep_matcher,
......
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