Index: runtime/vm/constants_dbc.h |
diff --git a/runtime/vm/constants_dbc.h b/runtime/vm/constants_dbc.h |
new file mode 100644 |
index 0000000000000000000000000000000000000000..62202432baf3e30563eeaea2f35ba1533f664bb1 |
--- /dev/null |
+++ b/runtime/vm/constants_dbc.h |
@@ -0,0 +1,490 @@ |
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file |
+// for details. All rights reserved. Use of this source code is governed by a |
+// BSD-style license that can be found in the LICENSE file. |
+ |
+#ifndef VM_CONSTANTS_DBC_H_ |
+#define VM_CONSTANTS_DBC_H_ |
+ |
+#include "platform/globals.h" |
+#include "platform/assert.h" |
+#include "platform/utils.h" |
+ |
+ |
+namespace dart { |
+ |
+// List of Dart Bytecode instructions. |
+// |
+// INTERPRETER STATE |
+// |
+// current frame info (see stack_frame_dbc.h for layout) |
+// v-----^-----v |
+// ~----+----~ ~----+-------+-------+-~ ~-+-------+-------+-~ |
+// ~ | ~ ~ | FP[0] | FP[1] | ~ ~ | SP[-1]| SP[0] | |
+// ~----+----~ ~----+-------+-------+-~ ~-+-------+-------+-~ |
+// ^ ^ |
+// FP SP |
+// |
+// |
+// The state of execution is captured in few interpreter registers: |
+// |
+// FP - base of the current frame |
+// SP - top of the stack (TOS) for the current frame |
+// PP - object pool for the currently execution function |
+// |
+// Frame info stored below FP additionally contains pointers to the currently |
+// executing function and code (see stack_frame_dbc.h for more information). |
+// |
+// In the unoptimized code most of bytecodes take operands implicitly from |
+// stack and store results again on the stack. Constant operands are usually |
+// taken from the object pool by index. |
+// |
+// ENCODING |
+// |
+// Each instruction is a 32-bit integer with opcode stored in the least |
+// significant byte. The following operand encodings are used: |
+// |
+// 0........8.......16.......24.......32 |
+// +--------+--------+--------+--------+ |
+// | opcode |~~~~~~~~~~~~~~~~~~~~~~~~~~| 0: no operands |
+// +--------+--------+--------+--------+ |
+// |
+// +--------+--------+--------+--------+ |
+// | 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 |
+// +--------+--------+--------+--------+ |
+// |
+// |
+// INSTRUCTIONS |
+// |
+// - Trap |
+// |
+// Unreachable instruction. |
+// |
+// - Compile |
+// |
+// Compile current function and start executing newly produced code |
+// (used to implement LazyCompileStub); |
+// |
+// - Intrinsic id |
+// |
+// Execute intrinsic with the given id. If intrinsic returns true then |
+// return from the current function to the caller passing value produced |
+// by the intrinsic as a result; |
+// |
+// - Drop1; DropR n; Drop n |
+// |
+// Drop 1 or n values from the stack, if instruction is DropR push the first |
+// dropped value to the stack; |
+// |
+// - Jump target |
+// |
+// Jump to the given target. Target is specified as offset from the PC of the |
+// jump instruction. |
+// |
+// - Return R; ReturnTOS |
+// |
+// Return to the caller using either a value from the given register or a |
+// value from the top-of-stack as a result. |
+// |
+// Note: return instruction knows how many arguments to remove from the |
+// stack because it can look at the call instruction at caller's PC and |
+// take argument count from it. |
+// |
+// - Move rA, rX |
+// |
+// FP[rA] <- FP[rX] |
+// Note: rX is signed so it can be used to address parameters which are |
+// at negative indices with respect to FP. |
+// |
+// - Push rX |
+// |
+// Push FP[rX] to the stack. |
+// |
+// - LoadConstant rA, D; PushConstant D |
+// |
+// Load value at index D from constant pool into FP[rA] or push it onto the |
+// stack. |
+// |
+// - StoreLocal rX; PopLocal rX |
+// |
+// Store top of the stack into FP[rX] and pop it if needed. |
+// |
+// - StaticCall ArgC, D |
+// |
+// Invoke function in SP[0] with arguments SP[-(1+ArgC)], ..., SP[-1] and |
+// argument descriptor PP[D]. |
+// |
+// - InstanceCall ArgC, D; InstanceCall2 ArgC, D; InstanceCall3 ArgC, D |
+// |
+// Lookup and invoke method using ICData in PP[D] with arguments |
+// SP[-(1+ArgC)], ..., SP[-1]. |
+// |
+// - NativeCall, NativeBootstrapCall |
+// |
+// Invoke native function SP[-1] with argc_tag SP[0]. |
+// |
+// - AddTOS; SubTOS; MulTOS; BitOrTOS; BitAndTOS; EqualTOS; LessThanTOS; |
+// GreaterThanTOS; |
+// |
+// Smi fast-path for a corresponding method. Checks if SP[0] and SP[-1] are |
+// both smis and result of SP[0] <op> SP[-1] is a smi - if this is true |
+// then pops operands and pushes result on the stack and skips the next |
+// instruction (which implements a slow path fallback). |
+// |
+// - StoreStaticTOS D |
+// |
+// Stores TOS into the static field PP[D]. |
+// |
+// - PushStatic |
+// |
+// Pushes value of the static field PP[D] on to the stack. |
+// |
+// - InitStaticTOS |
+// |
+// Takes static field from TOS and ensures that it is initialized. |
+// |
+// - IfNeStrictTOS; IfEqStrictTOS; IfNeStrictNumTOS; IfEqStrictNumTOS |
+// |
+// Skips the next instruction unless the given condition holds. 'Num' |
+// variants perform number check while non-Num variants just compare |
+// RawObject pointers. |
+// |
+// Used to implement conditional jump: |
+// |
+// IfNeStrictTOS |
+// Jump T ;; jump if not equal |
+// |
+// - CreateArrayTOS |
+// |
+// Allocate array of length SP[0] with type arguments SP[-1]. |
+// |
+// - Allocate D |
+// |
+// Allocate object of class PP[D] with no type arguments. |
+// |
+// - AllocateT |
+// |
+// Allocate object of class SP[0] with type arguments SP[-1]. |
+// |
+// - StoreIndexedTOS |
+// |
+// Store SP[0] into array SP[-2] at index SP[-1]. No typechecking is done. |
+// SP[-2] is assumed to be a RawArray, SP[-1] to be a smi. |
+// |
+// - StoreField rA, B, rC |
+// |
+// Store value FP[rC] into object FP[rA] at offset (in words) B. |
+// |
+// - StoreFieldTOS D |
+// |
+// Store value SP[0] into object SP[-1] at offset (in words) D. |
+// |
+// - LoadField rA, rB, C |
+// |
+// Load value at offset (in words) C from object FP[rB] into FP[rA]. |
+// |
+// - LoadFieldTOS D |
+// |
+// Push value at offset (in words) D from object SP[0]. |
+// |
+// - BooleanNegateTOS |
+// |
+// SP[0] = !SP[0] |
+// |
+// - Throw A |
+// |
+// Throw (Rethrow if A != 0) exception. Exception object and stack object |
+// are taken from TOS. |
+// |
+// - Entry A, B, rC |
+// |
+// Function prologue for the function with no optional or named arguments: |
+// A - expected number of positional arguments; |
+// B - number of local slots to reserve; |
+// rC - specifies context register to initialize with empty context. |
+// |
+// - EntryOpt A, B, C |
+// |
+// Function prologue for the function with optional or named arguments: |
+// A - expected number of positional arguments; |
+// B - number of optional arguments; |
+// C - number of named arguments; |
+// |
+// Only one of B and C can be not 0. |
+// |
+// If B is not 0 then EntryOpt bytecode is followed by B LoadConstant |
+// bytecodes specifying default values for optional arguments. |
+// |
+// If C is not 0 then EntryOpt is followed by 2 * B LoadConstant bytecodes. |
+// Bytecode at 2 * i specifies name of the i-th named argument and at |
+// 2 * i + 1 default value. rA part of the LoadConstant bytecode specifies |
+// the location of the parameter on the stack. Here named arguments are |
+// sorted alphabetically to enable linear matching similar to how function |
+// prologues are implemented on other architectures. |
+// |
+// Note: Unlike Entry bytecode EntryOpt does not setup the frame for |
+// local variables this is done by a separate bytecode Frame. |
+// |
+// - Frame D |
+// |
+// Reserve and initialize with null space for D local variables. |
+// |
+// - SetFrame A |
+// |
+// Reinitialize SP assuming that current frame has size A. |
+// Used to drop temporaries from the stack in the exception handler. |
+// |
+// - AllocateContext D |
+// |
+// Allocate Context object assuming for D context variables. |
+// |
+// - CloneContext |
+// |
+// Clone context stored in TOS. |
+// |
+// - MoveSpecial rA, D |
+// |
+// Copy special values from inside interpreter to FP[rA]. Currently only |
+// used to pass exception object (D = 0) and stack trace object (D = 1) to |
+// catch handler. |
+// |
+// - InstantiateType D |
+// |
+// Instantiate type PP[D] with instantiator type arguments SP[0]. |
+// |
+// - InstantiateTypeArgumentsTOS D |
+// |
+// Instantiate type arguments PP[D] with instantiator SP[0]. |
+// |
+// - AssertAssignable D |
+// |
+// Assert that SP[-3] is assignable to variable named SP[0] of type |
+// SP[-1] with type arguments SP[-2] using SubtypeTestCache PP[D]. |
+// |
+// - AssertBoolean A |
+// |
+// Assert that TOS is a boolean (A = 1) or that TOS is not null (A = 0). |
+// |
+// - CheckStack |
+// |
+// Compare SP against isolate stack limit and call StackOverflow handler if |
+// necessary. |
+// |
+// - DebugStep, DebugBreak A |
+// |
+// Debugger support. DebugBreak is bytecode that can be patched into the |
+// instruction stream to trigger in place breakpoint. |
+// |
+// When patching instance or static call with DebugBreak we set A to |
+// match patched call's argument count so that Return instructions continue |
+// to work. |
+// |
+// TODO(vegorov) the way we replace calls with DebugBreak does not work |
+// with our smi fast paths because DebugBreak is simply skipped. |
+// |
+// BYTECODE LIST FORMAT |
+// |
+// Bytecode list below is specified using the following format: |
+// |
+// V(BytecodeName, OperandForm, 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). |
+// |
+// - Op1, Op2, Op2 specify operand meaning. Possible values: |
+// |
+// ___ ignored / non-existent operand |
+// num immediate operand |
+// lit constant literal from object pool |
+// reg register (unsigned FP relative local) |
+// xeg x-register (signed FP relative local) |
+// tgt jump target relative to the PC of the current instruction |
+// |
+// TODO(vegorov) jump targets should be encoded relative to PC of the next |
+// instruction because PC is incremeted immediately after fetch |
+// and before decoding. |
+// |
+#define BYTECODES_LIST(V) \ |
+ V(Trap, 0, ___, ___, ___) \ |
+ V(Compile, 0, ___, ___, ___) \ |
+ V(Intrinsic, A, num, ___, ___) \ |
+ V(Drop1, 0, ___, ___, ___) \ |
+ V(DropR, A, num, ___, ___) \ |
+ V(Drop, A, num, ___, ___) \ |
+ V(Jump, T, tgt, ___, ___) \ |
+ V(Return, A, num, ___, ___) \ |
+ V(ReturnTOS, 0, ___, ___, ___) \ |
+ V(Move, A_X, reg, xeg, ___) \ |
+ V(Push, X, xeg, ___, ___) \ |
+ V(LoadConstant, A_D, reg, lit, ___) \ |
+ V(PushConstant, D, lit, ___, ___) \ |
+ V(StoreLocal, X, xeg, ___, ___) \ |
+ V(PopLocal, X, xeg, ___, ___) \ |
+ V(StaticCall, A_D, num, num, ___) \ |
+ V(InstanceCall, A_D, num, num, ___) \ |
+ V(InstanceCall2, A_D, num, num, ___) \ |
+ V(InstanceCall3, A_D, num, num, ___) \ |
+ V(NativeCall, 0, ___, ___, ___) \ |
+ V(NativeBootstrapCall, 0, ___, ___, ___) \ |
+ V(AddTOS, 0, ___, ___, ___) \ |
+ V(SubTOS, 0, ___, ___, ___) \ |
+ V(MulTOS, 0, ___, ___, ___) \ |
+ V(BitOrTOS, 0, ___, ___, ___) \ |
+ V(BitAndTOS, 0, ___, ___, ___) \ |
+ V(EqualTOS, 0, ___, ___, ___) \ |
+ V(LessThanTOS, 0, ___, ___, ___) \ |
+ V(GreaterThanTOS, 0, ___, ___, ___) \ |
+ V(StoreStaticTOS, D, lit, ___, ___) \ |
+ V(PushStatic, D, lit, ___, ___) \ |
+ V(InitStaticTOS, 0, ___, ___, ___) \ |
+ V(IfNeStrictTOS, 0, ___, ___, ___) \ |
+ V(IfEqStrictTOS, 0, ___, ___, ___) \ |
+ V(IfNeStrictNumTOS, 0, ___, ___, ___) \ |
+ V(IfEqStrictNumTOS, 0, ___, ___, ___) \ |
+ V(CreateArrayTOS, 0, ___, ___, ___) \ |
+ V(Allocate, D, lit, ___, ___) \ |
+ V(AllocateT, 0, ___, ___, ___) \ |
+ V(StoreIndexedTOS, 0, ___, ___, ___) \ |
+ V(StoreField, A_B_C, reg, reg, reg) \ |
+ V(StoreFieldTOS, D, num, ___, ___) \ |
+ V(LoadField, A_B_C, reg, reg, reg) \ |
+ V(LoadFieldTOS, D, num, ___, ___) \ |
+ V(BooleanNegateTOS, 0, ___, ___, ___) \ |
+ V(Throw, A, num, ___, ___) \ |
+ V(Entry, A_B_C, num, num, num) \ |
+ V(EntryOpt, A_B_C, num, num, num) \ |
+ V(Frame, D, num, ___, ___) \ |
+ V(SetFrame, A, num, ___, num) \ |
+ V(AllocateContext, D, num, ___, ___) \ |
+ V(CloneContext, 0, ___, ___, ___) \ |
+ V(MoveSpecial, A_D, reg, num, ___) \ |
+ V(InstantiateType, D, lit, ___, ___) \ |
+ V(InstantiateTypeArgumentsTOS, A_D, num, lit, ___) \ |
+ V(AssertAssignable, D, num, lit, ___) \ |
+ V(AssertBoolean, A, num, ___, ___) \ |
+ V(CheckStack, 0, ___, ___, ___) \ |
+ V(DebugStep, 0, ___, ___, ___) \ |
+ V(DebugBreak, A, num, ___, ___) \ |
+ |
+typedef uint32_t Instr; |
+ |
+class Bytecode { |
+ public: |
+ enum Opcode { |
+#define DECLARE_BYTECODE(name, encoding, op1, op2, op3) k##name, |
+BYTECODES_LIST(DECLARE_BYTECODE) |
+#undef DECLARE_BYTECODE |
+ }; |
+ |
+ 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 Instr Encode(Opcode op, uintptr_t a, uintptr_t b, uintptr_t c) { |
+ ASSERT((a & kAMask) == a); |
+ ASSERT((b & kBMask) == b); |
+ ASSERT((c & kCMask) == c); |
+ return op | (a << kAShift) | (b << kBShift) | (c << kCShift); |
+ } |
+ |
+ static Instr Encode(Opcode op, uintptr_t a, uintptr_t d) { |
+ ASSERT((a & kAMask) == a); |
+ ASSERT((d & kDMask) == d); |
+ return op | (a << kAShift) | (d << kDShift); |
+ } |
+ |
+ static Instr EncodeSigned(Opcode op, uintptr_t a, intptr_t x) { |
+ ASSERT((a & kAMask) == a); |
+ ASSERT((x << kDShift) >> kDShift == x); |
+ return op | (a << kAShift) | (x << kDShift); |
+ } |
+ |
+ static Instr EncodeSigned(Opcode op, intptr_t x) { |
+ ASSERT((x << kAShift) >> kAShift == x); |
+ return op | (x << kAShift); |
+ } |
+ |
+ static Instr Encode(Opcode op) { |
+ return op; |
+ } |
+ |
+ DART_FORCE_INLINE static uint8_t DecodeA(Instr bc) { |
+ return (bc >> kAShift) & kAMask; |
+ } |
+ |
+ DART_FORCE_INLINE static uint16_t DecodeD(Instr bc) { |
+ return (bc >> kDShift) & kDMask; |
+ } |
+ |
+ DART_FORCE_INLINE static Opcode DecodeOpcode(Instr bc) { |
+ return static_cast<Opcode>(bc & 0xFF); |
+ } |
+ |
+ DART_FORCE_INLINE static uint8_t DecodeArgc(Instr call) { |
+#if defined(DEBUG) |
+ const Opcode op = DecodeOpcode(call); |
+ ASSERT((op == Bytecode::kStaticCall) || |
+ (op == Bytecode::kInstanceCall) || |
+ (op == Bytecode::kInstanceCall2) || |
+ (op == Bytecode::kInstanceCall3) || |
+ (op == Bytecode::kDebugBreak)); |
+#endif |
+ return (call >> 8) & 0xFF; |
+ } |
+}; |
+ |
+// Various dummy declarations to make shared code compile. |
+// TODO(vegorov) we need to prune away as much dead code as possible instead |
+// of just making it compile. |
+typedef int16_t Register; |
+ |
+const int16_t FPREG = 0; |
+const int16_t SPREG = 1; |
+const intptr_t kNumberOfCpuRegisters = 20; |
+const intptr_t kDartAvailableCpuRegs = 0; |
+const intptr_t kNoRegister = -1; |
+const intptr_t kReservedCpuRegisters = 0; |
+const intptr_t ARGS_DESC_REG = 0; |
+const intptr_t CODE_REG = 0; |
+const intptr_t kExceptionObjectReg = 0; |
+const intptr_t kStackTraceObjectReg = 0; |
+const intptr_t CTX = 0; |
+ |
+enum FpuRegister { kNoFpuRegister = -1, kFakeFpuRegister }; |
+const FpuRegister FpuTMP = kFakeFpuRegister; |
+const intptr_t kNumberOfFpuRegisters = 1; |
+ |
+enum Condition { EQ, NE }; |
+ |
+} // namespace dart |
+ |
+#endif // VM_CONSTANTS_DBC_H_ |