summaryrefslogtreecommitdiff
path: root/deps/v8/src/interpreter/bytecodes.cc
diff options
context:
space:
mode:
Diffstat (limited to 'deps/v8/src/interpreter/bytecodes.cc')
-rw-r--r--deps/v8/src/interpreter/bytecodes.cc469
1 files changed, 202 insertions, 267 deletions
diff --git a/deps/v8/src/interpreter/bytecodes.cc b/deps/v8/src/interpreter/bytecodes.cc
index fd27f391aa..09bcd22b92 100644
--- a/deps/v8/src/interpreter/bytecodes.cc
+++ b/deps/v8/src/interpreter/bytecodes.cc
@@ -6,14 +6,15 @@
#include <iomanip>
-#include "src/frames.h"
+#include "src/base/bits.h"
+#include "src/globals.h"
#include "src/interpreter/bytecode-traits.h"
-#include "src/interpreter/interpreter.h"
namespace v8 {
namespace internal {
namespace interpreter {
+STATIC_CONST_MEMBER_DEFINITION const int Bytecodes::kMaxOperands;
// static
const char* Bytecodes::ToString(Bytecode bytecode) {
@@ -74,15 +75,13 @@ const char* Bytecodes::OperandTypeToString(OperandType operand_type) {
// static
const char* Bytecodes::OperandScaleToString(OperandScale operand_scale) {
switch (operand_scale) {
- case OperandScale::kSingle:
- return "Single";
- case OperandScale::kDouble:
- return "Double";
- case OperandScale::kQuadruple:
- return "Quadruple";
- case OperandScale::kInvalid:
- UNREACHABLE();
+#define CASE(Name, _) \
+ case OperandScale::k##Name: \
+ return #Name;
+ OPERAND_SCALE_LIST(CASE)
+#undef CASE
}
+ UNREACHABLE();
return "";
}
@@ -102,14 +101,12 @@ const char* Bytecodes::OperandSizeToString(OperandSize operand_size) {
return "";
}
-
// static
uint8_t Bytecodes::ToByte(Bytecode bytecode) {
- DCHECK(bytecode <= Bytecode::kLast);
+ DCHECK_LE(bytecode, Bytecode::kLast);
return static_cast<uint8_t>(bytecode);
}
-
// static
Bytecode Bytecodes::FromByte(uint8_t value) {
Bytecode bytecode = static_cast<Bytecode>(value);
@@ -117,7 +114,6 @@ Bytecode Bytecodes::FromByte(uint8_t value) {
return bytecode;
}
-
// static
Bytecode Bytecodes::GetDebugBreak(Bytecode bytecode) {
DCHECK(!IsDebugBreak(bytecode));
@@ -150,6 +146,10 @@ int Bytecodes::Size(Bytecode bytecode, OperandScale operand_scale) {
return size;
}
+// static
+size_t Bytecodes::ReturnCount(Bytecode bytecode) {
+ return bytecode == Bytecode::kReturn ? 1 : 0;
+}
// static
int Bytecodes::NumberOfOperands(Bytecode bytecode) {
@@ -165,7 +165,6 @@ int Bytecodes::NumberOfOperands(Bytecode bytecode) {
return 0;
}
-
// static
int Bytecodes::NumberOfRegisterOperands(Bytecode bytecode) {
DCHECK(bytecode <= Bytecode::kLast);
@@ -241,44 +240,122 @@ bool Bytecodes::WritesAccumulator(Bytecode bytecode) {
}
// static
+bool Bytecodes::WritesBooleanToAccumulator(Bytecode bytecode) {
+ switch (bytecode) {
+ case Bytecode::kLdaTrue:
+ case Bytecode::kLdaFalse:
+ case Bytecode::kToBooleanLogicalNot:
+ case Bytecode::kLogicalNot:
+ case Bytecode::kTestEqual:
+ case Bytecode::kTestNotEqual:
+ case Bytecode::kTestEqualStrict:
+ case Bytecode::kTestLessThan:
+ case Bytecode::kTestLessThanOrEqual:
+ case Bytecode::kTestGreaterThan:
+ case Bytecode::kTestGreaterThanOrEqual:
+ case Bytecode::kTestInstanceOf:
+ case Bytecode::kTestIn:
+ case Bytecode::kForInDone:
+ return true;
+ default:
+ return false;
+ }
+}
+
+// static
+bool Bytecodes::IsAccumulatorLoadWithoutEffects(Bytecode bytecode) {
+ switch (bytecode) {
+ case Bytecode::kLdaZero:
+ case Bytecode::kLdaSmi:
+ case Bytecode::kLdaUndefined:
+ case Bytecode::kLdaNull:
+ case Bytecode::kLdaTheHole:
+ case Bytecode::kLdaTrue:
+ case Bytecode::kLdaFalse:
+ case Bytecode::kLdaConstant:
+ case Bytecode::kLdar:
+ return true;
+ default:
+ return false;
+ }
+}
+
+// static
+bool Bytecodes::IsJumpWithoutEffects(Bytecode bytecode) {
+ return IsJump(bytecode) && !IsJumpIfToBoolean(bytecode);
+}
+
+// static
+bool Bytecodes::IsRegisterLoadWithoutEffects(Bytecode bytecode) {
+ switch (bytecode) {
+ case Bytecode::kMov:
+ case Bytecode::kPopContext:
+ case Bytecode::kPushContext:
+ case Bytecode::kStar:
+ case Bytecode::kLdrUndefined:
+ return true;
+ default:
+ return false;
+ }
+}
+
+// static
+bool Bytecodes::IsWithoutExternalSideEffects(Bytecode bytecode) {
+ // These bytecodes only manipulate interpreter frame state and will
+ // never throw.
+ return (IsAccumulatorLoadWithoutEffects(bytecode) ||
+ IsRegisterLoadWithoutEffects(bytecode) ||
+ bytecode == Bytecode::kNop || IsJumpWithoutEffects(bytecode));
+}
+
+// static
OperandType Bytecodes::GetOperandType(Bytecode bytecode, int i) {
+ DCHECK_LE(bytecode, Bytecode::kLast);
+ DCHECK_LT(i, NumberOfOperands(bytecode));
+ DCHECK_GE(i, 0);
+ return GetOperandTypes(bytecode)[i];
+}
+
+// static
+const OperandType* Bytecodes::GetOperandTypes(Bytecode bytecode) {
DCHECK(bytecode <= Bytecode::kLast);
switch (bytecode) {
#define CASE(Name, ...) \
case Bytecode::k##Name: \
- return BytecodeTraits<__VA_ARGS__>::GetOperandType(i);
+ return BytecodeTraits<__VA_ARGS__>::GetOperandTypes();
BYTECODE_LIST(CASE)
#undef CASE
}
UNREACHABLE();
- return OperandType::kNone;
-}
-
-// static
-OperandSize Bytecodes::GetOperandSize(Bytecode bytecode, int i,
- OperandScale operand_scale) {
- OperandType op_type = GetOperandType(bytecode, i);
- return ScaledOperandSize(op_type, operand_scale);
+ return nullptr;
}
// static
-int Bytecodes::GetRegisterOperandBitmap(Bytecode bytecode) {
+const OperandTypeInfo* Bytecodes::GetOperandTypeInfos(Bytecode bytecode) {
DCHECK(bytecode <= Bytecode::kLast);
switch (bytecode) {
-#define CASE(Name, ...) \
- case Bytecode::k##Name: \
- typedef BytecodeTraits<__VA_ARGS__> Name##Trait; \
- return Name##Trait::kRegisterOperandBitmap;
+#define CASE(Name, ...) \
+ case Bytecode::k##Name: \
+ return BytecodeTraits<__VA_ARGS__>::GetOperandTypeInfos();
BYTECODE_LIST(CASE)
#undef CASE
}
UNREACHABLE();
- return false;
+ return nullptr;
+}
+
+// static
+OperandSize Bytecodes::GetOperandSize(Bytecode bytecode, int i,
+ OperandScale operand_scale) {
+ DCHECK_LT(i, NumberOfOperands(bytecode));
+ OperandType operand_type = GetOperandType(bytecode, i);
+ return SizeOfOperand(operand_type, operand_scale);
}
// static
int Bytecodes::GetOperandOffset(Bytecode bytecode, int i,
OperandScale operand_scale) {
+ DCHECK_LT(i, Bytecodes::NumberOfOperands(bytecode));
// TODO(oth): restore this to a statically determined constant.
int offset = 1;
for (int operand_index = 0; operand_index < i; ++operand_index) {
@@ -307,7 +384,6 @@ bool Bytecodes::IsConditionalJumpImmediate(Bytecode bytecode) {
bytecode == Bytecode::kJumpIfUndefined;
}
-
// static
bool Bytecodes::IsConditionalJumpConstant(Bytecode bytecode) {
return bytecode == Bytecode::kJumpIfTrueConstant ||
@@ -343,6 +419,31 @@ bool Bytecodes::IsJump(Bytecode bytecode) {
return IsJumpImmediate(bytecode) || IsJumpConstant(bytecode);
}
+// static
+bool Bytecodes::IsJumpIfToBoolean(Bytecode bytecode) {
+ return bytecode == Bytecode::kJumpIfToBooleanTrue ||
+ bytecode == Bytecode::kJumpIfToBooleanFalse ||
+ bytecode == Bytecode::kJumpIfToBooleanTrueConstant ||
+ bytecode == Bytecode::kJumpIfToBooleanFalseConstant;
+}
+
+// static
+Bytecode Bytecodes::GetJumpWithoutToBoolean(Bytecode bytecode) {
+ switch (bytecode) {
+ case Bytecode::kJumpIfToBooleanTrue:
+ return Bytecode::kJumpIfTrue;
+ case Bytecode::kJumpIfToBooleanFalse:
+ return Bytecode::kJumpIfFalse;
+ case Bytecode::kJumpIfToBooleanTrueConstant:
+ return Bytecode::kJumpIfTrueConstant;
+ case Bytecode::kJumpIfToBooleanFalseConstant:
+ return Bytecode::kJumpIfFalseConstant;
+ default:
+ break;
+ }
+ UNREACHABLE();
+ return Bytecode::kIllegal;
+}
// static
bool Bytecodes::IsCallOrNew(Bytecode bytecode) {
@@ -371,6 +472,11 @@ bool Bytecodes::IsDebugBreak(Bytecode bytecode) {
}
// static
+bool Bytecodes::IsLdarOrStar(Bytecode bytecode) {
+ return bytecode == Bytecode::kLdar || bytecode == Bytecode::kStar;
+}
+
+// static
bool Bytecodes::IsBytecodeWithScalableOperands(Bytecode bytecode) {
switch (bytecode) {
#define CASE(Name, ...) \
@@ -398,6 +504,11 @@ bool Bytecodes::IsPrefixScalingBytecode(Bytecode bytecode) {
}
// static
+bool Bytecodes::PutsNameInAccumulator(Bytecode bytecode) {
+ return bytecode == Bytecode::kTypeOf;
+}
+
+// static
bool Bytecodes::IsJumpOrReturn(Bytecode bytecode) {
return bytecode == Bytecode::kReturn || IsJump(bytecode);
}
@@ -461,160 +572,83 @@ bool Bytecodes::IsRegisterOutputOperandType(OperandType operand_type) {
}
// static
-bool Bytecodes::IsUnsignedOperandType(OperandType operand_type) {
- switch (operand_type) {
-#define CASE(Name, _) \
- case OperandType::k##Name: \
- return OperandTraits<OperandType::k##Name>::TypeInfo::kIsUnsigned;
- OPERAND_TYPE_LIST(CASE)
-#undef CASE
+bool Bytecodes::IsStarLookahead(Bytecode bytecode, OperandScale operand_scale) {
+ if (operand_scale == OperandScale::kSingle) {
+ switch (bytecode) {
+ case Bytecode::kLdaZero:
+ case Bytecode::kLdaSmi:
+ case Bytecode::kLdaNull:
+ case Bytecode::kLdaTheHole:
+ case Bytecode::kLdaConstant:
+ case Bytecode::kAdd:
+ case Bytecode::kSub:
+ case Bytecode::kMul:
+ case Bytecode::kAddSmi:
+ case Bytecode::kSubSmi:
+ case Bytecode::kInc:
+ case Bytecode::kDec:
+ case Bytecode::kTypeOf:
+ case Bytecode::kCall:
+ case Bytecode::kNew:
+ return true;
+ default:
+ return false;
+ }
}
- UNREACHABLE();
return false;
}
// static
-OperandScale Bytecodes::NextOperandScale(OperandScale operand_scale) {
- DCHECK(operand_scale >= OperandScale::kSingle &&
- operand_scale <= OperandScale::kMaxValid);
- return static_cast<OperandScale>(2 * static_cast<int>(operand_scale));
-}
-
-// static
-Register Bytecodes::DecodeRegisterOperand(const uint8_t* operand_start,
- OperandType operand_type,
- OperandScale operand_scale) {
- DCHECK(Bytecodes::IsRegisterOperandType(operand_type));
- int32_t operand =
- DecodeSignedOperand(operand_start, operand_type, operand_scale);
- return Register::FromOperand(operand);
+int Bytecodes::GetNumberOfRegistersRepresentedBy(OperandType operand_type) {
+ switch (operand_type) {
+ case OperandType::kMaybeReg:
+ case OperandType::kReg:
+ case OperandType::kRegOut:
+ return 1;
+ case OperandType::kRegPair:
+ case OperandType::kRegOutPair:
+ return 2;
+ case OperandType::kRegOutTriple:
+ return 3;
+ default:
+ return 0;
+ }
+ return 0;
}
// static
-int32_t Bytecodes::DecodeSignedOperand(const uint8_t* operand_start,
- OperandType operand_type,
- OperandScale operand_scale) {
- DCHECK(!Bytecodes::IsUnsignedOperandType(operand_type));
- switch (Bytecodes::SizeOfOperand(operand_type, operand_scale)) {
- case OperandSize::kByte:
- return static_cast<int8_t>(*operand_start);
- case OperandSize::kShort:
- return static_cast<int16_t>(ReadUnalignedUInt16(operand_start));
- case OperandSize::kQuad:
- return static_cast<int32_t>(ReadUnalignedUInt32(operand_start));
- case OperandSize::kNone:
- UNREACHABLE();
+bool Bytecodes::IsUnsignedOperandType(OperandType operand_type) {
+ switch (operand_type) {
+#define CASE(Name, _) \
+ case OperandType::k##Name: \
+ return OperandTraits<OperandType::k##Name>::TypeInfoTraits::kIsUnsigned;
+ OPERAND_TYPE_LIST(CASE)
+#undef CASE
}
- return 0;
+ UNREACHABLE();
+ return false;
}
// static
-uint32_t Bytecodes::DecodeUnsignedOperand(const uint8_t* operand_start,
- OperandType operand_type,
- OperandScale operand_scale) {
- DCHECK(Bytecodes::IsUnsignedOperandType(operand_type));
- switch (Bytecodes::SizeOfOperand(operand_type, operand_scale)) {
- case OperandSize::kByte:
- return *operand_start;
- case OperandSize::kShort:
- return ReadUnalignedUInt16(operand_start);
- case OperandSize::kQuad:
- return ReadUnalignedUInt32(operand_start);
- case OperandSize::kNone:
- UNREACHABLE();
+OperandSize Bytecodes::SizeForSignedOperand(int value) {
+ if (value >= kMinInt8 && value <= kMaxInt8) {
+ return OperandSize::kByte;
+ } else if (value >= kMinInt16 && value <= kMaxInt16) {
+ return OperandSize::kShort;
+ } else {
+ return OperandSize::kQuad;
}
- return 0;
}
// static
-std::ostream& Bytecodes::Decode(std::ostream& os, const uint8_t* bytecode_start,
- int parameter_count) {
- Bytecode bytecode = Bytecodes::FromByte(bytecode_start[0]);
- int prefix_offset = 0;
- OperandScale operand_scale = OperandScale::kSingle;
- if (IsPrefixScalingBytecode(bytecode)) {
- prefix_offset = 1;
- operand_scale = Bytecodes::PrefixBytecodeToOperandScale(bytecode);
- bytecode = Bytecodes::FromByte(bytecode_start[1]);
- }
-
- // Prepare to print bytecode and operands as hex digits.
- std::ios saved_format(nullptr);
- saved_format.copyfmt(saved_format);
- os.fill('0');
- os.flags(std::ios::hex);
-
- int bytecode_size = Bytecodes::Size(bytecode, operand_scale);
- for (int i = 0; i < prefix_offset + bytecode_size; i++) {
- os << std::setw(2) << static_cast<uint32_t>(bytecode_start[i]) << ' ';
- }
- os.copyfmt(saved_format);
-
- const int kBytecodeColumnSize = 6;
- for (int i = prefix_offset + bytecode_size; i < kBytecodeColumnSize; i++) {
- os << " ";
- }
-
- os << Bytecodes::ToString(bytecode, operand_scale) << " ";
-
- // Operands for the debug break are from the original instruction.
- if (IsDebugBreak(bytecode)) return os;
-
- int number_of_operands = NumberOfOperands(bytecode);
- int range = 0;
- for (int i = 0; i < number_of_operands; i++) {
- OperandType op_type = GetOperandType(bytecode, i);
- const uint8_t* operand_start =
- &bytecode_start[prefix_offset +
- GetOperandOffset(bytecode, i, operand_scale)];
- switch (op_type) {
- case interpreter::OperandType::kRegCount:
- os << "#"
- << DecodeUnsignedOperand(operand_start, op_type, operand_scale);
- break;
- case interpreter::OperandType::kIdx:
- case interpreter::OperandType::kRuntimeId:
- os << "["
- << DecodeUnsignedOperand(operand_start, op_type, operand_scale)
- << "]";
- break;
- case interpreter::OperandType::kImm:
- os << "[" << DecodeSignedOperand(operand_start, op_type, operand_scale)
- << "]";
- break;
- case interpreter::OperandType::kFlag8:
- os << "#"
- << DecodeUnsignedOperand(operand_start, op_type, operand_scale);
- break;
- case interpreter::OperandType::kMaybeReg:
- case interpreter::OperandType::kReg:
- case interpreter::OperandType::kRegOut: {
- Register reg =
- DecodeRegisterOperand(operand_start, op_type, operand_scale);
- os << reg.ToString(parameter_count);
- break;
- }
- case interpreter::OperandType::kRegOutTriple:
- range += 1;
- case interpreter::OperandType::kRegOutPair:
- case interpreter::OperandType::kRegPair: {
- range += 1;
- Register first_reg =
- DecodeRegisterOperand(operand_start, op_type, operand_scale);
- Register last_reg = Register(first_reg.index() + range);
- os << first_reg.ToString(parameter_count) << "-"
- << last_reg.ToString(parameter_count);
- break;
- }
- case interpreter::OperandType::kNone:
- UNREACHABLE();
- break;
- }
- if (i != number_of_operands - 1) {
- os << ", ";
- }
+OperandSize Bytecodes::SizeForUnsignedOperand(uint32_t value) {
+ if (value <= kMaxUInt8) {
+ return OperandSize::kByte;
+ } else if (value <= kMaxUInt16) {
+ return OperandSize::kShort;
+ } else {
+ return OperandSize::kQuad;
}
- return os;
}
// static
@@ -644,105 +678,6 @@ std::ostream& operator<<(std::ostream& os, const OperandType& operand_type) {
return os << Bytecodes::OperandTypeToString(operand_type);
}
-static const int kLastParamRegisterIndex =
- -InterpreterFrameConstants::kLastParamFromRegisterPointer / kPointerSize;
-static const int kFunctionClosureRegisterIndex =
- -InterpreterFrameConstants::kFunctionFromRegisterPointer / kPointerSize;
-static const int kCurrentContextRegisterIndex =
- -InterpreterFrameConstants::kContextFromRegisterPointer / kPointerSize;
-static const int kNewTargetRegisterIndex =
- -InterpreterFrameConstants::kNewTargetFromRegisterPointer / kPointerSize;
-
-bool Register::is_byte_operand() const {
- return index_ >= -kMaxInt8 && index_ <= -kMinInt8;
-}
-
-bool Register::is_short_operand() const {
- return index_ >= -kMaxInt16 && index_ <= -kMinInt16;
-}
-
-Register Register::FromParameterIndex(int index, int parameter_count) {
- DCHECK_GE(index, 0);
- DCHECK_LT(index, parameter_count);
- int register_index = kLastParamRegisterIndex - parameter_count + index + 1;
- DCHECK_LT(register_index, 0);
- return Register(register_index);
-}
-
-
-int Register::ToParameterIndex(int parameter_count) const {
- DCHECK(is_parameter());
- return index() - kLastParamRegisterIndex + parameter_count - 1;
-}
-
-
-Register Register::function_closure() {
- return Register(kFunctionClosureRegisterIndex);
-}
-
-
-bool Register::is_function_closure() const {
- return index() == kFunctionClosureRegisterIndex;
-}
-
-
-Register Register::current_context() {
- return Register(kCurrentContextRegisterIndex);
-}
-
-
-bool Register::is_current_context() const {
- return index() == kCurrentContextRegisterIndex;
-}
-
-
-Register Register::new_target() { return Register(kNewTargetRegisterIndex); }
-
-
-bool Register::is_new_target() const {
- return index() == kNewTargetRegisterIndex;
-}
-
-bool Register::AreContiguous(Register reg1, Register reg2, Register reg3,
- Register reg4, Register reg5) {
- if (reg1.index() + 1 != reg2.index()) {
- return false;
- }
- if (reg3.is_valid() && reg2.index() + 1 != reg3.index()) {
- return false;
- }
- if (reg4.is_valid() && reg3.index() + 1 != reg4.index()) {
- return false;
- }
- if (reg5.is_valid() && reg4.index() + 1 != reg5.index()) {
- return false;
- }
- return true;
-}
-
-std::string Register::ToString(int parameter_count) {
- if (is_current_context()) {
- return std::string("<context>");
- } else if (is_function_closure()) {
- return std::string("<closure>");
- } else if (is_new_target()) {
- return std::string("<new.target>");
- } else if (is_parameter()) {
- int parameter_index = ToParameterIndex(parameter_count);
- if (parameter_index == 0) {
- return std::string("<this>");
- } else {
- std::ostringstream s;
- s << "a" << parameter_index - 1;
- return s.str();
- }
- } else {
- std::ostringstream s;
- s << "r" << index();
- return s.str();
- }
-}
-
} // namespace interpreter
} // namespace internal
} // namespace v8