mirror of
https://github.com/dart-lang/sdk
synced 2024-09-05 00:13:50 +00:00
[vm/bytecode] Support compact bytecode instructions in VM (part 2/3)
While adding support for new compact bytecode instructions, VM also keeps support for old bytecode instructions to preserve backwards compatibility and allow soft transition. This change is separate from bytecode generator changes in order to test VM with old bytecode generator. Corresponding bytecode generator changes: https://dart-review.googlesource.com/c/sdk/+/99400 Change-Id: Icf5ceee7d51f27ffe3f79d0eae81e0ddc0a7e855 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/101062 Reviewed-by: Ryan Macnak <rmacnak@google.com>
This commit is contained in:
parent
1cc4003e5a
commit
6fe73e4544
|
@ -7,6 +7,7 @@
|
|||
#include "platform/assert.h"
|
||||
#include "vm/bootstrap.h"
|
||||
#include "vm/compiler/backend/code_statistics.h"
|
||||
#include "vm/compiler/frontend/bytecode_reader.h"
|
||||
#include "vm/compiler/relocation.h"
|
||||
#include "vm/dart.h"
|
||||
#include "vm/heap/heap.h"
|
||||
|
@ -1291,6 +1292,14 @@ class KernelProgramInfoDeserializationCluster : public DeserializationCluster {
|
|||
info.set_libraries_cache(array);
|
||||
array = HashTables::New<UnorderedHashMap<SmiTraits>>(16, Heap::kOld);
|
||||
info.set_classes_cache(array);
|
||||
|
||||
static_assert(KernelBytecode::kMinSupportedBytecodeFormatVersion < 7,
|
||||
"Cleanup support for old bytecode format versions");
|
||||
array = info.bytecode_component();
|
||||
if (!array.IsNull()) {
|
||||
kernel::BytecodeReader::UseBytecodeVersion(
|
||||
kernel::BytecodeComponentData(array).GetVersion());
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -15,19 +15,23 @@
|
|||
namespace dart {
|
||||
|
||||
static const char* kOpcodeNames[] = {
|
||||
#define BYTECODE_NAME(name, encoding, op1, op2, op3) #name,
|
||||
#define BYTECODE_NAME(name, encoding, kind, op1, op2, op3) #name,
|
||||
KERNEL_BYTECODES_LIST(BYTECODE_NAME)
|
||||
#undef BYTECODE_NAME
|
||||
};
|
||||
|
||||
static const size_t kOpcodeCount =
|
||||
sizeof(kOpcodeNames) / sizeof(kOpcodeNames[0]);
|
||||
static_assert(kOpcodeCount <= 256, "Opcode should fit into a byte");
|
||||
|
||||
typedef void (*BytecodeFormatter)(char* buffer,
|
||||
intptr_t size,
|
||||
uword pc,
|
||||
uint32_t bc);
|
||||
typedef void (*Fmt)(char** buf, intptr_t* size, uword pc, int32_t value);
|
||||
KernelBytecode::Opcode opcode,
|
||||
const KBCInstr* instr);
|
||||
typedef void (*Fmt)(char** buf,
|
||||
intptr_t* size,
|
||||
const KBCInstr* instr,
|
||||
int32_t value);
|
||||
|
||||
template <typename ValueType>
|
||||
void FormatOperand(char** buf,
|
||||
|
@ -43,35 +47,53 @@ void FormatOperand(char** buf,
|
|||
}
|
||||
}
|
||||
|
||||
static void Fmt___(char** buf, intptr_t* size, uword pc, int32_t value) {}
|
||||
static void Fmt___(char** buf,
|
||||
intptr_t* size,
|
||||
const KBCInstr* instr,
|
||||
int32_t value) {}
|
||||
|
||||
static void Fmttgt(char** buf, intptr_t* size, uword pc, int32_t value) {
|
||||
FormatOperand(buf, size, "-> %" Px, pc + (value << 2));
|
||||
static void Fmttgt(char** buf,
|
||||
intptr_t* size,
|
||||
const KBCInstr* instr,
|
||||
int32_t value) {
|
||||
FormatOperand(buf, size, "-> %" Px, instr + value);
|
||||
}
|
||||
|
||||
static void Fmtlit(char** buf, intptr_t* size, uword pc, int32_t value) {
|
||||
static void Fmtlit(char** buf,
|
||||
intptr_t* size,
|
||||
const KBCInstr* instr,
|
||||
int32_t value) {
|
||||
FormatOperand(buf, size, "k%d", value);
|
||||
}
|
||||
|
||||
static void Fmtreg(char** buf, intptr_t* size, uword pc, int32_t value) {
|
||||
static void Fmtreg(char** buf,
|
||||
intptr_t* size,
|
||||
const KBCInstr* instr,
|
||||
int32_t value) {
|
||||
FormatOperand(buf, size, "r%d", value);
|
||||
}
|
||||
|
||||
static void Fmtxeg(char** buf, intptr_t* size, uword pc, int32_t value) {
|
||||
static void Fmtxeg(char** buf,
|
||||
intptr_t* size,
|
||||
const KBCInstr* instr,
|
||||
int32_t value) {
|
||||
if (value < 0) {
|
||||
FormatOperand(buf, size, "FP[%d]", value);
|
||||
} else {
|
||||
Fmtreg(buf, size, pc, value);
|
||||
Fmtreg(buf, size, instr, value);
|
||||
}
|
||||
}
|
||||
|
||||
static void Fmtnum(char** buf, intptr_t* size, uword pc, int32_t value) {
|
||||
static void Fmtnum(char** buf,
|
||||
intptr_t* size,
|
||||
const KBCInstr* instr,
|
||||
int32_t value) {
|
||||
FormatOperand(buf, size, "#%d", value);
|
||||
}
|
||||
|
||||
static void Apply(char** buf,
|
||||
intptr_t* size,
|
||||
uword pc,
|
||||
const KBCInstr* instr,
|
||||
Fmt fmt,
|
||||
int32_t value,
|
||||
const char* suffix) {
|
||||
|
@ -79,7 +101,7 @@ static void Apply(char** buf,
|
|||
return;
|
||||
}
|
||||
|
||||
fmt(buf, size, pc, value);
|
||||
fmt(buf, size, instr, value);
|
||||
if (*size > 0) {
|
||||
FormatOperand(buf, size, "%s", suffix);
|
||||
}
|
||||
|
@ -87,127 +109,200 @@ static void Apply(char** buf,
|
|||
|
||||
static void Format0(char* buf,
|
||||
intptr_t size,
|
||||
uword pc,
|
||||
uint32_t op,
|
||||
KernelBytecode::Opcode opcode,
|
||||
const KBCInstr* instr,
|
||||
Fmt op1,
|
||||
Fmt op2,
|
||||
Fmt op3) {}
|
||||
|
||||
static void FormatT(char* buf,
|
||||
intptr_t size,
|
||||
uword pc,
|
||||
uint32_t op,
|
||||
Fmt op1,
|
||||
Fmt op2,
|
||||
Fmt op3) {
|
||||
const int32_t x = static_cast<int32_t>(op) >> 8;
|
||||
Apply(&buf, &size, pc, op1, x, "");
|
||||
}
|
||||
|
||||
static void FormatA(char* buf,
|
||||
intptr_t size,
|
||||
uword pc,
|
||||
uint32_t op,
|
||||
KernelBytecode::Opcode opcode,
|
||||
const KBCInstr* instr,
|
||||
Fmt op1,
|
||||
Fmt op2,
|
||||
Fmt op3) {
|
||||
const int32_t a = (op & 0xFF00) >> 8;
|
||||
Apply(&buf, &size, pc, op1, a, "");
|
||||
}
|
||||
|
||||
static void FormatA_D(char* buf,
|
||||
intptr_t size,
|
||||
uword pc,
|
||||
uint32_t op,
|
||||
Fmt op1,
|
||||
Fmt op2,
|
||||
Fmt op3) {
|
||||
const int32_t a = (op & 0xFF00) >> 8;
|
||||
const int32_t bc = op >> 16;
|
||||
Apply(&buf, &size, pc, op1, a, ", ");
|
||||
Apply(&buf, &size, pc, op2, bc, "");
|
||||
}
|
||||
|
||||
static void FormatA_X(char* buf,
|
||||
intptr_t size,
|
||||
uword pc,
|
||||
uint32_t op,
|
||||
Fmt op1,
|
||||
Fmt op2,
|
||||
Fmt op3) {
|
||||
const int32_t a = (op & 0xFF00) >> 8;
|
||||
const int32_t bc = static_cast<int32_t>(op) >> 16;
|
||||
Apply(&buf, &size, pc, op1, a, ", ");
|
||||
Apply(&buf, &size, pc, op2, bc, "");
|
||||
}
|
||||
|
||||
static void FormatX(char* buf,
|
||||
intptr_t size,
|
||||
uword pc,
|
||||
uint32_t op,
|
||||
Fmt op1,
|
||||
Fmt op2,
|
||||
Fmt op3) {
|
||||
const int32_t bc = static_cast<int32_t>(op) >> 16;
|
||||
Apply(&buf, &size, pc, op1, bc, "");
|
||||
const int32_t a = KernelBytecode::DecodeA(instr);
|
||||
Apply(&buf, &size, instr, op1, a, "");
|
||||
}
|
||||
|
||||
static void FormatD(char* buf,
|
||||
intptr_t size,
|
||||
uword pc,
|
||||
uint32_t op,
|
||||
KernelBytecode::Opcode opcode,
|
||||
const KBCInstr* instr,
|
||||
Fmt op1,
|
||||
Fmt op2,
|
||||
Fmt op3) {
|
||||
const int32_t bc = op >> 16;
|
||||
Apply(&buf, &size, pc, op1, bc, "");
|
||||
const int32_t bc = KernelBytecode::DecodeD(instr);
|
||||
Apply(&buf, &size, instr, op1, bc, "");
|
||||
}
|
||||
|
||||
static void FormatX(char* buf,
|
||||
intptr_t size,
|
||||
KernelBytecode::Opcode opcode,
|
||||
const KBCInstr* instr,
|
||||
Fmt op1,
|
||||
Fmt op2,
|
||||
Fmt op3) {
|
||||
const int32_t bc = KernelBytecode::DecodeX(instr);
|
||||
Apply(&buf, &size, instr, op1, bc, "");
|
||||
}
|
||||
|
||||
static void FormatT(char* buf,
|
||||
intptr_t size,
|
||||
KernelBytecode::Opcode opcode,
|
||||
const KBCInstr* instr,
|
||||
Fmt op1,
|
||||
Fmt op2,
|
||||
Fmt op3) {
|
||||
const int32_t x = KernelBytecode::DecodeT(instr);
|
||||
Apply(&buf, &size, instr, op1, x, "");
|
||||
}
|
||||
|
||||
static void FormatA_D(char* buf,
|
||||
intptr_t size,
|
||||
KernelBytecode::Opcode opcode,
|
||||
const KBCInstr* instr,
|
||||
Fmt op1,
|
||||
Fmt op2,
|
||||
Fmt op3) {
|
||||
const int32_t a = KernelBytecode::DecodeA(instr);
|
||||
const int32_t bc = KernelBytecode::DecodeD(instr);
|
||||
Apply(&buf, &size, instr, op1, a, ", ");
|
||||
Apply(&buf, &size, instr, op2, bc, "");
|
||||
}
|
||||
|
||||
static void FormatA_X(char* buf,
|
||||
intptr_t size,
|
||||
KernelBytecode::Opcode opcode,
|
||||
const KBCInstr* instr,
|
||||
Fmt op1,
|
||||
Fmt op2,
|
||||
Fmt op3) {
|
||||
const int32_t a = KernelBytecode::DecodeA(instr);
|
||||
const int32_t bc = KernelBytecode::DecodeX(instr);
|
||||
Apply(&buf, &size, instr, op1, a, ", ");
|
||||
Apply(&buf, &size, instr, op2, bc, "");
|
||||
}
|
||||
|
||||
static void FormatA_E(char* buf,
|
||||
intptr_t size,
|
||||
KernelBytecode::Opcode opcode,
|
||||
const KBCInstr* instr,
|
||||
Fmt op1,
|
||||
Fmt op2,
|
||||
Fmt op3) {
|
||||
const int32_t a = KernelBytecode::DecodeA(instr);
|
||||
const int32_t e = KernelBytecode::DecodeE(instr);
|
||||
Apply(&buf, &size, instr, op1, a, ", ");
|
||||
Apply(&buf, &size, instr, op2, e, "");
|
||||
}
|
||||
|
||||
static void FormatA_Y(char* buf,
|
||||
intptr_t size,
|
||||
KernelBytecode::Opcode opcode,
|
||||
const KBCInstr* instr,
|
||||
Fmt op1,
|
||||
Fmt op2,
|
||||
Fmt op3) {
|
||||
const int32_t a = KernelBytecode::DecodeA(instr);
|
||||
const int32_t y = KernelBytecode::DecodeY(instr);
|
||||
Apply(&buf, &size, instr, op1, a, ", ");
|
||||
Apply(&buf, &size, instr, op2, y, "");
|
||||
}
|
||||
|
||||
static void FormatD_F(char* buf,
|
||||
intptr_t size,
|
||||
KernelBytecode::Opcode opcode,
|
||||
const KBCInstr* instr,
|
||||
Fmt op1,
|
||||
Fmt op2,
|
||||
Fmt op3) {
|
||||
const int32_t d = KernelBytecode::DecodeD(instr);
|
||||
const int32_t f = KernelBytecode::DecodeF(instr);
|
||||
Apply(&buf, &size, instr, op1, d, ", ");
|
||||
Apply(&buf, &size, instr, op2, f, "");
|
||||
}
|
||||
|
||||
static void FormatA_B_C(char* buf,
|
||||
intptr_t size,
|
||||
uword pc,
|
||||
uint32_t op,
|
||||
KernelBytecode::Opcode opcode,
|
||||
const KBCInstr* instr,
|
||||
Fmt op1,
|
||||
Fmt op2,
|
||||
Fmt op3) {
|
||||
const int32_t a = (op >> 8) & 0xFF;
|
||||
const int32_t b = (op >> 16) & 0xFF;
|
||||
const int32_t c = (op >> 24) & 0xFF;
|
||||
Apply(&buf, &size, pc, op1, a, ", ");
|
||||
Apply(&buf, &size, pc, op2, b, ", ");
|
||||
Apply(&buf, &size, pc, op3, c, "");
|
||||
const int32_t a = KernelBytecode::DecodeA(instr);
|
||||
const int32_t b = KernelBytecode::DecodeB(instr);
|
||||
const int32_t c = KernelBytecode::DecodeC(instr);
|
||||
Apply(&buf, &size, instr, op1, a, ", ");
|
||||
Apply(&buf, &size, instr, op2, b, ", ");
|
||||
Apply(&buf, &size, instr, op3, c, "");
|
||||
}
|
||||
|
||||
#define BYTECODE_FORMATTER(name, encoding, op1, op2, op3) \
|
||||
static void Format##name(char* buf, intptr_t size, uword pc, uint32_t op) { \
|
||||
Format##encoding(buf, size, pc, op, Fmt##op1, Fmt##op2, Fmt##op3); \
|
||||
#define BYTECODE_FORMATTER(name, encoding, kind, op1, op2, op3) \
|
||||
static void Format##name(char* buf, intptr_t size, \
|
||||
KernelBytecode::Opcode opcode, \
|
||||
const KBCInstr* instr) { \
|
||||
Format##encoding(buf, size, opcode, instr, Fmt##op1, Fmt##op2, Fmt##op3); \
|
||||
}
|
||||
KERNEL_BYTECODES_LIST(BYTECODE_FORMATTER)
|
||||
#undef BYTECODE_FORMATTER
|
||||
|
||||
static const BytecodeFormatter kFormatters[] = {
|
||||
#define BYTECODE_FORMATTER(name, encoding, op1, op2, op3) &Format##name,
|
||||
#define BYTECODE_FORMATTER(name, encoding, kind, op1, op2, op3) &Format##name,
|
||||
KERNEL_BYTECODES_LIST(BYTECODE_FORMATTER)
|
||||
#undef BYTECODE_FORMATTER
|
||||
};
|
||||
|
||||
static bool HasLoadFromPool(const KBCInstr* instr) {
|
||||
static intptr_t GetConstantPoolIndex(const KBCInstr* instr) {
|
||||
switch (KernelBytecode::DecodeOpcode(instr)) {
|
||||
case KernelBytecode::kLoadConstant_Old:
|
||||
case KernelBytecode::kInstantiateTypeArgumentsTOS_Old:
|
||||
case KernelBytecode::kAssertAssignable_Old:
|
||||
case KernelBytecode::kPushConstant_Old:
|
||||
case KernelBytecode::kStoreStaticTOS_Old:
|
||||
case KernelBytecode::kPushStatic_Old:
|
||||
case KernelBytecode::kAllocate_Old:
|
||||
case KernelBytecode::kAllocateClosure_Old:
|
||||
case KernelBytecode::kInstantiateType_Old:
|
||||
case KernelBytecode::kDirectCall_Old:
|
||||
case KernelBytecode::kInterfaceCall_Old:
|
||||
case KernelBytecode::kUncheckedInterfaceCall_Old:
|
||||
case KernelBytecode::kDynamicCall_Old:
|
||||
return KernelBytecode::DecodeD(instr);
|
||||
|
||||
case KernelBytecode::kLoadConstant:
|
||||
case KernelBytecode::kPushConstant:
|
||||
case KernelBytecode::kIndirectStaticCall:
|
||||
case KernelBytecode::kInterfaceCall:
|
||||
case KernelBytecode::kUncheckedInterfaceCall:
|
||||
case KernelBytecode::kDynamicCall:
|
||||
case KernelBytecode::kStoreStaticTOS:
|
||||
case KernelBytecode::kPushStatic:
|
||||
case KernelBytecode::kAllocate:
|
||||
case KernelBytecode::kInstantiateType:
|
||||
case KernelBytecode::kLoadConstant_Wide:
|
||||
case KernelBytecode::kInstantiateTypeArgumentsTOS:
|
||||
case KernelBytecode::kInstantiateTypeArgumentsTOS_Wide:
|
||||
case KernelBytecode::kAssertAssignable:
|
||||
return true;
|
||||
case KernelBytecode::kAssertAssignable_Wide:
|
||||
return KernelBytecode::DecodeE(instr);
|
||||
|
||||
case KernelBytecode::kPushConstant:
|
||||
case KernelBytecode::kPushConstant_Wide:
|
||||
case KernelBytecode::kStoreStaticTOS:
|
||||
case KernelBytecode::kStoreStaticTOS_Wide:
|
||||
case KernelBytecode::kPushStatic:
|
||||
case KernelBytecode::kPushStatic_Wide:
|
||||
case KernelBytecode::kAllocate:
|
||||
case KernelBytecode::kAllocate_Wide:
|
||||
case KernelBytecode::kAllocateClosure:
|
||||
case KernelBytecode::kAllocateClosure_Wide:
|
||||
case KernelBytecode::kInstantiateType:
|
||||
case KernelBytecode::kInstantiateType_Wide:
|
||||
case KernelBytecode::kDirectCall:
|
||||
case KernelBytecode::kDirectCall_Wide:
|
||||
case KernelBytecode::kInterfaceCall:
|
||||
case KernelBytecode::kInterfaceCall_Wide:
|
||||
case KernelBytecode::kUncheckedInterfaceCall:
|
||||
case KernelBytecode::kUncheckedInterfaceCall_Wide:
|
||||
case KernelBytecode::kDynamicCall:
|
||||
case KernelBytecode::kDynamicCall_Wide:
|
||||
return KernelBytecode::DecodeD(instr);
|
||||
|
||||
default:
|
||||
return false;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -215,8 +310,8 @@ static bool GetLoadedObjectAt(uword pc,
|
|||
const ObjectPool& object_pool,
|
||||
Object* obj) {
|
||||
const KBCInstr* instr = reinterpret_cast<const KBCInstr*>(pc);
|
||||
if (HasLoadFromPool(instr)) {
|
||||
uint16_t index = KernelBytecode::DecodeD(instr);
|
||||
const intptr_t index = GetConstantPoolIndex(instr);
|
||||
if (index >= 0) {
|
||||
if (object_pool.TypeAt(index) == ObjectPool::EntryType::kTaggedObject) {
|
||||
*obj = object_pool.ObjectAt(index);
|
||||
return true;
|
||||
|
@ -233,19 +328,26 @@ void KernelBytecodeDisassembler::DecodeInstruction(char* hex_buffer,
|
|||
const Bytecode& bytecode,
|
||||
Object** object,
|
||||
uword pc) {
|
||||
const uint32_t instr = *reinterpret_cast<uint32_t*>(pc);
|
||||
const uint8_t opcode = instr & 0xFF;
|
||||
const KBCInstr* instr = reinterpret_cast<const KBCInstr*>(pc);
|
||||
const KernelBytecode::Opcode opcode = KernelBytecode::DecodeOpcode(instr);
|
||||
ASSERT(opcode < kOpcodeCount);
|
||||
const intptr_t instr_size = KernelBytecode::kInstructionSize[opcode];
|
||||
|
||||
size_t name_size =
|
||||
Utils::SNPrint(human_buffer, human_size, "%-10s\t", kOpcodeNames[opcode]);
|
||||
|
||||
human_buffer += name_size;
|
||||
human_size -= name_size;
|
||||
kFormatters[opcode](human_buffer, human_size, pc, instr);
|
||||
kFormatters[opcode](human_buffer, human_size, opcode, instr);
|
||||
|
||||
Utils::SNPrint(hex_buffer, hex_size, "%08x", instr);
|
||||
const intptr_t kCharactersPerByte = 3;
|
||||
if (hex_size > instr_size * kCharactersPerByte) {
|
||||
for (intptr_t i = 0; i < instr_size; ++i) {
|
||||
Utils::SNPrint(hex_buffer + (i * kCharactersPerByte),
|
||||
hex_size - (i * kCharactersPerByte), " %02x", instr[i]);
|
||||
}
|
||||
}
|
||||
if (out_instr_size) {
|
||||
*out_instr_size = sizeof(uint32_t);
|
||||
*out_instr_size = instr_size;
|
||||
}
|
||||
|
||||
*object = NULL;
|
||||
|
|
|
@ -26,7 +26,7 @@ DEFINE_FLAG(bool,
|
|||
|
||||
namespace kernel {
|
||||
|
||||
// 8-bit unsigned operand at bits 8-15.
|
||||
// 8-bit unsigned operand.
|
||||
BytecodeFlowGraphBuilder::Operand BytecodeFlowGraphBuilder::DecodeOperandA() {
|
||||
if (is_generating_interpreter()) {
|
||||
UNIMPLEMENTED(); // TODO(alexmarkov): interpreter
|
||||
|
@ -36,7 +36,7 @@ BytecodeFlowGraphBuilder::Operand BytecodeFlowGraphBuilder::DecodeOperandA() {
|
|||
}
|
||||
}
|
||||
|
||||
// 8-bit unsigned operand at bits 16-23.
|
||||
// 8-bit unsigned operand.
|
||||
BytecodeFlowGraphBuilder::Operand BytecodeFlowGraphBuilder::DecodeOperandB() {
|
||||
if (is_generating_interpreter()) {
|
||||
UNIMPLEMENTED(); // TODO(alexmarkov): interpreter
|
||||
|
@ -46,7 +46,7 @@ BytecodeFlowGraphBuilder::Operand BytecodeFlowGraphBuilder::DecodeOperandB() {
|
|||
}
|
||||
}
|
||||
|
||||
// 8-bit unsigned operand at bits 24-31.
|
||||
// 8-bit unsigned operand.
|
||||
BytecodeFlowGraphBuilder::Operand BytecodeFlowGraphBuilder::DecodeOperandC() {
|
||||
if (is_generating_interpreter()) {
|
||||
UNIMPLEMENTED(); // TODO(alexmarkov): interpreter
|
||||
|
@ -56,7 +56,7 @@ BytecodeFlowGraphBuilder::Operand BytecodeFlowGraphBuilder::DecodeOperandC() {
|
|||
}
|
||||
}
|
||||
|
||||
// 16-bit unsigned operand at bits 16-31.
|
||||
// 8/16-bit unsigned operand.
|
||||
BytecodeFlowGraphBuilder::Operand BytecodeFlowGraphBuilder::DecodeOperandD() {
|
||||
if (is_generating_interpreter()) {
|
||||
UNIMPLEMENTED(); // TODO(alexmarkov): interpreter
|
||||
|
@ -66,7 +66,27 @@ BytecodeFlowGraphBuilder::Operand BytecodeFlowGraphBuilder::DecodeOperandD() {
|
|||
}
|
||||
}
|
||||
|
||||
// 16-bit signed operand at bits 16-31.
|
||||
// 8/16-bit unsigned operand.
|
||||
BytecodeFlowGraphBuilder::Operand BytecodeFlowGraphBuilder::DecodeOperandE() {
|
||||
if (is_generating_interpreter()) {
|
||||
UNIMPLEMENTED(); // TODO(alexmarkov): interpreter
|
||||
} else {
|
||||
intptr_t value = KernelBytecode::DecodeE(bytecode_instr_);
|
||||
return Operand(value);
|
||||
}
|
||||
}
|
||||
|
||||
// 8-bit unsigned operand.
|
||||
BytecodeFlowGraphBuilder::Operand BytecodeFlowGraphBuilder::DecodeOperandF() {
|
||||
if (is_generating_interpreter()) {
|
||||
UNIMPLEMENTED(); // TODO(alexmarkov): interpreter
|
||||
} else {
|
||||
intptr_t value = KernelBytecode::DecodeF(bytecode_instr_);
|
||||
return Operand(value);
|
||||
}
|
||||
}
|
||||
|
||||
// 8/16-bit signed operand.
|
||||
BytecodeFlowGraphBuilder::Operand BytecodeFlowGraphBuilder::DecodeOperandX() {
|
||||
if (is_generating_interpreter()) {
|
||||
UNIMPLEMENTED(); // TODO(alexmarkov): interpreter
|
||||
|
@ -76,7 +96,17 @@ BytecodeFlowGraphBuilder::Operand BytecodeFlowGraphBuilder::DecodeOperandX() {
|
|||
}
|
||||
}
|
||||
|
||||
// 24-bit signed operand at bits 8-31.
|
||||
// 8/16-bit signed operand.
|
||||
BytecodeFlowGraphBuilder::Operand BytecodeFlowGraphBuilder::DecodeOperandY() {
|
||||
if (is_generating_interpreter()) {
|
||||
UNIMPLEMENTED(); // TODO(alexmarkov): interpreter
|
||||
} else {
|
||||
intptr_t value = KernelBytecode::DecodeY(bytecode_instr_);
|
||||
return Operand(value);
|
||||
}
|
||||
}
|
||||
|
||||
// 8/24-bit signed operand.
|
||||
BytecodeFlowGraphBuilder::Operand BytecodeFlowGraphBuilder::DecodeOperandT() {
|
||||
if (is_generating_interpreter()) {
|
||||
UNIMPLEMENTED(); // TODO(alexmarkov): interpreter
|
||||
|
@ -86,23 +116,6 @@ BytecodeFlowGraphBuilder::Operand BytecodeFlowGraphBuilder::DecodeOperandT() {
|
|||
}
|
||||
}
|
||||
|
||||
const KBCInstr* BytecodeFlowGraphBuilder::InstructionAt(
|
||||
intptr_t pc,
|
||||
KernelBytecode::Opcode expect_opcode) {
|
||||
ASSERT(!is_generating_interpreter());
|
||||
ASSERT((0 <= pc) && (pc < bytecode_length_));
|
||||
|
||||
const KBCInstr* instr = &(raw_bytecode_[pc]);
|
||||
const KernelBytecode::Opcode opcode = KernelBytecode::DecodeOpcode(instr);
|
||||
if (opcode != expect_opcode) {
|
||||
FATAL3("Expected bytecode instruction %s, but found %s at %" Pd "",
|
||||
KernelBytecode::NameOf(expect_opcode),
|
||||
KernelBytecode::NameOf(opcode), pc);
|
||||
}
|
||||
|
||||
return instr;
|
||||
}
|
||||
|
||||
BytecodeFlowGraphBuilder::Constant BytecodeFlowGraphBuilder::ConstantAt(
|
||||
Operand entry_index,
|
||||
intptr_t add_index) {
|
||||
|
@ -370,14 +383,47 @@ void BytecodeFlowGraphBuilder::DropUnusedValuesFromStack() {
|
|||
|
||||
void BytecodeFlowGraphBuilder::BuildInstruction(KernelBytecode::Opcode opcode) {
|
||||
switch (opcode) {
|
||||
#define BUILD_BYTECODE_CASE(name, encoding, op1, op2, op3) \
|
||||
#define WIDE_CASE(name) case KernelBytecode::k##name##_Wide:
|
||||
#define WIDE_CASE_0(name)
|
||||
#define WIDE_CASE_A(name)
|
||||
#define WIDE_CASE_D(name) WIDE_CASE(name)
|
||||
#define WIDE_CASE_X(name) WIDE_CASE(name)
|
||||
#define WIDE_CASE_T(name) WIDE_CASE(name)
|
||||
#define WIDE_CASE_A_E(name) WIDE_CASE(name)
|
||||
#define WIDE_CASE_A_Y(name) WIDE_CASE(name)
|
||||
#define WIDE_CASE_D_F(name) WIDE_CASE(name)
|
||||
#define WIDE_CASE_A_B_C(name)
|
||||
|
||||
#define BUILD_BYTECODE_CASE(name, encoding, kind, op1, op2, op3) \
|
||||
BUILD_BYTECODE_CASE_##kind(name, encoding)
|
||||
|
||||
#define BUILD_BYTECODE_CASE_OLD(name, encoding)
|
||||
#define BUILD_BYTECODE_CASE_WIDE(name, encoding)
|
||||
#define BUILD_BYTECODE_CASE_RESV(name, encoding)
|
||||
#define BUILD_BYTECODE_CASE_ORDN(name, encoding) \
|
||||
case KernelBytecode::k##name: \
|
||||
Build##name(); \
|
||||
case KernelBytecode::k##name##_Old: \
|
||||
WIDE_CASE_##encoding(name) Build##name(); \
|
||||
break;
|
||||
|
||||
PUBLIC_KERNEL_BYTECODES_LIST(BUILD_BYTECODE_CASE)
|
||||
|
||||
#undef WIDE_CASE
|
||||
#undef WIDE_CASE_0
|
||||
#undef WIDE_CASE_A
|
||||
#undef WIDE_CASE_D
|
||||
#undef WIDE_CASE_X
|
||||
#undef WIDE_CASE_T
|
||||
#undef WIDE_CASE_A_E
|
||||
#undef WIDE_CASE_A_Y
|
||||
#undef WIDE_CASE_D_F
|
||||
#undef WIDE_CASE_A_B_C
|
||||
#undef BUILD_BYTECODE_CASE
|
||||
#undef BUILD_BYTECODE_CASE_OLD
|
||||
#undef BUILD_BYTECODE_CASE_WIDE
|
||||
#undef BUILD_BYTECODE_CASE_RESV
|
||||
#undef BUILD_BYTECODE_CASE_ORDN
|
||||
|
||||
default:
|
||||
FATAL1("Unsupported bytecode instruction %s\n",
|
||||
KernelBytecode::NameOf(opcode));
|
||||
|
@ -397,7 +443,7 @@ void BytecodeFlowGraphBuilder::BuildEntryFixed() {
|
|||
const intptr_t num_fixed_params = DecodeOperandA().value();
|
||||
ASSERT(num_fixed_params == function().num_fixed_parameters());
|
||||
|
||||
AllocateLocalVariables(DecodeOperandD());
|
||||
AllocateLocalVariables(DecodeOperandE());
|
||||
AllocateFixedParameters();
|
||||
|
||||
Fragment check_args;
|
||||
|
@ -450,7 +496,7 @@ void BytecodeFlowGraphBuilder::BuildEntryOptional() {
|
|||
for (intptr_t i = 0; i < num_load_const; ++i) {
|
||||
frame_instr = KernelBytecode::Next(frame_instr);
|
||||
}
|
||||
ASSERT(KernelBytecode::DecodeOpcode(frame_instr) == KernelBytecode::kFrame);
|
||||
ASSERT(KernelBytecode::IsFrameOpcode(frame_instr));
|
||||
const intptr_t num_extra_locals = KernelBytecode::DecodeD(frame_instr);
|
||||
const intptr_t num_params =
|
||||
num_fixed_params + num_opt_pos_params + num_opt_named_params;
|
||||
|
@ -474,11 +520,10 @@ void BytecodeFlowGraphBuilder::BuildEntryOptional() {
|
|||
for (intptr_t i = 0; i < num_opt_pos_params; ++i, ++param) {
|
||||
const KBCInstr* load_value_instr = instr;
|
||||
instr = KernelBytecode::Next(instr);
|
||||
ASSERT(KernelBytecode::DecodeOpcode(load_value_instr) ==
|
||||
KernelBytecode::kLoadConstant);
|
||||
ASSERT(KernelBytecode::IsLoadConstantOpcode(load_value_instr));
|
||||
ASSERT(KernelBytecode::DecodeA(load_value_instr) == param);
|
||||
const Object& default_value =
|
||||
ConstantAt(Operand(KernelBytecode::DecodeD(load_value_instr))).value();
|
||||
ConstantAt(Operand(KernelBytecode::DecodeE(load_value_instr))).value();
|
||||
|
||||
LocalVariable* param_var = AllocateParameter(param, VariableIndex(-param));
|
||||
raw_parameters->Add(param_var);
|
||||
|
@ -497,16 +542,14 @@ void BytecodeFlowGraphBuilder::BuildEntryOptional() {
|
|||
const KBCInstr* load_name_instr = instr;
|
||||
const KBCInstr* load_value_instr = KernelBytecode::Next(load_name_instr);
|
||||
instr = KernelBytecode::Next(load_value_instr);
|
||||
ASSERT(KernelBytecode::DecodeOpcode(load_name_instr) ==
|
||||
KernelBytecode::kLoadConstant);
|
||||
ASSERT(KernelBytecode::DecodeOpcode(load_value_instr) ==
|
||||
KernelBytecode::kLoadConstant);
|
||||
ASSERT(KernelBytecode::IsLoadConstantOpcode(load_name_instr));
|
||||
ASSERT(KernelBytecode::IsLoadConstantOpcode(load_value_instr));
|
||||
const String& param_name = String::Cast(
|
||||
ConstantAt(Operand(KernelBytecode::DecodeD(load_name_instr)))
|
||||
ConstantAt(Operand(KernelBytecode::DecodeE(load_name_instr)))
|
||||
.value());
|
||||
ASSERT(param_name.IsSymbol());
|
||||
const Object& default_value =
|
||||
ConstantAt(Operand(KernelBytecode::DecodeD(load_value_instr)))
|
||||
ConstantAt(Operand(KernelBytecode::DecodeE(load_value_instr)))
|
||||
.value();
|
||||
|
||||
intptr_t param_index = num_fixed_params;
|
||||
|
@ -597,7 +640,7 @@ void BytecodeFlowGraphBuilder::BuildCheckFunctionTypeArgs() {
|
|||
}
|
||||
|
||||
const intptr_t expected_num_type_args = DecodeOperandA().value();
|
||||
LocalVariable* type_args_var = LocalVariableAt(DecodeOperandD().value());
|
||||
LocalVariable* type_args_var = LocalVariableAt(DecodeOperandE().value());
|
||||
ASSERT(function().IsGeneric());
|
||||
|
||||
if (throw_no_such_method_ == nullptr) {
|
||||
|
@ -722,42 +765,13 @@ void BytecodeFlowGraphBuilder::BuildPush() {
|
|||
LoadLocal(local_index);
|
||||
}
|
||||
|
||||
void BytecodeFlowGraphBuilder::BuildIndirectStaticCall() {
|
||||
if (is_generating_interpreter()) {
|
||||
UNIMPLEMENTED(); // TODO(alexmarkov): interpreter
|
||||
}
|
||||
|
||||
const ICData& icdata = ICData::Cast(PopConstant().value());
|
||||
|
||||
const Function& target = Function::ZoneHandle(Z, icdata.GetTargetAt(0));
|
||||
const ArgumentsDescriptor arg_desc(
|
||||
Array::Cast(ConstantAt(DecodeOperandD()).value()));
|
||||
intptr_t argc = DecodeOperandA().value();
|
||||
ASSERT(ic_data_array_->At(icdata.deopt_id())->Original() == icdata.raw());
|
||||
|
||||
ArgumentArray arguments = GetArguments(argc);
|
||||
|
||||
// TODO(alexmarkov): pass ICData::kSuper for super calls
|
||||
// (need to distinguish them in bytecode).
|
||||
StaticCallInstr* call = new (Z) StaticCallInstr(
|
||||
position_, target, arg_desc.TypeArgsLen(),
|
||||
Array::ZoneHandle(Z, arg_desc.GetArgumentNames()), arguments,
|
||||
*ic_data_array_, icdata.deopt_id(), ICData::kStatic);
|
||||
|
||||
// TODO(alexmarkov): add type info
|
||||
// SetResultTypeForStaticCall(call, target, argument_count, result_type);
|
||||
|
||||
code_ <<= call;
|
||||
B->Push(call);
|
||||
}
|
||||
|
||||
void BytecodeFlowGraphBuilder::BuildDirectCall() {
|
||||
if (is_generating_interpreter()) {
|
||||
UNIMPLEMENTED(); // TODO(alexmarkov): interpreter
|
||||
}
|
||||
|
||||
const Function& target = Function::Cast(ConstantAt(DecodeOperandD()).value());
|
||||
const intptr_t argc = DecodeOperandA().value();
|
||||
const intptr_t argc = DecodeOperandF().value();
|
||||
|
||||
// Recognize identical() call.
|
||||
// Note: similar optimization is performed in AST flow graph builder - see
|
||||
|
@ -807,7 +821,7 @@ void BytecodeFlowGraphBuilder::BuildInterfaceCallCommon(
|
|||
Array::Cast(ConstantAt(DecodeOperandD(), 1).value());
|
||||
const ArgumentsDescriptor arg_desc(arg_desc_array);
|
||||
|
||||
const intptr_t argc = DecodeOperandA().value();
|
||||
const intptr_t argc = DecodeOperandF().value();
|
||||
Token::Kind token_kind = MethodTokenRecognizer::RecognizeTokenKind(name);
|
||||
|
||||
intptr_t checked_argument_count = 1;
|
||||
|
@ -858,7 +872,7 @@ void BytecodeFlowGraphBuilder::BuildDynamicCall() {
|
|||
const ICData& icdata = ICData::Cast(ConstantAt(DecodeOperandD()).value());
|
||||
ASSERT(ic_data_array_->At(icdata.deopt_id())->Original() == icdata.raw());
|
||||
|
||||
const intptr_t argc = DecodeOperandA().value();
|
||||
const intptr_t argc = DecodeOperandF().value();
|
||||
const ArgumentsDescriptor arg_desc(
|
||||
Array::Handle(Z, icdata.arguments_descriptor()));
|
||||
|
||||
|
@ -1118,7 +1132,7 @@ void BytecodeFlowGraphBuilder::BuildAllocateContext() {
|
|||
}
|
||||
|
||||
const intptr_t context_id = DecodeOperandA().value();
|
||||
const intptr_t num_context_vars = DecodeOperandD().value();
|
||||
const intptr_t num_context_vars = DecodeOperandE().value();
|
||||
|
||||
auto& context_variables = CompilerState::Current().GetDummyContextVariables(
|
||||
context_id, num_context_vars);
|
||||
|
@ -1132,7 +1146,7 @@ void BytecodeFlowGraphBuilder::BuildCloneContext() {
|
|||
|
||||
LoadStackSlots(1);
|
||||
const intptr_t context_id = DecodeOperandA().value();
|
||||
const intptr_t num_context_vars = DecodeOperandD().value();
|
||||
const intptr_t num_context_vars = DecodeOperandE().value();
|
||||
|
||||
auto& context_variables = CompilerState::Current().GetDummyContextVariables(
|
||||
context_id, num_context_vars);
|
||||
|
@ -1228,7 +1242,7 @@ void BytecodeFlowGraphBuilder::BuildStoreContextVar() {
|
|||
|
||||
LoadStackSlots(2);
|
||||
const intptr_t context_id = DecodeOperandA().value();
|
||||
const intptr_t var_index = DecodeOperandD().value();
|
||||
const intptr_t var_index = DecodeOperandE().value();
|
||||
|
||||
auto var =
|
||||
CompilerState::Current().GetDummyCapturedVariable(context_id, var_index);
|
||||
|
@ -1243,7 +1257,7 @@ void BytecodeFlowGraphBuilder::BuildLoadContextVar() {
|
|||
|
||||
LoadStackSlots(1);
|
||||
const intptr_t context_id = DecodeOperandA().value();
|
||||
const intptr_t var_index = DecodeOperandD().value();
|
||||
const intptr_t var_index = DecodeOperandE().value();
|
||||
|
||||
auto var =
|
||||
CompilerState::Current().GetDummyCapturedVariable(context_id, var_index);
|
||||
|
@ -1313,7 +1327,7 @@ void BytecodeFlowGraphBuilder::BuildInstantiateTypeArgumentsTOS() {
|
|||
}
|
||||
|
||||
const TypeArguments& type_args =
|
||||
TypeArguments::Cast(ConstantAt(DecodeOperandD()).value());
|
||||
TypeArguments::Cast(ConstantAt(DecodeOperandE()).value());
|
||||
|
||||
LoadStackSlots(2);
|
||||
code_ += B->InstantiateTypeArguments(type_args);
|
||||
|
@ -1534,7 +1548,7 @@ void BytecodeFlowGraphBuilder::BuildMoveSpecial() {
|
|||
}
|
||||
|
||||
code_ += B->LoadLocal(special_var);
|
||||
StoreLocal(DecodeOperandX());
|
||||
StoreLocal(DecodeOperandY());
|
||||
code_ += B->Drop();
|
||||
}
|
||||
|
||||
|
@ -1799,12 +1813,19 @@ JoinEntryInstr* BytecodeFlowGraphBuilder::EnsureControlFlowJoin(
|
|||
bool BytecodeFlowGraphBuilder::RequiresScratchVar(const KBCInstr* instr) {
|
||||
switch (KernelBytecode::DecodeOpcode(instr)) {
|
||||
case KernelBytecode::kEntryOptional:
|
||||
case KernelBytecode::kEntryOptional_Old:
|
||||
return KernelBytecode::DecodeC(instr) > 0;
|
||||
|
||||
case KernelBytecode::kEqualsNull:
|
||||
case KernelBytecode::kEqualsNull_Old:
|
||||
return true;
|
||||
|
||||
case KernelBytecode::kNativeCall:
|
||||
case KernelBytecode::kNativeCall_Wide:
|
||||
case KernelBytecode::kNativeCall_Old:
|
||||
return MethodRecognizer::RecognizeKind(function()) ==
|
||||
MethodRecognizer::kListFactory;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
@ -1820,8 +1841,7 @@ void BytecodeFlowGraphBuilder::CollectControlFlow(
|
|||
if (KernelBytecode::IsJumpOpcode(instr)) {
|
||||
const intptr_t target = pc + KernelBytecode::DecodeT(instr);
|
||||
EnsureControlFlowJoin(descriptors, target);
|
||||
} else if ((KernelBytecode::DecodeOpcode(instr) ==
|
||||
KernelBytecode::kCheckStack) &&
|
||||
} else if (KernelBytecode::IsCheckStackOpcode(instr) &&
|
||||
(KernelBytecode::DecodeA(instr) != 0)) {
|
||||
// (dartbug.com/36590) BlockEntryInstr::FindOsrEntryAndRelink assumes
|
||||
// that CheckStackOverflow instruction is at the beginning of a join
|
||||
|
@ -1872,7 +1892,7 @@ void BytecodeFlowGraphBuilder::CollectControlFlow(
|
|||
JoinEntryInstr* join = EnsureControlFlowJoin(descriptors, handler_pc);
|
||||
|
||||
// Make sure exception handler starts with SetFrame bytecode instruction.
|
||||
InstructionAt(handler_pc, KernelBytecode::kSetFrame);
|
||||
ASSERT(KernelBytecode::IsSetFrameOpcode(&(raw_bytecode_[handler_pc])));
|
||||
|
||||
const Array& handler_types =
|
||||
Array::ZoneHandle(Z, handlers.GetHandledTypes(try_index));
|
||||
|
|
|
@ -108,10 +108,11 @@ class BytecodeFlowGraphBuilder {
|
|||
Operand DecodeOperandB();
|
||||
Operand DecodeOperandC();
|
||||
Operand DecodeOperandD();
|
||||
Operand DecodeOperandE();
|
||||
Operand DecodeOperandF();
|
||||
Operand DecodeOperandX();
|
||||
Operand DecodeOperandY();
|
||||
Operand DecodeOperandT();
|
||||
const KBCInstr* InstructionAt(intptr_t pc,
|
||||
KernelBytecode::Opcode expect_opcode);
|
||||
Constant ConstantAt(Operand entry_index, intptr_t add_index = 0);
|
||||
void PushConstant(Constant constant);
|
||||
Constant PopConstant();
|
||||
|
@ -141,7 +142,8 @@ class BytecodeFlowGraphBuilder {
|
|||
|
||||
void BuildInstruction(KernelBytecode::Opcode opcode);
|
||||
|
||||
#define DECLARE_BUILD_METHOD(name, encoding, op1, op2, op3) void Build##name();
|
||||
#define DECLARE_BUILD_METHOD(name, encoding, kind, op1, op2, op3) \
|
||||
void Build##name();
|
||||
KERNEL_BYTECODES_LIST(DECLARE_BUILD_METHOD)
|
||||
#undef DECLARE_BUILD_METHOD
|
||||
|
||||
|
|
|
@ -686,9 +686,15 @@ RawBytecode* BytecodeReaderHelper::ReadBytecode(const ObjectPool& pool) {
|
|||
"BytecodeReaderHelper::ReadBytecode");
|
||||
#endif // defined(SUPPORT_TIMELINE)
|
||||
intptr_t size = helper_->ReadUInt();
|
||||
// TODO(alexmarkov): remove padding.
|
||||
const intptr_t kAlignment = 4;
|
||||
intptr_t offset = Utils::RoundUp(helper_->reader_.offset(), kAlignment);
|
||||
intptr_t offset = helper_->reader_.offset();
|
||||
|
||||
static_assert(KernelBytecode::kMinSupportedBytecodeFormatVersion < 7,
|
||||
"Cleanup support for old bytecode format versions");
|
||||
if (bytecode_component_->GetVersion() < 7) {
|
||||
const intptr_t kAlignment = 4;
|
||||
offset = Utils::RoundUp(offset, kAlignment);
|
||||
}
|
||||
|
||||
const uint8_t* data = helper_->reader_.BufferAt(offset);
|
||||
helper_->reader_.set_offset(offset + size);
|
||||
|
||||
|
@ -713,21 +719,24 @@ void BytecodeReaderHelper::ReadExceptionsTable(const Bytecode& bytecode,
|
|||
ExceptionHandlerList* exception_handlers_list =
|
||||
new (Z) ExceptionHandlerList();
|
||||
|
||||
static_assert(KernelBytecode::kMinSupportedBytecodeFormatVersion < 7,
|
||||
"Cleanup support for old bytecode format versions");
|
||||
const int kPCShifter = (bytecode_component_->GetVersion() < 7) ? 2 : 0;
|
||||
|
||||
// Encoding of ExceptionsTable is described in
|
||||
// pkg/vm/lib/bytecode/exceptions.dart.
|
||||
for (intptr_t try_index = 0; try_index < try_block_count; try_index++) {
|
||||
intptr_t outer_try_index_plus1 = helper_->reader_.ReadUInt();
|
||||
intptr_t outer_try_index = outer_try_index_plus1 - 1;
|
||||
// PcDescriptors are expressed in terms of return addresses.
|
||||
const int kPCMultiplier = 4;
|
||||
intptr_t start_pc = KernelBytecode::BytecodePcToOffset(
|
||||
helper_->reader_.ReadUInt() * kPCMultiplier,
|
||||
helper_->reader_.ReadUInt() << kPCShifter,
|
||||
/* is_return_address = */ true);
|
||||
intptr_t end_pc = KernelBytecode::BytecodePcToOffset(
|
||||
helper_->reader_.ReadUInt() * kPCMultiplier,
|
||||
helper_->reader_.ReadUInt() << kPCShifter,
|
||||
/* is_return_address = */ true);
|
||||
intptr_t handler_pc = KernelBytecode::BytecodePcToOffset(
|
||||
helper_->reader_.ReadUInt() * kPCMultiplier,
|
||||
helper_->reader_.ReadUInt() << kPCShifter,
|
||||
/* is_return_address = */ false);
|
||||
uint8_t flags = helper_->reader_.ReadByte();
|
||||
const uint8_t kFlagNeedsStackTrace = 1 << 0;
|
||||
|
@ -854,6 +863,9 @@ RawArray* BytecodeReaderHelper::ReadBytecodeComponent(intptr_t md_offset) {
|
|||
const intptr_t start_offset = helper_->reader_.offset();
|
||||
|
||||
intptr_t magic = helper_->reader_.ReadUInt32();
|
||||
|
||||
static_assert(KernelBytecode::kMinSupportedBytecodeFormatVersion < 3,
|
||||
"Cleanup support for old bytecode format versions");
|
||||
if (magic != KernelBytecode::kMagicValue) {
|
||||
return ReadBytecodeComponentV2(md_offset);
|
||||
}
|
||||
|
@ -868,6 +880,7 @@ RawArray* BytecodeReaderHelper::ReadBytecodeComponent(intptr_t md_offset) {
|
|||
version, KernelBytecode::kMinSupportedBytecodeFormatVersion,
|
||||
KernelBytecode::kMaxSupportedBytecodeFormatVersion);
|
||||
}
|
||||
BytecodeReader::UseBytecodeVersion(version);
|
||||
|
||||
helper_->reader_.ReadUInt32(); // Skip stringTable.numItems
|
||||
const intptr_t string_table_offset =
|
||||
|
@ -934,6 +947,8 @@ RawArray* BytecodeReaderHelper::ReadBytecodeComponent(intptr_t md_offset) {
|
|||
|
||||
// TODO(alexmarkov): obsolete, remove when dropping support for old bytecode
|
||||
// format version.
|
||||
static_assert(KernelBytecode::kMinSupportedBytecodeFormatVersion < 3,
|
||||
"Cleanup support for old bytecode format versions");
|
||||
RawArray* BytecodeReaderHelper::ReadBytecodeComponentV2(intptr_t md_offset) {
|
||||
AlternativeReadingScope alt(&helper_->reader_, &H.metadata_payloads(),
|
||||
md_offset);
|
||||
|
@ -945,6 +960,7 @@ RawArray* BytecodeReaderHelper::ReadBytecodeComponentV2(intptr_t md_offset) {
|
|||
if ((version < kMinVersion) || (version > kMaxVersion)) {
|
||||
FATAL1("Unsupported Dart bytecode format version %" Pd ".", version);
|
||||
}
|
||||
BytecodeReader::UseBytecodeVersion(version);
|
||||
|
||||
const intptr_t strings_size = helper_->reader_.ReadUInt();
|
||||
helper_->reader_.ReadUInt(); // Objects table size.
|
||||
|
@ -2038,8 +2054,7 @@ void BytecodeReaderHelper::ParseForwarderFunction(
|
|||
reinterpret_cast<const KBCInstr*>(target_bytecode.PayloadStart());
|
||||
const KBCInstr* entry = raw_bytecode;
|
||||
raw_bytecode = KernelBytecode::Next(raw_bytecode);
|
||||
ASSERT(KernelBytecode::DecodeOpcode(entry) ==
|
||||
KernelBytecode::kEntryOptional);
|
||||
ASSERT(KernelBytecode::IsEntryOptionalOpcode(entry));
|
||||
ASSERT(KernelBytecode::DecodeB(entry) ==
|
||||
function.NumOptionalPositionalParameters());
|
||||
ASSERT(KernelBytecode::DecodeC(entry) ==
|
||||
|
@ -2054,10 +2069,9 @@ void BytecodeReaderHelper::ParseForwarderFunction(
|
|||
i < n; ++i) {
|
||||
const KBCInstr* load = raw_bytecode;
|
||||
raw_bytecode = KernelBytecode::Next(raw_bytecode);
|
||||
ASSERT(KernelBytecode::DecodeOpcode(load) ==
|
||||
KernelBytecode::kLoadConstant);
|
||||
ASSERT(KernelBytecode::IsLoadConstantOpcode(load));
|
||||
const auto& value = Instance::CheckedZoneHandle(
|
||||
Z, obj_pool.ObjectAt(KernelBytecode::DecodeD(load)));
|
||||
Z, obj_pool.ObjectAt(KernelBytecode::DecodeE(load)));
|
||||
default_values->Add(&value);
|
||||
}
|
||||
} else {
|
||||
|
@ -2068,13 +2082,11 @@ void BytecodeReaderHelper::ParseForwarderFunction(
|
|||
const KBCInstr* load_name = raw_bytecode;
|
||||
const KBCInstr* load_value = KernelBytecode::Next(load_name);
|
||||
raw_bytecode = KernelBytecode::Next(load_value);
|
||||
ASSERT(KernelBytecode::DecodeOpcode(load_name) ==
|
||||
KernelBytecode::kLoadConstant);
|
||||
ASSERT(KernelBytecode::DecodeOpcode(load_value) ==
|
||||
KernelBytecode::kLoadConstant);
|
||||
param_name ^= obj_pool.ObjectAt(KernelBytecode::DecodeD(load_name));
|
||||
ASSERT(KernelBytecode::IsLoadConstantOpcode(load_name));
|
||||
ASSERT(KernelBytecode::IsLoadConstantOpcode(load_value));
|
||||
param_name ^= obj_pool.ObjectAt(KernelBytecode::DecodeE(load_name));
|
||||
const auto& value = Instance::CheckedZoneHandle(
|
||||
Z, obj_pool.ObjectAt(KernelBytecode::DecodeD(load_value)));
|
||||
Z, obj_pool.ObjectAt(KernelBytecode::DecodeE(load_value)));
|
||||
|
||||
const intptr_t num_params = function.NumParameters();
|
||||
intptr_t param_index = num_fixed_params;
|
||||
|
@ -2258,6 +2270,28 @@ RawObject* BytecodeReader::ReadAnnotation(const Field& annotation_field) {
|
|||
annotation_field.bytecode_offset());
|
||||
}
|
||||
|
||||
static_assert(KernelBytecode::kMinSupportedBytecodeFormatVersion < 7,
|
||||
"Cleanup support for old bytecode format versions");
|
||||
void BytecodeReader::UseBytecodeVersion(intptr_t version) {
|
||||
Isolate* isolate = Isolate::Current();
|
||||
bool using_old = isolate->is_using_old_bytecode_instructions();
|
||||
bool using_new = isolate->is_using_new_bytecode_instructions();
|
||||
if (version < 7) {
|
||||
using_old = true;
|
||||
isolate->set_is_using_old_bytecode_instructions(true);
|
||||
} else {
|
||||
using_new = true;
|
||||
isolate->set_is_using_new_bytecode_instructions(true);
|
||||
}
|
||||
|
||||
if (using_old && using_new) {
|
||||
FATAL1(
|
||||
"Unable to use both new and old bytecode instructions in the same Dart "
|
||||
"isolate (%s)",
|
||||
isolate->name());
|
||||
}
|
||||
}
|
||||
|
||||
bool IsStaticFieldGetterGeneratedAsInitializer(const Function& function,
|
||||
Zone* zone) {
|
||||
ASSERT(function.kind() == RawFunction::kImplicitStaticGetter);
|
||||
|
|
|
@ -261,6 +261,8 @@ class BytecodeReader : public AllStatic {
|
|||
|
||||
// Read annotation for the given annotation field.
|
||||
static RawObject* ReadAnnotation(const Field& annotation_field);
|
||||
|
||||
static void UseBytecodeVersion(intptr_t version);
|
||||
};
|
||||
|
||||
class BytecodeSourcePositionsIterator : ValueObject {
|
||||
|
@ -268,6 +270,8 @@ class BytecodeSourcePositionsIterator : ValueObject {
|
|||
BytecodeSourcePositionsIterator(Zone* zone, const Bytecode& bytecode)
|
||||
: reader_(ExternalTypedData::Handle(zone, bytecode.GetBinary(zone))),
|
||||
pairs_remaining_(0),
|
||||
pc_shifter_(
|
||||
Isolate::Current()->is_using_old_bytecode_instructions() ? 2 : 0),
|
||||
cur_bci_(0),
|
||||
cur_token_pos_(TokenPosition::kNoSource.value()) {
|
||||
if (bytecode.HasSourcePositions()) {
|
||||
|
@ -282,8 +286,7 @@ class BytecodeSourcePositionsIterator : ValueObject {
|
|||
}
|
||||
ASSERT(pairs_remaining_ > 0);
|
||||
--pairs_remaining_;
|
||||
const int kPCMultiplier = 4;
|
||||
cur_bci_ += reader_.ReadUInt() * kPCMultiplier;
|
||||
cur_bci_ += reader_.ReadUInt() << pc_shifter_;
|
||||
cur_token_pos_ += reader_.ReadSLEB128();
|
||||
return true;
|
||||
}
|
||||
|
@ -300,6 +303,7 @@ class BytecodeSourcePositionsIterator : ValueObject {
|
|||
private:
|
||||
Reader reader_;
|
||||
intptr_t pairs_remaining_;
|
||||
intptr_t pc_shifter_;
|
||||
intptr_t cur_bci_;
|
||||
intptr_t cur_token_pos_;
|
||||
};
|
||||
|
|
|
@ -7,9 +7,44 @@
|
|||
|
||||
namespace dart {
|
||||
|
||||
#define DECLARE_INSTRUCTIONS(name, fmt, fmta, fmtb, fmtc) \
|
||||
static_assert(KernelBytecode::kMinSupportedBytecodeFormatVersion < 7,
|
||||
"Cleanup support for old bytecode format versions");
|
||||
static const intptr_t kOldInstructionSize = 4;
|
||||
|
||||
static const intptr_t kInstructionSize0 = 1;
|
||||
static const intptr_t kInstructionSizeA = 2;
|
||||
static const intptr_t kInstructionSizeD = 2;
|
||||
static const intptr_t kInstructionSizeWideD = 5;
|
||||
static const intptr_t kInstructionSizeX = 2;
|
||||
static const intptr_t kInstructionSizeWideX = 5;
|
||||
static const intptr_t kInstructionSizeT = 2;
|
||||
static const intptr_t kInstructionSizeWideT = 4;
|
||||
static const intptr_t kInstructionSizeA_E = 3;
|
||||
static const intptr_t kInstructionSizeWideA_E = 6;
|
||||
static const intptr_t kInstructionSizeA_Y = 3;
|
||||
static const intptr_t kInstructionSizeWideA_Y = 6;
|
||||
static const intptr_t kInstructionSizeD_F = 3;
|
||||
static const intptr_t kInstructionSizeWideD_F = 6;
|
||||
static const intptr_t kInstructionSizeA_B_C = 4;
|
||||
|
||||
const intptr_t KernelBytecode::kInstructionSize[] = {
|
||||
#define SIZE_OLD(encoding) kOldInstructionSize
|
||||
#define SIZE_ORDN(encoding) kInstructionSize##encoding
|
||||
#define SIZE_WIDE(encoding) kInstructionSizeWide##encoding
|
||||
#define SIZE_RESV(encoding) SIZE_ORDN(encoding)
|
||||
#define SIZE(name, encoding, kind, op1, op2, op3) SIZE_##kind(encoding),
|
||||
KERNEL_BYTECODES_LIST(SIZE)
|
||||
#undef SIZE_OLD
|
||||
#undef SIZE_ORDN
|
||||
#undef SIZE_WIDE
|
||||
#undef SIZE_RESV
|
||||
#undef SIZE
|
||||
};
|
||||
|
||||
#define DECLARE_INSTRUCTIONS(name, fmt, kind, fmta, fmtb, fmtc) \
|
||||
static const KBCInstr k##name##Instructions[] = { \
|
||||
KernelBytecode::k##name, 0, 0, 0, KernelBytecode::kReturnTOS, 0, 0, 0, \
|
||||
KernelBytecode::k##name, \
|
||||
KernelBytecode::kReturnTOS, \
|
||||
};
|
||||
INTERNAL_KERNEL_BYTECODES_LIST(DECLARE_INSTRUCTIONS)
|
||||
#undef DECLARE_INSTRUCTIONS
|
||||
|
@ -19,7 +54,7 @@ void KernelBytecode::GetVMInternalBytecodeInstructions(
|
|||
const KBCInstr** instructions,
|
||||
intptr_t* instructions_size) {
|
||||
switch (opcode) {
|
||||
#define CASE(name, fmt, fmta, fmtb, fmtc) \
|
||||
#define CASE(name, fmt, kind, fmta, fmtb, fmtc) \
|
||||
case k##name: \
|
||||
*instructions = k##name##Instructions; \
|
||||
*instructions_size = sizeof(k##name##Instructions); \
|
||||
|
@ -33,4 +68,15 @@ void KernelBytecode::GetVMInternalBytecodeInstructions(
|
|||
}
|
||||
}
|
||||
|
||||
static const KBCInstr kNativeCallToGrowableListReturnTrampoline[] = {
|
||||
KernelBytecode::kDirectCall,
|
||||
0, // target (doesn't matter)
|
||||
KernelBytecode::kNativeCallToGrowableListArgc, // number of arguments
|
||||
KernelBytecode::kReturnTOS,
|
||||
};
|
||||
|
||||
const KBCInstr* KernelBytecode::GetNativeCallToGrowableListReturnTrampoline() {
|
||||
return KernelBytecode::Next(&kNativeCallToGrowableListReturnTrampoline[0]);
|
||||
}
|
||||
|
||||
} // namespace dart
|
||||
|
|
|
@ -40,40 +40,71 @@ namespace dart {
|
|||
//
|
||||
// ENCODING
|
||||
//
|
||||
// Each instruction is a 32-bit integer with opcode stored in the least
|
||||
// significant byte. The following operand encodings are used:
|
||||
// Each instruction starts with opcode byte. Certain instructions have
|
||||
// wide encoding variant. In such case, the least significant bit of opcode is
|
||||
// not set for compact variant and set for wide variant.
|
||||
//
|
||||
// 0........8.......16.......24.......32
|
||||
// +--------+--------+--------+--------+
|
||||
// | opcode |~~~~~~~~~~~~~~~~~~~~~~~~~~| 0: no operands
|
||||
// +--------+--------+--------+--------+
|
||||
// The following operand encodings are used:
|
||||
//
|
||||
// 0........8.......16.......24.......32.......40.......48
|
||||
// +--------+
|
||||
// | opcode | 0: no operands
|
||||
// +--------+
|
||||
//
|
||||
// +--------+--------+
|
||||
// | opcode | A | A: unsigned 8-bit operand
|
||||
// +--------+--------+
|
||||
//
|
||||
// +--------+--------+
|
||||
// | opcode | D | D: unsigned 8/32-bit operand
|
||||
// +--------+--------+
|
||||
//
|
||||
// +--------+----------------------------------+
|
||||
// | opcode | D | D (wide)
|
||||
// +--------+----------------------------------+
|
||||
//
|
||||
// +--------+--------+
|
||||
// | opcode | X | X: signed 8/32-bit operand
|
||||
// +--------+--------+
|
||||
//
|
||||
// +--------+----------------------------------+
|
||||
// | opcode | X | X (wide)
|
||||
// +--------+----------------------------------+
|
||||
//
|
||||
// +--------+--------+
|
||||
// | opcode | T | T: signed 8/24-bit operand
|
||||
// +--------+--------+
|
||||
//
|
||||
// +--------+--------------------------+
|
||||
// | opcode | T | T (wide)
|
||||
// +--------+--------------------------+
|
||||
//
|
||||
// +--------+--------+--------+
|
||||
// | opcode | A | E | A_E: unsigned 8-bit operand and
|
||||
// +--------+--------+--------+ unsigned 8/32-bit operand
|
||||
//
|
||||
// +--------+--------+----------------------------------+
|
||||
// | opcode | A | E | A_E (wide)
|
||||
// +--------+--------+----------------------------------+
|
||||
//
|
||||
// +--------+--------+--------+
|
||||
// | opcode | A | Y | A_Y: unsigned 8-bit operand and
|
||||
// +--------+--------+--------+ signed 8/32-bit operand
|
||||
//
|
||||
// +--------+--------+----------------------------------+
|
||||
// | opcode | A | Y | A_Y (wide)
|
||||
// +--------+--------+----------------------------------+
|
||||
//
|
||||
// +--------+--------+--------+
|
||||
// | opcode | D | F | D_F: unsigned 8/32-bit operand and
|
||||
// +--------+--------+--------+ unsigned 8-bit operand
|
||||
//
|
||||
// +--------+----------------------------------+--------+
|
||||
// | opcode | D | F | D_F (wide)
|
||||
// +--------+----------------------------------+--------+
|
||||
//
|
||||
// +--------+--------+--------+--------+
|
||||
// | opcode | A |~~~~~~~~~~~~~~~~~| A: single unsigned 8-bit operand
|
||||
// +--------+--------+--------+--------+
|
||||
//
|
||||
// +--------+--------+--------+--------+
|
||||
// | opcode | A | D | A_D: unsigned 8-bit operand and
|
||||
// +--------+--------+--------+--------+ unsigned 16-bit operand
|
||||
//
|
||||
// +--------+--------+--------+--------+
|
||||
// | opcode | A | X | A_X: unsigned 8-bit operand and
|
||||
// +--------+--------+--------+--------+ signed 16-bit operand
|
||||
//
|
||||
// +--------+--------+--------+--------+
|
||||
// | opcode |~~~~~~~~| D | D: unsigned 16-bit operand
|
||||
// +--------+--------+--------+--------+
|
||||
//
|
||||
// +--------+--------+--------+--------+
|
||||
// | opcode |~~~~~~~~| X | X: signed 16-bit operand
|
||||
// +--------+--------+--------+--------+
|
||||
//
|
||||
// +--------+--------+--------+--------+
|
||||
// | opcode | A | B | C | A_B_C: 3 unsigned 8-bit operands
|
||||
// +--------+--------+--------+--------+
|
||||
//
|
||||
// +--------+--------+--------+--------+
|
||||
// | opcode | T | T: signed 24-bit operand
|
||||
// | opcode | A | B | C | A_B_C: 3 unsigned 8-bit operands
|
||||
// +--------+--------+--------+--------+
|
||||
//
|
||||
//
|
||||
|
@ -419,12 +450,14 @@ namespace dart {
|
|||
//
|
||||
// KernelBytecode list below is specified using the following format:
|
||||
//
|
||||
// V(BytecodeName, OperandForm, Op1, Op2, Op3)
|
||||
// V(BytecodeName, OperandForm, BytecodeKind, Op1, Op2, Op3)
|
||||
//
|
||||
// - OperandForm specifies operand encoding and should be one of 0, A, T, A_D,
|
||||
// A_X, X, D (see ENCODING section above).
|
||||
// - OperandForm specifies operand encoding and should be one of 0, A, D, X, T,
|
||||
// A_D (old), A_X (old), A_E, A_Y, D_F or A_B_C (see ENCODING section above).
|
||||
//
|
||||
// - Op1, Op2, Op2 specify operand meaning. Possible values:
|
||||
// - BytecodeKind is one of OLD, WIDE, RESV (reserved), ORDN (ordinary)
|
||||
//
|
||||
// - Op1, Op2, Op3 specify operand meaning. Possible values:
|
||||
//
|
||||
// ___ ignored / non-existent operand
|
||||
// num immediate operand
|
||||
|
@ -438,105 +471,266 @@ namespace dart {
|
|||
// and before decoding.
|
||||
//
|
||||
#define PUBLIC_KERNEL_BYTECODES_LIST(V) \
|
||||
V(Trap, 0, ___, ___, ___) \
|
||||
V(Entry, D, num, ___, ___) \
|
||||
V(EntryFixed, A_D, num, num, ___) \
|
||||
V(EntryOptional, A_B_C, num, num, num) \
|
||||
V(LoadConstant, A_D, reg, lit, ___) \
|
||||
V(Frame, D, num, ___, ___) \
|
||||
V(CheckFunctionTypeArgs, A_D, num, reg, ___) \
|
||||
V(CheckStack, A, num, ___, ___) \
|
||||
V(Allocate, D, lit, ___, ___) \
|
||||
V(AllocateT, 0, ___, ___, ___) \
|
||||
V(CreateArrayTOS, 0, ___, ___, ___) \
|
||||
V(AllocateContext, D, num, ___, ___) \
|
||||
V(CloneContext, D, num, ___, ___) \
|
||||
V(LoadContextParent, 0, ___, ___, ___) \
|
||||
V(StoreContextParent, 0, ___, ___, ___) \
|
||||
V(LoadContextVar, D, num, ___, ___) \
|
||||
V(StoreContextVar, D, num, ___, ___) \
|
||||
V(PushConstant, D, lit, ___, ___) \
|
||||
V(PushNull, 0, ___, ___, ___) \
|
||||
V(PushTrue, 0, ___, ___, ___) \
|
||||
V(PushFalse, 0, ___, ___, ___) \
|
||||
V(PushInt, X, num, ___, ___) \
|
||||
V(Drop1, 0, ___, ___, ___) \
|
||||
V(Push, X, xeg, ___, ___) \
|
||||
V(PopLocal, X, xeg, ___, ___) \
|
||||
V(StoreLocal, X, xeg, ___, ___) \
|
||||
V(LoadFieldTOS, D, lit, ___, ___) \
|
||||
V(StoreFieldTOS, D, lit, ___, ___) \
|
||||
V(StoreIndexedTOS, 0, ___, ___, ___) \
|
||||
V(PushStatic, D, lit, ___, ___) \
|
||||
V(StoreStaticTOS, D, lit, ___, ___) \
|
||||
V(Jump, T, tgt, ___, ___) \
|
||||
V(JumpIfNoAsserts, T, tgt, ___, ___) \
|
||||
V(JumpIfNotZeroTypeArgs, T, tgt, ___, ___) \
|
||||
V(JumpIfEqStrict, T, tgt, ___, ___) \
|
||||
V(JumpIfNeStrict, T, tgt, ___, ___) \
|
||||
V(JumpIfTrue, T, tgt, ___, ___) \
|
||||
V(JumpIfFalse, T, tgt, ___, ___) \
|
||||
V(JumpIfNull, T, tgt, ___, ___) \
|
||||
V(JumpIfNotNull, T, tgt, ___, ___) \
|
||||
V(IndirectStaticCall, A_D, num, num, ___) \
|
||||
V(InterfaceCall, A_D, num, num, ___) \
|
||||
V(DynamicCall, A_D, num, num, ___) \
|
||||
V(NativeCall, D, lit, ___, ___) \
|
||||
V(ReturnTOS, 0, ___, ___, ___) \
|
||||
V(AssertAssignable, A_D, num, lit, ___) \
|
||||
V(AssertBoolean, A, num, ___, ___) \
|
||||
V(AssertSubtype, 0, ___, ___, ___) \
|
||||
V(LoadTypeArgumentsField, D, lit, ___, ___) \
|
||||
V(InstantiateType, D, lit, ___, ___) \
|
||||
V(InstantiateTypeArgumentsTOS, A_D, num, lit, ___) \
|
||||
V(Throw, A, num, ___, ___) \
|
||||
V(MoveSpecial, A_X, num, xeg, ___) \
|
||||
V(SetFrame, A, num, ___, num) \
|
||||
V(BooleanNegateTOS, 0, ___, ___, ___) \
|
||||
V(EqualsNull, 0, ___, ___, ___) \
|
||||
V(NegateInt, 0, ___, ___, ___) \
|
||||
V(AddInt, 0, ___, ___, ___) \
|
||||
V(SubInt, 0, ___, ___, ___) \
|
||||
V(MulInt, 0, ___, ___, ___) \
|
||||
V(TruncDivInt, 0, ___, ___, ___) \
|
||||
V(ModInt, 0, ___, ___, ___) \
|
||||
V(BitAndInt, 0, ___, ___, ___) \
|
||||
V(BitOrInt, 0, ___, ___, ___) \
|
||||
V(BitXorInt, 0, ___, ___, ___) \
|
||||
V(ShlInt, 0, ___, ___, ___) \
|
||||
V(ShrInt, 0, ___, ___, ___) \
|
||||
V(CompareIntEq, 0, ___, ___, ___) \
|
||||
V(CompareIntGt, 0, ___, ___, ___) \
|
||||
V(CompareIntLt, 0, ___, ___, ___) \
|
||||
V(CompareIntGe, 0, ___, ___, ___) \
|
||||
V(CompareIntLe, 0, ___, ___, ___) \
|
||||
V(DirectCall, A_D, num, num, ___) \
|
||||
V(AllocateClosure, D, lit, ___, ___) \
|
||||
V(UncheckedInterfaceCall, A_D, num, num, ___) \
|
||||
V(NegateDouble, 0, ___, ___, ___) \
|
||||
V(AddDouble, 0, ___, ___, ___) \
|
||||
V(SubDouble, 0, ___, ___, ___) \
|
||||
V(MulDouble, 0, ___, ___, ___) \
|
||||
V(DivDouble, 0, ___, ___, ___) \
|
||||
V(CompareDoubleEq, 0, ___, ___, ___) \
|
||||
V(CompareDoubleGt, 0, ___, ___, ___) \
|
||||
V(CompareDoubleLt, 0, ___, ___, ___) \
|
||||
V(CompareDoubleGe, 0, ___, ___, ___) \
|
||||
V(CompareDoubleLe, 0, ___, ___, ___) \
|
||||
V(Trap_Old, 0, OLD, ___, ___, ___) \
|
||||
V(Entry_Old, D, OLD, num, ___, ___) \
|
||||
V(EntryFixed_Old, A_D, OLD, num, num, ___) \
|
||||
V(EntryOptional_Old, A_B_C, OLD, num, num, num) \
|
||||
V(LoadConstant_Old, A_D, OLD, reg, lit, ___) \
|
||||
V(Frame_Old, D, OLD, num, ___, ___) \
|
||||
V(CheckFunctionTypeArgs_Old, A_D, OLD, num, reg, ___) \
|
||||
V(CheckStack_Old, A, OLD, num, ___, ___) \
|
||||
V(Allocate_Old, D, OLD, lit, ___, ___) \
|
||||
V(AllocateT_Old, 0, OLD, ___, ___, ___) \
|
||||
V(CreateArrayTOS_Old, 0, OLD, ___, ___, ___) \
|
||||
V(AllocateContext_Old, D, OLD, num, ___, ___) \
|
||||
V(CloneContext_Old, D, OLD, num, ___, ___) \
|
||||
V(LoadContextParent_Old, 0, OLD, ___, ___, ___) \
|
||||
V(StoreContextParent_Old, 0, OLD, ___, ___, ___) \
|
||||
V(LoadContextVar_Old, D, OLD, num, ___, ___) \
|
||||
V(StoreContextVar_Old, D, OLD, num, ___, ___) \
|
||||
V(PushConstant_Old, D, OLD, lit, ___, ___) \
|
||||
V(PushNull_Old, 0, OLD, ___, ___, ___) \
|
||||
V(PushTrue_Old, 0, OLD, ___, ___, ___) \
|
||||
V(PushFalse_Old, 0, OLD, ___, ___, ___) \
|
||||
V(PushInt_Old, X, OLD, num, ___, ___) \
|
||||
V(Drop1_Old, 0, OLD, ___, ___, ___) \
|
||||
V(Push_Old, X, OLD, xeg, ___, ___) \
|
||||
V(PopLocal_Old, X, OLD, xeg, ___, ___) \
|
||||
V(StoreLocal_Old, X, OLD, xeg, ___, ___) \
|
||||
V(LoadFieldTOS_Old, D, OLD, lit, ___, ___) \
|
||||
V(StoreFieldTOS_Old, D, OLD, lit, ___, ___) \
|
||||
V(StoreIndexedTOS_Old, 0, OLD, ___, ___, ___) \
|
||||
V(PushStatic_Old, D, OLD, lit, ___, ___) \
|
||||
V(StoreStaticTOS_Old, D, OLD, lit, ___, ___) \
|
||||
V(Jump_Old, T, OLD, tgt, ___, ___) \
|
||||
V(JumpIfNoAsserts_Old, T, OLD, tgt, ___, ___) \
|
||||
V(JumpIfNotZeroTypeArgs_Old, T, OLD, tgt, ___, ___) \
|
||||
V(JumpIfEqStrict_Old, T, OLD, tgt, ___, ___) \
|
||||
V(JumpIfNeStrict_Old, T, OLD, tgt, ___, ___) \
|
||||
V(JumpIfTrue_Old, T, OLD, tgt, ___, ___) \
|
||||
V(JumpIfFalse_Old, T, OLD, tgt, ___, ___) \
|
||||
V(JumpIfNull_Old, T, OLD, tgt, ___, ___) \
|
||||
V(JumpIfNotNull_Old, T, OLD, tgt, ___, ___) \
|
||||
V(Unused00_Old, 0, RESV, num, num, ___) \
|
||||
V(InterfaceCall_Old, A_D, OLD, num, num, ___) \
|
||||
V(DynamicCall_Old, A_D, OLD, num, num, ___) \
|
||||
V(NativeCall_Old, D, OLD, lit, ___, ___) \
|
||||
V(ReturnTOS_Old, 0, OLD, ___, ___, ___) \
|
||||
V(AssertAssignable_Old, A_D, OLD, num, lit, ___) \
|
||||
V(AssertBoolean_Old, A, OLD, num, ___, ___) \
|
||||
V(AssertSubtype_Old, 0, OLD, ___, ___, ___) \
|
||||
V(LoadTypeArgumentsField_Old, D, OLD, lit, ___, ___) \
|
||||
V(InstantiateType_Old, D, OLD, lit, ___, ___) \
|
||||
V(InstantiateTypeArgumentsTOS_Old, A_D, OLD, num, lit, ___) \
|
||||
V(Throw_Old, A, OLD, num, ___, ___) \
|
||||
V(MoveSpecial_Old, A_X, OLD, num, xeg, ___) \
|
||||
V(SetFrame_Old, A, OLD, num, ___, num) \
|
||||
V(BooleanNegateTOS_Old, 0, OLD, ___, ___, ___) \
|
||||
V(EqualsNull_Old, 0, OLD, ___, ___, ___) \
|
||||
V(NegateInt_Old, 0, OLD, ___, ___, ___) \
|
||||
V(AddInt_Old, 0, OLD, ___, ___, ___) \
|
||||
V(SubInt_Old, 0, OLD, ___, ___, ___) \
|
||||
V(MulInt_Old, 0, OLD, ___, ___, ___) \
|
||||
V(TruncDivInt_Old, 0, OLD, ___, ___, ___) \
|
||||
V(ModInt_Old, 0, OLD, ___, ___, ___) \
|
||||
V(BitAndInt_Old, 0, OLD, ___, ___, ___) \
|
||||
V(BitOrInt_Old, 0, OLD, ___, ___, ___) \
|
||||
V(BitXorInt_Old, 0, OLD, ___, ___, ___) \
|
||||
V(ShlInt_Old, 0, OLD, ___, ___, ___) \
|
||||
V(ShrInt_Old, 0, OLD, ___, ___, ___) \
|
||||
V(CompareIntEq_Old, 0, OLD, ___, ___, ___) \
|
||||
V(CompareIntGt_Old, 0, OLD, ___, ___, ___) \
|
||||
V(CompareIntLt_Old, 0, OLD, ___, ___, ___) \
|
||||
V(CompareIntGe_Old, 0, OLD, ___, ___, ___) \
|
||||
V(CompareIntLe_Old, 0, OLD, ___, ___, ___) \
|
||||
V(DirectCall_Old, A_D, OLD, num, num, ___) \
|
||||
V(AllocateClosure_Old, D, OLD, lit, ___, ___) \
|
||||
V(UncheckedInterfaceCall_Old, A_D, OLD, num, num, ___) \
|
||||
V(NegateDouble_Old, 0, OLD, ___, ___, ___) \
|
||||
V(AddDouble_Old, 0, OLD, ___, ___, ___) \
|
||||
V(SubDouble_Old, 0, OLD, ___, ___, ___) \
|
||||
V(MulDouble_Old, 0, OLD, ___, ___, ___) \
|
||||
V(DivDouble_Old, 0, OLD, ___, ___, ___) \
|
||||
V(CompareDoubleEq_Old, 0, OLD, ___, ___, ___) \
|
||||
V(CompareDoubleGt_Old, 0, OLD, ___, ___, ___) \
|
||||
V(CompareDoubleLt_Old, 0, OLD, ___, ___, ___) \
|
||||
V(CompareDoubleGe_Old, 0, OLD, ___, ___, ___) \
|
||||
V(CompareDoubleLe_Old, 0, OLD, ___, ___, ___) \
|
||||
V(Trap, 0, ORDN, ___, ___, ___) \
|
||||
V(Entry, D, ORDN, num, ___, ___) \
|
||||
V(Entry_Wide, D, WIDE, num, ___, ___) \
|
||||
V(EntryFixed, A_E, ORDN, num, num, ___) \
|
||||
V(EntryFixed_Wide, A_E, WIDE, num, num, ___) \
|
||||
V(EntryOptional, A_B_C, ORDN, num, num, num) \
|
||||
V(Unused00, 0, RESV, ___, ___, ___) \
|
||||
V(LoadConstant, A_E, ORDN, reg, lit, ___) \
|
||||
V(LoadConstant_Wide, A_E, WIDE, reg, lit, ___) \
|
||||
V(Frame, D, ORDN, num, ___, ___) \
|
||||
V(Frame_Wide, D, WIDE, num, ___, ___) \
|
||||
V(CheckFunctionTypeArgs, A_E, ORDN, num, reg, ___) \
|
||||
V(CheckFunctionTypeArgs_Wide, A_E, WIDE, num, reg, ___) \
|
||||
V(CheckStack, A, ORDN, num, ___, ___) \
|
||||
V(Unused01, 0, RESV, ___, ___, ___) \
|
||||
V(Unused02, 0, RESV, ___, ___, ___) \
|
||||
V(Unused03, 0, RESV, ___, ___, ___) \
|
||||
V(Allocate, D, ORDN, lit, ___, ___) \
|
||||
V(Allocate_Wide, D, WIDE, lit, ___, ___) \
|
||||
V(AllocateT, 0, ORDN, ___, ___, ___) \
|
||||
V(CreateArrayTOS, 0, ORDN, ___, ___, ___) \
|
||||
V(AllocateClosure, D, ORDN, lit, ___, ___) \
|
||||
V(AllocateClosure_Wide, D, WIDE, lit, ___, ___) \
|
||||
V(AllocateContext, A_E, ORDN, num, ___, ___) \
|
||||
V(AllocateContext_Wide, A_E, WIDE, num, ___, ___) \
|
||||
V(CloneContext, A_E, ORDN, num, ___, ___) \
|
||||
V(CloneContext_Wide, A_E, WIDE, num, ___, ___) \
|
||||
V(LoadContextParent, 0, ORDN, ___, ___, ___) \
|
||||
V(StoreContextParent, 0, ORDN, ___, ___, ___) \
|
||||
V(LoadContextVar, A_E, ORDN, num, ___, ___) \
|
||||
V(LoadContextVar_Wide, A_E, WIDE, num, ___, ___) \
|
||||
V(Unused04, 0, RESV, ___, ___, ___) \
|
||||
V(Unused05, 0, RESV, ___, ___, ___) \
|
||||
V(StoreContextVar, A_E, ORDN, num, ___, ___) \
|
||||
V(StoreContextVar_Wide, A_E, WIDE, num, ___, ___) \
|
||||
V(PushConstant, D, ORDN, lit, ___, ___) \
|
||||
V(PushConstant_Wide, D, WIDE, lit, ___, ___) \
|
||||
V(Unused06, 0, RESV, ___, ___, ___) \
|
||||
V(Unused07, 0, RESV, ___, ___, ___) \
|
||||
V(PushTrue, 0, ORDN, ___, ___, ___) \
|
||||
V(PushFalse, 0, ORDN, ___, ___, ___) \
|
||||
V(PushInt, X, ORDN, num, ___, ___) \
|
||||
V(PushInt_Wide, X, WIDE, num, ___, ___) \
|
||||
V(Unused08, 0, RESV, ___, ___, ___) \
|
||||
V(Unused09, 0, RESV, ___, ___, ___) \
|
||||
V(Unused10, 0, RESV, ___, ___, ___) \
|
||||
V(Unused11, 0, RESV, ___, ___, ___) \
|
||||
V(PushNull, 0, ORDN, ___, ___, ___) \
|
||||
V(Drop1, 0, ORDN, ___, ___, ___) \
|
||||
V(Push, X, ORDN, xeg, ___, ___) \
|
||||
V(Push_Wide, X, WIDE, xeg, ___, ___) \
|
||||
V(Unused12, 0, RESV, ___, ___, ___) \
|
||||
V(Unused13, 0, RESV, ___, ___, ___) \
|
||||
V(Unused14, 0, RESV, ___, ___, ___) \
|
||||
V(Unused15, 0, RESV, ___, ___, ___) \
|
||||
V(Unused16, 0, RESV, ___, ___, ___) \
|
||||
V(Unused17, 0, RESV, ___, ___, ___) \
|
||||
V(PopLocal, X, ORDN, xeg, ___, ___) \
|
||||
V(PopLocal_Wide, X, WIDE, xeg, ___, ___) \
|
||||
V(Unused18, 0, RESV, ___, ___, ___) \
|
||||
V(Unused19, 0, RESV, ___, ___, ___) \
|
||||
V(StoreLocal, X, ORDN, xeg, ___, ___) \
|
||||
V(StoreLocal_Wide, X, WIDE, xeg, ___, ___) \
|
||||
V(LoadFieldTOS, D, ORDN, lit, ___, ___) \
|
||||
V(LoadFieldTOS_Wide, D, WIDE, lit, ___, ___) \
|
||||
V(StoreFieldTOS, D, ORDN, lit, ___, ___) \
|
||||
V(StoreFieldTOS_Wide, D, WIDE, lit, ___, ___) \
|
||||
V(StoreIndexedTOS, 0, ORDN, ___, ___, ___) \
|
||||
V(Unused20, 0, RESV, ___, ___, ___) \
|
||||
V(PushStatic, D, ORDN, lit, ___, ___) \
|
||||
V(PushStatic_Wide, D, WIDE, lit, ___, ___) \
|
||||
V(StoreStaticTOS, D, ORDN, lit, ___, ___) \
|
||||
V(StoreStaticTOS_Wide, D, WIDE, lit, ___, ___) \
|
||||
V(Jump, T, ORDN, tgt, ___, ___) \
|
||||
V(Jump_Wide, T, WIDE, tgt, ___, ___) \
|
||||
V(JumpIfNoAsserts, T, ORDN, tgt, ___, ___) \
|
||||
V(JumpIfNoAsserts_Wide, T, WIDE, tgt, ___, ___) \
|
||||
V(JumpIfNotZeroTypeArgs, T, ORDN, tgt, ___, ___) \
|
||||
V(JumpIfNotZeroTypeArgs_Wide, T, WIDE, tgt, ___, ___) \
|
||||
V(JumpIfEqStrict, T, ORDN, tgt, ___, ___) \
|
||||
V(JumpIfEqStrict_Wide, T, WIDE, tgt, ___, ___) \
|
||||
V(JumpIfNeStrict, T, ORDN, tgt, ___, ___) \
|
||||
V(JumpIfNeStrict_Wide, T, WIDE, tgt, ___, ___) \
|
||||
V(JumpIfTrue, T, ORDN, tgt, ___, ___) \
|
||||
V(JumpIfTrue_Wide, T, WIDE, tgt, ___, ___) \
|
||||
V(JumpIfFalse, T, ORDN, tgt, ___, ___) \
|
||||
V(JumpIfFalse_Wide, T, WIDE, tgt, ___, ___) \
|
||||
V(JumpIfNull, T, ORDN, tgt, ___, ___) \
|
||||
V(JumpIfNull_Wide, T, WIDE, tgt, ___, ___) \
|
||||
V(JumpIfNotNull, T, ORDN, tgt, ___, ___) \
|
||||
V(JumpIfNotNull_Wide, T, WIDE, tgt, ___, ___) \
|
||||
V(DirectCall, D_F, ORDN, num, num, ___) \
|
||||
V(DirectCall_Wide, D_F, WIDE, num, num, ___) \
|
||||
V(Unused21, 0, RESV, ___, ___, ___) \
|
||||
V(Unused22, 0, RESV, ___, ___, ___) \
|
||||
V(InterfaceCall, D_F, ORDN, num, num, ___) \
|
||||
V(InterfaceCall_Wide, D_F, WIDE, num, num, ___) \
|
||||
V(Unused23, 0, RESV, ___, ___, ___) \
|
||||
V(Unused24, 0, RESV, ___, ___, ___) \
|
||||
V(Unused25, 0, RESV, ___, ___, ___) \
|
||||
V(Unused26, 0, RESV, ___, ___, ___) \
|
||||
V(Unused27, 0, RESV, ___, ___, ___) \
|
||||
V(Unused28, 0, RESV, ___, ___, ___) \
|
||||
V(UncheckedInterfaceCall, D_F, ORDN, num, num, ___) \
|
||||
V(UncheckedInterfaceCall_Wide, D_F, WIDE, num, num, ___) \
|
||||
V(DynamicCall, D_F, ORDN, num, num, ___) \
|
||||
V(DynamicCall_Wide, D_F, WIDE, num, num, ___) \
|
||||
V(NativeCall, D, ORDN, lit, ___, ___) \
|
||||
V(NativeCall_Wide, D, WIDE, lit, ___, ___) \
|
||||
V(ReturnTOS, 0, ORDN, ___, ___, ___) \
|
||||
V(Unused29, 0, RESV, ___, ___, ___) \
|
||||
V(AssertAssignable, A_E, ORDN, num, lit, ___) \
|
||||
V(AssertAssignable_Wide, A_E, WIDE, num, lit, ___) \
|
||||
V(Unused30, 0, RESV, ___, ___, ___) \
|
||||
V(Unused31, 0, RESV, ___, ___, ___) \
|
||||
V(AssertBoolean, A, ORDN, num, ___, ___) \
|
||||
V(AssertSubtype, 0, ORDN, ___, ___, ___) \
|
||||
V(LoadTypeArgumentsField, D, ORDN, lit, ___, ___) \
|
||||
V(LoadTypeArgumentsField_Wide, D, WIDE, lit, ___, ___) \
|
||||
V(InstantiateType, D, ORDN, lit, ___, ___) \
|
||||
V(InstantiateType_Wide, D, WIDE, lit, ___, ___) \
|
||||
V(InstantiateTypeArgumentsTOS, A_E, ORDN, num, lit, ___) \
|
||||
V(InstantiateTypeArgumentsTOS_Wide, A_E, WIDE, num, lit, ___) \
|
||||
V(Unused32, 0, RESV, ___, ___, ___) \
|
||||
V(Unused33, 0, RESV, ___, ___, ___) \
|
||||
V(Unused34, 0, RESV, ___, ___, ___) \
|
||||
V(Unused35, 0, RESV, ___, ___, ___) \
|
||||
V(Throw, A, ORDN, num, ___, ___) \
|
||||
V(SetFrame, A, ORDN, num, ___, num) \
|
||||
V(MoveSpecial, A_Y, ORDN, num, xeg, ___) \
|
||||
V(MoveSpecial_Wide, A_Y, WIDE, num, xeg, ___) \
|
||||
V(BooleanNegateTOS, 0, ORDN, ___, ___, ___) \
|
||||
V(EqualsNull, 0, ORDN, ___, ___, ___) \
|
||||
V(Unused36, 0, RESV, ___, ___, ___) \
|
||||
V(Unused37, 0, RESV, ___, ___, ___) \
|
||||
V(NegateInt, 0, ORDN, ___, ___, ___) \
|
||||
V(AddInt, 0, ORDN, ___, ___, ___) \
|
||||
V(SubInt, 0, ORDN, ___, ___, ___) \
|
||||
V(MulInt, 0, ORDN, ___, ___, ___) \
|
||||
V(TruncDivInt, 0, ORDN, ___, ___, ___) \
|
||||
V(ModInt, 0, ORDN, ___, ___, ___) \
|
||||
V(BitAndInt, 0, ORDN, ___, ___, ___) \
|
||||
V(BitOrInt, 0, ORDN, ___, ___, ___) \
|
||||
V(BitXorInt, 0, ORDN, ___, ___, ___) \
|
||||
V(ShlInt, 0, ORDN, ___, ___, ___) \
|
||||
V(ShrInt, 0, ORDN, ___, ___, ___) \
|
||||
V(CompareIntEq, 0, ORDN, ___, ___, ___) \
|
||||
V(CompareIntGt, 0, ORDN, ___, ___, ___) \
|
||||
V(CompareIntLt, 0, ORDN, ___, ___, ___) \
|
||||
V(CompareIntGe, 0, ORDN, ___, ___, ___) \
|
||||
V(CompareIntLe, 0, ORDN, ___, ___, ___) \
|
||||
V(NegateDouble, 0, ORDN, ___, ___, ___) \
|
||||
V(AddDouble, 0, ORDN, ___, ___, ___) \
|
||||
V(SubDouble, 0, ORDN, ___, ___, ___) \
|
||||
V(MulDouble, 0, ORDN, ___, ___, ___) \
|
||||
V(DivDouble, 0, ORDN, ___, ___, ___) \
|
||||
V(CompareDoubleEq, 0, ORDN, ___, ___, ___) \
|
||||
V(CompareDoubleGt, 0, ORDN, ___, ___, ___) \
|
||||
V(CompareDoubleLt, 0, ORDN, ___, ___, ___) \
|
||||
V(CompareDoubleGe, 0, ORDN, ___, ___, ___) \
|
||||
V(CompareDoubleLe, 0, ORDN, ___, ___, ___) \
|
||||
|
||||
// These bytecodes are only generated within the VM. Reassigning their
|
||||
// opcodes is not a breaking change.
|
||||
#define INTERNAL_KERNEL_BYTECODES_LIST(V) \
|
||||
V(VMInternal_ImplicitGetter, 0, ___, ___, ___) \
|
||||
V(VMInternal_ImplicitSetter, 0, ___, ___, ___) \
|
||||
V(VMInternal_ImplicitStaticGetter, 0, ___, ___, ___) \
|
||||
V(VMInternal_MethodExtractor, 0, ___, ___, ___) \
|
||||
V(VMInternal_InvokeClosure, 0, ___, ___, ___) \
|
||||
V(VMInternal_InvokeField, 0, ___, ___, ___) \
|
||||
V(VMInternal_ForwardDynamicInvocation, 0, ___, ___, ___) \
|
||||
V(VMInternal_NoSuchMethodDispatcher, 0, ___, ___, ___) \
|
||||
V(VMInternal_ImplicitStaticClosure, 0, ___, ___, ___) \
|
||||
V(VMInternal_ImplicitInstanceClosure, 0, ___, ___, ___) \
|
||||
V(VMInternal_ImplicitGetter, 0, ORDN, ___, ___, ___) \
|
||||
V(VMInternal_ImplicitSetter, 0, ORDN, ___, ___, ___) \
|
||||
V(VMInternal_ImplicitStaticGetter, 0, ORDN, ___, ___, ___) \
|
||||
V(VMInternal_MethodExtractor, 0, ORDN, ___, ___, ___) \
|
||||
V(VMInternal_InvokeClosure, 0, ORDN, ___, ___, ___) \
|
||||
V(VMInternal_InvokeField, 0, ORDN, ___, ___, ___) \
|
||||
V(VMInternal_ForwardDynamicInvocation, 0, ORDN, ___, ___, ___) \
|
||||
V(VMInternal_NoSuchMethodDispatcher, 0, ORDN, ___, ___, ___) \
|
||||
V(VMInternal_ImplicitStaticClosure, 0, ORDN, ___, ___, ___) \
|
||||
V(VMInternal_ImplicitInstanceClosure, 0, ORDN, ___, ___, ___) \
|
||||
|
||||
#define KERNEL_BYTECODES_LIST(V) \
|
||||
PUBLIC_KERNEL_BYTECODES_LIST(V) \
|
||||
|
@ -547,9 +741,6 @@ namespace dart {
|
|||
typedef uint8_t KBCInstr;
|
||||
|
||||
class KernelBytecode {
|
||||
private:
|
||||
static const intptr_t kInstructionSize = 4;
|
||||
|
||||
public:
|
||||
// Magic value of bytecode files.
|
||||
static const intptr_t kMagicValue = 0x44424332; // 'DBC2'
|
||||
|
@ -558,62 +749,130 @@ class KernelBytecode {
|
|||
// Maximum bytecode format version supported by VM.
|
||||
// The range of supported versions should include version produced by bytecode
|
||||
// generator (currentBytecodeFormatVersion in pkg/vm/lib/bytecode/dbc.dart).
|
||||
static const intptr_t kMaxSupportedBytecodeFormatVersion = 6;
|
||||
static const intptr_t kMaxSupportedBytecodeFormatVersion = 7;
|
||||
|
||||
enum Opcode {
|
||||
#define DECLARE_BYTECODE(name, encoding, op1, op2, op3) k##name,
|
||||
#define DECLARE_BYTECODE(name, encoding, kind, op1, op2, op3) k##name,
|
||||
KERNEL_BYTECODES_LIST(DECLARE_BYTECODE)
|
||||
#undef DECLARE_BYTECODE
|
||||
};
|
||||
|
||||
static const char* NameOf(Opcode op) {
|
||||
const char* names[] = {
|
||||
#define NAME(name, encoding, op1, op2, op3) #name,
|
||||
#define NAME(name, encoding, kind, op1, op2, op3) #name,
|
||||
KERNEL_BYTECODES_LIST(NAME)
|
||||
#undef NAME
|
||||
};
|
||||
return names[op];
|
||||
}
|
||||
|
||||
static const intptr_t kInstructionSize[];
|
||||
|
||||
enum SpecialIndex {
|
||||
kExceptionSpecialIndex,
|
||||
kStackTraceSpecialIndex,
|
||||
kSpecialIndexCount
|
||||
};
|
||||
|
||||
static const intptr_t kOpShift = 0;
|
||||
static const intptr_t kAShift = 8;
|
||||
static const intptr_t kAMask = 0xFF;
|
||||
static const intptr_t kBShift = 16;
|
||||
static const intptr_t kBMask = 0xFF;
|
||||
static const intptr_t kCShift = 24;
|
||||
static const intptr_t kCMask = 0xFF;
|
||||
static const intptr_t kDShift = 16;
|
||||
static const intptr_t kDMask = 0xFFFF;
|
||||
static const intptr_t kYShift = 24;
|
||||
static const intptr_t kYMask = 0xFF;
|
||||
static const intptr_t kTShift = 8;
|
||||
private:
|
||||
static const intptr_t kWideModifier = 1;
|
||||
|
||||
static_assert(kMinSupportedBytecodeFormatVersion < 7,
|
||||
"Cleanup support for old bytecode format versions");
|
||||
DART_FORCE_INLINE static bool IsOld(const KBCInstr* instr) {
|
||||
return DecodeOpcode(instr) < kTrap;
|
||||
}
|
||||
|
||||
// Should be used only on instructions with wide variants.
|
||||
DART_FORCE_INLINE static bool IsWide(const KBCInstr* instr) {
|
||||
return ((DecodeOpcode(instr) & kWideModifier) != 0);
|
||||
}
|
||||
|
||||
public:
|
||||
DART_FORCE_INLINE static uint8_t DecodeA(const KBCInstr* bc) { return bc[1]; }
|
||||
|
||||
DART_FORCE_INLINE static uint8_t DecodeB(const KBCInstr* bc) { return bc[2]; }
|
||||
|
||||
DART_FORCE_INLINE static uint8_t DecodeC(const KBCInstr* bc) { return bc[3]; }
|
||||
|
||||
DART_FORCE_INLINE static uint16_t DecodeD(const KBCInstr* bc) {
|
||||
return static_cast<uint16_t>(bc[2]) | (static_cast<uint16_t>(bc[3]) << 8);
|
||||
DART_FORCE_INLINE static uint32_t DecodeD(const KBCInstr* bc) {
|
||||
if (IsOld(bc)) {
|
||||
return static_cast<uint16_t>(bc[2]) | (static_cast<uint16_t>(bc[3]) << 8);
|
||||
} else if (IsWide(bc)) {
|
||||
return static_cast<uint32_t>(bc[1]) |
|
||||
(static_cast<uint32_t>(bc[2]) << 8) |
|
||||
(static_cast<uint32_t>(bc[3]) << 16) |
|
||||
(static_cast<uint32_t>(bc[4]) << 24);
|
||||
} else {
|
||||
return bc[1];
|
||||
}
|
||||
}
|
||||
|
||||
DART_FORCE_INLINE static int16_t DecodeX(const KBCInstr* bc) {
|
||||
return static_cast<int16_t>(static_cast<uint16_t>(bc[2]) |
|
||||
(static_cast<uint16_t>(bc[3]) << 8));
|
||||
DART_FORCE_INLINE static int32_t DecodeX(const KBCInstr* bc) {
|
||||
if (IsOld(bc)) {
|
||||
return static_cast<int16_t>(static_cast<uint16_t>(bc[2]) |
|
||||
(static_cast<uint16_t>(bc[3]) << 8));
|
||||
} else if (IsWide(bc)) {
|
||||
return static_cast<int32_t>(static_cast<uint32_t>(bc[1]) |
|
||||
(static_cast<uint32_t>(bc[2]) << 8) |
|
||||
(static_cast<uint32_t>(bc[3]) << 16) |
|
||||
(static_cast<uint32_t>(bc[4]) << 24));
|
||||
} else {
|
||||
return static_cast<int8_t>(bc[1]);
|
||||
}
|
||||
}
|
||||
|
||||
DART_FORCE_INLINE static int32_t DecodeT(const KBCInstr* bc) {
|
||||
return static_cast<int32_t>((static_cast<uint32_t>(bc[1]) << 8) |
|
||||
(static_cast<uint32_t>(bc[2]) << 16) |
|
||||
(static_cast<uint32_t>(bc[3]) << 24)) >>
|
||||
(8 - 2);
|
||||
if (IsOld(bc)) {
|
||||
return static_cast<int32_t>((static_cast<uint32_t>(bc[1]) << 8) |
|
||||
(static_cast<uint32_t>(bc[2]) << 16) |
|
||||
(static_cast<uint32_t>(bc[3]) << 24)) >>
|
||||
(8 - 2);
|
||||
} else if (IsWide(bc)) {
|
||||
return static_cast<int32_t>((static_cast<uint32_t>(bc[1]) << 8) |
|
||||
(static_cast<uint32_t>(bc[2]) << 16) |
|
||||
(static_cast<uint32_t>(bc[3]) << 24)) >>
|
||||
8;
|
||||
} else {
|
||||
return static_cast<int8_t>(bc[1]);
|
||||
}
|
||||
}
|
||||
|
||||
DART_FORCE_INLINE static uint32_t DecodeE(const KBCInstr* bc) {
|
||||
if (IsOld(bc)) {
|
||||
return static_cast<uint16_t>(bc[2]) | (static_cast<uint16_t>(bc[3]) << 8);
|
||||
} else if (IsWide(bc)) {
|
||||
return static_cast<uint32_t>(bc[2]) |
|
||||
(static_cast<uint32_t>(bc[3]) << 8) |
|
||||
(static_cast<uint32_t>(bc[4]) << 16) |
|
||||
(static_cast<uint32_t>(bc[5]) << 24);
|
||||
} else {
|
||||
return bc[2];
|
||||
}
|
||||
}
|
||||
|
||||
DART_FORCE_INLINE static int32_t DecodeY(const KBCInstr* bc) {
|
||||
if (IsOld(bc)) {
|
||||
return static_cast<int16_t>(static_cast<uint16_t>(bc[2]) |
|
||||
(static_cast<uint16_t>(bc[3]) << 8));
|
||||
} else if (IsWide(bc)) {
|
||||
return static_cast<int32_t>(static_cast<uint32_t>(bc[2]) |
|
||||
(static_cast<uint32_t>(bc[3]) << 8) |
|
||||
(static_cast<uint32_t>(bc[4]) << 16) |
|
||||
(static_cast<uint32_t>(bc[5]) << 24));
|
||||
} else {
|
||||
return static_cast<int8_t>(bc[2]);
|
||||
}
|
||||
}
|
||||
|
||||
DART_FORCE_INLINE static uint8_t DecodeF(const KBCInstr* bc) {
|
||||
if (IsOld(bc)) {
|
||||
return bc[1];
|
||||
} else if (IsWide(bc)) {
|
||||
return bc[5];
|
||||
} else {
|
||||
return bc[2];
|
||||
}
|
||||
}
|
||||
|
||||
DART_FORCE_INLINE static Opcode DecodeOpcode(const KBCInstr* bc) {
|
||||
|
@ -621,28 +880,38 @@ class KernelBytecode {
|
|||
}
|
||||
|
||||
DART_FORCE_INLINE static const KBCInstr* Next(const KBCInstr* bc) {
|
||||
return bc + kInstructionSize;
|
||||
}
|
||||
|
||||
DART_FORCE_INLINE static const KBCInstr* Previous(const KBCInstr* bc) {
|
||||
return bc - kInstructionSize;
|
||||
}
|
||||
|
||||
DART_FORCE_INLINE static bool IsTrap(const KBCInstr* instr) {
|
||||
return DecodeOpcode(instr) == KernelBytecode::kTrap;
|
||||
return bc + kInstructionSize[DecodeOpcode(bc)];
|
||||
}
|
||||
|
||||
DART_FORCE_INLINE static bool IsJumpOpcode(const KBCInstr* instr) {
|
||||
switch (DecodeOpcode(instr)) {
|
||||
case KernelBytecode::kJump_Old:
|
||||
case KernelBytecode::kJumpIfNoAsserts_Old:
|
||||
case KernelBytecode::kJumpIfNotZeroTypeArgs_Old:
|
||||
case KernelBytecode::kJumpIfEqStrict_Old:
|
||||
case KernelBytecode::kJumpIfNeStrict_Old:
|
||||
case KernelBytecode::kJumpIfTrue_Old:
|
||||
case KernelBytecode::kJumpIfFalse_Old:
|
||||
case KernelBytecode::kJumpIfNull_Old:
|
||||
case KernelBytecode::kJumpIfNotNull_Old:
|
||||
case KernelBytecode::kJump:
|
||||
case KernelBytecode::kJump_Wide:
|
||||
case KernelBytecode::kJumpIfNoAsserts:
|
||||
case KernelBytecode::kJumpIfNoAsserts_Wide:
|
||||
case KernelBytecode::kJumpIfNotZeroTypeArgs:
|
||||
case KernelBytecode::kJumpIfNotZeroTypeArgs_Wide:
|
||||
case KernelBytecode::kJumpIfEqStrict:
|
||||
case KernelBytecode::kJumpIfEqStrict_Wide:
|
||||
case KernelBytecode::kJumpIfNeStrict:
|
||||
case KernelBytecode::kJumpIfNeStrict_Wide:
|
||||
case KernelBytecode::kJumpIfTrue:
|
||||
case KernelBytecode::kJumpIfTrue_Wide:
|
||||
case KernelBytecode::kJumpIfFalse:
|
||||
case KernelBytecode::kJumpIfFalse_Wide:
|
||||
case KernelBytecode::kJumpIfNull:
|
||||
case KernelBytecode::kJumpIfNull_Wide:
|
||||
case KernelBytecode::kJumpIfNotNull:
|
||||
case KernelBytecode::kJumpIfNotNull_Wide:
|
||||
return true;
|
||||
|
||||
default:
|
||||
|
@ -650,13 +919,72 @@ class KernelBytecode {
|
|||
}
|
||||
}
|
||||
|
||||
DART_FORCE_INLINE static bool IsLoadConstantOpcode(const KBCInstr* instr) {
|
||||
switch (DecodeOpcode(instr)) {
|
||||
case KernelBytecode::kLoadConstant:
|
||||
case KernelBytecode::kLoadConstant_Wide:
|
||||
case KernelBytecode::kLoadConstant_Old:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
DART_FORCE_INLINE static bool IsCheckStackOpcode(const KBCInstr* instr) {
|
||||
switch (DecodeOpcode(instr)) {
|
||||
case KernelBytecode::kCheckStack:
|
||||
case KernelBytecode::kCheckStack_Old:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
DART_FORCE_INLINE static bool IsEntryOptionalOpcode(const KBCInstr* instr) {
|
||||
switch (DecodeOpcode(instr)) {
|
||||
case KernelBytecode::kEntryOptional:
|
||||
case KernelBytecode::kEntryOptional_Old:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
DART_FORCE_INLINE static bool IsFrameOpcode(const KBCInstr* instr) {
|
||||
switch (DecodeOpcode(instr)) {
|
||||
case KernelBytecode::kFrame:
|
||||
case KernelBytecode::kFrame_Wide:
|
||||
case KernelBytecode::kFrame_Old:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
DART_FORCE_INLINE static bool IsSetFrameOpcode(const KBCInstr* instr) {
|
||||
switch (DecodeOpcode(instr)) {
|
||||
case KernelBytecode::kSetFrame:
|
||||
case KernelBytecode::kSetFrame_Old:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
DART_FORCE_INLINE static bool IsCallOpcode(const KBCInstr* instr) {
|
||||
switch (DecodeOpcode(instr)) {
|
||||
case KernelBytecode::kIndirectStaticCall:
|
||||
case KernelBytecode::kInterfaceCall:
|
||||
case KernelBytecode::kUncheckedInterfaceCall:
|
||||
case KernelBytecode::kDynamicCall:
|
||||
case KernelBytecode::kDirectCall_Old:
|
||||
case KernelBytecode::kInterfaceCall_Old:
|
||||
case KernelBytecode::kUncheckedInterfaceCall_Old:
|
||||
case KernelBytecode::kDynamicCall_Old:
|
||||
case KernelBytecode::kDirectCall:
|
||||
case KernelBytecode::kDirectCall_Wide:
|
||||
case KernelBytecode::kInterfaceCall:
|
||||
case KernelBytecode::kInterfaceCall_Wide:
|
||||
case KernelBytecode::kUncheckedInterfaceCall:
|
||||
case KernelBytecode::kUncheckedInterfaceCall_Wide:
|
||||
case KernelBytecode::kDynamicCall:
|
||||
case KernelBytecode::kDynamicCall_Wide:
|
||||
return true;
|
||||
|
||||
default:
|
||||
|
@ -664,11 +992,24 @@ class KernelBytecode {
|
|||
}
|
||||
}
|
||||
|
||||
DART_FORCE_INLINE static bool IsNativeCallOpcode(const KBCInstr* instr) {
|
||||
switch (DecodeOpcode(instr)) {
|
||||
case KernelBytecode::kNativeCall:
|
||||
case KernelBytecode::kNativeCall_Wide:
|
||||
case KernelBytecode::kNativeCall_Old:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static const uint8_t kNativeCallToGrowableListArgc = 2;
|
||||
|
||||
DART_FORCE_INLINE static uint8_t DecodeArgc(const KBCInstr* ret_addr) {
|
||||
const KBCInstr* call = Previous(ret_addr);
|
||||
if (DecodeOpcode(call) == KernelBytecode::kNativeCall) {
|
||||
DART_FORCE_INLINE static uint8_t DecodeArgc_Old(const KBCInstr* ret_addr) {
|
||||
const intptr_t kOldInstructionSize = 4;
|
||||
const KBCInstr* call = ret_addr - kOldInstructionSize;
|
||||
ASSERT(IsOld(call));
|
||||
if (DecodeOpcode(call) == KernelBytecode::kNativeCall_Old) {
|
||||
// The only NativeCall redirecting to a bytecode function is the call
|
||||
// to new _GrowableList<E>(0).
|
||||
return kNativeCallToGrowableListArgc;
|
||||
|
@ -677,15 +1018,24 @@ class KernelBytecode {
|
|||
return DecodeA(call);
|
||||
}
|
||||
|
||||
// Returns a fake return address which points after the 2-argument
|
||||
// bytecode call, followed by ReturnTOS instructions.
|
||||
static const KBCInstr* GetNativeCallToGrowableListReturnTrampoline();
|
||||
|
||||
DART_FORCE_INLINE static uint8_t DecodeArgc(const KBCInstr* ret_addr) {
|
||||
// All call instructions have DF encoding, with argc being the last byte
|
||||
// regardless of whether the wide variant is used or not.
|
||||
return ret_addr[-1];
|
||||
}
|
||||
|
||||
// Converts bytecode PC into an offset.
|
||||
// For return addresses used in PcDescriptors, PC is also advanced to the
|
||||
// next instruction.
|
||||
// For return addresses used in PcDescriptors, PC is also augmented by 1.
|
||||
static intptr_t BytecodePcToOffset(uint32_t pc, bool is_return_address) {
|
||||
return pc + (is_return_address ? kInstructionSize : 0);
|
||||
return pc + (is_return_address ? 1 : 0);
|
||||
}
|
||||
|
||||
static uint32_t OffsetToBytecodePc(intptr_t offset, bool is_return_address) {
|
||||
return offset - (is_return_address ? kInstructionSize : 0);
|
||||
return offset - (is_return_address ? 1 : 0);
|
||||
}
|
||||
|
||||
static void GetVMInternalBytecodeInstructions(Opcode opcode,
|
||||
|
|
|
@ -17,11 +17,22 @@ RawTypedData* KBCNativeCallPattern::GetNativeEntryDataAt(
|
|||
uword pc,
|
||||
const Bytecode& bytecode) {
|
||||
ASSERT(bytecode.ContainsInstructionAt(pc));
|
||||
const KBCInstr* call_instr =
|
||||
KernelBytecode::Previous(reinterpret_cast<const KBCInstr*>(pc));
|
||||
ASSERT(KernelBytecode::DecodeOpcode(call_instr) ==
|
||||
KernelBytecode::kNativeCall);
|
||||
intptr_t native_entry_data_pool_index = KernelBytecode::DecodeD(call_instr);
|
||||
|
||||
const KBCInstr* return_addr = reinterpret_cast<const KBCInstr*>(pc);
|
||||
const KBCInstr* instr =
|
||||
reinterpret_cast<const KBCInstr*>(bytecode.PayloadStart());
|
||||
ASSERT(instr < return_addr);
|
||||
while (!KernelBytecode::IsNativeCallOpcode(instr)) {
|
||||
instr = KernelBytecode::Next(instr);
|
||||
if (instr >= return_addr) {
|
||||
FATAL1(
|
||||
"Unable to find NativeCall bytecode instruction"
|
||||
" corresponding to PC %" Px,
|
||||
pc);
|
||||
}
|
||||
}
|
||||
|
||||
intptr_t native_entry_data_pool_index = KernelBytecode::DecodeD(instr);
|
||||
const ObjectPool& obj_pool = ObjectPool::Handle(bytecode.object_pool());
|
||||
TypedData& native_entry_data = TypedData::Handle();
|
||||
native_entry_data ^= obj_pool.ObjectAt(native_entry_data_pool_index);
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
|
||||
#include "vm/compiler/assembler/assembler.h"
|
||||
#include "vm/compiler/assembler/disassembler_kbc.h"
|
||||
#include "vm/compiler/frontend/bytecode_reader.h"
|
||||
#include "vm/compiler/jit/compiler.h"
|
||||
#include "vm/cpu.h"
|
||||
#include "vm/dart_entry.h"
|
||||
|
@ -900,72 +901,185 @@ DART_FORCE_INLINE bool Interpreter::InstanceCall2(Thread* thread,
|
|||
// Load target of a jump instruction into PC.
|
||||
#define LOAD_JUMP_TARGET() pc = rT
|
||||
|
||||
// Define entry point that handles bytecode Name with the given operand format.
|
||||
#define BYTECODE(Name, Operands) \
|
||||
BYTECODE_HEADER(Name, DECLARE_##Operands, DECODE_##Operands)
|
||||
#define BYTECODE_ENTRY_LABEL(Name) bc##Name:
|
||||
#define BYTECODE_WIDE_ENTRY_LABEL(Name) bc##Name##_Wide:
|
||||
#define BYTECODE_OLD_ENTRY_LABEL(Name) bc##Name##_Old:
|
||||
#define BYTECODE_IMPL_LABEL(Name) bc##Name##Impl:
|
||||
#define GOTO_BYTECODE_IMPL(Name) goto bc##Name##Impl;
|
||||
|
||||
#define BYTECODE_HEADER(Name, Declare, Decode) \
|
||||
Declare; \
|
||||
bc##Name : Decode
|
||||
// Define entry point that handles bytecode Name with the given operand format.
|
||||
#define BYTECODE(Name, Operands) BYTECODE_HEADER_##Operands##_WITH_OLD(Name)
|
||||
|
||||
// TODO(alexmarkov): switch BYTECODE macro to BYTECODE_NEW implementation
|
||||
// and replace BYTECODE_NEW with BYTECODE when old instructions are gone.
|
||||
// Cleanup BYTECODE_HEADER_*_WITH_OLD macros and drop _WITH_OLD.
|
||||
static_assert(KernelBytecode::kMinSupportedBytecodeFormatVersion < 7,
|
||||
"Cleanup support for old bytecode format versions");
|
||||
|
||||
#define BYTECODE_NEW(Name, Operands) BYTECODE_HEADER_##Operands(Name)
|
||||
|
||||
// Helpers to decode common instruction formats. Used in conjunction with
|
||||
// BYTECODE() macro.
|
||||
#define DECLARE_A_B_C \
|
||||
uint16_t rB, rC; \
|
||||
USE(rB); \
|
||||
USE(rC)
|
||||
#define DECODE_A_B_C \
|
||||
|
||||
#define BYTECODE_HEADER_0(Name) \
|
||||
BYTECODE_ENTRY_LABEL(Name) \
|
||||
pc += 1;
|
||||
|
||||
#define BYTECODE_HEADER_0_WITH_OLD(Name) \
|
||||
BYTECODE_OLD_ENTRY_LABEL(Name) \
|
||||
pc += 4; \
|
||||
GOTO_BYTECODE_IMPL(Name); \
|
||||
BYTECODE_HEADER_0(Name) \
|
||||
BYTECODE_IMPL_LABEL(Name)
|
||||
|
||||
#define BYTECODE_HEADER_A_WITH_OLD(Name) \
|
||||
BYTECODE_OLD_ENTRY_LABEL(Name) \
|
||||
rA = pc[1]; \
|
||||
rB = pc[2]; \
|
||||
rC = pc[3]; \
|
||||
pc += 4;
|
||||
|
||||
#define DECLARE_0
|
||||
#define DECODE_0 pc += 4;
|
||||
|
||||
#define DECLARE_A
|
||||
#define DECODE_A \
|
||||
pc += 4; \
|
||||
GOTO_BYTECODE_IMPL(Name); \
|
||||
BYTECODE_ENTRY_LABEL(Name) \
|
||||
rA = pc[1]; \
|
||||
pc += 4;
|
||||
pc += 2; \
|
||||
BYTECODE_IMPL_LABEL(Name)
|
||||
|
||||
#define DECLARE_D \
|
||||
#define BYTECODE_HEADER_D_WITH_OLD(Name) \
|
||||
uint32_t rD; \
|
||||
USE(rD)
|
||||
#define DECODE_D \
|
||||
USE(rD); \
|
||||
BYTECODE_OLD_ENTRY_LABEL(Name) \
|
||||
rD = static_cast<uint32_t>(pc[2]) | (static_cast<uint32_t>(pc[3]) << 8); \
|
||||
pc += 4;
|
||||
pc += 4; \
|
||||
GOTO_BYTECODE_IMPL(Name); \
|
||||
BYTECODE_WIDE_ENTRY_LABEL(Name) \
|
||||
rD = static_cast<uint32_t>(pc[1]) | (static_cast<uint32_t>(pc[2]) << 8) | \
|
||||
(static_cast<uint32_t>(pc[3]) << 16) | \
|
||||
(static_cast<uint32_t>(pc[4]) << 24); \
|
||||
pc += 5; \
|
||||
GOTO_BYTECODE_IMPL(Name); \
|
||||
BYTECODE_ENTRY_LABEL(Name) \
|
||||
rD = pc[1]; \
|
||||
pc += 2; \
|
||||
BYTECODE_IMPL_LABEL(Name)
|
||||
|
||||
#define DECLARE_A_D DECLARE_D
|
||||
#define DECODE_A_D \
|
||||
rA = pc[1]; \
|
||||
rD = static_cast<uint32_t>(pc[2]) | (static_cast<uint32_t>(pc[3]) << 8); \
|
||||
pc += 4;
|
||||
|
||||
#define DECLARE_X \
|
||||
// TODO(alexmarkov): Rename rD to rX.
|
||||
#define BYTECODE_HEADER_X_WITH_OLD(Name) \
|
||||
int32_t rD; \
|
||||
USE(rD)
|
||||
#define DECODE_X \
|
||||
USE(rD); \
|
||||
BYTECODE_OLD_ENTRY_LABEL(Name) \
|
||||
rD = static_cast<int16_t>(static_cast<uint16_t>(pc[2]) | \
|
||||
(static_cast<uint16_t>(pc[3]) << 8)); \
|
||||
pc += 4;
|
||||
pc += 4; \
|
||||
GOTO_BYTECODE_IMPL(Name); \
|
||||
BYTECODE_WIDE_ENTRY_LABEL(Name) \
|
||||
rD = static_cast<int32_t>(static_cast<uint32_t>(pc[1]) | \
|
||||
(static_cast<uint32_t>(pc[2]) << 8) | \
|
||||
(static_cast<uint32_t>(pc[3]) << 16) | \
|
||||
(static_cast<uint32_t>(pc[4]) << 24)); \
|
||||
pc += 5; \
|
||||
GOTO_BYTECODE_IMPL(Name); \
|
||||
BYTECODE_ENTRY_LABEL(Name) \
|
||||
rD = static_cast<int8_t>(pc[1]); \
|
||||
pc += 2; \
|
||||
BYTECODE_IMPL_LABEL(Name)
|
||||
|
||||
#define DECLARE_A_X \
|
||||
int32_t rD; \
|
||||
USE(rD)
|
||||
#define DECODE_A_X \
|
||||
rA = pc[1]; \
|
||||
rD = static_cast<int16_t>(static_cast<uint16_t>(pc[2]) | \
|
||||
(static_cast<uint16_t>(pc[3]) << 8)); \
|
||||
pc += 4;
|
||||
|
||||
#define DECLARE_T \
|
||||
#define BYTECODE_HEADER_T_WITH_OLD(Name) \
|
||||
const KBCInstr* rT; \
|
||||
USE(rT)
|
||||
#define DECODE_T \
|
||||
USE(rT); \
|
||||
BYTECODE_OLD_ENTRY_LABEL(Name) \
|
||||
rT = pc + (static_cast<int32_t>((static_cast<uint32_t>(pc[1]) << 8) | \
|
||||
(static_cast<uint32_t>(pc[2]) << 16) | \
|
||||
(static_cast<uint32_t>(pc[3]) << 24)) >> \
|
||||
(8 - 2)); \
|
||||
pc += 4; \
|
||||
GOTO_BYTECODE_IMPL(Name); \
|
||||
BYTECODE_WIDE_ENTRY_LABEL(Name) \
|
||||
rT = pc + (static_cast<int32_t>((static_cast<uint32_t>(pc[1]) << 8) | \
|
||||
(static_cast<uint32_t>(pc[2]) << 16) | \
|
||||
(static_cast<uint32_t>(pc[3]) << 24)) >> \
|
||||
8); \
|
||||
pc += 4; \
|
||||
GOTO_BYTECODE_IMPL(Name); \
|
||||
BYTECODE_ENTRY_LABEL(Name) \
|
||||
rT = pc + static_cast<int8_t>(pc[1]); \
|
||||
pc += 2; \
|
||||
BYTECODE_IMPL_LABEL(Name)
|
||||
|
||||
// TODO(alexmarkov): Rename rD to rE.
|
||||
#define BYTECODE_HEADER_A_E_WITH_OLD(Name) \
|
||||
uint32_t rD; \
|
||||
USE(rD); \
|
||||
BYTECODE_OLD_ENTRY_LABEL(Name) \
|
||||
rA = pc[1]; \
|
||||
rD = static_cast<uint32_t>(pc[2]) | (static_cast<uint32_t>(pc[3]) << 8); \
|
||||
pc += 4; \
|
||||
GOTO_BYTECODE_IMPL(Name); \
|
||||
BYTECODE_WIDE_ENTRY_LABEL(Name) \
|
||||
rA = pc[1]; \
|
||||
rD = static_cast<uint32_t>(pc[2]) | (static_cast<uint32_t>(pc[3]) << 8) | \
|
||||
(static_cast<uint32_t>(pc[4]) << 16) | \
|
||||
(static_cast<uint32_t>(pc[5]) << 24); \
|
||||
pc += 6; \
|
||||
GOTO_BYTECODE_IMPL(Name); \
|
||||
BYTECODE_ENTRY_LABEL(Name) \
|
||||
rA = pc[1]; \
|
||||
rD = pc[2]; \
|
||||
pc += 3; \
|
||||
BYTECODE_IMPL_LABEL(Name)
|
||||
|
||||
// TODO(alexmarkov): Rename rD to rY.
|
||||
#define BYTECODE_HEADER_A_Y_WITH_OLD(Name) \
|
||||
int32_t rD; \
|
||||
USE(rD); \
|
||||
BYTECODE_OLD_ENTRY_LABEL(Name) \
|
||||
rA = pc[1]; \
|
||||
rD = static_cast<int16_t>(static_cast<uint16_t>(pc[2]) | \
|
||||
(static_cast<uint16_t>(pc[3]) << 8)); \
|
||||
pc += 4; \
|
||||
GOTO_BYTECODE_IMPL(Name); \
|
||||
BYTECODE_WIDE_ENTRY_LABEL(Name) \
|
||||
rA = pc[1]; \
|
||||
rD = static_cast<int32_t>(static_cast<uint32_t>(pc[2]) | \
|
||||
(static_cast<uint32_t>(pc[3]) << 8) | \
|
||||
(static_cast<uint32_t>(pc[4]) << 16) | \
|
||||
(static_cast<uint32_t>(pc[5]) << 24)); \
|
||||
pc += 6; \
|
||||
GOTO_BYTECODE_IMPL(Name); \
|
||||
BYTECODE_ENTRY_LABEL(Name) \
|
||||
rA = pc[1]; \
|
||||
rD = static_cast<int8_t>(pc[2]); \
|
||||
pc += 3; \
|
||||
BYTECODE_IMPL_LABEL(Name)
|
||||
|
||||
// TODO(alexmarkov): Rename rA to rF.
|
||||
#define BYTECODE_HEADER_D_F_WITH_OLD(Name) \
|
||||
uint32_t rD; \
|
||||
USE(rD); \
|
||||
BYTECODE_OLD_ENTRY_LABEL(Name) \
|
||||
rA = pc[1]; \
|
||||
rD = static_cast<uint32_t>(pc[2]) | (static_cast<uint32_t>(pc[3]) << 8); \
|
||||
pc += 4; \
|
||||
GOTO_BYTECODE_IMPL(Name); \
|
||||
BYTECODE_WIDE_ENTRY_LABEL(Name) \
|
||||
rD = static_cast<uint32_t>(pc[1]) | (static_cast<uint32_t>(pc[2]) << 8) | \
|
||||
(static_cast<uint32_t>(pc[3]) << 16) | \
|
||||
(static_cast<uint32_t>(pc[4]) << 24); \
|
||||
rA = pc[5]; \
|
||||
pc += 6; \
|
||||
GOTO_BYTECODE_IMPL(Name); \
|
||||
BYTECODE_ENTRY_LABEL(Name) \
|
||||
rD = pc[1]; \
|
||||
rA = pc[2]; \
|
||||
pc += 3; \
|
||||
BYTECODE_IMPL_LABEL(Name)
|
||||
|
||||
#define BYTECODE_HEADER_A_B_C_WITH_OLD(Name) \
|
||||
uint16_t rB, rC; \
|
||||
USE(rB); \
|
||||
USE(rC); \
|
||||
BYTECODE_OLD_ENTRY_LABEL(Name) \
|
||||
BYTECODE_ENTRY_LABEL(Name) \
|
||||
rA = pc[1]; \
|
||||
rB = pc[2]; \
|
||||
rC = pc[3]; \
|
||||
pc += 4;
|
||||
|
||||
#define HANDLE_EXCEPTION \
|
||||
|
@ -1369,7 +1483,7 @@ RawObject* Interpreter::Call(RawFunction* function,
|
|||
RawObject** SP; // Stack Pointer.
|
||||
|
||||
uint32_t op; // Currently executing op.
|
||||
uint16_t rA; // A component of the currently executing op.
|
||||
uint32_t rA; // A component of the currently executing op.
|
||||
|
||||
bool reentering = fp_ != NULL;
|
||||
if (!reentering) {
|
||||
|
@ -1460,7 +1574,7 @@ RawObject* Interpreter::Call(RawFunction* function,
|
|||
|
||||
#ifdef DART_HAS_COMPUTED_GOTO
|
||||
static const void* dispatch[] = {
|
||||
#define TARGET(name, fmt, fmta, fmtb, fmtc) &&bc##name,
|
||||
#define TARGET(name, fmt, kind, fmta, fmtb, fmtc) &&bc##name,
|
||||
KERNEL_BYTECODES_LIST(TARGET)
|
||||
#undef TARGET
|
||||
};
|
||||
|
@ -1469,7 +1583,7 @@ RawObject* Interpreter::Call(RawFunction* function,
|
|||
DISPATCH(); // Enter the dispatch loop.
|
||||
SwitchDispatch:
|
||||
switch (op & 0xFF) {
|
||||
#define TARGET(name, fmt, fmta, fmtb, fmtc) \
|
||||
#define TARGET(name, fmt, kind, fmta, fmtb, fmtc) \
|
||||
case KernelBytecode::k##name: \
|
||||
goto bc##name;
|
||||
KERNEL_BYTECODES_LIST(TARGET)
|
||||
|
@ -1494,7 +1608,7 @@ SwitchDispatch:
|
|||
}
|
||||
|
||||
{
|
||||
BYTECODE(EntryFixed, A_D);
|
||||
BYTECODE(EntryFixed, A_E);
|
||||
const uint16_t num_fixed_params = rA;
|
||||
const uint16_t num_locals = rD;
|
||||
|
||||
|
@ -1550,15 +1664,13 @@ SwitchDispatch:
|
|||
const KBCInstr* load_name = pc;
|
||||
const KBCInstr* load_value = KernelBytecode::Next(load_name);
|
||||
pc = KernelBytecode::Next(load_value);
|
||||
ASSERT(KernelBytecode::DecodeOpcode(load_name) ==
|
||||
KernelBytecode::kLoadConstant);
|
||||
ASSERT(KernelBytecode::DecodeOpcode(load_value) ==
|
||||
KernelBytecode::kLoadConstant);
|
||||
ASSERT(KernelBytecode::IsLoadConstantOpcode(load_name));
|
||||
ASSERT(KernelBytecode::IsLoadConstantOpcode(load_value));
|
||||
const uint8_t reg = KernelBytecode::DecodeA(load_name);
|
||||
ASSERT(reg == KernelBytecode::DecodeA(load_value));
|
||||
|
||||
RawString* name = static_cast<RawString*>(
|
||||
LOAD_CONSTANT(KernelBytecode::DecodeD(load_name)));
|
||||
LOAD_CONSTANT(KernelBytecode::DecodeE(load_name)));
|
||||
if (name == argdesc_data[ArgumentsDescriptor::name_index(i)]) {
|
||||
// Parameter was passed. Fetch passed value.
|
||||
const intptr_t arg_index = Smi::Value(static_cast<RawSmi*>(
|
||||
|
@ -1567,7 +1679,7 @@ SwitchDispatch:
|
|||
++i; // Consume passed argument.
|
||||
} else {
|
||||
// Parameter was not passed. Fetch default value.
|
||||
FP[reg] = LOAD_CONSTANT(KernelBytecode::DecodeD(load_value));
|
||||
FP[reg] = LOAD_CONSTANT(KernelBytecode::DecodeE(load_value));
|
||||
}
|
||||
++j; // Next formal parameter.
|
||||
}
|
||||
|
@ -1578,14 +1690,12 @@ SwitchDispatch:
|
|||
const KBCInstr* load_name = pc;
|
||||
const KBCInstr* load_value = KernelBytecode::Next(load_name);
|
||||
pc = KernelBytecode::Next(load_value);
|
||||
ASSERT(KernelBytecode::DecodeOpcode(load_name) ==
|
||||
KernelBytecode::kLoadConstant);
|
||||
ASSERT(KernelBytecode::DecodeOpcode(load_value) ==
|
||||
KernelBytecode::kLoadConstant);
|
||||
ASSERT(KernelBytecode::IsLoadConstantOpcode(load_name));
|
||||
ASSERT(KernelBytecode::IsLoadConstantOpcode(load_value));
|
||||
const uint8_t reg = KernelBytecode::DecodeA(load_name);
|
||||
ASSERT(reg == KernelBytecode::DecodeA(load_value));
|
||||
|
||||
FP[reg] = LOAD_CONSTANT(KernelBytecode::DecodeD(load_value));
|
||||
FP[reg] = LOAD_CONSTANT(KernelBytecode::DecodeE(load_value));
|
||||
++j;
|
||||
}
|
||||
|
||||
|
@ -1611,17 +1721,15 @@ SwitchDispatch:
|
|||
// LoadConstant instructions after EntryOpt bytecode.
|
||||
// Execute only those that correspond to parameters that were not passed.
|
||||
for (intptr_t i = num_fixed_params; i < pos_count; ++i) {
|
||||
ASSERT(KernelBytecode::DecodeOpcode(pc) ==
|
||||
KernelBytecode::kLoadConstant);
|
||||
ASSERT(KernelBytecode::IsLoadConstantOpcode(pc));
|
||||
pc = KernelBytecode::Next(pc);
|
||||
}
|
||||
for (intptr_t i = pos_count; i < max_num_pos_args; ++i) {
|
||||
const KBCInstr* load_value = pc;
|
||||
pc = KernelBytecode::Next(load_value);
|
||||
ASSERT(KernelBytecode::DecodeOpcode(load_value) ==
|
||||
KernelBytecode::kLoadConstant);
|
||||
ASSERT(KernelBytecode::IsLoadConstantOpcode(load_value));
|
||||
ASSERT(KernelBytecode::DecodeA(load_value) == i);
|
||||
FP[i] = LOAD_CONSTANT(KernelBytecode::DecodeD(load_value));
|
||||
FP[i] = LOAD_CONSTANT(KernelBytecode::DecodeE(load_value));
|
||||
}
|
||||
|
||||
// SP points past the last copied parameter.
|
||||
|
@ -1676,7 +1784,7 @@ SwitchDispatch:
|
|||
}
|
||||
|
||||
{
|
||||
BYTECODE(CheckFunctionTypeArgs, A_D);
|
||||
BYTECODE(CheckFunctionTypeArgs, A_E);
|
||||
const uint16_t declared_type_args_len = rA;
|
||||
const uint16_t first_stack_local_index = rD;
|
||||
|
||||
|
@ -1714,7 +1822,7 @@ SwitchDispatch:
|
|||
}
|
||||
|
||||
{
|
||||
BYTECODE(InstantiateTypeArgumentsTOS, A_D);
|
||||
BYTECODE(InstantiateTypeArgumentsTOS, A_E);
|
||||
// Stack: instantiator type args, function type args
|
||||
RawTypeArguments* type_arguments =
|
||||
static_cast<RawTypeArguments*>(LOAD_CONSTANT(rD));
|
||||
|
@ -1777,7 +1885,7 @@ SwitchDispatch:
|
|||
}
|
||||
|
||||
{
|
||||
BYTECODE(LoadConstant, A_D);
|
||||
BYTECODE(LoadConstant, A_E);
|
||||
FP[rA] = LOAD_CONSTANT(rD);
|
||||
DISPATCH();
|
||||
}
|
||||
|
@ -1831,7 +1939,7 @@ SwitchDispatch:
|
|||
}
|
||||
|
||||
{
|
||||
BYTECODE(MoveSpecial, A_X);
|
||||
BYTECODE(MoveSpecial, A_Y);
|
||||
ASSERT(rA < KernelBytecode::kSpecialIndexCount);
|
||||
FP[rD] = special_[rA];
|
||||
DISPATCH();
|
||||
|
@ -1844,39 +1952,7 @@ SwitchDispatch:
|
|||
}
|
||||
|
||||
{
|
||||
BYTECODE(IndirectStaticCall, A_D);
|
||||
|
||||
#ifndef PRODUCT
|
||||
// Check if single stepping.
|
||||
if (thread->isolate()->single_step()) {
|
||||
Exit(thread, FP, SP + 1, pc);
|
||||
NativeArguments args(thread, 0, NULL, NULL);
|
||||
INVOKE_RUNTIME(DRT_SingleStepHandler, args);
|
||||
}
|
||||
#endif // !PRODUCT
|
||||
|
||||
// Invoke target function.
|
||||
{
|
||||
const uint16_t argc = rA;
|
||||
// Look up the function in the ICData.
|
||||
RawObject* ic_data_obj = SP[0];
|
||||
RawICData* ic_data = RAW_CAST(ICData, ic_data_obj);
|
||||
RawObject** data = ic_data->ptr()->entries_->ptr()->data();
|
||||
InterpreterHelpers::IncrementICUsageCount(data, 0, 0);
|
||||
SP[0] = data[ICData::TargetIndexFor(ic_data->ptr()->state_bits_ & 0x3)];
|
||||
RawObject** call_base = SP - argc;
|
||||
RawObject** call_top = SP; // *SP contains function
|
||||
argdesc_ = static_cast<RawArray*>(LOAD_CONSTANT(rD));
|
||||
if (!Invoke(thread, call_base, call_top, &pc, &FP, &SP)) {
|
||||
HANDLE_EXCEPTION;
|
||||
}
|
||||
}
|
||||
|
||||
DISPATCH();
|
||||
}
|
||||
|
||||
{
|
||||
BYTECODE(DirectCall, A_D);
|
||||
BYTECODE(DirectCall, D_F);
|
||||
|
||||
#ifndef PRODUCT
|
||||
// Check if single stepping.
|
||||
|
@ -1906,7 +1982,7 @@ SwitchDispatch:
|
|||
}
|
||||
|
||||
{
|
||||
BYTECODE(InterfaceCall, A_D);
|
||||
BYTECODE(InterfaceCall, D_F);
|
||||
|
||||
#ifndef PRODUCT
|
||||
// Check if single stepping.
|
||||
|
@ -1938,7 +2014,7 @@ SwitchDispatch:
|
|||
}
|
||||
|
||||
{
|
||||
BYTECODE(UncheckedInterfaceCall, A_D);
|
||||
BYTECODE(UncheckedInterfaceCall, D_F);
|
||||
|
||||
#ifndef PRODUCT
|
||||
// Check if single stepping.
|
||||
|
@ -1970,7 +2046,7 @@ SwitchDispatch:
|
|||
}
|
||||
|
||||
{
|
||||
BYTECODE(DynamicCall, A_D);
|
||||
BYTECODE(DynamicCall, D_F);
|
||||
|
||||
#ifndef PRODUCT
|
||||
// Check if single stepping.
|
||||
|
@ -2078,7 +2154,12 @@ SwitchDispatch:
|
|||
// Change the ArgumentsDescriptor of the call with a new cached one.
|
||||
argdesc_ = ArgumentsDescriptor::New(
|
||||
0, KernelBytecode::kNativeCallToGrowableListArgc);
|
||||
// Note the special handling of the return of this call in DecodeArgc.
|
||||
if (!thread->isolate()->is_using_old_bytecode_instructions()) {
|
||||
// Replace PC to the return trampoline so ReturnTOS would see
|
||||
// a call bytecode at return address and will be able to get argc
|
||||
// via DecodeArgc.
|
||||
pc = KernelBytecode::GetNativeCallToGrowableListReturnTrampoline();
|
||||
}
|
||||
if (!Invoke(thread, SP - 1, SP + 1, &pc, &FP, &SP)) {
|
||||
HANDLE_EXCEPTION;
|
||||
}
|
||||
|
@ -2228,7 +2309,9 @@ SwitchDispatch:
|
|||
}
|
||||
|
||||
// Look at the caller to determine how many arguments to pop.
|
||||
const uint8_t argc = KernelBytecode::DecodeArgc(pc);
|
||||
const uint8_t argc = thread->isolate()->is_using_old_bytecode_instructions()
|
||||
? KernelBytecode::DecodeArgc_Old(pc)
|
||||
: KernelBytecode::DecodeArgc(pc);
|
||||
|
||||
// Restore SP, FP and PP. Push result and dispatch.
|
||||
SP = FrameArguments(FP, argc);
|
||||
|
@ -2237,6 +2320,14 @@ SwitchDispatch:
|
|||
NOT_IN_PRODUCT(pc_ = pc); // For the profiler.
|
||||
pp_ = InterpreterHelpers::FrameBytecode(FP)->ptr()->object_pool_;
|
||||
*SP = result;
|
||||
#if defined(DEBUG)
|
||||
if (IsTracingExecution()) {
|
||||
THR_Print("%" Pu64 " ", icount_);
|
||||
THR_Print("Returning to %s (argc %d)\n",
|
||||
Function::Handle(FrameFunction(FP)).ToFullyQualifiedCString(),
|
||||
static_cast<int>(argc));
|
||||
}
|
||||
#endif
|
||||
DISPATCH();
|
||||
}
|
||||
|
||||
|
@ -2347,7 +2438,7 @@ SwitchDispatch:
|
|||
}
|
||||
|
||||
{
|
||||
BYTECODE(StoreContextVar, A_D);
|
||||
BYTECODE(StoreContextVar, A_E);
|
||||
const uword offset_in_words =
|
||||
static_cast<uword>(Context::variable_offset(rD) / kWordSize);
|
||||
RawContext* instance = reinterpret_cast<RawContext*>(SP[-1]);
|
||||
|
@ -2399,7 +2490,7 @@ SwitchDispatch:
|
|||
}
|
||||
|
||||
{
|
||||
BYTECODE(LoadContextVar, A_D);
|
||||
BYTECODE(LoadContextVar, A_E);
|
||||
const uword offset_in_words =
|
||||
static_cast<uword>(Context::variable_offset(rD) / kWordSize);
|
||||
RawContext* instance = static_cast<RawContext*>(SP[0]);
|
||||
|
@ -2409,7 +2500,7 @@ SwitchDispatch:
|
|||
}
|
||||
|
||||
{
|
||||
BYTECODE(AllocateContext, A_D);
|
||||
BYTECODE(AllocateContext, A_E);
|
||||
++SP;
|
||||
const uint16_t num_context_variables = rD;
|
||||
if (!AllocateContext(thread, num_context_variables, pc, FP, SP)) {
|
||||
|
@ -2419,7 +2510,7 @@ SwitchDispatch:
|
|||
}
|
||||
|
||||
{
|
||||
BYTECODE(CloneContext, A_D);
|
||||
BYTECODE(CloneContext, A_E);
|
||||
{
|
||||
SP[1] = SP[0]; // Context to clone.
|
||||
Exit(thread, FP, SP + 2, pc);
|
||||
|
@ -2504,7 +2595,7 @@ SwitchDispatch:
|
|||
}
|
||||
|
||||
{
|
||||
BYTECODE(AssertAssignable, A_D);
|
||||
BYTECODE(AssertAssignable, A_E);
|
||||
// Stack: instance, type, instantiator type args, function type args, name
|
||||
RawObject** args = SP - 4;
|
||||
const bool may_be_smi = (rA == 1);
|
||||
|
@ -2970,12 +3061,50 @@ SwitchDispatch:
|
|||
|
||||
{
|
||||
BYTECODE(Trap, 0);
|
||||
BYTECODE(Unused00, 0);
|
||||
BYTECODE_NEW(Unused01, 0);
|
||||
BYTECODE_NEW(Unused02, 0);
|
||||
BYTECODE_NEW(Unused03, 0);
|
||||
BYTECODE_NEW(Unused04, 0);
|
||||
BYTECODE_NEW(Unused05, 0);
|
||||
BYTECODE_NEW(Unused06, 0);
|
||||
BYTECODE_NEW(Unused07, 0);
|
||||
BYTECODE_NEW(Unused08, 0);
|
||||
BYTECODE_NEW(Unused09, 0);
|
||||
BYTECODE_NEW(Unused10, 0);
|
||||
BYTECODE_NEW(Unused11, 0);
|
||||
BYTECODE_NEW(Unused12, 0);
|
||||
BYTECODE_NEW(Unused13, 0);
|
||||
BYTECODE_NEW(Unused14, 0);
|
||||
BYTECODE_NEW(Unused15, 0);
|
||||
BYTECODE_NEW(Unused16, 0);
|
||||
BYTECODE_NEW(Unused17, 0);
|
||||
BYTECODE_NEW(Unused18, 0);
|
||||
BYTECODE_NEW(Unused19, 0);
|
||||
BYTECODE_NEW(Unused20, 0);
|
||||
BYTECODE_NEW(Unused21, 0);
|
||||
BYTECODE_NEW(Unused22, 0);
|
||||
BYTECODE_NEW(Unused23, 0);
|
||||
BYTECODE_NEW(Unused24, 0);
|
||||
BYTECODE_NEW(Unused25, 0);
|
||||
BYTECODE_NEW(Unused26, 0);
|
||||
BYTECODE_NEW(Unused27, 0);
|
||||
BYTECODE_NEW(Unused28, 0);
|
||||
BYTECODE_NEW(Unused29, 0);
|
||||
BYTECODE_NEW(Unused30, 0);
|
||||
BYTECODE_NEW(Unused31, 0);
|
||||
BYTECODE_NEW(Unused32, 0);
|
||||
BYTECODE_NEW(Unused33, 0);
|
||||
BYTECODE_NEW(Unused34, 0);
|
||||
BYTECODE_NEW(Unused35, 0);
|
||||
BYTECODE_NEW(Unused36, 0);
|
||||
BYTECODE_NEW(Unused37, 0);
|
||||
UNIMPLEMENTED();
|
||||
DISPATCH();
|
||||
}
|
||||
|
||||
{
|
||||
BYTECODE(VMInternal_ImplicitGetter, 0);
|
||||
BYTECODE_NEW(VMInternal_ImplicitGetter, 0);
|
||||
|
||||
RawFunction* function = FrameFunction(FP);
|
||||
ASSERT(Function::kind(function) == RawFunction::kImplicitGetter);
|
||||
|
@ -3024,7 +3153,7 @@ SwitchDispatch:
|
|||
}
|
||||
|
||||
{
|
||||
BYTECODE(VMInternal_ImplicitSetter, 0);
|
||||
BYTECODE_NEW(VMInternal_ImplicitSetter, 0);
|
||||
|
||||
RawFunction* function = FrameFunction(FP);
|
||||
ASSERT(Function::kind(function) == RawFunction::kImplicitSetter);
|
||||
|
@ -3145,7 +3274,7 @@ SwitchDispatch:
|
|||
}
|
||||
|
||||
{
|
||||
BYTECODE(VMInternal_ImplicitStaticGetter, 0);
|
||||
BYTECODE_NEW(VMInternal_ImplicitStaticGetter, 0);
|
||||
|
||||
RawFunction* function = FrameFunction(FP);
|
||||
ASSERT(Function::kind(function) == RawFunction::kImplicitStaticGetter);
|
||||
|
@ -3177,7 +3306,7 @@ SwitchDispatch:
|
|||
}
|
||||
|
||||
{
|
||||
BYTECODE(VMInternal_MethodExtractor, 0);
|
||||
BYTECODE_NEW(VMInternal_MethodExtractor, 0);
|
||||
|
||||
RawFunction* function = FrameFunction(FP);
|
||||
ASSERT(Function::kind(function) == RawFunction::kMethodExtractor);
|
||||
|
@ -3217,7 +3346,7 @@ SwitchDispatch:
|
|||
}
|
||||
|
||||
{
|
||||
BYTECODE(VMInternal_InvokeClosure, 0);
|
||||
BYTECODE_NEW(VMInternal_InvokeClosure, 0);
|
||||
|
||||
RawFunction* function = FrameFunction(FP);
|
||||
ASSERT(Function::kind(function) == RawFunction::kInvokeFieldDispatcher);
|
||||
|
@ -3239,7 +3368,7 @@ SwitchDispatch:
|
|||
}
|
||||
|
||||
{
|
||||
BYTECODE(VMInternal_InvokeField, 0);
|
||||
BYTECODE_NEW(VMInternal_InvokeField, 0);
|
||||
|
||||
RawFunction* function = FrameFunction(FP);
|
||||
ASSERT(Function::kind(function) == RawFunction::kInvokeFieldDispatcher);
|
||||
|
@ -3343,7 +3472,7 @@ SwitchDispatch:
|
|||
}
|
||||
|
||||
{
|
||||
BYTECODE(VMInternal_ForwardDynamicInvocation, 0);
|
||||
BYTECODE_NEW(VMInternal_ForwardDynamicInvocation, 0);
|
||||
RawFunction* function = FrameFunction(FP);
|
||||
ASSERT(Function::kind(function) ==
|
||||
RawFunction::kDynamicInvocationForwarder);
|
||||
|
@ -3352,14 +3481,14 @@ SwitchDispatch:
|
|||
}
|
||||
|
||||
{
|
||||
BYTECODE(VMInternal_NoSuchMethodDispatcher, 0);
|
||||
BYTECODE_NEW(VMInternal_NoSuchMethodDispatcher, 0);
|
||||
RawFunction* function = FrameFunction(FP);
|
||||
ASSERT(Function::kind(function) == RawFunction::kNoSuchMethodDispatcher);
|
||||
goto NoSuchMethodFromPrologue;
|
||||
}
|
||||
|
||||
{
|
||||
BYTECODE(VMInternal_ImplicitStaticClosure, 0);
|
||||
BYTECODE_NEW(VMInternal_ImplicitStaticClosure, 0);
|
||||
RawFunction* function = FrameFunction(FP);
|
||||
ASSERT(Function::kind(function) == RawFunction::kImplicitClosureFunction);
|
||||
UNIMPLEMENTED();
|
||||
|
@ -3367,7 +3496,7 @@ SwitchDispatch:
|
|||
}
|
||||
|
||||
{
|
||||
BYTECODE(VMInternal_ImplicitInstanceClosure, 0);
|
||||
BYTECODE_NEW(VMInternal_ImplicitInstanceClosure, 0);
|
||||
RawFunction* function = FrameFunction(FP);
|
||||
ASSERT(Function::kind(function) == RawFunction::kImplicitClosureFunction);
|
||||
UNIMPLEMENTED();
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#include "platform/atomic.h"
|
||||
#include "vm/base_isolate.h"
|
||||
#include "vm/class_table.h"
|
||||
#include "vm/constants_kbc.h"
|
||||
#include "vm/exceptions.h"
|
||||
#include "vm/fixed_cache.h"
|
||||
#include "vm/growable_array.h"
|
||||
|
@ -783,6 +784,23 @@ class Isolate : public BaseIsolate {
|
|||
return !unsafe_trust_strong_mode_types();
|
||||
}
|
||||
|
||||
static_assert(KernelBytecode::kMinSupportedBytecodeFormatVersion < 7,
|
||||
"Cleanup support for old bytecode format versions");
|
||||
bool is_using_old_bytecode_instructions() const {
|
||||
return UsingOldBytecodeInstructionsBit::decode(isolate_flags_);
|
||||
}
|
||||
void set_is_using_old_bytecode_instructions(bool value) {
|
||||
isolate_flags_ =
|
||||
UsingOldBytecodeInstructionsBit::update(value, isolate_flags_);
|
||||
}
|
||||
bool is_using_new_bytecode_instructions() const {
|
||||
return UsingNewBytecodeInstructionsBit::decode(isolate_flags_);
|
||||
}
|
||||
void set_is_using_new_bytecode_instructions(bool value) {
|
||||
isolate_flags_ =
|
||||
UsingNewBytecodeInstructionsBit::update(value, isolate_flags_);
|
||||
}
|
||||
|
||||
static void KillAllIsolates(LibMsgId msg_id);
|
||||
static void KillIfExists(Isolate* isolate, LibMsgId msg_id);
|
||||
|
||||
|
@ -907,7 +925,13 @@ class Isolate : public BaseIsolate {
|
|||
V(Obfuscate) \
|
||||
V(CompactionInProgress) \
|
||||
V(ShouldLoadVmService) \
|
||||
V(UnsafeTrustStrongModeTypes)
|
||||
V(UnsafeTrustStrongModeTypes) \
|
||||
V(UsingOldBytecodeInstructions) \
|
||||
V(UsingNewBytecodeInstructions)
|
||||
|
||||
static_assert(
|
||||
KernelBytecode::kMinSupportedBytecodeFormatVersion < 7,
|
||||
"Cleanup UsingOldBytecodeInstructions and UsingNewBytecodeInstructions");
|
||||
|
||||
// Isolate specific flags.
|
||||
enum FlagBits {
|
||||
|
|
Loading…
Reference in a new issue