Commit a32a67c7 authored by leszeks's avatar leszeks Committed by Commit bot

[ignition] Optimize jump checks to range checks

Reorders the jump bytecodes so that the majority of jump checks can be
implemented as range checks (rather than a list of comparisons that get
compiled to a bunch of jumps).

Review-Url: https://codereview.chromium.org/2537123002
Cr-Commit-Position: refs/heads/master@{#41498}
parent 0315bfff
......@@ -213,24 +213,33 @@ namespace interpreter {
V(CreateUnmappedArguments, AccumulatorUse::kWrite) \
V(CreateRestParameter, AccumulatorUse::kWrite) \
\
/* Control Flow */ \
/* Control Flow -- carefully ordered for efficient checks */ \
/* - [Unconditional jumps] */ \
V(JumpLoop, AccumulatorUse::kNone, OperandType::kImm, OperandType::kImm) \
/* - [Forward jumps] */ \
V(Jump, AccumulatorUse::kNone, OperandType::kImm) \
/* - [Start constant jumps] */ \
V(JumpConstant, AccumulatorUse::kNone, OperandType::kIdx) \
V(JumpIfTrue, AccumulatorUse::kRead, OperandType::kImm) \
/* - [Conditional jumps] */ \
/* - [Conditional constant jumps] */ \
V(JumpIfNullConstant, AccumulatorUse::kRead, OperandType::kIdx) \
V(JumpIfUndefinedConstant, AccumulatorUse::kRead, OperandType::kIdx) \
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(JumpIfNotHoleConstant, AccumulatorUse::kRead, OperandType::kIdx) \
/* - [Start ToBoolean jumps] */ \
V(JumpIfToBooleanTrueConstant, AccumulatorUse::kRead, OperandType::kIdx) \
V(JumpIfToBooleanFalse, AccumulatorUse::kRead, OperandType::kImm) \
V(JumpIfToBooleanFalseConstant, AccumulatorUse::kRead, OperandType::kIdx) \
/* - [End constant jumps] */ \
/* - [Conditional immediate jumps] */ \
V(JumpIfToBooleanTrue, AccumulatorUse::kRead, OperandType::kImm) \
V(JumpIfToBooleanFalse, AccumulatorUse::kRead, OperandType::kImm) \
/* - [End ToBoolean jumps] */ \
V(JumpIfTrue, AccumulatorUse::kRead, OperandType::kImm) \
V(JumpIfFalse, AccumulatorUse::kRead, OperandType::kImm) \
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) \
V(JumpLoop, AccumulatorUse::kNone, OperandType::kImm, OperandType::kImm) \
\
/* Complex flow control For..in */ \
V(ForInPrepare, AccumulatorUse::kNone, OperandType::kReg, \
......@@ -300,6 +309,67 @@ namespace interpreter {
DEBUG_BREAK_PLAIN_BYTECODE_LIST(V) \
DEBUG_BREAK_PREFIX_BYTECODE_LIST(V)
// Lists of jump bytecodes.
#define JUMP_UNCONDITIONAL_IMMEDIATE_BYTECODE_LIST(V) \
V(JumpLoop) \
V(Jump)
#define JUMP_UNCONDITIONAL_CONSTANT_BYTECODE_LIST(V) V(JumpConstant)
#define JUMP_TOBOOLEAN_CONDITIONAL_IMMEDIATE_BYTECODE_LIST(V) \
V(JumpIfToBooleanTrue) \
V(JumpIfToBooleanFalse)
#define JUMP_TOBOOLEAN_CONDITIONAL_CONSTANT_BYTECODE_LIST(V) \
V(JumpIfToBooleanTrueConstant) \
V(JumpIfToBooleanFalseConstant)
#define JUMP_CONDITIONAL_IMMEDIATE_BYTECODE_LIST(V) \
JUMP_TOBOOLEAN_CONDITIONAL_IMMEDIATE_BYTECODE_LIST(V) \
V(JumpIfTrue) \
V(JumpIfFalse) \
V(JumpIfNull) \
V(JumpIfUndefined) \
V(JumpIfNotHole)
#define JUMP_CONDITIONAL_CONSTANT_BYTECODE_LIST(V) \
JUMP_TOBOOLEAN_CONDITIONAL_CONSTANT_BYTECODE_LIST(V) \
V(JumpIfNullConstant) \
V(JumpIfUndefinedConstant) \
V(JumpIfTrueConstant) \
V(JumpIfFalseConstant) \
V(JumpIfNotHoleConstant)
#define JUMP_CONSTANT_BYTECODE_LIST(V) \
JUMP_UNCONDITIONAL_CONSTANT_BYTECODE_LIST(V) \
JUMP_CONDITIONAL_CONSTANT_BYTECODE_LIST(V)
#define JUMP_IMMEDIATE_BYTECODE_LIST(V) \
JUMP_UNCONDITIONAL_IMMEDIATE_BYTECODE_LIST(V) \
JUMP_CONDITIONAL_IMMEDIATE_BYTECODE_LIST(V)
#define JUMP_TO_BOOLEAN_BYTECODE_LIST(V) \
JUMP_TOBOOLEAN_CONDITIONAL_IMMEDIATE_BYTECODE_LIST(V) \
JUMP_TOBOOLEAN_CONDITIONAL_CONSTANT_BYTECODE_LIST(V)
#define JUMP_UNCONDITIONAL_BYTECODE_LIST(V) \
JUMP_UNCONDITIONAL_IMMEDIATE_BYTECODE_LIST(V) \
JUMP_UNCONDITIONAL_CONSTANT_BYTECODE_LIST(V)
#define JUMP_CONDITIONAL_BYTECODE_LIST(V) \
JUMP_CONDITIONAL_IMMEDIATE_BYTECODE_LIST(V) \
JUMP_CONDITIONAL_CONSTANT_BYTECODE_LIST(V)
#define JUMP_FORWARD_BYTECODE_LIST(V) \
V(Jump) \
V(JumpConstant) \
JUMP_CONDITIONAL_BYTECODE_LIST(V)
#define JUMP_BYTECODE_LIST(V) \
JUMP_FORWARD_BYTECODE_LIST(V) \
V(JumpLoop)
// Enumeration of interpreter bytecodes.
enum class Bytecode : uint8_t {
#define DECLARE_BYTECODE(Name, ...) k##Name,
......@@ -443,38 +513,28 @@ class V8_EXPORT_PRIVATE Bytecodes final {
// Returns true if the bytecode is a conditional jump taking
// an immediate byte operand (OperandType::kImm).
static CONSTEXPR bool IsConditionalJumpImmediate(Bytecode bytecode) {
return bytecode == Bytecode::kJumpIfTrue ||
bytecode == Bytecode::kJumpIfFalse ||
bytecode == Bytecode::kJumpIfToBooleanTrue ||
bytecode == Bytecode::kJumpIfToBooleanFalse ||
bytecode == Bytecode::kJumpIfNotHole ||
bytecode == Bytecode::kJumpIfNull ||
bytecode == Bytecode::kJumpIfUndefined;
return bytecode >= Bytecode::kJumpIfToBooleanTrue &&
bytecode <= Bytecode::kJumpIfNotHole;
}
// Returns true if the bytecode is a conditional jump taking
// a constant pool entry (OperandType::kIdx).
static CONSTEXPR bool IsConditionalJumpConstant(Bytecode bytecode) {
return bytecode == Bytecode::kJumpIfTrueConstant ||
bytecode == Bytecode::kJumpIfFalseConstant ||
bytecode == Bytecode::kJumpIfToBooleanTrueConstant ||
bytecode == Bytecode::kJumpIfToBooleanFalseConstant ||
bytecode == Bytecode::kJumpIfNotHoleConstant ||
bytecode == Bytecode::kJumpIfNullConstant ||
bytecode == Bytecode::kJumpIfUndefinedConstant;
return bytecode >= Bytecode::kJumpIfNullConstant &&
bytecode <= Bytecode::kJumpIfToBooleanFalseConstant;
}
// Returns true if the bytecode is a conditional jump taking
// any kind of operand.
static CONSTEXPR bool IsConditionalJump(Bytecode bytecode) {
return IsConditionalJumpImmediate(bytecode) ||
IsConditionalJumpConstant(bytecode);
return bytecode >= Bytecode::kJumpIfNullConstant &&
bytecode <= Bytecode::kJumpIfNotHole;
}
// Returns true if the bytecode is an unconditional jump.
static CONSTEXPR bool IsUnconditionalJump(Bytecode bytecode) {
return bytecode == Bytecode::kJump || bytecode == Bytecode::kJumpConstant ||
bytecode == Bytecode::kJumpLoop;
return bytecode >= Bytecode::kJumpLoop &&
bytecode <= Bytecode::kJumpConstant;
}
// Returns true if the bytecode is a jump or a conditional jump taking
......@@ -487,29 +547,28 @@ class V8_EXPORT_PRIVATE Bytecodes final {
// Returns true if the bytecode is a jump or conditional jump taking a
// constant pool entry (OperandType::kIdx).
static CONSTEXPR bool IsJumpConstant(Bytecode bytecode) {
return bytecode == Bytecode::kJumpConstant ||
IsConditionalJumpConstant(bytecode);
return bytecode >= Bytecode::kJumpConstant &&
bytecode <= Bytecode::kJumpIfToBooleanFalseConstant;
}
// Returns true if the bytecode is a jump that internally coerces the
// accumulator to a boolean.
static CONSTEXPR bool IsJumpIfToBoolean(Bytecode bytecode) {
return bytecode == Bytecode::kJumpIfToBooleanTrue ||
bytecode == Bytecode::kJumpIfToBooleanFalse ||
bytecode == Bytecode::kJumpIfToBooleanTrueConstant ||
bytecode == Bytecode::kJumpIfToBooleanFalseConstant;
return bytecode >= Bytecode::kJumpIfToBooleanTrueConstant &&
bytecode <= Bytecode::kJumpIfToBooleanFalse;
}
// Returns true if the bytecode is a jump or conditional jump taking
// any kind of operand.
static CONSTEXPR bool IsJump(Bytecode bytecode) {
return IsJumpImmediate(bytecode) || IsJumpConstant(bytecode);
return bytecode >= Bytecode::kJumpLoop &&
bytecode <= Bytecode::kJumpIfNotHole;
}
// Returns true if the bytecode is a forward jump or conditional jump taking
// any kind of operand.
static CONSTEXPR bool IsForwardJump(Bytecode bytecode) {
return bytecode != Bytecode::kJumpLoop && IsJump(bytecode);
return bytecode >= Bytecode::kJump && bytecode <= Bytecode::kJumpIfNotHole;
}
// Returns true if the bytecode is a conditional jump, a jump, or a return.
......
......@@ -200,6 +200,126 @@ TEST(Bytecodes, SizesForUnsignedOperands) {
OperandSize::kQuad);
}
// Helper macros to generate a check for if a bytecode is in a macro list of
// bytecodes. We can use these to exhaustively test a check over all bytecodes,
// both those that should pass and those that should fail the check.
#define OR_IS_BYTECODE(Name, ...) || bytecode == Bytecode::k##Name
#define IN_BYTECODE_LIST(BYTECODE, LIST) \
([](Bytecode bytecode) { return false LIST(OR_IS_BYTECODE); }(BYTECODE))
TEST(Bytecodes, IsJump) {
#define TEST_BYTECODE(Name, ...) \
if (IN_BYTECODE_LIST(Bytecode::k##Name, JUMP_BYTECODE_LIST)) { \
EXPECT_TRUE(Bytecodes::IsJump(Bytecode::k##Name)); \
} else { \
EXPECT_FALSE(Bytecodes::IsJump(Bytecode::k##Name)); \
}
BYTECODE_LIST(TEST_BYTECODE)
#undef TEST_BYTECODE
}
TEST(Bytecodes, IsForwardJump) {
#define TEST_BYTECODE(Name, ...) \
if (IN_BYTECODE_LIST(Bytecode::k##Name, JUMP_FORWARD_BYTECODE_LIST)) { \
EXPECT_TRUE(Bytecodes::IsForwardJump(Bytecode::k##Name)); \
} else { \
EXPECT_FALSE(Bytecodes::IsForwardJump(Bytecode::k##Name)); \
}
BYTECODE_LIST(TEST_BYTECODE)
#undef TEST_BYTECODE
}
TEST(Bytecodes, IsConditionalJump) {
#define TEST_BYTECODE(Name, ...) \
if (IN_BYTECODE_LIST(Bytecode::k##Name, JUMP_CONDITIONAL_BYTECODE_LIST)) { \
EXPECT_TRUE(Bytecodes::IsConditionalJump(Bytecode::k##Name)); \
} else { \
EXPECT_FALSE(Bytecodes::IsConditionalJump(Bytecode::k##Name)); \
}
BYTECODE_LIST(TEST_BYTECODE)
#undef TEST_BYTECODE
}
TEST(Bytecodes, IsUnconditionalJump) {
#define TEST_BYTECODE(Name, ...) \
if (IN_BYTECODE_LIST(Bytecode::k##Name, JUMP_UNCONDITIONAL_BYTECODE_LIST)) { \
EXPECT_TRUE(Bytecodes::IsUnconditionalJump(Bytecode::k##Name)); \
} else { \
EXPECT_FALSE(Bytecodes::IsUnconditionalJump(Bytecode::k##Name)); \
}
BYTECODE_LIST(TEST_BYTECODE)
#undef TEST_BYTECODE
}
TEST(Bytecodes, IsJumpImmediate) {
#define TEST_BYTECODE(Name, ...) \
if (IN_BYTECODE_LIST(Bytecode::k##Name, JUMP_IMMEDIATE_BYTECODE_LIST)) { \
EXPECT_TRUE(Bytecodes::IsJumpImmediate(Bytecode::k##Name)); \
} else { \
EXPECT_FALSE(Bytecodes::IsJumpImmediate(Bytecode::k##Name)); \
}
BYTECODE_LIST(TEST_BYTECODE)
#undef TEST_BYTECODE
}
TEST(Bytecodes, IsJumpConstant) {
#define TEST_BYTECODE(Name, ...) \
if (IN_BYTECODE_LIST(Bytecode::k##Name, JUMP_CONSTANT_BYTECODE_LIST)) { \
EXPECT_TRUE(Bytecodes::IsJumpConstant(Bytecode::k##Name)); \
} else { \
EXPECT_FALSE(Bytecodes::IsJumpConstant(Bytecode::k##Name)); \
}
BYTECODE_LIST(TEST_BYTECODE)
#undef TEST_BYTECODE
}
TEST(Bytecodes, IsConditionalJumpImmediate) {
#define TEST_BYTECODE(Name, ...) \
if (IN_BYTECODE_LIST(Bytecode::k##Name, JUMP_CONDITIONAL_BYTECODE_LIST) && \
IN_BYTECODE_LIST(Bytecode::k##Name, JUMP_IMMEDIATE_BYTECODE_LIST)) { \
EXPECT_TRUE(Bytecodes::IsConditionalJumpImmediate(Bytecode::k##Name)); \
} else { \
EXPECT_FALSE(Bytecodes::IsConditionalJumpImmediate(Bytecode::k##Name)); \
}
BYTECODE_LIST(TEST_BYTECODE)
#undef TEST_BYTECODE
}
TEST(Bytecodes, IsConditionalJumpConstant) {
#define TEST_BYTECODE(Name, ...) \
if (IN_BYTECODE_LIST(Bytecode::k##Name, JUMP_CONDITIONAL_BYTECODE_LIST) && \
IN_BYTECODE_LIST(Bytecode::k##Name, JUMP_CONSTANT_BYTECODE_LIST)) { \
EXPECT_TRUE(Bytecodes::IsConditionalJumpConstant(Bytecode::k##Name)); \
} else { \
EXPECT_FALSE(Bytecodes::IsConditionalJumpConstant(Bytecode::k##Name)); \
}
BYTECODE_LIST(TEST_BYTECODE)
#undef TEST_BYTECODE
}
TEST(Bytecodes, IsJumpIfToBoolean) {
#define TEST_BYTECODE(Name, ...) \
if (IN_BYTECODE_LIST(Bytecode::k##Name, JUMP_TO_BOOLEAN_BYTECODE_LIST)) { \
EXPECT_TRUE(Bytecodes::IsJumpIfToBoolean(Bytecode::k##Name)); \
} else { \
EXPECT_FALSE(Bytecodes::IsJumpIfToBoolean(Bytecode::k##Name)); \
}
BYTECODE_LIST(TEST_BYTECODE)
#undef TEST_BYTECODE
}
#undef OR_IS_BYTECODE
#undef IN_BYTECODE_LIST
TEST(OperandScale, PrefixesRequired) {
CHECK(!Bytecodes::OperandScaleRequiresPrefixBytecode(OperandScale::kSingle));
CHECK(Bytecodes::OperandScaleRequiresPrefixBytecode(OperandScale::kDouble));
......
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