| Index: runtime/vm/simulator_dbc.cc
|
| diff --git a/runtime/vm/simulator_dbc.cc b/runtime/vm/simulator_dbc.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..fd48ea500ccfead7feeacdcebefb29958d9c41e8
|
| --- /dev/null
|
| +++ b/runtime/vm/simulator_dbc.cc
|
| @@ -0,0 +1,1737 @@
|
| +// 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.
|
| +
|
| +#include <setjmp.h> // NOLINT
|
| +#include <stdlib.h>
|
| +
|
| +#include "vm/globals.h"
|
| +#if defined(TARGET_ARCH_DBC)
|
| +
|
| +#if !defined(USING_SIMULATOR)
|
| +#error "DBC is a simulated architecture"
|
| +#endif
|
| +
|
| +#include "vm/simulator.h"
|
| +
|
| +#include "vm/assembler.h"
|
| +#include "vm/compiler.h"
|
| +#include "vm/constants_dbc.h"
|
| +#include "vm/cpu.h"
|
| +#include "vm/dart_entry.h"
|
| +#include "vm/debugger.h"
|
| +#include "vm/disassembler.h"
|
| +#include "vm/lockers.h"
|
| +#include "vm/native_arguments.h"
|
| +#include "vm/native_entry.h"
|
| +#include "vm/object.h"
|
| +#include "vm/object_store.h"
|
| +#include "vm/os_thread.h"
|
| +#include "vm/stack_frame.h"
|
| +
|
| +namespace dart {
|
| +
|
| +DEFINE_FLAG(uint64_t, trace_sim_after, ULLONG_MAX,
|
| + "Trace simulator execution after instruction count reached.");
|
| +DEFINE_FLAG(uint64_t, stop_sim_at, ULLONG_MAX,
|
| + "Instruction address or instruction count to stop simulator at.");
|
| +
|
| +// SimulatorSetjmpBuffer are linked together, and the last created one
|
| +// is referenced by the Simulator. When an exception is thrown, the exception
|
| +// runtime looks at where to jump and finds the corresponding
|
| +// SimulatorSetjmpBuffer based on the stack pointer of the exception handler.
|
| +// The runtime then does a Longjmp on that buffer to return to the simulator.
|
| +class SimulatorSetjmpBuffer {
|
| + public:
|
| + void Longjmp() {
|
| + // "This" is now the last setjmp buffer.
|
| + simulator_->set_last_setjmp_buffer(this);
|
| + longjmp(buffer_, 1);
|
| + }
|
| +
|
| + explicit SimulatorSetjmpBuffer(Simulator* sim) {
|
| + simulator_ = sim;
|
| + link_ = sim->last_setjmp_buffer();
|
| + sim->set_last_setjmp_buffer(this);
|
| + top_ = sim->top_;
|
| + base_ = sim->base_;
|
| + }
|
| +
|
| + ~SimulatorSetjmpBuffer() {
|
| + ASSERT(simulator_->last_setjmp_buffer() == this);
|
| + simulator_->set_last_setjmp_buffer(link_);
|
| + }
|
| +
|
| + SimulatorSetjmpBuffer* link() { return link_; }
|
| +
|
| + uintptr_t* top() const { return top_; }
|
| + uword base() const { return reinterpret_cast<uword>(base_); }
|
| +
|
| + jmp_buf buffer_;
|
| +
|
| + private:
|
| + uintptr_t* top_;
|
| + uintptr_t* base_;
|
| + Simulator* simulator_;
|
| + SimulatorSetjmpBuffer* link_;
|
| +
|
| + friend class Simulator;
|
| +};
|
| +
|
| +
|
| +DART_FORCE_INLINE static RawObject** SavedCallerFP(RawObject** FP) {
|
| + return reinterpret_cast<RawObject**>(FP[kSavedCallerFpSlotFromFp]);
|
| +}
|
| +
|
| +
|
| +DART_FORCE_INLINE static RawCode* FrameCode(RawObject** FP) {
|
| + return static_cast<RawCode*>(FP[kPcMarkerSlotFromFp]);
|
| +}
|
| +
|
| +
|
| +DART_FORCE_INLINE static void SetFrameCode(RawObject** FP, RawCode* code) {
|
| + FP[kPcMarkerSlotFromFp] = code;
|
| +}
|
| +
|
| +
|
| +DART_FORCE_INLINE static RawObject** FrameArguments(RawObject** FP,
|
| + intptr_t argc) {
|
| + return FP - (kDartFrameFixedSize + argc);
|
| +}
|
| +
|
| +
|
| +class SimulatorHelpers {
|
| + public:
|
| + DART_FORCE_INLINE static RawSmi* GetClassIdAsSmi(RawObject* obj) {
|
| + return Smi::New(obj->IsHeapObject() ? obj->GetClassId() : kSmiCid);
|
| + }
|
| +
|
| + DART_FORCE_INLINE static intptr_t GetClassId(RawObject* obj) {
|
| + return obj->IsHeapObject() ? obj->GetClassId() : kSmiCid;
|
| + }
|
| +
|
| + DART_FORCE_INLINE static void IncrementUsageCounter(RawICData* icdata) {
|
| + reinterpret_cast<RawFunction*>(icdata->ptr()->owner_)
|
| + ->ptr()
|
| + ->usage_counter_++;
|
| + }
|
| +
|
| + DART_FORCE_INLINE static bool IsStrictEqualWithNumberCheck(RawObject* lhs,
|
| + RawObject* rhs) {
|
| + if (lhs == rhs) {
|
| + return true;
|
| + }
|
| +
|
| + if (lhs->IsHeapObject() && rhs->IsHeapObject()) {
|
| + const intptr_t lhs_cid = lhs->GetClassId();
|
| + const intptr_t rhs_cid = rhs->GetClassId();
|
| + if (lhs_cid == rhs_cid) {
|
| + switch (lhs_cid) {
|
| + case kDoubleCid:
|
| + return (bit_cast<uint64_t, double>(
|
| + static_cast<RawDouble*>(lhs)->ptr()->value_) ==
|
| + bit_cast<uint64_t, double>(
|
| + static_cast<RawDouble*>(rhs)->ptr()->value_));
|
| +
|
| + case kMintCid:
|
| + return (static_cast<RawMint*>(lhs)->ptr()->value_ ==
|
| + static_cast<RawMint*>(rhs)->ptr()->value_);
|
| +
|
| + case kBigintCid:
|
| + return (DLRT_BigintCompare(static_cast<RawBigint*>(lhs),
|
| + static_cast<RawBigint*>(rhs)) == 0);
|
| + }
|
| + }
|
| + }
|
| +
|
| + return false;
|
| + }
|
| +
|
| + template <typename T>
|
| + DART_FORCE_INLINE static T* Untag(T* tagged) {
|
| + return tagged->ptr();
|
| + }
|
| +
|
| + static bool ObjectArraySetIndexed(Thread* thread, RawObject** B,
|
| + RawObject** result) {
|
| + if (thread->isolate()->type_checks()) {
|
| + return false;
|
| + }
|
| +
|
| + RawObject** args = FrameArguments(B, 3);
|
| + RawSmi* index = static_cast<RawSmi*>(args[1]);
|
| + RawArray* array = static_cast<RawArray*>(args[0]);
|
| + if (!index->IsHeapObject() && reinterpret_cast<intptr_t>(index) >= 0 &&
|
| + reinterpret_cast<intptr_t>(index) <
|
| + reinterpret_cast<intptr_t>(array->ptr()->length_)) {
|
| + array->StorePointer(array->ptr()->data() + Smi::Value(index), args[2]);
|
| + return true;
|
| + }
|
| + return false;
|
| + }
|
| +
|
| + static bool ObjectArrayGetIndexed(Thread* thread, RawObject** B,
|
| + RawObject** result) {
|
| + RawObject** args = FrameArguments(B, 2);
|
| + RawSmi* index = static_cast<RawSmi*>(args[1]);
|
| + RawArray* array = static_cast<RawArray*>(args[0]);
|
| + if (!index->IsHeapObject() && reinterpret_cast<intptr_t>(index) >= 0 &&
|
| + reinterpret_cast<intptr_t>(index) <
|
| + reinterpret_cast<intptr_t>(array->ptr()->length_)) {
|
| + *result = array->ptr()->data()[Smi::Value(index)];
|
| + return true;
|
| + }
|
| + return false;
|
| + }
|
| +
|
| + static bool GrowableArraySetIndexed(Thread* thread, RawObject** B,
|
| + RawObject** result) {
|
| + if (thread->isolate()->type_checks()) {
|
| + return false;
|
| + }
|
| +
|
| + RawObject** args = FrameArguments(B, 3);
|
| + RawSmi* index = static_cast<RawSmi*>(args[1]);
|
| + RawGrowableObjectArray* array =
|
| + static_cast<RawGrowableObjectArray*>(args[0]);
|
| + if (!index->IsHeapObject() && reinterpret_cast<intptr_t>(index) >= 0 &&
|
| + reinterpret_cast<intptr_t>(index) <
|
| + reinterpret_cast<intptr_t>(array->ptr()->length_)) {
|
| + RawArray* data = array->ptr()->data_;
|
| + data->StorePointer(data->ptr()->data() + Smi::Value(index), args[2]);
|
| + return true;
|
| + }
|
| + return false;
|
| + }
|
| +
|
| + static bool GrowableArrayGetIndexed(Thread* thread, RawObject** B,
|
| + RawObject** result) {
|
| + RawObject** args = FrameArguments(B, 2);
|
| + RawSmi* index = static_cast<RawSmi*>(args[1]);
|
| + RawGrowableObjectArray* array =
|
| + static_cast<RawGrowableObjectArray*>(args[0]);
|
| + if (!index->IsHeapObject() && reinterpret_cast<intptr_t>(index) >= 0 &&
|
| + reinterpret_cast<intptr_t>(index) <
|
| + reinterpret_cast<intptr_t>(array->ptr()->length_)) {
|
| + *result = array->ptr()->data_->ptr()->data()[Smi::Value(index)];
|
| + return true;
|
| + }
|
| + return false;
|
| + }
|
| +};
|
| +
|
| +
|
| +DART_FORCE_INLINE static uint32_t* SavedCallerPC(RawObject** FP) {
|
| + return reinterpret_cast<uint32_t*>(FP[kSavedCallerPcSlotFromFp]);
|
| +}
|
| +
|
| +
|
| +DART_FORCE_INLINE static RawFunction* FrameFunction(RawObject** FP) {
|
| + RawFunction* function = static_cast<RawFunction*>(FP[kFunctionSlotFromFp]);
|
| + ASSERT(SimulatorHelpers::GetClassId(function) == kFunctionCid);
|
| + return function;
|
| +}
|
| +
|
| +
|
| +IntrinsicHandler Simulator::intrinsics_[Simulator::kIntrinsicCount];
|
| +
|
| +
|
| +// Synchronization primitives support.
|
| +void Simulator::InitOnce() {
|
| + for (intptr_t i = 0; i < kIntrinsicCount; i++) {
|
| + intrinsics_[i] = 0;
|
| + }
|
| +
|
| + intrinsics_[kObjectArraySetIndexedIntrinsic] =
|
| + SimulatorHelpers::ObjectArraySetIndexed;
|
| + intrinsics_[kObjectArrayGetIndexedIntrinsic] =
|
| + SimulatorHelpers::ObjectArrayGetIndexed;
|
| + intrinsics_[kGrowableArraySetIndexedIntrinsic] =
|
| + SimulatorHelpers::GrowableArraySetIndexed;
|
| + intrinsics_[kGrowableArrayGetIndexedIntrinsic] =
|
| + SimulatorHelpers::GrowableArrayGetIndexed;
|
| +}
|
| +
|
| +
|
| +Simulator::Simulator() {
|
| + // Setup simulator support first. Some of this information is needed to
|
| + // setup the architecture state.
|
| + // We allocate the stack here, the size is computed as the sum of
|
| + // the size specified by the user and the buffer space needed for
|
| + // handling stack overflow exceptions. To be safe in potential
|
| + // stack underflows we also add some underflow buffer space.
|
| + stack_ = new uintptr_t[(OSThread::GetSpecifiedStackSize() +
|
| + OSThread::kStackSizeBuffer +
|
| + kSimulatorStackUnderflowSize) /
|
| + sizeof(uintptr_t)];
|
| + base_ = top_ = stack_;
|
| + last_setjmp_buffer_ = NULL;
|
| + top_exit_frame_info_ = 0;
|
| +}
|
| +
|
| +
|
| +Simulator::~Simulator() {
|
| + delete[] stack_;
|
| + Isolate* isolate = Isolate::Current();
|
| + if (isolate != NULL) {
|
| + isolate->set_simulator(NULL);
|
| + }
|
| +}
|
| +
|
| +
|
| +// Get the active Simulator for the current isolate.
|
| +Simulator* Simulator::Current() {
|
| + Simulator* simulator = Isolate::Current()->simulator();
|
| + if (simulator == NULL) {
|
| + simulator = new Simulator();
|
| + Isolate::Current()->set_simulator(simulator);
|
| + }
|
| + return simulator;
|
| +}
|
| +
|
| +
|
| +// Returns the top of the stack area to enable checking for stack pointer
|
| +// validity.
|
| +uword Simulator::StackTop() const {
|
| + // To be safe in potential stack underflows we leave some buffer above and
|
| + // set the stack top.
|
| + return StackBase() +
|
| + (OSThread::GetSpecifiedStackSize() + OSThread::kStackSizeBuffer);
|
| +}
|
| +
|
| +
|
| +// Calls into the Dart runtime are based on this interface.
|
| +typedef void (*SimulatorRuntimeCall)(NativeArguments arguments);
|
| +
|
| +// Calls to leaf Dart runtime functions are based on this interface.
|
| +typedef int32_t (*SimulatorLeafRuntimeCall)(int32_t r0, int32_t r1, int32_t r2,
|
| + int32_t r3);
|
| +
|
| +// Calls to leaf float Dart runtime functions are based on this interface.
|
| +typedef double (*SimulatorLeafFloatRuntimeCall)(double d0, double d1);
|
| +
|
| +// Calls to native Dart functions are based on this interface.
|
| +typedef void (*SimulatorBootstrapNativeCall)(NativeArguments* arguments);
|
| +typedef void (*SimulatorNativeCall)(NativeArguments* arguments, uword target);
|
| +
|
| +
|
| +void Simulator::Exit(Thread* thread, RawObject** base, RawObject** frame,
|
| + uint32_t* pc) {
|
| + frame[0] = Function::null();
|
| + frame[1] = Code::null();
|
| + frame[2] = reinterpret_cast<RawObject*>(pc);
|
| + frame[3] = reinterpret_cast<RawObject*>(base);
|
| + base_ = top_ = reinterpret_cast<uintptr_t*>(frame + kDartFrameFixedSize);
|
| + thread->set_top_exit_frame_info(reinterpret_cast<uword>(top_));
|
| +}
|
| +
|
| +
|
| +#if defined(__has_builtin)
|
| +#if __has_builtin(__builtin_smul_overflow)
|
| +#define HAS_MUL_OVERFLOW
|
| +#endif
|
| +#if __has_builtin(__builtin_sadd_overflow)
|
| +#define HAS_ADD_OVERFLOW
|
| +#endif
|
| +#if __has_builtin(__builtin_ssub_overflow)
|
| +#define HAS_SUB_OVERFLOW
|
| +#endif
|
| +#endif
|
| +
|
| +
|
| +DART_FORCE_INLINE static int32_t SignedAddWithOverflow(int32_t lhs, int32_t rhs,
|
| + intptr_t* out) {
|
| + int32_t res = 1;
|
| +#if defined(HAS_ADD_OVERFLOW)
|
| + res = __builtin_sadd_overflow(lhs, rhs, out);
|
| +#elif defined(__i386__)
|
| + asm volatile(
|
| + "add %2, %1\n"
|
| + "jo 1f;\n"
|
| + "xor %0, %0\n"
|
| + "mov %1, 0(%3)\n"
|
| + "1: "
|
| + : "+r"(res), "+r"(lhs)
|
| + : "r"(rhs), "r"(out)
|
| + : "cc");
|
| +#elif defined(__arm__)
|
| + asm volatile(
|
| + "adds %1, %1, %2;\n"
|
| + "bvs 1f;\n"
|
| + "mov %0, $0;\n"
|
| + "str %1, [%3, #0]\n"
|
| + "1:"
|
| + : "+r"(res), "+r"(lhs)
|
| + : "r"(rhs), "r"(out)
|
| + : "cc", "r12");
|
| +#else
|
| +#error "Unsupported platform"
|
| +#endif
|
| + return res;
|
| +}
|
| +
|
| +
|
| +DART_FORCE_INLINE static int32_t SignedSubWithOverflow(int32_t lhs, int32_t rhs,
|
| + intptr_t* out) {
|
| + int32_t res = 1;
|
| +#if defined(HAS_SUB_OVERFLOW)
|
| + res = __builtin_ssub_overflow(lhs, rhs, out);
|
| +#elif defined(__i386__)
|
| + asm volatile(
|
| + "sub %2, %1\n"
|
| + "jo 1f;\n"
|
| + "xor %0, %0\n"
|
| + "mov %1, 0(%3)\n"
|
| + "1: "
|
| + : "+r"(res), "+r"(lhs)
|
| + : "r"(rhs), "r"(out)
|
| + : "cc");
|
| +#elif defined(__arm__)
|
| + asm volatile(
|
| + "subs %1, %1, %2;\n"
|
| + "bvs 1f;\n"
|
| + "mov %0, $0;\n"
|
| + "str %1, [%3, #0]\n"
|
| + "1:"
|
| + : "+r"(res), "+r"(lhs)
|
| + : "r"(rhs), "r"(out)
|
| + : "cc", "r12");
|
| +#else
|
| +#error "Unsupported platform"
|
| +#endif
|
| + return res;
|
| +}
|
| +
|
| +
|
| +DART_FORCE_INLINE static int32_t SignedMulWithOverflow(int32_t lhs, int32_t rhs,
|
| + intptr_t* out) {
|
| + int32_t res = 1;
|
| +#if defined(HAS_MUL_OVERFLOW)
|
| + res = __builtin_smul_overflow(lhs, rhs, out);
|
| +#elif defined(__i386__)
|
| + asm volatile(
|
| + "imul %2, %1\n"
|
| + "jo 1f;\n"
|
| + "xor %0, %0\n"
|
| + "mov %1, 0(%3)\n"
|
| + "1: "
|
| + : "+r"(res), "+r"(lhs)
|
| + : "r"(rhs), "r"(out)
|
| + : "cc");
|
| +#elif defined(__arm__)
|
| + asm volatile(
|
| + "smull %1, ip, %1, %2;\n"
|
| + "cmp ip, %1, ASR #31;\n"
|
| + "bne 1f;\n"
|
| + "mov %0, $0;\n"
|
| + "str %1, [%3, #0]\n"
|
| + "1:"
|
| + : "+r"(res), "+r"(lhs)
|
| + : "r"(rhs), "r"(out)
|
| + : "cc", "r12");
|
| +#else
|
| +#error "Unsupported platform"
|
| +#endif
|
| + return res;
|
| +}
|
| +
|
| +DART_FORCE_INLINE static int32_t SMI_DIV(int32_t lhs, int32_t rhs,
|
| + intptr_t* out) {
|
| + if (rhs == 0) {
|
| + return 1;
|
| + }
|
| +
|
| + const int32_t res = (lhs >> 1) / (rhs >> 1);
|
| + if (res == 0x40000000) {
|
| + return 1; // Overflow
|
| + }
|
| +
|
| + *out = res << 1;
|
| + return 0;
|
| +}
|
| +
|
| +
|
| +#define LIKELY(cond) __builtin_expect((cond), 1)
|
| +
|
| +
|
| +DART_FORCE_INLINE static bool AreBothSmis(intptr_t a, intptr_t b) {
|
| + return ((a | b) & kHeapObjectTag) == 0;
|
| +}
|
| +
|
| +
|
| +#define SMI_MUL(lhs, rhs, pres) SignedMulWithOverflow((lhs), (rhs) >> 1, pres)
|
| +#define SMI_COND(cond, lhs, rhs, pres) \
|
| + ((*(pres) = ((lhs cond rhs) ? true_value : false_value)), false)
|
| +#define SMI_EQ(lhs, rhs, pres) SMI_COND(==, lhs, rhs, pres)
|
| +#define SMI_LT(lhs, rhs, pres) SMI_COND(<, lhs, rhs, pres)
|
| +#define SMI_GT(lhs, rhs, pres) SMI_COND(>, lhs, rhs, pres)
|
| +#define SMI_BITOR(lhs, rhs, pres) ((*(pres) = (lhs | rhs)), false)
|
| +#define SMI_BITAND(lhs, rhs, pres) ((*(pres) = (lhs & rhs)), false)
|
| +
|
| +
|
| +void Simulator::CallRuntime(Thread* thread, RawObject** base,
|
| + RawObject** exit_frame, uint32_t* pc,
|
| + intptr_t argc_tag, RawObject** args,
|
| + RawObject** result, uword target) {
|
| + Exit(thread, base, exit_frame, pc);
|
| + NativeArguments native_args(thread, argc_tag, args, result);
|
| + reinterpret_cast<RuntimeFunction>(target)(native_args);
|
| +}
|
| +
|
| +
|
| +DART_FORCE_INLINE void Simulator::Invoke(Thread* thread, RawObject** call_base,
|
| + RawObject** call_top,
|
| + RawObjectPool** pp, uint32_t** pc,
|
| + RawObject*** B, RawObject*** SP) {
|
| + RawObject** callee_fp = call_top + kDartFrameFixedSize;
|
| +
|
| + RawFunction* function = FrameFunction(callee_fp);
|
| + RawCode* code = function->ptr()->code_;
|
| + callee_fp[kPcMarkerSlotFromFp] = code;
|
| + callee_fp[kSavedCallerPcSlotFromFp] = reinterpret_cast<RawObject*>(*pc);
|
| + callee_fp[kSavedCallerFpSlotFromFp] = reinterpret_cast<RawObject*>(*B);
|
| + *pp = code->ptr()->object_pool_->ptr();
|
| + *pc = reinterpret_cast<uint32_t*>(code->ptr()->entry_point_);
|
| + *B = callee_fp;
|
| + *SP = *B - 1;
|
| +}
|
| +
|
| +
|
| +void Simulator::InlineCacheMiss(int checked_args, Thread* thread,
|
| + RawICData* icdata, RawObject** call_base,
|
| + RawObject** top, uint32_t* pc, RawObject** B,
|
| + RawObject** SP) {
|
| + RawObject** args = call_base;
|
| + for (intptr_t i = 0; i < checked_args; i++) {
|
| + top[1 + i] = args[i];
|
| + }
|
| + top[1 + checked_args] = icdata;
|
| + RuntimeFunction handler = NULL;
|
| + switch (checked_args) {
|
| + case 1:
|
| + handler = DRT_InlineCacheMissHandlerOneArg;
|
| + break;
|
| + case 2:
|
| + handler = DRT_InlineCacheMissHandlerTwoArgs;
|
| + break;
|
| + case 3:
|
| + handler = DRT_InlineCacheMissHandlerThreeArgs;
|
| + break;
|
| + default:
|
| + UNREACHABLE();
|
| + break;
|
| + }
|
| + CallRuntime(thread, B, top + checked_args + 1 + 1, pc, checked_args + 1,
|
| + top + 1, top, reinterpret_cast<uword>(handler));
|
| +}
|
| +
|
| +
|
| +DART_FORCE_INLINE void Simulator::InstanceCall1(
|
| + Thread* thread, RawICData* icdata, RawObject** call_base, RawObject** top,
|
| + Array* argdesc, RawObjectPool** pp, uint32_t** pc, RawObject*** B,
|
| + RawObject*** SP) {
|
| + ASSERT(icdata->GetClassId() == kICDataCid);
|
| + SimulatorHelpers::IncrementUsageCounter(icdata);
|
| +
|
| + const intptr_t kCheckedArgs = 1;
|
| + RawObject** args = call_base;
|
| + RawArray* cache = icdata->ptr()->ic_data_->ptr();
|
| +
|
| + RawSmi* receiver_cid = SimulatorHelpers::GetClassIdAsSmi(args[0]);
|
| +
|
| + bool found = false;
|
| + for (intptr_t i = 0, length = Smi::Value(cache->length_);
|
| + i < (length - (kCheckedArgs + 2)); i += (kCheckedArgs + 2)) {
|
| + if (cache->data()[i + 0] == receiver_cid) {
|
| + top[0] = cache->data()[i + kCheckedArgs];
|
| + found = true;
|
| + break;
|
| + }
|
| + }
|
| +
|
| + if (!found) {
|
| + InlineCacheMiss(kCheckedArgs, thread, icdata, call_base, top, *pc, *B, *SP);
|
| + }
|
| +
|
| + *argdesc = icdata->ptr()->args_descriptor_;
|
| + Invoke(thread, call_base, top, pp, pc, B, SP);
|
| +}
|
| +
|
| +
|
| +DART_FORCE_INLINE void Simulator::InstanceCall2(
|
| + Thread* thread, RawICData* icdata, RawObject** call_base, RawObject** top,
|
| + Array* argdesc, RawObjectPool** pp, uint32_t** pc, RawObject*** B,
|
| + RawObject*** SP) {
|
| + ASSERT(icdata->GetClassId() == kICDataCid);
|
| + SimulatorHelpers::IncrementUsageCounter(icdata);
|
| +
|
| + const intptr_t kCheckedArgs = 2;
|
| + RawObject** args = call_base;
|
| + RawArray* cache = icdata->ptr()->ic_data_->ptr();
|
| +
|
| + RawSmi* receiver_cid = SimulatorHelpers::GetClassIdAsSmi(args[0]);
|
| + RawSmi* arg0_cid = SimulatorHelpers::GetClassIdAsSmi(args[1]);
|
| +
|
| + bool found = false;
|
| + for (intptr_t i = 0, length = Smi::Value(cache->length_);
|
| + i < (length - (kCheckedArgs + 2)); i += (kCheckedArgs + 2)) {
|
| + if (cache->data()[i + 0] == receiver_cid &&
|
| + cache->data()[i + 1] == arg0_cid) {
|
| + top[0] = cache->data()[i + kCheckedArgs];
|
| + found = true;
|
| + break;
|
| + }
|
| + }
|
| +
|
| + if (!found) {
|
| + InlineCacheMiss(kCheckedArgs, thread, icdata, call_base, top, *pc, *B, *SP);
|
| + }
|
| +
|
| + *argdesc = icdata->ptr()->args_descriptor_;
|
| + Invoke(thread, call_base, top, pp, pc, B, SP);
|
| +}
|
| +
|
| +
|
| +DART_FORCE_INLINE void Simulator::InstanceCall3(
|
| + Thread* thread, RawICData* icdata, RawObject** call_base, RawObject** top,
|
| + Array* argdesc, RawObjectPool** pp, uint32_t** pc, RawObject*** B,
|
| + RawObject*** SP) {
|
| + ASSERT(icdata->GetClassId() == kICDataCid);
|
| + SimulatorHelpers::IncrementUsageCounter(icdata);
|
| +
|
| + const intptr_t kCheckedArgs = 3;
|
| + RawObject** args = call_base;
|
| + RawArray* cache = icdata->ptr()->ic_data_->ptr();
|
| +
|
| + RawSmi* receiver_cid = SimulatorHelpers::GetClassIdAsSmi(args[0]);
|
| + RawSmi* arg0_cid = SimulatorHelpers::GetClassIdAsSmi(args[1]);
|
| + RawSmi* arg1_cid = SimulatorHelpers::GetClassIdAsSmi(args[2]);
|
| +
|
| + bool found = false;
|
| + for (intptr_t i = 0, length = Smi::Value(cache->length_);
|
| + i < (length - (kCheckedArgs + 2)); i += (kCheckedArgs + 2)) {
|
| + if (cache->data()[i + 0] == receiver_cid &&
|
| + cache->data()[i + 1] == arg0_cid && cache->data()[i + 2] == arg1_cid) {
|
| + top[0] = cache->data()[i + kCheckedArgs];
|
| + found = true;
|
| + break;
|
| + }
|
| + }
|
| +
|
| + if (!found) {
|
| + InlineCacheMiss(kCheckedArgs, thread, icdata, call_base, top, *pc, *B, *SP);
|
| + }
|
| +
|
| + *argdesc = icdata->ptr()->args_descriptor_;
|
| + Invoke(thread, call_base, top, pp, pc, B, SP);
|
| +}
|
| +
|
| +
|
| +static __attribute__((noinline)) bool InvokeRuntime(
|
| + Thread* thread, Simulator* sim, RuntimeFunction drt,
|
| + const NativeArguments& args) {
|
| + SimulatorSetjmpBuffer buffer(sim);
|
| + if (!setjmp(buffer.buffer_)) {
|
| + thread->set_vm_tag(reinterpret_cast<uword>(drt));
|
| + drt(args);
|
| + thread->set_vm_tag(VMTag::kDartTagId);
|
| + return true;
|
| + } else {
|
| + return false;
|
| + }
|
| +}
|
| +
|
| +
|
| +static __attribute__((noinline)) bool InvokeNative(
|
| + Thread* thread, Simulator* sim, SimulatorBootstrapNativeCall f,
|
| + NativeArguments* args) {
|
| + SimulatorSetjmpBuffer buffer(sim);
|
| + if (!setjmp(buffer.buffer_)) {
|
| + thread->set_vm_tag(reinterpret_cast<uword>(f));
|
| + f(args);
|
| + thread->set_vm_tag(VMTag::kDartTagId);
|
| + return true;
|
| + } else {
|
| + return false;
|
| + }
|
| +}
|
| +
|
| +
|
| +static __attribute__((noinline)) bool InvokeNativeWrapper(
|
| + Thread* thread, Simulator* sim, Dart_NativeFunction f,
|
| + NativeArguments* args) {
|
| + SimulatorSetjmpBuffer buffer(sim);
|
| + if (!setjmp(buffer.buffer_)) {
|
| + thread->set_vm_tag(reinterpret_cast<uword>(f));
|
| + NativeEntry::NativeCallWrapper(
|
| + reinterpret_cast<Dart_NativeArguments>(args), f);
|
| + thread->set_vm_tag(VMTag::kDartTagId);
|
| + return true;
|
| + } else {
|
| + return false;
|
| + }
|
| +}
|
| +
|
| +
|
| +RawObject* Simulator::Call(const Code& code, const Array& arguments_descriptor,
|
| + const Array& arguments, Thread* thread) {
|
| + static const void* dispatch[] = {
|
| +#define TARGET(name, fmt, fmta, fmtb, fmtc) &&bc##name,
|
| + BYTECODES_LIST(TARGET)
|
| +#undef TARGET
|
| + };
|
| +
|
| + const uword vm_tag = thread->vm_tag();
|
| + thread->set_vm_tag(VMTag::kDartTagId);
|
| +
|
| + StackResource* top_resource = thread->top_resource();
|
| + thread->set_top_resource(NULL);
|
| +
|
| + if (top_ == NULL) {
|
| + top_ = base_ = stack_;
|
| + }
|
| +
|
| + top_[0] = thread->top_exit_frame_info();
|
| +
|
| + // Unpack arguments.
|
| + {
|
| + const intptr_t argc = arguments.Length();
|
| + RawObject** call_base = reinterpret_cast<RawObject**>(top_ + 1);
|
| + RawObject** call_top = call_base + argc;
|
| + for (intptr_t i = 0; i < argc; i++) {
|
| + call_base[i] = arguments.At(i);
|
| + }
|
| +
|
| + call_top[0] = code.function();
|
| + call_top[1] = code.raw();
|
| + call_top[2] =
|
| + reinterpret_cast<RawObject*>((argc << 2) | 2); // Return address.
|
| + call_top[3] = reinterpret_cast<RawObject*>(top_); // Caller FP
|
| + }
|
| +
|
| + RawObject** B =
|
| + reinterpret_cast<RawObject**>(top_ +
|
| + arguments.Length() +
|
| + kDartFrameFixedSize +
|
| + 1);
|
| + RawObject** SP = B - 1;
|
| + uint32_t* pc = reinterpret_cast<uint32_t*>(code.raw()->ptr()->entry_point_);
|
| + RawObjectPool* pp = code.object_pool();
|
| +
|
| + pp = pp->ptr();
|
| + RawBool* true_value = Bool::True().raw();
|
| + RawBool* false_value = Bool::False().raw();
|
| + RawObject* null_value = Object::null();
|
| + RawObject* empty_context = thread->isolate()->object_store()->empty_context();
|
| +
|
| + Array& argdesc = Array::Handle();
|
| +#if defined(DEBUG)
|
| + Function& function_h = Function::Handle();
|
| +#endif
|
| + argdesc = arguments_descriptor.raw();
|
| +
|
| +#define DECLARE_A_B_C \
|
| + uint16_t rB, rC; \
|
| + USE(rB); \
|
| + USE(rC)
|
| +#define DECODE_A_B_C(type, shiftB, shiftC, mask) \
|
| + rB = ((__op >> shiftB) & mask) /* | rBx */; \
|
| + rC = ((__op >> shiftC) & mask) /* | rCx */;
|
| +
|
| +#define DECLARE_0
|
| +#define DECODE_0(type, shiftB, shiftC, mask)
|
| +
|
| +#define DECLARE_A
|
| +#define DECODE_A(type, shiftB, shiftC, mask)
|
| +
|
| +#define DECLARE_A_D \
|
| + uint32_t rD; \
|
| + USE(rD)
|
| +#define DECODE_A_D(type, shiftB, shiftC, mask) rD = (__op >> shiftB);
|
| +
|
| +#define DECLARE___D \
|
| + uint32_t rD; \
|
| + USE(rD)
|
| +#define DECODE___D(type, shiftB, shiftC, mask) rD = (__op >> shiftB);
|
| +
|
| +#define DECLARE_A_X \
|
| + int32_t rD; \
|
| + USE(rD)
|
| +#define DECODE_A_X(type, shiftB, shiftC, mask) \
|
| + rD = (static_cast<int32_t>(__op) >> shiftB);
|
| +
|
| +#define BYTECODE_HEADER(Name, Declare, Decode) \
|
| + Declare; \
|
| + bc##Name : Decode(uint8_t, 16, 24, 0xFF); \
|
| + goto bc##Name##Entry; \
|
| + bc##Name##Entry:
|
| +
|
| +#define BYTECODE(Name, type) \
|
| + BYTECODE_HEADER(Name, DECLARE_##type, DECODE_##type)
|
| +
|
| +#define DISPATCH_OP(val) \
|
| + do { \
|
| + __op = (val); \
|
| + rA = ((__op >> 8) & 0xFF); \
|
| + goto* dispatch[__op & 0xFF]; \
|
| + } while (0)
|
| +
|
| +#define DISPATCH() DISPATCH_OP(*pc++)
|
| +
|
| +#define SMI_FASTPATH_TOS(ResultT, F) \
|
| + { \
|
| + const intptr_t lhs = reinterpret_cast<intptr_t>(SP[-1]); \
|
| + const intptr_t rhs = reinterpret_cast<intptr_t>(SP[-0]); \
|
| + ResultT* slot = reinterpret_cast<ResultT*>(SP - 1); \
|
| + if (LIKELY(AreBothSmis(lhs, rhs) && !F(lhs, rhs, slot))) { \
|
| + pc += 1; \
|
| + --SP; \
|
| + } \
|
| + DISPATCH(); \
|
| + }
|
| +
|
| +#define FALLTHROUGH
|
| +
|
| +#define HANDLE_EXCEPTION(name, ON_EXCEPTION) \
|
| + do { \
|
| + B = reinterpret_cast<RawObject**>(base_); \
|
| + pc = reinterpret_cast<uint32_t*>(pc_); \
|
| + if ((reinterpret_cast<uword>(pc) & 2) != 0) { \
|
| + base_ = top_ = reinterpret_cast<uintptr_t*>(base_[0]); \
|
| + thread->set_top_exit_frame_info(reinterpret_cast<uword>(top_)); \
|
| + thread->set_top_resource(top_resource); \
|
| + thread->set_vm_tag(vm_tag); \
|
| + return special_[0]; \
|
| + } \
|
| + pp = FrameCode(B)->ptr()->object_pool_->ptr(); \
|
| + ON_EXCEPTION; \
|
| + } while (0)
|
| +
|
| +#define INVOKE_RUNTIME(func, args, onexception) \
|
| + if (!InvokeRuntime(thread, this, func, args)) { \
|
| + HANDLE_EXCEPTION(InvokeRuntime, onexception); \
|
| + }
|
| +
|
| +#define INVOKE_NATIVE(func, args, onexception) \
|
| + if (!InvokeNative(thread, this, func, &args)) { \
|
| + HANDLE_EXCEPTION(InvokeRuntime, onexception); \
|
| + }
|
| +
|
| +#define INVOKE_NATIVE_WRAPPER(func, args, onexception) \
|
| + if (!InvokeNativeWrapper(thread, this, func, &args)) { \
|
| + HANDLE_EXCEPTION(InvokeRuntime, onexception); \
|
| + }
|
| +
|
| + uint16_t rA;
|
| + uint32_t __op;
|
| + DISPATCH();
|
| + while (true) {
|
| + {
|
| + {
|
| + ClosureNoSuchMethod:
|
| +#if defined(DEBUG)
|
| + function_h ^= FrameFunction(B);
|
| + ASSERT(function_h.IsClosureFunction());
|
| +#endif
|
| + pc = SavedCallerPC(B);
|
| +
|
| + const bool has_dart_callee = (reinterpret_cast<uword>(pc) & 2) == 0;
|
| + const intptr_t argc = has_dart_callee
|
| + ? Bytecode::DecodeArgc(pc[-1])
|
| + : (reinterpret_cast<uword>(pc) >> 2);
|
| +
|
| + SP = FrameArguments(B, 0);
|
| + RawObject** args = SP - argc;
|
| + B = SavedCallerFP(B);
|
| + if (has_dart_callee) {
|
| + pp = FrameCode(B)->ptr()->object_pool_->ptr();
|
| + }
|
| +
|
| + *++SP = null_value;
|
| + *++SP = args[0];
|
| + *++SP = argdesc.raw();
|
| + *++SP = null_value; // will contain array
|
| + {
|
| + SP[1] = Smi::New(argc); // length
|
| + SP[2] = null_value; // type
|
| + Exit(thread, B, SP + 3, pc);
|
| + NativeArguments native_args(thread, 2, SP + 1, SP);
|
| + INVOKE_RUNTIME(DRT_AllocateArray, native_args,
|
| + goto ClosureNoSuchMethodDispatch);
|
| +
|
| + RawArray* array = static_cast<RawArray*>(SP[0]);
|
| + ASSERT(array->GetClassId() == kArrayCid);
|
| + for (intptr_t i = 0; i < argc; i++) {
|
| + array->ptr()->data()[i] = args[i];
|
| + }
|
| + }
|
| + {
|
| + Exit(thread, B, SP + 1, pc);
|
| + NativeArguments native_args(thread, 3, SP - 2, SP - 3);
|
| + INVOKE_RUNTIME(DRT_InvokeClosureNoSuchMethod, native_args,
|
| + goto ClosureNoSuchMethodDispatch);
|
| + UNREACHABLE();
|
| + }
|
| + ClosureNoSuchMethodDispatch:
|
| + DISPATCH();
|
| + }
|
| +
|
| + {
|
| + BYTECODE(Entry, A_B_C);
|
| + const uint16_t num_locals = rB;
|
| + const uint16_t context_reg = rC;
|
| + const intptr_t pos_count = Smi::Value(
|
| + *reinterpret_cast<RawSmi**>(
|
| + reinterpret_cast<uword>(argdesc.raw()->ptr()) +
|
| + Array::element_offset(
|
| + ArgumentsDescriptor::kPositionalCountIndex)));
|
| +
|
| + if (pos_count != rA) {
|
| + goto ClosureNoSuchMethod;
|
| + }
|
| +
|
| + {
|
| + RawObject** L = B;
|
| + for (intptr_t i = 0; i < num_locals; i++) {
|
| + L[i] = null_value;
|
| + }
|
| + L[context_reg] = empty_context;
|
| + SP = B + num_locals - 1;
|
| + }
|
| +
|
| + DISPATCH();
|
| + }
|
| +
|
| + {
|
| + BYTECODE(DebugStep, A);
|
| + if (thread->isolate()->single_step()) {
|
| + Exit(thread, B, SP + 1, pc);
|
| + NativeArguments args(thread, 0, NULL, NULL);
|
| + INVOKE_RUNTIME(DRT_SingleStepHandler, args, FALLTHROUGH);
|
| + }
|
| + DISPATCH();
|
| + }
|
| +
|
| + {
|
| + BYTECODE(DebugBreak, A);
|
| + {
|
| + const uint32_t original_bc =
|
| + static_cast<uint32_t>(reinterpret_cast<uintptr_t>(
|
| + thread->isolate()->debugger()->GetPatchedStubAddress(
|
| + reinterpret_cast<uword>(pc))));
|
| +
|
| + SP[1] = null_value;
|
| + Exit(thread, B, SP + 2, pc);
|
| + NativeArguments args(thread, 0, NULL, SP + 1);
|
| + INVOKE_RUNTIME(DRT_BreakpointRuntimeHandler, args, FALLTHROUGH) else {
|
| + DISPATCH_OP(original_bc);
|
| + }
|
| + }
|
| + DISPATCH();
|
| + }
|
| +
|
| + {
|
| + BYTECODE(CheckStack, A);
|
| + {
|
| + if (reinterpret_cast<uword>(SP) >= thread->isolate()->stack_limit()) {
|
| + Exit(thread, B, SP + 1, pc);
|
| + NativeArguments args(thread, 0, NULL, NULL);
|
| + INVOKE_RUNTIME(DRT_StackOverflow, args, FALLTHROUGH);
|
| + }
|
| + }
|
| + DISPATCH();
|
| + }
|
| +
|
| + {
|
| + BYTECODE(EntryOpt, A_B_C);
|
| + const uint16_t num_fixed_params = rA;
|
| + const uint16_t num_opt_pos_params = rB;
|
| + const uint16_t num_opt_named_params = rC;
|
| +
|
| + const intptr_t min_num_pos_args = num_fixed_params;
|
| + const intptr_t max_num_pos_args = num_fixed_params + num_opt_pos_params;
|
| + const intptr_t arg_count = Smi::Value(*reinterpret_cast<RawSmi**>(
|
| + reinterpret_cast<uword>(argdesc.raw()->ptr()) +
|
| + Array::element_offset(ArgumentsDescriptor::kCountIndex)));
|
| + const intptr_t pos_count = Smi::Value(*reinterpret_cast<RawSmi**>(
|
| + reinterpret_cast<uword>(argdesc.raw()->ptr()) +
|
| + Array::element_offset(ArgumentsDescriptor::kPositionalCountIndex)));
|
| + const intptr_t named_count = (arg_count - pos_count);
|
| + if (!(min_num_pos_args <= pos_count && pos_count <= max_num_pos_args)) {
|
| + goto ClosureNoSuchMethod;
|
| + }
|
| +
|
| + // Copy all passed position arguments.Entry
|
| + RawObject** first_arg = FrameArguments(B, arg_count);
|
| + memmove(B, first_arg, pos_count * kWordSize);
|
| + if (num_opt_named_params != 0) {
|
| + // RawObject** opt_copy = first_arg + pos_count;
|
| +
|
| + intptr_t i = named_count - 1;
|
| + intptr_t j = num_opt_named_params - 1;
|
| + while (j >= 0 && i >= 0) {
|
| + const uint32_t load_name = pc[2 * j];
|
| + const uint32_t load_value = pc[2 * j + 1];
|
| + ASSERT((load_name & 0xFF) == Bytecode::kLoadConstant);
|
| + ASSERT((load_value & 0xFF) == Bytecode::kLoadConstant);
|
| + ASSERT((load_value & 0xFF00) == (load_name & 0xFF00));
|
| + const uint8_t reg = (load_name >> 8) & 0xFF;
|
| + RawString* name = reinterpret_cast<RawString*>(
|
| + pp->data()[load_name >> 16].raw_obj_);
|
| + if (name == argdesc.At(ArgumentsDescriptor::name_index(i))) {
|
| + const intptr_t copy_idx = Smi::Value(static_cast<RawSmi*>(
|
| + argdesc.At(ArgumentsDescriptor::position_index(i))));
|
| + B[reg] = first_arg[copy_idx];
|
| + i--;
|
| + } else {
|
| + RawObject* value = pp->data()[load_value >> 16].raw_obj_;
|
| + B[reg] = value;
|
| + }
|
| + j--;
|
| + }
|
| +
|
| + while (j >= 0) {
|
| + const uint32_t load_name = pc[2 * j];
|
| + const uint32_t load_value = pc[2 * j + 1];
|
| + ASSERT((load_name & 0xFF) == Bytecode::kLoadConstant);
|
| + ASSERT((load_value & 0xFF) == Bytecode::kLoadConstant);
|
| + ASSERT((load_value & 0xFF00) == (load_name & 0xFF00));
|
| + const uint8_t reg = (load_name >> 8) & 0xFF;
|
| + RawObject* value = pp->data()[load_value >> 16].raw_obj_;
|
| + B[reg] = value;
|
| + j--;
|
| + }
|
| +
|
| + if (i != -1) {
|
| + goto ClosureNoSuchMethod;
|
| + }
|
| +
|
| + pc += num_opt_named_params * 2;
|
| + SP = B + num_fixed_params + num_opt_named_params - 1;
|
| + } else {
|
| + ASSERT(num_opt_pos_params != 0);
|
| + if (named_count != 0) {
|
| + goto ClosureNoSuchMethod;
|
| + }
|
| +
|
| + RawObject** opt_base = B + rA;
|
| + for (intptr_t i = pos_count - rA; i < num_opt_pos_params; i++) {
|
| + const uint32_t load_value = pc[i];
|
| + ASSERT((load_value & 0xFF) == Bytecode::kLoadConstant);
|
| + const uint8_t reg = (load_value >> 8) & 0xFF;
|
| + RawObject* value = pp->data()[load_value >> 16].raw_obj_;
|
| + ASSERT((i + rA) == reg);
|
| + opt_base[i] = value;
|
| + }
|
| +
|
| + pc += num_opt_pos_params;
|
| + SP = B + max_num_pos_args - 1;
|
| + }
|
| +
|
| + DISPATCH();
|
| + }
|
| +
|
| + {
|
| + BYTECODE(InstantiateType, A_D);
|
| + RawObject* type = pp->data()[rD].raw_obj_;
|
| + SP[1] = type;
|
| + SP[2] = SP[0];
|
| + SP[0] = null_value;
|
| + Exit(thread, B, SP + 3, pc);
|
| + {
|
| + NativeArguments args(thread, 2, SP + 1, SP);
|
| + INVOKE_RUNTIME(DRT_InstantiateType, args, FALLTHROUGH);
|
| + }
|
| + DISPATCH();
|
| + }
|
| +
|
| + {
|
| + BYTECODE(InstantiateTypeArgumentsTOS, A_D);
|
| + RawTypeArguments* type_arguments =
|
| + static_cast<RawTypeArguments*>(pp->data()[rD].raw_obj_);
|
| +
|
| + RawObject* instantiator = SP[0];
|
| + // If the instantiator is null and if the type argument vector
|
| + // instantiated from null becomes a vector of dynamic, then use null as
|
| + // the type arguments.
|
| + if (rA == 0 || null_value != instantiator) {
|
| + RawArray* instantiations = type_arguments->ptr()->instantiations_;
|
| + for (intptr_t i = 0;
|
| + instantiations->ptr()->data()[i] != NULL; // kNoInstantiator
|
| + i += 2) {
|
| + if (instantiations->ptr()->data()[i] == instantiator) {
|
| + SP[0] = instantiations->ptr()->data()[i + 1];
|
| + goto InstantiateTypeArgumentsTOSDone;
|
| + }
|
| + }
|
| +
|
| + SP[1] = type_arguments;
|
| + SP[2] = instantiator;
|
| +
|
| + Exit(thread, B, SP + 3, pc);
|
| + NativeArguments args(thread, 2, SP + 1, SP);
|
| + INVOKE_RUNTIME(DRT_InstantiateTypeArguments, args, FALLTHROUGH);
|
| + }
|
| +
|
| + InstantiateTypeArgumentsTOSDone:
|
| + DISPATCH();
|
| + }
|
| +
|
| + {
|
| + BYTECODE(Throw, A);
|
| + {
|
| + SP[1] = 0;
|
| + Exit(thread, B, SP + 2, pc);
|
| + if (rA == 0) {
|
| + NativeArguments args(thread, 1, SP, SP + 1);
|
| + INVOKE_RUNTIME(DRT_Throw, args, FALLTHROUGH);
|
| + } else {
|
| + NativeArguments args(thread, 2, SP - 1, SP + 1);
|
| + INVOKE_RUNTIME(DRT_ReThrow, args, FALLTHROUGH);
|
| + }
|
| + }
|
| + DISPATCH();
|
| + }
|
| +
|
| + {
|
| + BYTECODE(Frame, A_D);
|
| + const uint16_t num_locals = rD;
|
| + for (intptr_t i = 1; i <= num_locals; i++) {
|
| + SP[i] = null_value;
|
| + }
|
| + SP += num_locals;
|
| +
|
| + DISPATCH();
|
| + }
|
| +
|
| + {
|
| + BYTECODE(SetFrame, A);
|
| + SP = B + rA - 1;
|
| + DISPATCH();
|
| + }
|
| +
|
| + {
|
| + BYTECODE(Drop1, 0);
|
| + SP--;
|
| + DISPATCH();
|
| + }
|
| +
|
| + {
|
| + BYTECODE(Drop, 0);
|
| + SP -= rA;
|
| + DISPATCH();
|
| + }
|
| +
|
| + {
|
| + BYTECODE(DropR, 0);
|
| + RawObject* result = SP[0];
|
| + SP -= rA;
|
| + SP[0] = result;
|
| + DISPATCH();
|
| + }
|
| +
|
| + {
|
| + BYTECODE(LoadConstant, A_D);
|
| + B[rA] = pp->data()[rD].raw_obj_;
|
| + DISPATCH();
|
| + }
|
| +
|
| + {
|
| + BYTECODE(PushConstant, __D);
|
| + *++SP = pp->data()[rD].raw_obj_;
|
| + DISPATCH();
|
| + }
|
| +
|
| + {
|
| + BYTECODE(Push, A_X);
|
| + *++SP = B[rD];
|
| + DISPATCH();
|
| + }
|
| +
|
| + {
|
| + BYTECODE(Move, A_X);
|
| + B[rA] = B[rD];
|
| + DISPATCH();
|
| + }
|
| +
|
| + {
|
| + BYTECODE(StoreLocal, A_X);
|
| + B[rD] = *SP;
|
| + DISPATCH();
|
| + }
|
| +
|
| + {
|
| + BYTECODE(PopLocal, A_X);
|
| + B[rD] = *SP--;
|
| + DISPATCH();
|
| + }
|
| +
|
| + {
|
| + BYTECODE(MoveSpecial, A_D);
|
| + B[rA] = special_[rD];
|
| + DISPATCH();
|
| + }
|
| +
|
| + {
|
| + BYTECODE(BooleanNegateTOS, 0);
|
| + SP[0] = (SP[0] == true_value) ? false_value : true_value;
|
| + DISPATCH();
|
| + }
|
| +
|
| + {
|
| + BYTECODE(StaticCall, A_D);
|
| + if (thread->isolate()->single_step()) {
|
| + Exit(thread, B, SP + 1, pc);
|
| + NativeArguments args(thread, 0, NULL, NULL);
|
| + INVOKE_RUNTIME(DRT_SingleStepHandler, args, goto StaticCallDispatch);
|
| + }
|
| +
|
| + {
|
| + const uint16_t argc = rA;
|
| + RawObject** call_base = SP - argc;
|
| + RawObject** call_top = SP; // *SP contains function
|
| + argdesc ^= pp->data()[rD].raw_obj_;
|
| + Invoke(thread, call_base, call_top, &pp, &pc, &B, &SP);
|
| + }
|
| +
|
| + StaticCallDispatch:
|
| + DISPATCH();
|
| + }
|
| +
|
| + {
|
| + BYTECODE(InstanceCall, A_D);
|
| + if (thread->isolate()->single_step()) {
|
| + Exit(thread, B, SP + 1, pc);
|
| + NativeArguments args(thread, 0, NULL, NULL);
|
| + INVOKE_RUNTIME(DRT_SingleStepHandler, args,
|
| + goto InstanceCallDispatch);
|
| + }
|
| +
|
| + {
|
| + const uint16_t argc = rA;
|
| + const uint16_t kidx = rD;
|
| +
|
| + RawObject** call_base = SP - argc + 1;
|
| + RawObject** call_top = SP + 1;
|
| + InstanceCall1(thread,
|
| + static_cast<RawICData*>(pp->data()[kidx].raw_obj_),
|
| + call_base, call_top, &argdesc, &pp, &pc, &B, &SP);
|
| + }
|
| +
|
| + InstanceCallDispatch:
|
| + DISPATCH();
|
| + }
|
| +
|
| + {
|
| + BYTECODE(InstanceCall2, A_D);
|
| + if (thread->isolate()->single_step()) {
|
| + Exit(thread, B, SP + 1, pc);
|
| + NativeArguments args(thread, 0, NULL, NULL);
|
| + INVOKE_RUNTIME(DRT_SingleStepHandler, args,
|
| + goto InstanceCall2Dispatch);
|
| + }
|
| +
|
| + {
|
| + const uint16_t argc = rA;
|
| + const uint16_t kidx = rD;
|
| +
|
| + RawObject** call_base = SP - argc + 1;
|
| + RawObject** call_top = SP + 1;
|
| + InstanceCall2(thread,
|
| + static_cast<RawICData*>(pp->data()[kidx].raw_obj_),
|
| + call_base, call_top, &argdesc, &pp, &pc, &B, &SP);
|
| + }
|
| +
|
| + InstanceCall2Dispatch:
|
| + DISPATCH();
|
| + }
|
| +
|
| + {
|
| + BYTECODE(InstanceCall3, A_D);
|
| + if (thread->isolate()->single_step()) {
|
| + Exit(thread, B, SP + 1, pc);
|
| + NativeArguments args(thread, 0, NULL, NULL);
|
| + INVOKE_RUNTIME(DRT_SingleStepHandler, args,
|
| + goto InstanceCall3Dispatch);
|
| + }
|
| +
|
| + {
|
| + const uint16_t argc = rA;
|
| + const uint16_t kidx = rD;
|
| +
|
| + RawObject** call_base = SP - argc + 1;
|
| + RawObject** call_top = SP + 1;
|
| + InstanceCall3(thread,
|
| + static_cast<RawICData*>(pp->data()[kidx].raw_obj_),
|
| + call_base, call_top, &argdesc, &pp, &pc, &B, &SP);
|
| + }
|
| +
|
| + InstanceCall3Dispatch:
|
| + DISPATCH();
|
| + }
|
| +
|
| + {
|
| + BYTECODE(NativeBootstrapCall, 0);
|
| + RawFunction* function = FrameFunction(B);
|
| + RawObject** incoming_args =
|
| + function->ptr()->num_optional_parameters_ == 0
|
| + ? FrameArguments(B, function->ptr()->num_fixed_parameters_)
|
| + : B;
|
| +
|
| + SimulatorBootstrapNativeCall native_target =
|
| + reinterpret_cast<SimulatorBootstrapNativeCall>(SP[-1]);
|
| + intptr_t argc_tag = reinterpret_cast<intptr_t>(SP[-0]);
|
| + SP[-0] = 0; // Note: argc_tag is not smi-tagged.
|
| + SP[-1] = null_value;
|
| + Exit(thread, B, SP + 1, pc);
|
| + NativeArguments args(thread, argc_tag, incoming_args, SP - 1);
|
| + INVOKE_NATIVE(native_target, args, FALLTHROUGH) else { SP -= 1; }
|
| + DISPATCH();
|
| + }
|
| +
|
| + {
|
| + BYTECODE(NativeCall, 0);
|
| + RawFunction* function = FrameFunction(B);
|
| + RawObject** incoming_args =
|
| + function->ptr()->num_optional_parameters_ == 0
|
| + ? FrameArguments(B, function->ptr()->num_fixed_parameters_)
|
| + : B;
|
| +
|
| + Dart_NativeFunction native_target =
|
| + reinterpret_cast<Dart_NativeFunction>(SP[-1]);
|
| + intptr_t argc_tag = reinterpret_cast<intptr_t>(SP[-0]);
|
| + SP[-0] = 0; // argc_tag is not smi tagged!
|
| + SP[-1] = null_value;
|
| + Exit(thread, B, SP + 1, pc);
|
| + NativeArguments args(thread, argc_tag, incoming_args, SP - 1);
|
| + INVOKE_NATIVE_WRAPPER(native_target, args, FALLTHROUGH) else {
|
| + SP -= 1;
|
| + }
|
| + DISPATCH();
|
| + }
|
| +
|
| + {
|
| + BYTECODE(AddTOS, A_B_C);
|
| + SMI_FASTPATH_TOS(intptr_t, SignedAddWithOverflow);
|
| + }
|
| + {
|
| + BYTECODE(SubTOS, A_B_C);
|
| + SMI_FASTPATH_TOS(intptr_t, SignedSubWithOverflow);
|
| + }
|
| + {
|
| + BYTECODE(MulTOS, A_B_C);
|
| + SMI_FASTPATH_TOS(intptr_t, SMI_MUL);
|
| + }
|
| + {
|
| + BYTECODE(BitOrTOS, A_B_C);
|
| + SMI_FASTPATH_TOS(intptr_t, SMI_BITOR);
|
| + }
|
| + {
|
| + BYTECODE(BitAndTOS, A_B_C);
|
| + SMI_FASTPATH_TOS(intptr_t, SMI_BITAND);
|
| + }
|
| + {
|
| + BYTECODE(EqualTOS, A_B_C);
|
| + SMI_FASTPATH_TOS(RawObject*, SMI_EQ);
|
| + }
|
| + {
|
| + BYTECODE(LessThanTOS, A_B_C);
|
| + SMI_FASTPATH_TOS(RawObject*, SMI_LT);
|
| + }
|
| + {
|
| + BYTECODE(GreaterThanTOS, A_B_C);
|
| + SMI_FASTPATH_TOS(RawObject*, SMI_GT);
|
| + }
|
| +
|
| + {
|
| + BYTECODE(Compile, 0);
|
| + B[0] = FrameFunction(B);
|
| + B[1] = 0;
|
| + Exit(thread, B, B + 2, pc);
|
| + NativeArguments args(thread, 1, B, B + 1);
|
| + INVOKE_RUNTIME(DRT_CompileFunction, args, FALLTHROUGH) else {
|
| + // Function should be compiled now.
|
| + RawCode* code = FrameFunction(B)->ptr()->code_;
|
| + SetFrameCode(B, code);
|
| + pp = code->ptr()->object_pool_->ptr();
|
| + pc = reinterpret_cast<uint32_t*>(code->ptr()->entry_point_);
|
| + }
|
| + DISPATCH();
|
| + }
|
| +
|
| + {
|
| + RawObject* result;
|
| +
|
| + BYTECODE(Intrinsic, A);
|
| + result = null_value;
|
| + if (!intrinsics_[rA](thread, B, &result)) {
|
| + DISPATCH();
|
| + }
|
| + goto ReturnImpl;
|
| +
|
| + BYTECODE(Return, A);
|
| + result = B[rA];
|
| + goto ReturnImpl;
|
| +
|
| + BYTECODE(ReturnTOS, 0);
|
| + result = *SP;
|
| +
|
| + ReturnImpl:
|
| + pc = SavedCallerPC(B);
|
| + if ((reinterpret_cast<uword>(pc) & 2) != 0) {
|
| + const intptr_t argc = reinterpret_cast<uword>(pc) >> 2;
|
| + base_ = top_ = reinterpret_cast<uintptr_t*>(
|
| + FrameArguments(B, argc + 1)[0]);
|
| + thread->set_top_exit_frame_info(reinterpret_cast<uword>(top_));
|
| + thread->set_top_resource(top_resource);
|
| + thread->set_vm_tag(vm_tag);
|
| + return result;
|
| + }
|
| + const uint8_t argc = Bytecode::DecodeArgc(pc[-1]);
|
| + SP = FrameArguments(B, argc);
|
| + B = SavedCallerFP(B);
|
| + *SP = result;
|
| + RawCode* code = FrameCode(B);
|
| + pp = code->ptr()->object_pool_->ptr();
|
| + DISPATCH();
|
| + }
|
| +
|
| + {
|
| + BYTECODE(StoreStaticTOS, A_D);
|
| + RawField* field = reinterpret_cast<RawField*>(pp->data()[rD].raw_obj_);
|
| + RawInstance* value = static_cast<RawInstance*>(*SP--);
|
| + field->StorePointer(&field->ptr()->value_.static_value_, value);
|
| + DISPATCH();
|
| + }
|
| +
|
| + {
|
| + BYTECODE(PushStatic, A_D);
|
| + RawField* field = reinterpret_cast<RawField*>(pp->data()[rD].raw_obj_);
|
| + *SP = field->ptr()->value_.static_value_; // Note: field on the stack.
|
| + DISPATCH();
|
| + }
|
| +
|
| + {
|
| + BYTECODE(StoreField, A_B_C);
|
| + const uint16_t offset_in_words = rB;
|
| + const uint16_t value_reg = rC;
|
| +
|
| + RawInstance* instance = reinterpret_cast<RawInstance*>(B[rA]);
|
| + RawObject* value = reinterpret_cast<RawObject*>(B[value_reg]);
|
| +
|
| + instance->StorePointer(
|
| + reinterpret_cast<RawObject**>(instance->ptr()) + offset_in_words,
|
| + value);
|
| + DISPATCH();
|
| + }
|
| +
|
| + {
|
| + BYTECODE(StoreFieldTOS, A_D);
|
| + const uint16_t offset_in_words = rD;
|
| + RawInstance* instance = reinterpret_cast<RawInstance*>(SP[-1]);
|
| + RawObject* value = reinterpret_cast<RawObject*>(SP[0]);
|
| + SP -= 2;
|
| + instance->StorePointer(
|
| + reinterpret_cast<RawObject**>(instance->ptr()) + offset_in_words,
|
| + value);
|
| +
|
| + DISPATCH();
|
| + }
|
| +
|
| + {
|
| + BYTECODE(LoadField, A_B_C);
|
| + const uint16_t instance_reg = rB;
|
| + const uint16_t offset_in_words = rC;
|
| + RawInstance* instance = reinterpret_cast<RawInstance*>(B[instance_reg]);
|
| + B[rA] = reinterpret_cast<RawObject**>(instance->ptr())[offset_in_words];
|
| + DISPATCH();
|
| + }
|
| +
|
| + {
|
| + BYTECODE(LoadFieldTOS, A_D);
|
| + const uint16_t offset_in_words = rD;
|
| + RawInstance* instance = static_cast<RawInstance*>(SP[0]);
|
| + SP[0] = reinterpret_cast<RawObject**>(instance->ptr())[offset_in_words];
|
| + DISPATCH();
|
| + }
|
| +
|
| + {
|
| + BYTECODE(InitStaticTOS, A);
|
| + RawField* field = static_cast<RawField*>(*SP--);
|
| + RawObject* value = field->ptr()->value_.static_value_;
|
| + if ((value == Object::sentinel().raw()) ||
|
| + (value == Object::transition_sentinel().raw())) {
|
| + /* SP[1] field */
|
| + SP[2] = 0;
|
| + Exit(thread, B, SP + 3, pc);
|
| + NativeArguments args(thread, 1, SP + 1, SP + 2);
|
| + INVOKE_RUNTIME(DRT_InitStaticField, args, FALLTHROUGH);
|
| + }
|
| + DISPATCH();
|
| + }
|
| +
|
| + // TODO(vegorov) allocation bytecodes can benefit from the new-space
|
| + // allocation fast-path that does not transition into the runtime system.
|
| + {
|
| + BYTECODE(AllocateContext, A_D);
|
| + const uint16_t num_context_variables = rD;
|
| + {
|
| + *++SP = 0;
|
| + SP[1] = Smi::New(num_context_variables);
|
| + Exit(thread, B, SP + 2, pc);
|
| + NativeArguments args(thread, 1, SP + 1, SP);
|
| + INVOKE_RUNTIME(DRT_AllocateContext, args, FALLTHROUGH);
|
| + }
|
| + DISPATCH();
|
| + }
|
| +
|
| + {
|
| + BYTECODE(CloneContext, A);
|
| + {
|
| + SP[1] = SP[0];
|
| + Exit(thread, B, SP + 2, pc);
|
| + NativeArguments args(thread, 1, SP + 1, SP);
|
| + INVOKE_RUNTIME(DRT_CloneContext, args, FALLTHROUGH);
|
| + }
|
| + DISPATCH();
|
| + }
|
| +
|
| + {
|
| + BYTECODE(Allocate, A_D);
|
| + SP[1] = 0; // result
|
| + SP[2] = pp->data()[rD].raw_obj_;
|
| + SP[3] = null_value;
|
| + Exit(thread, B, SP + 4, pc);
|
| + NativeArguments args(thread, 2, SP + 2, SP + 1);
|
| + INVOKE_RUNTIME(DRT_AllocateObject, args, FALLTHROUGH);
|
| + SP++;
|
| + DISPATCH();
|
| + }
|
| +
|
| + {
|
| + BYTECODE(AllocateT, 0);
|
| + SP[1] = SP[-0]; // class
|
| + SP[2] = SP[-1]; // type arguments
|
| + Exit(thread, B, SP + 3, pc);
|
| + NativeArguments args(thread, 2, SP + 1, SP - 1);
|
| + INVOKE_RUNTIME(DRT_AllocateObject, args, FALLTHROUGH);
|
| + SP -= 1;
|
| + DISPATCH();
|
| + }
|
| +
|
| + {
|
| + BYTECODE(CreateArrayTOS, 0);
|
| + SP[1] = SP[-0]; // length
|
| + SP[2] = SP[-1]; // type
|
| + Exit(thread, B, SP + 3, pc);
|
| + NativeArguments args(thread, 2, SP + 1, SP - 1);
|
| + INVOKE_RUNTIME(DRT_AllocateArray, args, FALLTHROUGH);
|
| + SP -= 1;
|
| + DISPATCH();
|
| + }
|
| +
|
| + {
|
| + BYTECODE(AssertAssignable, A_D); // instance, type args, type, name
|
| + RawObject** args = SP - 3;
|
| + if (args[0] != null_value) {
|
| + RawSubtypeTestCache* cache =
|
| + static_cast<RawSubtypeTestCache*>(pp->data()[rD].raw_obj_);
|
| + if (cache != null_value) {
|
| + RawInstance* instance = static_cast<RawInstance*>(args[0]);
|
| + RawTypeArguments* instantiator_type_arguments =
|
| + static_cast<RawTypeArguments*>(args[1]);
|
| +
|
| + const intptr_t cid = SimulatorHelpers::GetClassId(instance);
|
| +
|
| + RawTypeArguments* instance_type_arguments =
|
| + static_cast<RawTypeArguments*>(null_value);
|
| + RawObject* instance_cid_or_function;
|
| + if (cid == kClosureCid) {
|
| + RawClosure* closure = static_cast<RawClosure*>(instance);
|
| + instance_type_arguments = closure->ptr()->type_arguments_;
|
| + instance_cid_or_function = closure->ptr()->function_;
|
| + } else {
|
| + instance_cid_or_function = Smi::New(cid);
|
| +
|
| + RawClass* instance_class =
|
| + thread->isolate()->class_table()->At(cid);
|
| + if (instance_class->ptr()->num_type_arguments_ < 0) {
|
| + goto AssertAssignableCallRuntime;
|
| + } else if (instance_class->ptr()->num_type_arguments_ > 0) {
|
| + instance_type_arguments = reinterpret_cast<RawTypeArguments**>(
|
| + instance
|
| + ->ptr())[instance_class->ptr()
|
| + ->type_arguments_field_offset_in_words_];
|
| + }
|
| + }
|
| +
|
| + for (RawObject** entries = cache->ptr()->cache_->ptr()->data();
|
| + entries[0] != null_value;
|
| + entries += SubtypeTestCache::kTestEntryLength) {
|
| + if (entries[SubtypeTestCache::kInstanceClassIdOrFunction] ==
|
| + instance_cid_or_function &&
|
| + entries[SubtypeTestCache::kInstanceTypeArguments] ==
|
| + instance_type_arguments &&
|
| + entries[SubtypeTestCache::kInstantiatorTypeArguments] ==
|
| + instantiator_type_arguments) {
|
| + if (true_value == entries[SubtypeTestCache::kTestResult]) {
|
| + goto AssertAssignableOk;
|
| + } else {
|
| + break;
|
| + }
|
| + }
|
| + }
|
| + }
|
| +
|
| + AssertAssignableCallRuntime:
|
| + SP[1] = args[0]; // instance
|
| + SP[2] = args[2]; // type
|
| + SP[3] = args[1]; // type args
|
| + SP[4] = args[3]; // name
|
| + SP[5] = cache;
|
| + Exit(thread, B, SP + 6, pc);
|
| + NativeArguments args(thread, 5, SP + 1, SP - 3);
|
| + INVOKE_RUNTIME(DRT_TypeCheck, args, FALLTHROUGH);
|
| + }
|
| +
|
| + AssertAssignableOk:
|
| + SP -= 3;
|
| + DISPATCH();
|
| + }
|
| +
|
| + {
|
| + BYTECODE(AssertBoolean, A);
|
| + RawObject* value = SP[0];
|
| + if (rA) {
|
| + if (value == true_value || value == false_value) {
|
| + goto AssertBooleanOk;
|
| + }
|
| + } else if (value != null_value) {
|
| + goto AssertBooleanOk;
|
| + }
|
| +
|
| + {
|
| + SP[1] = SP[0]; // instance
|
| + Exit(thread, B, SP + 2, pc);
|
| + NativeArguments args(thread, 1, SP + 1, SP);
|
| + INVOKE_RUNTIME(DRT_NonBoolTypeError, args, FALLTHROUGH);
|
| + }
|
| +
|
| + AssertBooleanOk:
|
| + DISPATCH();
|
| + }
|
| +
|
| + {
|
| + BYTECODE(IfEqStrictTOS, A_D);
|
| + SP -= 2;
|
| + if (SP[1] != SP[2]) {
|
| + pc++;
|
| + }
|
| + DISPATCH();
|
| + }
|
| +
|
| + {
|
| + BYTECODE(IfNeStrictTOS, A_D);
|
| + SP -= 2;
|
| + if (SP[1] == SP[2]) {
|
| + pc++;
|
| + }
|
| + DISPATCH();
|
| + }
|
| +
|
| + {
|
| + BYTECODE(IfEqStrictNumTOS, A_D);
|
| + if (thread->isolate()->single_step()) {
|
| + Exit(thread, B, SP + 1, pc);
|
| + NativeArguments args(thread, 0, NULL, NULL);
|
| + INVOKE_RUNTIME(DRT_SingleStepHandler, args, FALLTHROUGH);
|
| + }
|
| +
|
| + SP -= 2;
|
| + if (!SimulatorHelpers::IsStrictEqualWithNumberCheck(SP[1], SP[2])) {
|
| + pc++;
|
| + }
|
| + DISPATCH();
|
| + }
|
| +
|
| + {
|
| + BYTECODE(IfNeStrictNumTOS, A_D);
|
| + if (thread->isolate()->single_step()) {
|
| + Exit(thread, B, SP + 1, pc);
|
| + NativeArguments args(thread, 0, NULL, NULL);
|
| + INVOKE_RUNTIME(DRT_SingleStepHandler, args, FALLTHROUGH);
|
| + }
|
| +
|
| + SP -= 2;
|
| + if (SimulatorHelpers::IsStrictEqualWithNumberCheck(SP[1], SP[2])) {
|
| + pc++;
|
| + }
|
| + DISPATCH();
|
| + }
|
| +
|
| + {
|
| + BYTECODE(Jump, 0);
|
| + const int32_t tgt = static_cast<int32_t>(__op) >> 8;
|
| + pc += (tgt - 1);
|
| + DISPATCH();
|
| + }
|
| +
|
| + {
|
| + BYTECODE(StoreIndexedTOS, 0);
|
| + SP -= 3;
|
| + RawArray* array = static_cast<RawArray*>(SP[1]);
|
| + RawSmi* index = static_cast<RawSmi*>(SP[2]);
|
| + RawObject* value = SP[3];
|
| + ASSERT(array->GetClassId() == kArrayCid);
|
| + ASSERT(!index->IsHeapObject());
|
| + array->StorePointer(array->ptr()->data() + Smi::Value(index), value);
|
| + DISPATCH();
|
| + }
|
| +
|
| + {
|
| + BYTECODE(Trap, 0);
|
| + UNIMPLEMENTED();
|
| + DISPATCH();
|
| + }
|
| + }
|
| + }
|
| +
|
| + UNREACHABLE();
|
| + return 0;
|
| +}
|
| +
|
| +void Simulator::Longjmp(uword pc, uword sp, uword fp, RawObject* raw_exception,
|
| + RawObject* raw_stacktrace, Thread* thread) {
|
| + // Walk over all setjmp buffers (simulated --> C++ transitions)
|
| + // and try to find the setjmp associated with the simulated stack pointer.
|
| + SimulatorSetjmpBuffer* buf = last_setjmp_buffer();
|
| + while ((buf->link() != NULL) && (buf->link()->base() > fp)) {
|
| + buf = buf->link();
|
| + }
|
| + ASSERT(buf != NULL);
|
| + ASSERT(last_setjmp_buffer() == buf);
|
| +
|
| + // The C++ caller has not cleaned up the stack memory of C++ frames.
|
| + // Prepare for unwinding frames by destroying all the stack resources
|
| + // in the previous C++ frames.
|
| + StackResource::Unwind(thread);
|
| +
|
| + // Set the tag.
|
| + thread->set_vm_tag(VMTag::kDartTagId);
|
| + // Clear top exit frame.
|
| + thread->set_top_exit_frame_info(0);
|
| +
|
| + ASSERT(raw_exception != Object::null());
|
| + top_ = reinterpret_cast<uintptr_t*>(sp);
|
| + base_ = reinterpret_cast<uintptr_t*>(fp);
|
| + pc_ = pc;
|
| + special_[kExceptionSpecialIndex] = raw_exception;
|
| + special_[kStacktraceSpecialIndex] = raw_stacktrace;
|
| + buf->Longjmp();
|
| + UNREACHABLE();
|
| +}
|
| +
|
| +} // namespace dart
|
| +
|
| +
|
| +#endif // defined TARGET_ARCH_DBC
|
|
|