2015-07-23 14:21:26 +00:00
|
|
|
// Copyright 2015 the V8 project authors. All rights reserved.
|
|
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
|
|
// found in the LICENSE file.
|
|
|
|
|
|
|
|
#include "src/interpreter/bytecodes.h"
|
|
|
|
|
2016-03-24 10:31:20 +00:00
|
|
|
#include <iomanip>
|
|
|
|
|
2016-06-10 10:34:50 +00:00
|
|
|
#include "src/base/bits.h"
|
2016-09-22 05:53:14 +00:00
|
|
|
#include "src/globals.h"
|
2015-10-01 17:22:58 +00:00
|
|
|
#include "src/interpreter/bytecode-traits.h"
|
2015-08-13 11:27:54 +00:00
|
|
|
|
2015-07-23 14:21:26 +00:00
|
|
|
namespace v8 {
|
|
|
|
namespace internal {
|
|
|
|
namespace interpreter {
|
|
|
|
|
2016-09-22 05:53:14 +00:00
|
|
|
STATIC_CONST_MEMBER_DEFINITION const int Bytecodes::kMaxOperands;
|
2015-07-30 13:56:47 +00:00
|
|
|
|
2015-07-23 14:21:26 +00:00
|
|
|
// static
|
|
|
|
const char* Bytecodes::ToString(Bytecode bytecode) {
|
|
|
|
switch (bytecode) {
|
2015-07-30 13:56:47 +00:00
|
|
|
#define CASE(Name, ...) \
|
|
|
|
case Bytecode::k##Name: \
|
|
|
|
return #Name;
|
2015-07-23 14:21:26 +00:00
|
|
|
BYTECODE_LIST(CASE)
|
|
|
|
#undef CASE
|
|
|
|
}
|
|
|
|
UNREACHABLE();
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
|
2016-03-21 17:08:21 +00:00
|
|
|
// static
|
|
|
|
std::string Bytecodes::ToString(Bytecode bytecode, OperandScale operand_scale) {
|
|
|
|
static const char kSeparator = '.';
|
|
|
|
|
|
|
|
std::string value(ToString(bytecode));
|
|
|
|
if (operand_scale > OperandScale::kSingle) {
|
|
|
|
Bytecode prefix_bytecode = OperandScaleToPrefixBytecode(operand_scale);
|
|
|
|
std::string suffix = ToString(prefix_bytecode);
|
|
|
|
return value.append(1, kSeparator).append(suffix);
|
|
|
|
} else {
|
|
|
|
return value;
|
|
|
|
}
|
|
|
|
}
|
2015-07-23 14:21:26 +00:00
|
|
|
|
2016-09-22 05:53:14 +00:00
|
|
|
// 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) {
|
|
|
|
#define CASE(Name, _) \
|
|
|
|
case OperandType::k##Name: \
|
|
|
|
return #Name;
|
|
|
|
OPERAND_TYPE_LIST(CASE)
|
|
|
|
#undef CASE
|
|
|
|
}
|
|
|
|
UNREACHABLE();
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
|
|
|
|
// static
|
|
|
|
const char* Bytecodes::OperandScaleToString(OperandScale operand_scale) {
|
|
|
|
switch (operand_scale) {
|
|
|
|
#define CASE(Name, _) \
|
|
|
|
case OperandScale::k##Name: \
|
|
|
|
return #Name;
|
|
|
|
OPERAND_SCALE_LIST(CASE)
|
|
|
|
#undef CASE
|
|
|
|
}
|
|
|
|
UNREACHABLE();
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
|
|
|
|
// static
|
|
|
|
const char* Bytecodes::OperandSizeToString(OperandSize operand_size) {
|
|
|
|
switch (operand_size) {
|
|
|
|
case OperandSize::kNone:
|
|
|
|
return "None";
|
|
|
|
case OperandSize::kByte:
|
|
|
|
return "Byte";
|
|
|
|
case OperandSize::kShort:
|
|
|
|
return "Short";
|
|
|
|
case OperandSize::kQuad:
|
|
|
|
return "Quad";
|
|
|
|
}
|
|
|
|
UNREACHABLE();
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
|
|
|
|
// static
|
|
|
|
uint8_t Bytecodes::ToByte(Bytecode bytecode) {
|
|
|
|
DCHECK_LE(bytecode, Bytecode::kLast);
|
|
|
|
return static_cast<uint8_t>(bytecode);
|
|
|
|
}
|
|
|
|
|
|
|
|
// static
|
|
|
|
Bytecode Bytecodes::FromByte(uint8_t value) {
|
|
|
|
Bytecode bytecode = static_cast<Bytecode>(value);
|
|
|
|
DCHECK(bytecode <= Bytecode::kLast);
|
|
|
|
return bytecode;
|
|
|
|
}
|
|
|
|
|
2016-02-22 13:16:46 +00:00
|
|
|
// static
|
|
|
|
Bytecode Bytecodes::GetDebugBreak(Bytecode bytecode) {
|
2016-03-21 17:08:21 +00:00
|
|
|
DCHECK(!IsDebugBreak(bytecode));
|
|
|
|
if (bytecode == Bytecode::kWide) {
|
|
|
|
return Bytecode::kDebugBreakWide;
|
|
|
|
}
|
|
|
|
if (bytecode == Bytecode::kExtraWide) {
|
|
|
|
return Bytecode::kDebugBreakExtraWide;
|
2016-02-22 13:16:46 +00:00
|
|
|
}
|
2016-03-21 17:08:21 +00:00
|
|
|
int bytecode_size = Size(bytecode, OperandScale::kSingle);
|
2016-09-22 05:53:14 +00:00
|
|
|
#define RETURN_IF_DEBUG_BREAK_SIZE_MATCHES(Name, ...) \
|
2016-03-21 17:08:21 +00:00
|
|
|
if (bytecode_size == Size(Bytecode::k##Name, OperandScale::kSingle)) { \
|
|
|
|
return Bytecode::k##Name; \
|
|
|
|
}
|
|
|
|
DEBUG_BREAK_PLAIN_BYTECODE_LIST(RETURN_IF_DEBUG_BREAK_SIZE_MATCHES)
|
|
|
|
#undef RETURN_IF_DEBUG_BREAK_SIZE_MATCHES
|
2016-02-22 13:16:46 +00:00
|
|
|
UNREACHABLE();
|
2016-03-21 17:08:21 +00:00
|
|
|
return Bytecode::kIllegal;
|
2016-02-22 13:16:46 +00:00
|
|
|
}
|
|
|
|
|
2016-09-22 05:53:14 +00:00
|
|
|
// static
|
|
|
|
int Bytecodes::Size(Bytecode bytecode, OperandScale operand_scale) {
|
|
|
|
int size = 1;
|
|
|
|
for (int i = 0; i < NumberOfOperands(bytecode); i++) {
|
|
|
|
OperandSize operand_size = GetOperandSize(bytecode, i, operand_scale);
|
|
|
|
int delta = static_cast<int>(operand_size);
|
|
|
|
DCHECK(base::bits::IsPowerOfTwo32(static_cast<uint32_t>(delta)));
|
|
|
|
size += delta;
|
|
|
|
}
|
|
|
|
return size;
|
|
|
|
}
|
|
|
|
|
|
|
|
// static
|
|
|
|
size_t Bytecodes::ReturnCount(Bytecode bytecode) {
|
|
|
|
return bytecode == Bytecode::kReturn ? 1 : 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// static
|
|
|
|
int Bytecodes::NumberOfOperands(Bytecode bytecode) {
|
|
|
|
DCHECK(bytecode <= Bytecode::kLast);
|
|
|
|
switch (bytecode) {
|
|
|
|
#define CASE(Name, ...) \
|
|
|
|
case Bytecode::k##Name: \
|
|
|
|
return BytecodeTraits<__VA_ARGS__>::kOperandCount;
|
|
|
|
BYTECODE_LIST(CASE)
|
|
|
|
#undef CASE
|
|
|
|
}
|
|
|
|
UNREACHABLE();
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// static
|
|
|
|
int Bytecodes::NumberOfRegisterOperands(Bytecode bytecode) {
|
|
|
|
DCHECK(bytecode <= Bytecode::kLast);
|
|
|
|
switch (bytecode) {
|
|
|
|
#define CASE(Name, ...) \
|
|
|
|
case Bytecode::k##Name: \
|
|
|
|
typedef BytecodeTraits<__VA_ARGS__> Name##Trait; \
|
|
|
|
return Name##Trait::kRegisterOperandCount;
|
|
|
|
BYTECODE_LIST(CASE)
|
|
|
|
#undef CASE
|
|
|
|
}
|
|
|
|
UNREACHABLE();
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// static
|
|
|
|
Bytecode Bytecodes::OperandScaleToPrefixBytecode(OperandScale operand_scale) {
|
|
|
|
switch (operand_scale) {
|
|
|
|
case OperandScale::kQuadruple:
|
|
|
|
return Bytecode::kExtraWide;
|
|
|
|
case OperandScale::kDouble:
|
|
|
|
return Bytecode::kWide;
|
|
|
|
default:
|
|
|
|
UNREACHABLE();
|
|
|
|
return Bytecode::kIllegal;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// static
|
|
|
|
bool Bytecodes::OperandScaleRequiresPrefixBytecode(OperandScale operand_scale) {
|
|
|
|
return operand_scale != OperandScale::kSingle;
|
|
|
|
}
|
|
|
|
|
|
|
|
// static
|
|
|
|
OperandScale Bytecodes::PrefixBytecodeToOperandScale(Bytecode bytecode) {
|
|
|
|
switch (bytecode) {
|
|
|
|
case Bytecode::kExtraWide:
|
|
|
|
case Bytecode::kDebugBreakExtraWide:
|
|
|
|
return OperandScale::kQuadruple;
|
|
|
|
case Bytecode::kWide:
|
|
|
|
case Bytecode::kDebugBreakWide:
|
|
|
|
return OperandScale::kDouble;
|
|
|
|
default:
|
|
|
|
UNREACHABLE();
|
|
|
|
return OperandScale::kSingle;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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
|
|
|
|
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::kForInContinue:
|
|
|
|
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_LE(bytecode, Bytecode::kLast);
|
|
|
|
switch (bytecode) {
|
|
|
|
#define CASE(Name, ...) \
|
|
|
|
case Bytecode::k##Name: \
|
|
|
|
return BytecodeTraits<__VA_ARGS__>::GetOperandTypes();
|
|
|
|
BYTECODE_LIST(CASE)
|
|
|
|
#undef CASE
|
|
|
|
}
|
|
|
|
UNREACHABLE();
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
// static
|
|
|
|
const OperandTypeInfo* Bytecodes::GetOperandTypeInfos(Bytecode bytecode) {
|
|
|
|
DCHECK(bytecode <= Bytecode::kLast);
|
|
|
|
switch (bytecode) {
|
|
|
|
#define CASE(Name, ...) \
|
|
|
|
case Bytecode::k##Name: \
|
|
|
|
return BytecodeTraits<__VA_ARGS__>::GetOperandTypeInfos();
|
|
|
|
BYTECODE_LIST(CASE)
|
|
|
|
#undef CASE
|
|
|
|
}
|
|
|
|
UNREACHABLE();
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2015-07-30 13:56:47 +00:00
|
|
|
// static
|
2016-03-21 17:08:21 +00:00
|
|
|
int Bytecodes::GetOperandOffset(Bytecode bytecode, int i,
|
|
|
|
OperandScale operand_scale) {
|
2016-05-12 19:18:07 +00:00
|
|
|
DCHECK_LT(i, Bytecodes::NumberOfOperands(bytecode));
|
2016-03-21 17:08:21 +00:00
|
|
|
// TODO(oth): restore this to a statically determined constant.
|
|
|
|
int offset = 1;
|
|
|
|
for (int operand_index = 0; operand_index < i; ++operand_index) {
|
|
|
|
OperandSize operand_size =
|
|
|
|
GetOperandSize(bytecode, operand_index, operand_scale);
|
|
|
|
offset += static_cast<int>(operand_size);
|
2015-10-01 17:22:58 +00:00
|
|
|
}
|
2016-03-21 17:08:21 +00:00
|
|
|
return offset;
|
2015-10-01 17:22:58 +00:00
|
|
|
}
|
2015-07-30 13:56:47 +00:00
|
|
|
|
2016-09-22 05:53:14 +00:00
|
|
|
// static
|
|
|
|
OperandSize Bytecodes::SizeOfOperand(OperandType operand_type,
|
|
|
|
OperandScale operand_scale) {
|
|
|
|
DCHECK_LE(operand_type, OperandType::kLast);
|
|
|
|
DCHECK_GE(operand_scale, OperandScale::kSingle);
|
|
|
|
DCHECK_LE(operand_scale, OperandScale::kLast);
|
|
|
|
return static_cast<OperandSize>(
|
|
|
|
ScaledOperandSize(operand_type, operand_scale));
|
|
|
|
}
|
|
|
|
|
|
|
|
// static
|
|
|
|
bool Bytecodes::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;
|
|
|
|
}
|
|
|
|
|
|
|
|
// static
|
|
|
|
bool Bytecodes::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;
|
|
|
|
}
|
|
|
|
|
|
|
|
// static
|
|
|
|
bool Bytecodes::IsConditionalJump(Bytecode bytecode) {
|
|
|
|
return IsConditionalJumpImmediate(bytecode) ||
|
|
|
|
IsConditionalJumpConstant(bytecode);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// static
|
|
|
|
bool Bytecodes::IsJumpImmediate(Bytecode bytecode) {
|
|
|
|
return bytecode == Bytecode::kJump || bytecode == Bytecode::kJumpLoop ||
|
|
|
|
IsConditionalJumpImmediate(bytecode);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// static
|
|
|
|
bool Bytecodes::IsJumpConstant(Bytecode bytecode) {
|
|
|
|
return bytecode == Bytecode::kJumpConstant ||
|
|
|
|
IsConditionalJumpConstant(bytecode);
|
|
|
|
}
|
|
|
|
|
|
|
|
// static
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2016-05-12 19:18:07 +00:00
|
|
|
// 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;
|
|
|
|
}
|
2015-12-16 16:29:09 +00:00
|
|
|
|
2016-09-22 05:53:14 +00:00
|
|
|
// static
|
|
|
|
bool Bytecodes::IsCallOrNew(Bytecode bytecode) {
|
|
|
|
return bytecode == Bytecode::kCall || bytecode == Bytecode::kTailCall ||
|
|
|
|
bytecode == Bytecode::kNew;
|
|
|
|
}
|
|
|
|
|
|
|
|
// static
|
|
|
|
bool Bytecodes::IsCallRuntime(Bytecode bytecode) {
|
|
|
|
return bytecode == Bytecode::kCallRuntime ||
|
|
|
|
bytecode == Bytecode::kCallRuntimeForPair ||
|
|
|
|
bytecode == Bytecode::kInvokeIntrinsic;
|
|
|
|
}
|
|
|
|
|
2016-02-22 13:16:46 +00:00
|
|
|
// static
|
|
|
|
bool Bytecodes::IsDebugBreak(Bytecode bytecode) {
|
|
|
|
switch (bytecode) {
|
|
|
|
#define CASE(Name, ...) case Bytecode::k##Name:
|
|
|
|
DEBUG_BREAK_BYTECODE_LIST(CASE);
|
|
|
|
#undef CASE
|
|
|
|
return true;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2016-09-22 05:53:14 +00:00
|
|
|
// static
|
|
|
|
bool Bytecodes::IsLdarOrStar(Bytecode bytecode) {
|
|
|
|
return bytecode == Bytecode::kLdar || bytecode == Bytecode::kStar;
|
|
|
|
}
|
|
|
|
|
|
|
|
// static
|
|
|
|
bool Bytecodes::IsBytecodeWithScalableOperands(Bytecode bytecode) {
|
|
|
|
switch (bytecode) {
|
|
|
|
#define CASE(Name, ...) \
|
|
|
|
case Bytecode::k##Name: \
|
|
|
|
typedef BytecodeTraits<__VA_ARGS__> Name##Trait; \
|
|
|
|
return Name##Trait::IsScalable();
|
|
|
|
BYTECODE_LIST(CASE)
|
|
|
|
#undef CASE
|
|
|
|
}
|
|
|
|
UNREACHABLE();
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// static
|
|
|
|
bool Bytecodes::IsPrefixScalingBytecode(Bytecode bytecode) {
|
|
|
|
switch (bytecode) {
|
|
|
|
case Bytecode::kExtraWide:
|
|
|
|
case Bytecode::kDebugBreakExtraWide:
|
|
|
|
case Bytecode::kWide:
|
|
|
|
case Bytecode::kDebugBreakWide:
|
|
|
|
return true;
|
|
|
|
default:
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// static
|
|
|
|
bool Bytecodes::PutsNameInAccumulator(Bytecode bytecode) {
|
|
|
|
return bytecode == Bytecode::kTypeOf;
|
|
|
|
}
|
|
|
|
|
|
|
|
// static
|
|
|
|
bool Bytecodes::IsJumpOrReturn(Bytecode bytecode) {
|
|
|
|
return bytecode == Bytecode::kReturn || IsJump(bytecode);
|
|
|
|
}
|
|
|
|
|
|
|
|
// static
|
|
|
|
bool Bytecodes::IsMaybeRegisterOperandType(OperandType operand_type) {
|
|
|
|
return operand_type == OperandType::kMaybeReg;
|
|
|
|
}
|
|
|
|
|
2016-01-27 11:15:25 +00:00
|
|
|
// static
|
|
|
|
bool Bytecodes::IsRegisterOperandType(OperandType operand_type) {
|
|
|
|
switch (operand_type) {
|
|
|
|
#define CASE(Name, _) \
|
|
|
|
case OperandType::k##Name: \
|
|
|
|
return true;
|
|
|
|
REGISTER_OPERAND_TYPE_LIST(CASE)
|
|
|
|
#undef CASE
|
|
|
|
#define CASE(Name, _) \
|
|
|
|
case OperandType::k##Name: \
|
|
|
|
break;
|
|
|
|
NON_REGISTER_OPERAND_TYPE_LIST(CASE)
|
|
|
|
#undef CASE
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// static
|
|
|
|
bool Bytecodes::IsRegisterInputOperandType(OperandType operand_type) {
|
|
|
|
switch (operand_type) {
|
|
|
|
#define CASE(Name, _) \
|
|
|
|
case OperandType::k##Name: \
|
|
|
|
return true;
|
|
|
|
REGISTER_INPUT_OPERAND_TYPE_LIST(CASE)
|
|
|
|
#undef CASE
|
|
|
|
#define CASE(Name, _) \
|
|
|
|
case OperandType::k##Name: \
|
|
|
|
break;
|
|
|
|
NON_REGISTER_OPERAND_TYPE_LIST(CASE)
|
|
|
|
REGISTER_OUTPUT_OPERAND_TYPE_LIST(CASE)
|
|
|
|
#undef CASE
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// static
|
|
|
|
bool Bytecodes::IsRegisterOutputOperandType(OperandType operand_type) {
|
|
|
|
switch (operand_type) {
|
|
|
|
#define CASE(Name, _) \
|
|
|
|
case OperandType::k##Name: \
|
|
|
|
return true;
|
|
|
|
REGISTER_OUTPUT_OPERAND_TYPE_LIST(CASE)
|
|
|
|
#undef CASE
|
|
|
|
#define CASE(Name, _) \
|
|
|
|
case OperandType::k##Name: \
|
|
|
|
break;
|
|
|
|
NON_REGISTER_OPERAND_TYPE_LIST(CASE)
|
|
|
|
REGISTER_INPUT_OPERAND_TYPE_LIST(CASE)
|
|
|
|
#undef CASE
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
2015-12-16 16:29:09 +00:00
|
|
|
|
2016-07-20 12:51:11 +00:00
|
|
|
// static
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2016-05-12 19:18:07 +00:00
|
|
|
// static
|
2016-09-22 05:53:14 +00:00
|
|
|
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;
|
2016-05-12 19:18:07 +00:00
|
|
|
}
|
2016-09-22 05:53:14 +00:00
|
|
|
return 0;
|
2016-05-12 19:18:07 +00:00
|
|
|
}
|
|
|
|
|
2016-03-21 17:08:21 +00:00
|
|
|
// static
|
|
|
|
bool Bytecodes::IsUnsignedOperandType(OperandType operand_type) {
|
|
|
|
switch (operand_type) {
|
|
|
|
#define CASE(Name, _) \
|
|
|
|
case OperandType::k##Name: \
|
2016-06-10 10:34:50 +00:00
|
|
|
return OperandTraits<OperandType::k##Name>::TypeInfoTraits::kIsUnsigned;
|
2016-03-21 17:08:21 +00:00
|
|
|
OPERAND_TYPE_LIST(CASE)
|
|
|
|
#undef CASE
|
|
|
|
}
|
|
|
|
UNREACHABLE();
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// static
|
2016-09-22 05:53:14 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// static
|
|
|
|
OperandSize Bytecodes::SizeForUnsignedOperand(uint32_t value) {
|
|
|
|
if (value <= kMaxUInt8) {
|
|
|
|
return OperandSize::kByte;
|
|
|
|
} else if (value <= kMaxUInt16) {
|
|
|
|
return OperandSize::kShort;
|
|
|
|
} else {
|
|
|
|
return OperandSize::kQuad;
|
|
|
|
}
|
2016-05-12 19:18:07 +00:00
|
|
|
}
|
|
|
|
|
2016-04-05 10:05:33 +00:00
|
|
|
// static
|
|
|
|
bool Bytecodes::BytecodeHasHandler(Bytecode bytecode,
|
|
|
|
OperandScale operand_scale) {
|
|
|
|
return operand_scale == OperandScale::kSingle ||
|
|
|
|
Bytecodes::IsBytecodeWithScalableOperands(bytecode);
|
|
|
|
}
|
|
|
|
|
2015-07-23 14:21:26 +00:00
|
|
|
std::ostream& operator<<(std::ostream& os, const Bytecode& bytecode) {
|
|
|
|
return os << Bytecodes::ToString(bytecode);
|
|
|
|
}
|
|
|
|
|
2016-09-22 05:53:14 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
|
|
|
std::ostream& operator<<(std::ostream& os, const OperandScale& operand_scale) {
|
|
|
|
return os << Bytecodes::OperandScaleToString(operand_scale);
|
|
|
|
}
|
|
|
|
|
|
|
|
std::ostream& operator<<(std::ostream& os, const OperandType& operand_type) {
|
|
|
|
return os << Bytecodes::OperandTypeToString(operand_type);
|
|
|
|
}
|
|
|
|
|
2015-07-23 14:21:26 +00:00
|
|
|
} // namespace interpreter
|
|
|
|
} // namespace internal
|
|
|
|
} // namespace v8
|