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