| Index: runtime/vm/constants_dbc.h
|
| diff --git a/runtime/vm/constants_dbc.h b/runtime/vm/constants_dbc.h
|
| index 54fc66b477a12e22d9d5374a3e8e6cc86af12df1..657ffb03c563066e6ab7cc66438e7287b200666b 100644
|
| --- a/runtime/vm/constants_dbc.h
|
| +++ b/runtime/vm/constants_dbc.h
|
| @@ -119,6 +119,12 @@ namespace dart {
|
| // Note: rX is signed so it can be used to address parameters which are
|
| // at negative indices with respect to FP.
|
| //
|
| +// - Swap rA, rX
|
| +//
|
| +// FP[rA], FP[rX] <- FP[rX], FP[rA]
|
| +// 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.
|
| @@ -137,10 +143,10 @@ namespace dart {
|
| // 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
|
| +// - InstanceCall<N> ArgC, D; InstanceCall<N>Opt ArgC, D
|
| //
|
| -// Lookup and invoke method using ICData in PP[D] with arguments
|
| -// SP[-(1+ArgC)], ..., SP[-1].
|
| +// Lookup and invoke method with N checked arguments using ICData in PP[D]
|
| +// with arguments SP[-(1+ArgC)], ..., SP[-1].
|
| //
|
| // - NativeCall, NativeBootstrapCall
|
| //
|
| @@ -166,7 +172,10 @@ namespace dart {
|
| //
|
| // Takes static field from TOS and ensures that it is initialized.
|
| //
|
| -// - IfNeStrictTOS; IfEqStrictTOS; IfNeStrictNumTOS; IfEqStrictNumTOS
|
| +// - If<Cond>(Num)TOS
|
| +// If<Cond>(Num) rA, rD
|
| +//
|
| +// Cond is either NeStrict or EqStrict
|
| //
|
| // Skips the next instruction unless the given condition holds. 'Num'
|
| // variants perform number check while non-Num variants just compare
|
| @@ -194,6 +203,11 @@ namespace dart {
|
| // 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.
|
| //
|
| +// - StoreIndexed rA, rB, rC
|
| +//
|
| +// Store rC into array rA at index rB. No typechecking is done.
|
| +// rA is assumed to be a RawArray, rB to be a smi.
|
| +//
|
| // - StoreField rA, B, rC
|
| //
|
| // Store value FP[rC] into object FP[rA] at offset (in words) B.
|
| @@ -214,6 +228,10 @@ namespace dart {
|
| //
|
| // SP[0] = !SP[0]
|
| //
|
| +// - BooleanNegate rA, rD
|
| +//
|
| +// FP[rA] = !FP[rD]
|
| +//
|
| // - Throw A
|
| //
|
| // Throw (Rethrow if A != 0) exception. Exception object and stack object
|
| @@ -226,7 +244,7 @@ namespace dart {
|
| // B - number of local slots to reserve;
|
| // rC - specifies context register to initialize with empty context.
|
| //
|
| -// - EntryOpt A, B, C
|
| +// - EntryOptional A, B, C
|
| //
|
| // Function prologue for the function with optional or named arguments:
|
| // A - expected number of positional arguments;
|
| @@ -235,19 +253,36 @@ namespace dart {
|
| //
|
| // Only one of B and C can be not 0.
|
| //
|
| -// If B is not 0 then EntryOpt bytecode is followed by B LoadConstant
|
| +// If B is not 0 then EntryOptional 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.
|
| +// If C is not 0 then EntryOptional 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
|
| +// Note: Unlike Entry bytecode EntryOptional does not setup the frame for
|
| // local variables this is done by a separate bytecode Frame.
|
| //
|
| +// - EntryOptimized A, D
|
| +//
|
| +// Function prologue for optimized functions with no optional or named
|
| +// arguments.
|
| +// A - expected number of positional arguments;
|
| +// B - number of local slots to reserve for registers;
|
| +//
|
| +// Note: reserved slots are not initialized because optimized code
|
| +// has stack maps attached to call sites.
|
| +//
|
| +// - HotCheck A, D
|
| +//
|
| +// Increment current function's usage counter by A and check if it
|
| +// exceeds D. If it does trigger (re)optimization of the current
|
| +// function.
|
| +//
|
| // - Frame D
|
| //
|
| // Reserve and initialize with null space for D local variables.
|
| @@ -302,14 +337,29 @@ namespace dart {
|
| // 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.
|
| +//
|
| // - LoadClassIdTOS, LoadClassId rA, D
|
| //
|
| // LoadClassIdTOS loads the class id from the object at SP[0] and stores it
|
| // to SP[0]. LoadClassId loads the class id from FP[rA] and stores it to
|
| // FP[D].
|
| //
|
| -// TODO(vegorov) the way we replace calls with DebugBreak does not work
|
| -// with our smi fast paths because DebugBreak is simply skipped.
|
| +// - Deopt ArgC, D
|
| +//
|
| +// If D != 0 then trigger eager deoptimization with deopt id (D - 1).
|
| +// If D == 0 then trigger lazy deoptimization.
|
| +//
|
| +// The meaning of operand ArgC (encoded as A operand) matches that of an
|
| +// ArgC operand in call instructions. This is needed because we could
|
| +// potentially patch calls instructions with a lazy deopt and we need to
|
| +// ensure that any Return/ReturnTOS instructions
|
| +// returning from the patched calls will continue to function,
|
| +// e.g. in bytecode sequences like
|
| +//
|
| +// InstanceCall ... <- lazy deopt inside first call
|
| +// InstanceCall ... <- patches seconds call with Deopt
|
| //
|
| // BYTECODE LIST FORMAT
|
| //
|
| @@ -336,14 +386,16 @@ namespace dart {
|
| #define BYTECODES_LIST(V) \
|
| V(Trap, 0, ___, ___, ___) \
|
| V(Compile, 0, ___, ___, ___) \
|
| + V(HotCheck, A_D, num, num, ___) \
|
| V(Intrinsic, A, num, ___, ___) \
|
| V(Drop1, 0, ___, ___, ___) \
|
| V(DropR, A, num, ___, ___) \
|
| V(Drop, A, num, ___, ___) \
|
| V(Jump, T, tgt, ___, ___) \
|
| - V(Return, A, num, ___, ___) \
|
| + V(Return, A, reg, ___, ___) \
|
| V(ReturnTOS, 0, ___, ___, ___) \
|
| V(Move, A_X, reg, xeg, ___) \
|
| + V(Swap, A_X, reg, xeg, ___) \
|
| V(Push, X, xeg, ___, ___) \
|
| V(LoadConstant, A_D, reg, lit, ___) \
|
| V(LoadClassId, A_D, reg, reg, ___) \
|
| @@ -352,9 +404,10 @@ namespace dart {
|
| V(StoreLocal, X, xeg, ___, ___) \
|
| V(PopLocal, X, xeg, ___, ___) \
|
| V(StaticCall, A_D, num, num, ___) \
|
| - V(InstanceCall, A_D, num, num, ___) \
|
| + V(InstanceCall1, A_D, num, num, ___) \
|
| V(InstanceCall2, A_D, num, num, ___) \
|
| - V(InstanceCall3, A_D, num, num, ___) \
|
| + V(InstanceCall1Opt, A_D, num, num, ___) \
|
| + V(InstanceCall2Opt, A_D, num, num, ___) \
|
| V(NativeCall, 0, ___, ___, ___) \
|
| V(NativeBootstrapCall, 0, ___, ___, ___) \
|
| V(AddTOS, 0, ___, ___, ___) \
|
| @@ -372,18 +425,25 @@ namespace dart {
|
| V(IfEqStrictTOS, 0, ___, ___, ___) \
|
| V(IfNeStrictNumTOS, 0, ___, ___, ___) \
|
| V(IfEqStrictNumTOS, 0, ___, ___, ___) \
|
| + V(IfNeStrict, A_D, reg, reg, ___) \
|
| + V(IfEqStrict, A_D, reg, reg, ___) \
|
| + V(IfNeStrictNum, A_D, reg, reg, ___) \
|
| + V(IfEqStrictNum, A_D, reg, reg, ___) \
|
| V(CreateArrayTOS, 0, ___, ___, ___) \
|
| V(Allocate, D, lit, ___, ___) \
|
| V(AllocateT, 0, ___, ___, ___) \
|
| V(StoreIndexedTOS, 0, ___, ___, ___) \
|
| - V(StoreField, A_B_C, reg, reg, reg) \
|
| + V(StoreIndexed, A_B_C, reg, reg, reg) \
|
| + V(StoreField, A_B_C, reg, num, reg) \
|
| V(StoreFieldTOS, D, num, ___, ___) \
|
| - V(LoadField, A_B_C, reg, reg, reg) \
|
| + V(LoadField, A_B_C, reg, reg, num) \
|
| V(LoadFieldTOS, D, num, ___, ___) \
|
| V(BooleanNegateTOS, 0, ___, ___, ___) \
|
| + V(BooleanNegate, A_D, reg, reg, ___) \
|
| V(Throw, A, num, ___, ___) \
|
| V(Entry, A_B_C, num, num, num) \
|
| - V(EntryOpt, A_B_C, num, num, num) \
|
| + V(EntryOptional, A_B_C, num, num, num) \
|
| + V(EntryOptimized, A_D, num, num, ___) \
|
| V(Frame, D, num, ___, ___) \
|
| V(SetFrame, A, num, ___, num) \
|
| V(AllocateContext, D, num, ___, ___) \
|
| @@ -396,6 +456,7 @@ namespace dart {
|
| V(CheckStack, 0, ___, ___, ___) \
|
| V(DebugStep, 0, ___, ___, ___) \
|
| V(DebugBreak, A, num, ___, ___) \
|
| + V(Deopt, A_D, num, num, ___) \
|
|
|
| typedef uint32_t Instr;
|
|
|
| @@ -457,15 +518,23 @@ BYTECODES_LIST(DECLARE_BYTECODE)
|
| return static_cast<Opcode>(bc & 0xFF);
|
| }
|
|
|
| + DART_FORCE_INLINE static bool IsCallOpcode(Instr instr) {
|
| + switch (DecodeOpcode(instr)) {
|
| + case Bytecode::kStaticCall:
|
| + case Bytecode::kInstanceCall1:
|
| + case Bytecode::kInstanceCall2:
|
| + case Bytecode::kInstanceCall1Opt:
|
| + case Bytecode::kInstanceCall2Opt:
|
| + case Bytecode::kDebugBreak:
|
| + return true;
|
| +
|
| + default:
|
| + return false;
|
| + }
|
| + }
|
| +
|
| 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
|
| + ASSERT(IsCallOpcode(call));
|
| return (call >> 8) & 0xFF;
|
| }
|
|
|
| @@ -484,7 +553,7 @@ 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 kDartAvailableCpuRegs = -1;
|
| const intptr_t kNoRegister = -1;
|
| const intptr_t kReservedCpuRegisters = 0;
|
| const intptr_t ARGS_DESC_REG = 0;
|
|
|