diff --git a/runtime/vm/clustered_snapshot.cc b/runtime/vm/clustered_snapshot.cc index d30764c1e31..dba74ea5fd9 100644 --- a/runtime/vm/clustered_snapshot.cc +++ b/runtime/vm/clustered_snapshot.cc @@ -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>(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()); + } } } }; diff --git a/runtime/vm/compiler/assembler/disassembler_kbc.cc b/runtime/vm/compiler/assembler/disassembler_kbc.cc index fb42751d0d7..411e1cfffce 100644 --- a/runtime/vm/compiler/assembler/disassembler_kbc.cc +++ b/runtime/vm/compiler/assembler/disassembler_kbc.cc @@ -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 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(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(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(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(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(pc); - const uint8_t opcode = instr & 0xFF; + const KBCInstr* instr = reinterpret_cast(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; diff --git a/runtime/vm/compiler/frontend/bytecode_flow_graph_builder.cc b/runtime/vm/compiler/frontend/bytecode_flow_graph_builder.cc index e92bde23a8e..a0ad951bd78 100644 --- a/runtime/vm/compiler/frontend/bytecode_flow_graph_builder.cc +++ b/runtime/vm/compiler/frontend/bytecode_flow_graph_builder.cc @@ -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)); diff --git a/runtime/vm/compiler/frontend/bytecode_flow_graph_builder.h b/runtime/vm/compiler/frontend/bytecode_flow_graph_builder.h index 50e77a159ed..833deb208c3 100644 --- a/runtime/vm/compiler/frontend/bytecode_flow_graph_builder.h +++ b/runtime/vm/compiler/frontend/bytecode_flow_graph_builder.h @@ -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 diff --git a/runtime/vm/compiler/frontend/bytecode_reader.cc b/runtime/vm/compiler/frontend/bytecode_reader.cc index a6368f33e47..d71fc30c942 100644 --- a/runtime/vm/compiler/frontend/bytecode_reader.cc +++ b/runtime/vm/compiler/frontend/bytecode_reader.cc @@ -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(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); diff --git a/runtime/vm/compiler/frontend/bytecode_reader.h b/runtime/vm/compiler/frontend/bytecode_reader.h index f03cc4f1c8b..bc4d03cbfb4 100644 --- a/runtime/vm/compiler/frontend/bytecode_reader.h +++ b/runtime/vm/compiler/frontend/bytecode_reader.h @@ -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_; }; diff --git a/runtime/vm/constants_kbc.cc b/runtime/vm/constants_kbc.cc index 1b96d579d0c..d5ed600cf23 100644 --- a/runtime/vm/constants_kbc.cc +++ b/runtime/vm/constants_kbc.cc @@ -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 diff --git a/runtime/vm/constants_kbc.h b/runtime/vm/constants_kbc.h index 116a1c0a492..9c10bfb6024 100644 --- a/runtime/vm/constants_kbc.h +++ b/runtime/vm/constants_kbc.h @@ -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(bc[2]) | (static_cast(bc[3]) << 8); + DART_FORCE_INLINE static uint32_t DecodeD(const KBCInstr* bc) { + if (IsOld(bc)) { + return static_cast(bc[2]) | (static_cast(bc[3]) << 8); + } else if (IsWide(bc)) { + return static_cast(bc[1]) | + (static_cast(bc[2]) << 8) | + (static_cast(bc[3]) << 16) | + (static_cast(bc[4]) << 24); + } else { + return bc[1]; + } } - DART_FORCE_INLINE static int16_t DecodeX(const KBCInstr* bc) { - return static_cast(static_cast(bc[2]) | - (static_cast(bc[3]) << 8)); + DART_FORCE_INLINE static int32_t DecodeX(const KBCInstr* bc) { + if (IsOld(bc)) { + return static_cast(static_cast(bc[2]) | + (static_cast(bc[3]) << 8)); + } else if (IsWide(bc)) { + return static_cast(static_cast(bc[1]) | + (static_cast(bc[2]) << 8) | + (static_cast(bc[3]) << 16) | + (static_cast(bc[4]) << 24)); + } else { + return static_cast(bc[1]); + } } DART_FORCE_INLINE static int32_t DecodeT(const KBCInstr* bc) { - return static_cast((static_cast(bc[1]) << 8) | - (static_cast(bc[2]) << 16) | - (static_cast(bc[3]) << 24)) >> - (8 - 2); + if (IsOld(bc)) { + return static_cast((static_cast(bc[1]) << 8) | + (static_cast(bc[2]) << 16) | + (static_cast(bc[3]) << 24)) >> + (8 - 2); + } else if (IsWide(bc)) { + return static_cast((static_cast(bc[1]) << 8) | + (static_cast(bc[2]) << 16) | + (static_cast(bc[3]) << 24)) >> + 8; + } else { + return static_cast(bc[1]); + } + } + + DART_FORCE_INLINE static uint32_t DecodeE(const KBCInstr* bc) { + if (IsOld(bc)) { + return static_cast(bc[2]) | (static_cast(bc[3]) << 8); + } else if (IsWide(bc)) { + return static_cast(bc[2]) | + (static_cast(bc[3]) << 8) | + (static_cast(bc[4]) << 16) | + (static_cast(bc[5]) << 24); + } else { + return bc[2]; + } + } + + DART_FORCE_INLINE static int32_t DecodeY(const KBCInstr* bc) { + if (IsOld(bc)) { + return static_cast(static_cast(bc[2]) | + (static_cast(bc[3]) << 8)); + } else if (IsWide(bc)) { + return static_cast(static_cast(bc[2]) | + (static_cast(bc[3]) << 8) | + (static_cast(bc[4]) << 16) | + (static_cast(bc[5]) << 24)); + } else { + return static_cast(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(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, diff --git a/runtime/vm/instructions_kbc.cc b/runtime/vm/instructions_kbc.cc index 909a98c89fd..a8a3608c21b 100644 --- a/runtime/vm/instructions_kbc.cc +++ b/runtime/vm/instructions_kbc.cc @@ -17,11 +17,22 @@ RawTypedData* KBCNativeCallPattern::GetNativeEntryDataAt( uword pc, const Bytecode& bytecode) { ASSERT(bytecode.ContainsInstructionAt(pc)); - const KBCInstr* call_instr = - KernelBytecode::Previous(reinterpret_cast(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(pc); + const KBCInstr* instr = + reinterpret_cast(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); diff --git a/runtime/vm/interpreter.cc b/runtime/vm/interpreter.cc index 9df73b02f9e..2bdb64d22c7 100644 --- a/runtime/vm/interpreter.cc +++ b/runtime/vm/interpreter.cc @@ -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(pc[2]) | (static_cast(pc[3]) << 8); \ - pc += 4; + pc += 4; \ + GOTO_BYTECODE_IMPL(Name); \ + BYTECODE_WIDE_ENTRY_LABEL(Name) \ + rD = static_cast(pc[1]) | (static_cast(pc[2]) << 8) | \ + (static_cast(pc[3]) << 16) | \ + (static_cast(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(pc[2]) | (static_cast(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(static_cast(pc[2]) | \ (static_cast(pc[3]) << 8)); \ - pc += 4; + pc += 4; \ + GOTO_BYTECODE_IMPL(Name); \ + BYTECODE_WIDE_ENTRY_LABEL(Name) \ + rD = static_cast(static_cast(pc[1]) | \ + (static_cast(pc[2]) << 8) | \ + (static_cast(pc[3]) << 16) | \ + (static_cast(pc[4]) << 24)); \ + pc += 5; \ + GOTO_BYTECODE_IMPL(Name); \ + BYTECODE_ENTRY_LABEL(Name) \ + rD = static_cast(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(static_cast(pc[2]) | \ - (static_cast(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((static_cast(pc[1]) << 8) | \ (static_cast(pc[2]) << 16) | \ (static_cast(pc[3]) << 24)) >> \ (8 - 2)); \ + pc += 4; \ + GOTO_BYTECODE_IMPL(Name); \ + BYTECODE_WIDE_ENTRY_LABEL(Name) \ + rT = pc + (static_cast((static_cast(pc[1]) << 8) | \ + (static_cast(pc[2]) << 16) | \ + (static_cast(pc[3]) << 24)) >> \ + 8); \ + pc += 4; \ + GOTO_BYTECODE_IMPL(Name); \ + BYTECODE_ENTRY_LABEL(Name) \ + rT = pc + static_cast(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(pc[2]) | (static_cast(pc[3]) << 8); \ + pc += 4; \ + GOTO_BYTECODE_IMPL(Name); \ + BYTECODE_WIDE_ENTRY_LABEL(Name) \ + rA = pc[1]; \ + rD = static_cast(pc[2]) | (static_cast(pc[3]) << 8) | \ + (static_cast(pc[4]) << 16) | \ + (static_cast(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(static_cast(pc[2]) | \ + (static_cast(pc[3]) << 8)); \ + pc += 4; \ + GOTO_BYTECODE_IMPL(Name); \ + BYTECODE_WIDE_ENTRY_LABEL(Name) \ + rA = pc[1]; \ + rD = static_cast(static_cast(pc[2]) | \ + (static_cast(pc[3]) << 8) | \ + (static_cast(pc[4]) << 16) | \ + (static_cast(pc[5]) << 24)); \ + pc += 6; \ + GOTO_BYTECODE_IMPL(Name); \ + BYTECODE_ENTRY_LABEL(Name) \ + rA = pc[1]; \ + rD = static_cast(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(pc[2]) | (static_cast(pc[3]) << 8); \ + pc += 4; \ + GOTO_BYTECODE_IMPL(Name); \ + BYTECODE_WIDE_ENTRY_LABEL(Name) \ + rD = static_cast(pc[1]) | (static_cast(pc[2]) << 8) | \ + (static_cast(pc[3]) << 16) | \ + (static_cast(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( - 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( @@ -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(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(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(argc)); + } +#endif DISPATCH(); } @@ -2347,7 +2438,7 @@ SwitchDispatch: } { - BYTECODE(StoreContextVar, A_D); + BYTECODE(StoreContextVar, A_E); const uword offset_in_words = static_cast(Context::variable_offset(rD) / kWordSize); RawContext* instance = reinterpret_cast(SP[-1]); @@ -2399,7 +2490,7 @@ SwitchDispatch: } { - BYTECODE(LoadContextVar, A_D); + BYTECODE(LoadContextVar, A_E); const uword offset_in_words = static_cast(Context::variable_offset(rD) / kWordSize); RawContext* instance = static_cast(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(); diff --git a/runtime/vm/isolate.h b/runtime/vm/isolate.h index f0484c9e7f1..142a87ff94c 100644 --- a/runtime/vm/isolate.h +++ b/runtime/vm/isolate.h @@ -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 {