| 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..780e44f4842099043972d641ddb1a0594c3872cf
 | 
| --- /dev/null
 | 
| +++ b/runtime/vm/simulator_dbc.cc
 | 
| @@ -0,0 +1,1903 @@
 | 
| +// 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);
 | 
| +    sp_ = sim->sp_;
 | 
| +    fp_ = sim->fp_;
 | 
| +  }
 | 
| +
 | 
| +  ~SimulatorSetjmpBuffer() {
 | 
| +    ASSERT(simulator_->last_setjmp_buffer() == this);
 | 
| +    simulator_->set_last_setjmp_buffer(link_);
 | 
| +  }
 | 
| +
 | 
| +  SimulatorSetjmpBuffer* link() const { return link_; }
 | 
| +
 | 
| +  uword sp() const { return reinterpret_cast<uword>(sp_); }
 | 
| +  uword fp() const { return reinterpret_cast<uword>(fp_); }
 | 
| +
 | 
| +  jmp_buf buffer_;
 | 
| +
 | 
| + private:
 | 
| +  RawObject** sp_;
 | 
| +  RawObject** fp_;
 | 
| +  Simulator* simulator_;
 | 
| +  SimulatorSetjmpBuffer* link_;
 | 
| +
 | 
| +  friend class Simulator;
 | 
| +
 | 
| +  DISALLOW_ALLOCATION();
 | 
| +  DISALLOW_COPY_AND_ASSIGN(SimulatorSetjmpBuffer);
 | 
| +};
 | 
| +
 | 
| +
 | 
| +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();
 | 
| +  }
 | 
| +
 | 
| +  DART_FORCE_INLINE static bool CheckIndex(RawSmi* index, RawSmi* length) {
 | 
| +    return !index->IsHeapObject() &&
 | 
| +           (reinterpret_cast<intptr_t>(index) >= 0) &&
 | 
| +           (reinterpret_cast<intptr_t>(index) <
 | 
| +                reinterpret_cast<intptr_t>(length));
 | 
| +  }
 | 
| +
 | 
| +  static bool ObjectArraySetIndexed(Thread* thread,
 | 
| +                                    RawObject** FP,
 | 
| +                                    RawObject** result) {
 | 
| +    if (thread->isolate()->type_checks()) {
 | 
| +      return false;
 | 
| +    }
 | 
| +
 | 
| +    RawObject** args = FrameArguments(FP, 3);
 | 
| +    RawSmi* index = static_cast<RawSmi*>(args[1]);
 | 
| +    RawArray* array = static_cast<RawArray*>(args[0]);
 | 
| +    if (CheckIndex(index, array->ptr()->length_)) {
 | 
| +      array->StorePointer(array->ptr()->data() + Smi::Value(index), args[2]);
 | 
| +      return true;
 | 
| +    }
 | 
| +    return false;
 | 
| +  }
 | 
| +
 | 
| +  static bool ObjectArrayGetIndexed(Thread* thread,
 | 
| +                                    RawObject** FP,
 | 
| +                                    RawObject** result) {
 | 
| +    RawObject** args = FrameArguments(FP, 2);
 | 
| +    RawSmi* index = static_cast<RawSmi*>(args[1]);
 | 
| +    RawArray* array = static_cast<RawArray*>(args[0]);
 | 
| +    if (CheckIndex(index, array->ptr()->length_)) {
 | 
| +      *result = array->ptr()->data()[Smi::Value(index)];
 | 
| +      return true;
 | 
| +    }
 | 
| +    return false;
 | 
| +  }
 | 
| +
 | 
| +  static bool GrowableArraySetIndexed(Thread* thread,
 | 
| +                                      RawObject** FP,
 | 
| +                                      RawObject** result) {
 | 
| +    if (thread->isolate()->type_checks()) {
 | 
| +      return false;
 | 
| +    }
 | 
| +
 | 
| +    RawObject** args = FrameArguments(FP, 3);
 | 
| +    RawSmi* index = static_cast<RawSmi*>(args[1]);
 | 
| +    RawGrowableObjectArray* array =
 | 
| +        static_cast<RawGrowableObjectArray*>(args[0]);
 | 
| +    if (CheckIndex(index, 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** FP,
 | 
| +                                      RawObject** result) {
 | 
| +    RawObject** args = FrameArguments(FP, 2);
 | 
| +    RawSmi* index = static_cast<RawSmi*>(args[1]);
 | 
| +    RawGrowableObjectArray* array =
 | 
| +        static_cast<RawGrowableObjectArray*>(args[0]);
 | 
| +    if (CheckIndex(index, 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()
 | 
| +    : stack_(NULL),
 | 
| +      fp_(NULL),
 | 
| +      sp_(NULL) {
 | 
| +  // 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)];
 | 
| +  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);
 | 
| +  fp_ = sp_ = frame + kDartFrameFixedSize;
 | 
| +  thread->set_top_exit_frame_info(reinterpret_cast<uword>(sp_));
 | 
| +}
 | 
| +
 | 
| +
 | 
| +#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 bool SignedAddWithOverflow(int32_t lhs,
 | 
| +                                                    int32_t rhs,
 | 
| +                                                    intptr_t* out) {
 | 
| +  int32_t res = 1;
 | 
| +#if defined(HAS_ADD_OVERFLOW)
 | 
| +  res = static_cast<int32_t>(__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 != 0);
 | 
| +}
 | 
| +
 | 
| +
 | 
| +DART_FORCE_INLINE static bool SignedSubWithOverflow(int32_t lhs,
 | 
| +                                                    int32_t rhs,
 | 
| +                                                    intptr_t* out) {
 | 
| +  int32_t res = 1;
 | 
| +#if defined(HAS_SUB_OVERFLOW)
 | 
| +  res = static_cast<int32_t>(__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 != 0);
 | 
| +}
 | 
| +
 | 
| +
 | 
| +DART_FORCE_INLINE static bool SignedMulWithOverflow(int32_t lhs,
 | 
| +                                                    int32_t rhs,
 | 
| +                                                    intptr_t* out) {
 | 
| +  int32_t res = 1;
 | 
| +#if defined(HAS_MUL_OVERFLOW)
 | 
| +  res = static_cast<int32_t>(__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 != 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*** FP,
 | 
| +                                         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*>(*FP);
 | 
| +  *pp = code->ptr()->object_pool_->ptr();
 | 
| +  *pc = reinterpret_cast<uint32_t*>(code->ptr()->entry_point_);
 | 
| +  *FP = callee_fp;
 | 
| +  *SP = *FP - 1;
 | 
| +}
 | 
| +
 | 
| +
 | 
| +void Simulator::InlineCacheMiss(int checked_args,
 | 
| +                                Thread* thread,
 | 
| +                                RawICData* icdata,
 | 
| +                                RawObject** args,
 | 
| +                                RawObject** top,
 | 
| +                                uint32_t* pc,
 | 
| +                                RawObject** FP,
 | 
| +                                RawObject** SP) {
 | 
| +  RawObject** result = top;
 | 
| +  RawObject** miss_handler_args = top + 1;
 | 
| +  for (intptr_t i = 0; i < checked_args; i++) {
 | 
| +    miss_handler_args[i] = args[i];
 | 
| +  }
 | 
| +  miss_handler_args[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;
 | 
| +  }
 | 
| +
 | 
| +  // Handler arguments: arguments to check and an ICData object.
 | 
| +  const intptr_t miss_handler_argc = checked_args + 1;
 | 
| +  RawObject** exit_frame = miss_handler_args + miss_handler_argc;
 | 
| +  CallRuntime(thread,
 | 
| +              FP,
 | 
| +              exit_frame,
 | 
| +              pc,
 | 
| +              miss_handler_argc,
 | 
| +              miss_handler_args,
 | 
| +              result,
 | 
| +              reinterpret_cast<uword>(handler));
 | 
| +}
 | 
| +
 | 
| +
 | 
| +DART_FORCE_INLINE void Simulator::InstanceCall1(Thread* thread,
 | 
| +                                                RawICData* icdata,
 | 
| +                                                RawObject** call_base,
 | 
| +                                                RawObject** top,
 | 
| +                                                RawArray** argdesc,
 | 
| +                                                RawObjectPool** pp,
 | 
| +                                                uint32_t** pc,
 | 
| +                                                RawObject*** FP,
 | 
| +                                                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;
 | 
| +  const intptr_t length = Smi::Value(cache->length_);
 | 
| +  for (intptr_t i = 0;
 | 
| +       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, *FP, *SP);
 | 
| +  }
 | 
| +
 | 
| +  *argdesc = icdata->ptr()->args_descriptor_;
 | 
| +  Invoke(thread, call_base, top, pp, pc, FP, SP);
 | 
| +}
 | 
| +
 | 
| +
 | 
| +DART_FORCE_INLINE void Simulator::InstanceCall2(Thread* thread,
 | 
| +                                                RawICData* icdata,
 | 
| +                                                RawObject** call_base,
 | 
| +                                                RawObject** top,
 | 
| +                                                RawArray** argdesc,
 | 
| +                                                RawObjectPool** pp,
 | 
| +                                                uint32_t** pc,
 | 
| +                                                RawObject*** FP,
 | 
| +                                                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;
 | 
| +  const intptr_t length = Smi::Value(cache->length_);
 | 
| +  for (intptr_t i = 0;
 | 
| +       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, *FP, *SP);
 | 
| +  }
 | 
| +
 | 
| +  *argdesc = icdata->ptr()->args_descriptor_;
 | 
| +  Invoke(thread, call_base, top, pp, pc, FP, SP);
 | 
| +}
 | 
| +
 | 
| +
 | 
| +DART_FORCE_INLINE void Simulator::InstanceCall3(Thread* thread,
 | 
| +                                                RawICData* icdata,
 | 
| +                                                RawObject** call_base,
 | 
| +                                                RawObject** top,
 | 
| +                                                RawArray** argdesc,
 | 
| +                                                RawObjectPool** pp,
 | 
| +                                                uint32_t** pc,
 | 
| +                                                RawObject*** FP,
 | 
| +                                                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;
 | 
| +  const intptr_t length = Smi::Value(cache->length_);
 | 
| +  for (intptr_t i = 0;
 | 
| +       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, *FP, *SP);
 | 
| +  }
 | 
| +
 | 
| +  *argdesc = icdata->ptr()->args_descriptor_;
 | 
| +  Invoke(thread, call_base, top, pp, pc, FP, SP);
 | 
| +}
 | 
| +
 | 
| +
 | 
| +// Note: functions below are marked DART_NOINLINE to recover performance on
 | 
| +// ARM where inlining these functions into the interpreter loop seemed to cause
 | 
| +// some code quality issues.
 | 
| +static DART_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 DART_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 DART_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;
 | 
| +  }
 | 
| +}
 | 
| +
 | 
| +// Note: all macro helpers are intended to be used only inside Simulator::Call.
 | 
| +
 | 
| +// Decode opcode and A part of the given value and dispatch to the
 | 
| +// corresponding bytecode handler.
 | 
| +#define DISPATCH_OP(val)         \
 | 
| +  do {                           \
 | 
| +    op = (val);                \
 | 
| +    rA = ((op >> 8) & 0xFF);   \
 | 
| +    goto* dispatch[op & 0xFF]; \
 | 
| +  } while (0)
 | 
| +
 | 
| +// Fetch next operation from PC, increment program counter and dispatch.
 | 
| +#define DISPATCH() DISPATCH_OP(*pc++)
 | 
| +
 | 
| +// 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_HEADER(Name, Declare, Decode) \
 | 
| +  Declare;                                     \
 | 
| +  bc##Name : Decode                            \
 | 
| +
 | 
| +// 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 \
 | 
| +  rB = ((op >> Bytecode::kBShift) & Bytecode::kBMask);    \
 | 
| +  rC = ((op >> Bytecode::kCShift) & Bytecode::kCMask);
 | 
| +
 | 
| +#define DECLARE_0
 | 
| +#define DECODE_0
 | 
| +
 | 
| +#define DECLARE_A
 | 
| +#define DECODE_A
 | 
| +
 | 
| +#define DECLARE___D uint32_t rD; USE(rD)
 | 
| +#define DECODE___D rD = (op >> Bytecode::kDShift);
 | 
| +
 | 
| +#define DECLARE_A_D DECLARE___D
 | 
| +#define DECODE_A_D DECODE___D
 | 
| +
 | 
| +#define DECLARE_A_X int32_t rD; USE(rD)
 | 
| +#define DECODE_A_X rD = (static_cast<int32_t>(op) >> Bytecode::kDShift);
 | 
| +
 | 
| +// Declare bytecode handler for a smi operation (e.g. AddTOS) with the
 | 
| +// given result type and the given behavior specified as a function
 | 
| +// that takes left and right operands and result slot and returns
 | 
| +// true if fast-path succeeds.
 | 
| +#define SMI_FASTPATH_TOS(ResultT, Func)                                        \
 | 
| +  {                                                                            \
 | 
| +    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) && !Func(lhs, rhs, slot))) {              \
 | 
| +      /* Fast path succeeded. Skip the generic call that follows. */           \
 | 
| +      pc++;                                                                    \
 | 
| +      /* We dropped 2 arguments and push result                   */           \
 | 
| +      SP--;                                                                    \
 | 
| +    }                                                                          \
 | 
| +  }
 | 
| +
 | 
| +// Exception handling helper. Gets handler FP and PC from the Simulator where
 | 
| +// they were stored by Simulator::Longjmp and proceeds to execute the handler.
 | 
| +// Corner case: handler PC can be a fake marker that marks entry frame, which
 | 
| +// means exception was not handled in the Dart code. In this case we return
 | 
| +// caught exception from Simulator::Call.
 | 
| +#define HANDLE_EXCEPTION                                                       \
 | 
| +  do {                                                                         \
 | 
| +    FP = reinterpret_cast<RawObject**>(fp_);                                   \
 | 
| +    pc = reinterpret_cast<uint32_t*>(pc_);                                     \
 | 
| +    if ((reinterpret_cast<uword>(pc) & 2) != 0) {  /* Entry frame? */          \
 | 
| +      fp_ = sp_ = reinterpret_cast<RawObject**>(fp_[0]);                       \
 | 
| +      thread->set_top_exit_frame_info(reinterpret_cast<uword>(sp_));           \
 | 
| +      thread->set_top_resource(top_resource);                                  \
 | 
| +      thread->set_vm_tag(vm_tag);                                              \
 | 
| +      return special_[kExceptionSpecialIndex];                                 \
 | 
| +    }                                                                          \
 | 
| +    pp = FrameCode(FP)->ptr()->object_pool_->ptr();                            \
 | 
| +    goto DispatchAfterException;                                               \
 | 
| +  } while (0)                                                                  \
 | 
| +
 | 
| +// Runtime call helpers: handle invocation and potential exception after return.
 | 
| +#define INVOKE_RUNTIME(Func, Args)                \
 | 
| +  if (!InvokeRuntime(thread, this, Func, Args)) { \
 | 
| +    HANDLE_EXCEPTION;                             \
 | 
| +  }                                               \
 | 
| +
 | 
| +#define INVOKE_NATIVE(Func, Args)                 \
 | 
| +  if (!InvokeNative(thread, this, Func, &Args)) { \
 | 
| +    HANDLE_EXCEPTION;                             \
 | 
| +  }                                               \
 | 
| +
 | 
| +#define INVOKE_NATIVE_WRAPPER(Func, Args)                \
 | 
| +  if (!InvokeNativeWrapper(thread, this, Func, &Args)) { \
 | 
| +    HANDLE_EXCEPTION;                                    \
 | 
| +  }                                                      \
 | 
| +
 | 
| +#define LOAD_CONSTANT(index) (pp->data()[(index)].raw_obj_)
 | 
| +
 | 
| +RawObject* Simulator::Call(const Code& code,
 | 
| +                           const Array& arguments_descriptor,
 | 
| +                           const Array& arguments,
 | 
| +                           Thread* thread) {
 | 
| +  // Dispatch used to interpret bytecode. Contains addresses of
 | 
| +  // labels of bytecode handlers. Handlers themselves are defined below.
 | 
| +  static const void* dispatch[] = {
 | 
| +#define TARGET(name, fmt, fmta, fmtb, fmtc) &&bc##name,
 | 
| +      BYTECODES_LIST(TARGET)
 | 
| +#undef TARGET
 | 
| +  };
 | 
| +
 | 
| +  // Interpreter state (see constants_dbc.h for high-level overview).
 | 
| +  uint32_t* pc;  // Program Counter: points to the next op to execute.
 | 
| +  RawObjectPool* pp;  // Pool Pointer.
 | 
| +  RawObject** FP;  // Frame Pointer.
 | 
| +  RawObject** SP;  // Stack Pointer.
 | 
| +
 | 
| +  RawArray* argdesc;  // Arguments Descriptor: used to pass information between
 | 
| +                      // call instruction and the function entry.
 | 
| +
 | 
| +  uint32_t op;  // Currently executing op.
 | 
| +  uint16_t rA;  // A component of the currently executing op.
 | 
| +
 | 
| +  if (sp_ == NULL) {
 | 
| +    fp_ = sp_ = reinterpret_cast<RawObject**>(stack_);
 | 
| +  }
 | 
| +
 | 
| +  // Save current VM tag and mark thread as executing Dart code.
 | 
| +  const uword vm_tag = thread->vm_tag();
 | 
| +  thread->set_vm_tag(VMTag::kDartTagId);
 | 
| +
 | 
| +  // Save current top stack resource and reset the list.
 | 
| +  StackResource* top_resource = thread->top_resource();
 | 
| +  thread->set_top_resource(NULL);
 | 
| +
 | 
| +  // Setup entry frame:
 | 
| +  //
 | 
| +  //                        ^
 | 
| +  //                        |  previous Dart frames
 | 
| +  //       ~~~~~~~~~~~~~~~  |
 | 
| +  //       | ........... | -+
 | 
| +  // fp_ > |             |     saved top_exit_frame_info
 | 
| +  //       | arg 0       | -+
 | 
| +  //       ~~~~~~~~~~~~~~~  |
 | 
| +  //                         > incoming arguments
 | 
| +  //       ~~~~~~~~~~~~~~~  |
 | 
| +  //       | arg 1       | -+
 | 
| +  //       | function    | -+
 | 
| +  //       | code        |  |
 | 
| +  //       | callee PC   | ---> special fake PC marking an entry frame
 | 
| +  //  SP > | fp_         |  |
 | 
| +  //  FP > | ........... |   > normal Dart frame (see stack_frame_dbc.h)
 | 
| +  //                        |
 | 
| +  //                        v
 | 
| +  //
 | 
| +  FP = fp_ + 1 + arguments.Length() + kDartFrameFixedSize;
 | 
| +  SP = FP - 1;
 | 
| +
 | 
| +  // Save outer top_exit_frame_info.
 | 
| +  fp_[0] = reinterpret_cast<RawObject*>(thread->top_exit_frame_info());
 | 
| +
 | 
| +  // Copy arguments and setup the Dart frame.
 | 
| +  const intptr_t argc = arguments.Length();
 | 
| +  for (intptr_t i = 0; i < argc; i++) {
 | 
| +    fp_[1 + i] = arguments.At(i);
 | 
| +  }
 | 
| +
 | 
| +  FP[kFunctionSlotFromFp] = code.function();
 | 
| +  FP[kPcMarkerSlotFromFp] = code.raw();
 | 
| +  FP[kSavedCallerPcSlotFromFp] = reinterpret_cast<RawObject*>((argc << 2) | 2);
 | 
| +  FP[kSavedCallerFpSlotFromFp] = reinterpret_cast<RawObject*>(fp_);
 | 
| +
 | 
| +  // Load argument descriptor.
 | 
| +  argdesc = arguments_descriptor.raw();
 | 
| +
 | 
| +  // Ready to start executing bytecode. Load entry point and corresponding
 | 
| +  // object pool.
 | 
| +  pc = reinterpret_cast<uint32_t*>(code.raw()->ptr()->entry_point_);
 | 
| +  pp = code.object_pool()->ptr();
 | 
| +
 | 
| +  // Cache some frequently used values in the frame.
 | 
| +  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();
 | 
| +
 | 
| +#if defined(DEBUG)
 | 
| +  Function& function_h = Function::Handle();
 | 
| +#endif
 | 
| +
 | 
| +  // Enter the dispatch loop.
 | 
| +  DISPATCH();
 | 
| +
 | 
| +  // Bytecode handlers (see constants_dbc.h for bytecode descriptions).
 | 
| +  {
 | 
| +    BYTECODE(Entry, A_B_C);
 | 
| +    const uint8_t num_fixed_params = rA;
 | 
| +    const uint16_t num_locals = rB;
 | 
| +    const uint16_t context_reg = rC;
 | 
| +
 | 
| +    // Decode arguments descriptor.
 | 
| +    const intptr_t pos_count = Smi::Value(*reinterpret_cast<RawSmi**>(
 | 
| +        reinterpret_cast<uword>(argdesc->ptr()) +
 | 
| +        Array::element_offset(ArgumentsDescriptor::kPositionalCountIndex)));
 | 
| +
 | 
| +    // Check that we got the right number of positional parameters.
 | 
| +    if (pos_count != num_fixed_params) {
 | 
| +      // Mismatch can only occur if current function is a closure.
 | 
| +      goto ClosureNoSuchMethod;
 | 
| +    }
 | 
| +
 | 
| +    // Initialize locals with null and set current context variable to
 | 
| +    // empty context.
 | 
| +    {
 | 
| +      RawObject** L = FP;
 | 
| +      for (intptr_t i = 0; i < num_locals; i++) {
 | 
| +        L[i] = null_value;
 | 
| +      }
 | 
| +      L[context_reg] = empty_context;
 | 
| +      SP = FP + num_locals - 1;
 | 
| +    }
 | 
| +
 | 
| +    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;
 | 
| +
 | 
| +    // Decode arguments descriptor.
 | 
| +    const intptr_t arg_count = Smi::Value(*reinterpret_cast<RawSmi**>(
 | 
| +        reinterpret_cast<uword>(argdesc->ptr()) +
 | 
| +        Array::element_offset(ArgumentsDescriptor::kCountIndex)));
 | 
| +    const intptr_t pos_count = Smi::Value(*reinterpret_cast<RawSmi**>(
 | 
| +        reinterpret_cast<uword>(argdesc->ptr()) +
 | 
| +        Array::element_offset(ArgumentsDescriptor::kPositionalCountIndex)));
 | 
| +    const intptr_t named_count = (arg_count - pos_count);
 | 
| +
 | 
| +    // Check that got the right number of positional parameters.
 | 
| +    if ((min_num_pos_args > pos_count) || (pos_count > max_num_pos_args)) {
 | 
| +      goto ClosureNoSuchMethod;
 | 
| +    }
 | 
| +
 | 
| +    // Copy all passed position arguments.
 | 
| +    RawObject** first_arg = FrameArguments(FP, arg_count);
 | 
| +    memmove(FP, first_arg, pos_count * kWordSize);
 | 
| +
 | 
| +    if (num_opt_named_params != 0) {
 | 
| +      // This is a function with named parameters.
 | 
| +      // Walk the list of named parameters and their
 | 
| +      // default values encoded as pairs of LoadConstant instructions that
 | 
| +      // follows the entry point and find matching values via arguments
 | 
| +      // descriptor.
 | 
| +      RawObject** argdesc_data = argdesc->ptr()->data();
 | 
| +
 | 
| +      intptr_t i = named_count - 1;  // argument position
 | 
| +      intptr_t j = num_opt_named_params - 1;  // parameter position
 | 
| +      while ((j >= 0) && (i >= 0)) {
 | 
| +        // Fetch formal parameter information: name, default value, target slot.
 | 
| +        const uint32_t load_name = pc[2 * j];
 | 
| +        const uint32_t load_value = pc[2 * j + 1];
 | 
| +        ASSERT(Bytecode::DecodeOpcode(load_name) == Bytecode::kLoadConstant);
 | 
| +        ASSERT(Bytecode::DecodeOpcode(load_value) == Bytecode::kLoadConstant);
 | 
| +        const uint8_t reg = Bytecode::DecodeA(load_name);
 | 
| +        ASSERT(reg == Bytecode::DecodeA(load_value));
 | 
| +
 | 
| +        RawString* name = static_cast<RawString*>(
 | 
| +            LOAD_CONSTANT(Bytecode::DecodeD(load_name)));
 | 
| +        if (name == argdesc_data[ArgumentsDescriptor::name_index(i)]) {
 | 
| +          // Parameter was passed. Fetch passed value.
 | 
| +          const intptr_t arg_index = Smi::Value(static_cast<RawSmi*>(
 | 
| +              argdesc_data[ArgumentsDescriptor::position_index(i)]));
 | 
| +          FP[reg] = first_arg[arg_index];
 | 
| +          i--;  // Consume passed argument.
 | 
| +        } else {
 | 
| +          // Parameter was not passed. Fetch default value.
 | 
| +          FP[reg] = LOAD_CONSTANT(Bytecode::DecodeD(load_value));
 | 
| +        }
 | 
| +        j--;  // Next formal parameter.
 | 
| +      }
 | 
| +
 | 
| +      // If we have unprocessed formal parameters then initialize them all
 | 
| +      // using default values.
 | 
| +      while (j >= 0) {
 | 
| +        const uint32_t load_name = pc[2 * j];
 | 
| +        const uint32_t load_value = pc[2 * j + 1];
 | 
| +        ASSERT(Bytecode::DecodeOpcode(load_name) == Bytecode::kLoadConstant);
 | 
| +        ASSERT(Bytecode::DecodeOpcode(load_value) == Bytecode::kLoadConstant);
 | 
| +        const uint8_t reg = Bytecode::DecodeA(load_name);
 | 
| +        ASSERT(reg == Bytecode::DecodeA(load_value));
 | 
| +
 | 
| +        FP[reg] = LOAD_CONSTANT(Bytecode::DecodeD(load_value));
 | 
| +        j--;
 | 
| +      }
 | 
| +
 | 
| +      // If we have unprocessed passed arguments that means we have mismatch
 | 
| +      // between formal parameters and concrete arguments. This can only
 | 
| +      // occur if the current function is a closure.
 | 
| +      if (i != -1) {
 | 
| +        goto ClosureNoSuchMethod;
 | 
| +      }
 | 
| +
 | 
| +      // Skip LoadConstant-s encoding information about named parameters.
 | 
| +      pc += num_opt_named_params * 2;
 | 
| +
 | 
| +      // SP points past copied arguments.
 | 
| +      SP = FP + num_fixed_params + num_opt_named_params - 1;
 | 
| +    } else {
 | 
| +      ASSERT(num_opt_pos_params != 0);
 | 
| +      if (named_count != 0) {
 | 
| +        // Function can't have both named and optional positional parameters.
 | 
| +        // This kind of mismatch can only occur if the current function
 | 
| +        // is a closure.
 | 
| +        goto ClosureNoSuchMethod;
 | 
| +      }
 | 
| +
 | 
| +      // Process the list of default values encoded as a sequence of
 | 
| +      // LoadConstant instructions after EntryOpt bytecode.
 | 
| +      // Execute only those that correspond to parameters the were not passed.
 | 
| +      for (intptr_t i = pos_count - num_fixed_params;
 | 
| +           i < num_opt_pos_params;
 | 
| +           i++) {
 | 
| +        const uint32_t load_value = pc[i];
 | 
| +        ASSERT(Bytecode::DecodeOpcode(load_value) == Bytecode::kLoadConstant);
 | 
| +#if defined(DEBUG)
 | 
| +        const uint8_t reg = Bytecode::DecodeA(load_value);
 | 
| +        ASSERT((num_fixed_params + i) == reg);
 | 
| +#endif
 | 
| +        FP[num_fixed_params + i] = LOAD_CONSTANT(Bytecode::DecodeD(load_value));
 | 
| +      }
 | 
| +
 | 
| +      // Skip LoadConstant-s encoding default values for optional positional
 | 
| +      // parameters.
 | 
| +      pc += num_opt_pos_params;
 | 
| +
 | 
| +      // SP points past the last copied parameter.
 | 
| +      SP = FP + max_num_pos_args - 1;
 | 
| +    }
 | 
| +
 | 
| +    DISPATCH();
 | 
| +  }
 | 
| +
 | 
| +  {
 | 
| +    BYTECODE(Frame, A_D);
 | 
| +    // Initialize locals with null and increment SP.
 | 
| +    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 = FP + rA - 1;
 | 
| +    DISPATCH();
 | 
| +  }
 | 
| +
 | 
| +  {
 | 
| +    BYTECODE(Compile, 0);
 | 
| +    FP[0] = FrameFunction(FP);
 | 
| +    FP[1] = 0;
 | 
| +    Exit(thread, FP, FP + 2, pc);
 | 
| +    NativeArguments args(thread, 1, FP, FP + 1);
 | 
| +    INVOKE_RUNTIME(DRT_CompileFunction, args);
 | 
| +    {
 | 
| +      // Function should be compiled now, dispatch to its entry point.
 | 
| +      RawCode* code = FrameFunction(FP)->ptr()->code_;
 | 
| +      SetFrameCode(FP, code);
 | 
| +      pp = code->ptr()->object_pool_->ptr();
 | 
| +      pc = reinterpret_cast<uint32_t*>(code->ptr()->entry_point_);
 | 
| +    }
 | 
| +    DISPATCH();
 | 
| +  }
 | 
| +
 | 
| +  {
 | 
| +    BYTECODE(CheckStack, A);
 | 
| +    {
 | 
| +      if (reinterpret_cast<uword>(SP) >= thread->stack_limit()) {
 | 
| +        Exit(thread, FP, SP + 1, pc);
 | 
| +        NativeArguments args(thread, 0, NULL, NULL);
 | 
| +        INVOKE_RUNTIME(DRT_StackOverflow, args);
 | 
| +      }
 | 
| +    }
 | 
| +    DISPATCH();
 | 
| +  }
 | 
| +
 | 
| +  {
 | 
| +    BYTECODE(DebugStep, A);
 | 
| +    if (thread->isolate()->single_step()) {
 | 
| +      Exit(thread, FP, SP + 1, pc);
 | 
| +      NativeArguments args(thread, 0, NULL, NULL);
 | 
| +      INVOKE_RUNTIME(DRT_SingleStepHandler, args);
 | 
| +    }
 | 
| +    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, FP, SP + 2, pc);
 | 
| +      NativeArguments args(thread, 0, NULL, SP + 1);
 | 
| +      INVOKE_RUNTIME(DRT_BreakpointRuntimeHandler, args)
 | 
| +      DISPATCH_OP(original_bc);
 | 
| +    }
 | 
| +    DISPATCH();
 | 
| +  }
 | 
| +
 | 
| +  {
 | 
| +    BYTECODE(InstantiateType, A_D);
 | 
| +    RawObject* type = LOAD_CONSTANT(rD);
 | 
| +    SP[1] = type;
 | 
| +    SP[2] = SP[0];
 | 
| +    SP[0] = null_value;
 | 
| +    Exit(thread, FP, SP + 3, pc);
 | 
| +    {
 | 
| +      NativeArguments args(thread, 2, SP + 1, SP);
 | 
| +      INVOKE_RUNTIME(DRT_InstantiateType, args);
 | 
| +    }
 | 
| +    DISPATCH();
 | 
| +  }
 | 
| +
 | 
| +  {
 | 
| +    BYTECODE(InstantiateTypeArgumentsTOS, A_D);
 | 
| +    RawTypeArguments* type_arguments =
 | 
| +        static_cast<RawTypeArguments*>(LOAD_CONSTANT(rD));
 | 
| +
 | 
| +    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) {
 | 
| +      // First lookup in the cache.
 | 
| +      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) {
 | 
| +          // Found in the cache.
 | 
| +          SP[0] = instantiations->ptr()->data()[i + 1];
 | 
| +          goto InstantiateTypeArgumentsTOSDone;
 | 
| +        }
 | 
| +      }
 | 
| +
 | 
| +      // Cache lookup failed, call runtime.
 | 
| +      SP[1] = type_arguments;
 | 
| +      SP[2] = instantiator;
 | 
| +
 | 
| +      Exit(thread, FP, SP + 3, pc);
 | 
| +      NativeArguments args(thread, 2, SP + 1, SP);
 | 
| +      INVOKE_RUNTIME(DRT_InstantiateTypeArguments, args);
 | 
| +    }
 | 
| +
 | 
| +  InstantiateTypeArgumentsTOSDone:
 | 
| +    DISPATCH();
 | 
| +  }
 | 
| +
 | 
| +  {
 | 
| +    BYTECODE(Throw, A);
 | 
| +    {
 | 
| +      SP[1] = 0;  // Space for result.
 | 
| +      Exit(thread, FP, SP + 2, pc);
 | 
| +      if (rA == 0) {  // Throw
 | 
| +        NativeArguments args(thread, 1, SP, SP + 1);
 | 
| +        INVOKE_RUNTIME(DRT_Throw, args);
 | 
| +      } else {  // ReThrow
 | 
| +        NativeArguments args(thread, 2, SP - 1, SP + 1);
 | 
| +        INVOKE_RUNTIME(DRT_ReThrow, args);
 | 
| +      }
 | 
| +    }
 | 
| +    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);
 | 
| +    FP[rA] = LOAD_CONSTANT(rD);
 | 
| +    DISPATCH();
 | 
| +  }
 | 
| +
 | 
| +  {
 | 
| +    BYTECODE(PushConstant, __D);
 | 
| +    *++SP = LOAD_CONSTANT(rD);
 | 
| +    DISPATCH();
 | 
| +  }
 | 
| +
 | 
| +  {
 | 
| +    BYTECODE(Push, A_X);
 | 
| +    *++SP = FP[rD];
 | 
| +    DISPATCH();
 | 
| +  }
 | 
| +
 | 
| +  {
 | 
| +    BYTECODE(Move, A_X);
 | 
| +    FP[rA] = FP[rD];
 | 
| +    DISPATCH();
 | 
| +  }
 | 
| +
 | 
| +  {
 | 
| +    BYTECODE(StoreLocal, A_X);
 | 
| +    FP[rD] = *SP;
 | 
| +    DISPATCH();
 | 
| +  }
 | 
| +
 | 
| +  {
 | 
| +    BYTECODE(PopLocal, A_X);
 | 
| +    FP[rD] = *SP--;
 | 
| +    DISPATCH();
 | 
| +  }
 | 
| +
 | 
| +  {
 | 
| +    BYTECODE(MoveSpecial, A_D);
 | 
| +    FP[rA] = special_[rD];
 | 
| +    DISPATCH();
 | 
| +  }
 | 
| +
 | 
| +  {
 | 
| +    BYTECODE(BooleanNegateTOS, 0);
 | 
| +    SP[0] = (SP[0] == true_value) ? false_value : true_value;
 | 
| +    DISPATCH();
 | 
| +  }
 | 
| +
 | 
| +  {
 | 
| +    BYTECODE(StaticCall, A_D);
 | 
| +
 | 
| +    // 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);
 | 
| +    }
 | 
| +
 | 
| +    // Invoke target function.
 | 
| +    {
 | 
| +      const uint16_t argc = rA;
 | 
| +      RawObject** call_base = SP - argc;
 | 
| +      RawObject** call_top = SP;  // *SP contains function
 | 
| +      argdesc = static_cast<RawArray*>(LOAD_CONSTANT(rD));
 | 
| +      Invoke(thread, call_base, call_top, &pp, &pc, &FP, &SP);
 | 
| +    }
 | 
| +
 | 
| +    DISPATCH();
 | 
| +  }
 | 
| +
 | 
| +  {
 | 
| +    BYTECODE(InstanceCall, A_D);
 | 
| +
 | 
| +    // 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);
 | 
| +    }
 | 
| +
 | 
| +    {
 | 
| +      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*>(LOAD_CONSTANT(kidx)),
 | 
| +                    call_base, call_top, &argdesc, &pp, &pc, &FP, &SP);
 | 
| +    }
 | 
| +
 | 
| +    DISPATCH();
 | 
| +  }
 | 
| +
 | 
| +  {
 | 
| +    BYTECODE(InstanceCall2, A_D);
 | 
| +    if (thread->isolate()->single_step()) {
 | 
| +      Exit(thread, FP, SP + 1, pc);
 | 
| +      NativeArguments args(thread, 0, NULL, NULL);
 | 
| +      INVOKE_RUNTIME(DRT_SingleStepHandler, args);
 | 
| +    }
 | 
| +
 | 
| +    {
 | 
| +      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*>(LOAD_CONSTANT(kidx)),
 | 
| +                    call_base, call_top, &argdesc, &pp, &pc, &FP, &SP);
 | 
| +    }
 | 
| +
 | 
| +    DISPATCH();
 | 
| +  }
 | 
| +
 | 
| +  {
 | 
| +    BYTECODE(InstanceCall3, A_D);
 | 
| +    if (thread->isolate()->single_step()) {
 | 
| +      Exit(thread, FP, SP + 1, pc);
 | 
| +      NativeArguments args(thread, 0, NULL, NULL);
 | 
| +      INVOKE_RUNTIME(DRT_SingleStepHandler, args);
 | 
| +    }
 | 
| +
 | 
| +    {
 | 
| +      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*>(LOAD_CONSTANT(kidx)),
 | 
| +                    call_base, call_top, &argdesc, &pp, &pc, &FP, &SP);
 | 
| +    }
 | 
| +
 | 
| +    DISPATCH();
 | 
| +  }
 | 
| +
 | 
| +  {
 | 
| +    BYTECODE(NativeBootstrapCall, 0);
 | 
| +    RawFunction* function = FrameFunction(FP);
 | 
| +    RawObject** incoming_args =
 | 
| +        (function->ptr()->num_optional_parameters_ == 0)
 | 
| +            ? FrameArguments(FP, function->ptr()->num_fixed_parameters_)
 | 
| +            : FP;
 | 
| +
 | 
| +    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, FP, SP + 1, pc);
 | 
| +    NativeArguments args(thread, argc_tag, incoming_args, SP - 1);
 | 
| +    INVOKE_NATIVE(native_target, args);
 | 
| +    SP -= 1;
 | 
| +    DISPATCH();
 | 
| +  }
 | 
| +
 | 
| +  {
 | 
| +    BYTECODE(NativeCall, 0);
 | 
| +    RawFunction* function = FrameFunction(FP);
 | 
| +    RawObject** incoming_args =
 | 
| +        (function->ptr()->num_optional_parameters_ == 0)
 | 
| +            ? FrameArguments(FP, function->ptr()->num_fixed_parameters_)
 | 
| +            : FP;
 | 
| +
 | 
| +    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, FP, SP + 1, pc);
 | 
| +    NativeArguments args(thread, argc_tag, incoming_args, SP - 1);
 | 
| +    INVOKE_NATIVE_WRAPPER(native_target, args);
 | 
| +    SP -= 1;
 | 
| +    DISPATCH();
 | 
| +  }
 | 
| +
 | 
| +  {
 | 
| +    BYTECODE(AddTOS, A_B_C);
 | 
| +    SMI_FASTPATH_TOS(intptr_t, SignedAddWithOverflow);
 | 
| +    DISPATCH();
 | 
| +  }
 | 
| +  {
 | 
| +    BYTECODE(SubTOS, A_B_C);
 | 
| +    SMI_FASTPATH_TOS(intptr_t, SignedSubWithOverflow);
 | 
| +    DISPATCH();
 | 
| +  }
 | 
| +  {
 | 
| +    BYTECODE(MulTOS, A_B_C);
 | 
| +    SMI_FASTPATH_TOS(intptr_t, SMI_MUL);
 | 
| +    DISPATCH();
 | 
| +  }
 | 
| +  {
 | 
| +    BYTECODE(BitOrTOS, A_B_C);
 | 
| +    SMI_FASTPATH_TOS(intptr_t, SMI_BITOR);
 | 
| +    DISPATCH();
 | 
| +  }
 | 
| +  {
 | 
| +    BYTECODE(BitAndTOS, A_B_C);
 | 
| +    SMI_FASTPATH_TOS(intptr_t, SMI_BITAND);
 | 
| +    DISPATCH();
 | 
| +  }
 | 
| +  {
 | 
| +    BYTECODE(EqualTOS, A_B_C);
 | 
| +    SMI_FASTPATH_TOS(RawObject*, SMI_EQ);
 | 
| +    DISPATCH();
 | 
| +  }
 | 
| +  {
 | 
| +    BYTECODE(LessThanTOS, A_B_C);
 | 
| +    SMI_FASTPATH_TOS(RawObject*, SMI_LT);
 | 
| +    DISPATCH();
 | 
| +  }
 | 
| +  {
 | 
| +    BYTECODE(GreaterThanTOS, A_B_C);
 | 
| +    SMI_FASTPATH_TOS(RawObject*, SMI_GT);
 | 
| +    DISPATCH();
 | 
| +  }
 | 
| +
 | 
| +  // Return and return like instructions (Instrinsic).
 | 
| +  {
 | 
| +    RawObject* result;  // result to return to the caller.
 | 
| +
 | 
| +    BYTECODE(Intrinsic, A);
 | 
| +    // Try invoking intrinsic handler. If it succeeds (returns true)
 | 
| +    // then just return the value it returned to the caller.
 | 
| +    result = null_value;
 | 
| +    if (!intrinsics_[rA](thread, FP, &result)) {
 | 
| +      DISPATCH();
 | 
| +    }
 | 
| +    goto ReturnImpl;
 | 
| +
 | 
| +    BYTECODE(Return, A);
 | 
| +    result = FP[rA];
 | 
| +    goto ReturnImpl;
 | 
| +
 | 
| +    BYTECODE(ReturnTOS, 0);
 | 
| +    result = *SP;
 | 
| +    // Fall through to the ReturnImpl.
 | 
| +
 | 
| +  ReturnImpl:
 | 
| +    // Restore caller PC.
 | 
| +    pc = SavedCallerPC(FP);
 | 
| +
 | 
| +    // Check if it is a fake PC marking the entry frame.
 | 
| +    if ((reinterpret_cast<uword>(pc) & 2) != 0) {
 | 
| +      const intptr_t argc = reinterpret_cast<uword>(pc) >> 2;
 | 
| +      fp_ = sp_ =
 | 
| +          reinterpret_cast<RawObject**>(FrameArguments(FP, argc + 1)[0]);
 | 
| +      thread->set_top_exit_frame_info(reinterpret_cast<uword>(sp_));
 | 
| +      thread->set_top_resource(top_resource);
 | 
| +      thread->set_vm_tag(vm_tag);
 | 
| +      return result;
 | 
| +    }
 | 
| +
 | 
| +    // Look at the caller to determine how many arguments to pop.
 | 
| +    const uint8_t argc = Bytecode::DecodeArgc(pc[-1]);
 | 
| +
 | 
| +    // Restore SP, FP and PP. Push result and dispatch.
 | 
| +    SP = FrameArguments(FP, argc);
 | 
| +    FP = SavedCallerFP(FP);
 | 
| +    pp = FrameCode(FP)->ptr()->object_pool_->ptr();
 | 
| +    *SP = result;
 | 
| +    DISPATCH();
 | 
| +  }
 | 
| +
 | 
| +  {
 | 
| +    BYTECODE(StoreStaticTOS, A_D);
 | 
| +    RawField* field = reinterpret_cast<RawField*>(LOAD_CONSTANT(rD));
 | 
| +    RawInstance* value = static_cast<RawInstance*>(*SP--);
 | 
| +    field->StorePointer(&field->ptr()->value_.static_value_, value);
 | 
| +    DISPATCH();
 | 
| +  }
 | 
| +
 | 
| +  {
 | 
| +    BYTECODE(PushStatic, A_D);
 | 
| +    RawField* field = reinterpret_cast<RawField*>(LOAD_CONSTANT(rD));
 | 
| +    // Note: field is also on the stack, hence no increment.
 | 
| +    *SP = field->ptr()->value_.static_value_;
 | 
| +    DISPATCH();
 | 
| +  }
 | 
| +
 | 
| +  {
 | 
| +    BYTECODE(StoreField, A_B_C);
 | 
| +    const uint16_t offset_in_words = rB;
 | 
| +    const uint16_t value_reg = rC;
 | 
| +
 | 
| +    RawInstance* instance = reinterpret_cast<RawInstance*>(FP[rA]);
 | 
| +    RawObject* value = reinterpret_cast<RawObject*>(FP[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;  // Drop instance and value.
 | 
| +    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*>(FP[instance_reg]);
 | 
| +    FP[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())) {
 | 
| +      // Note: SP[1] already contains the field object.
 | 
| +      SP[2] = 0;
 | 
| +      Exit(thread, FP, SP + 3, pc);
 | 
| +      NativeArguments args(thread, 1, SP + 1, SP + 2);
 | 
| +      INVOKE_RUNTIME(DRT_InitStaticField, args);
 | 
| +    }
 | 
| +    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, FP, SP + 2, pc);
 | 
| +      NativeArguments args(thread, 1, SP + 1, SP);
 | 
| +      INVOKE_RUNTIME(DRT_AllocateContext, args);
 | 
| +    }
 | 
| +    DISPATCH();
 | 
| +  }
 | 
| +
 | 
| +  {
 | 
| +    BYTECODE(CloneContext, A);
 | 
| +    {
 | 
| +      SP[1] = SP[0];  // Context to clone.
 | 
| +      Exit(thread, FP, SP + 2, pc);
 | 
| +      NativeArguments args(thread, 1, SP + 1, SP);
 | 
| +      INVOKE_RUNTIME(DRT_CloneContext, args);
 | 
| +    }
 | 
| +    DISPATCH();
 | 
| +  }
 | 
| +
 | 
| +  {
 | 
| +    BYTECODE(Allocate, A_D);
 | 
| +    SP[1] = 0;  // Space for the result.
 | 
| +    SP[2] = LOAD_CONSTANT(rD);  // Class object.
 | 
| +    SP[3] = null_value;  // Type arguments.
 | 
| +    Exit(thread, FP, SP + 4, pc);
 | 
| +    NativeArguments args(thread, 2, SP + 2, SP + 1);
 | 
| +    INVOKE_RUNTIME(DRT_AllocateObject, args);
 | 
| +    SP++;  // Result is in SP[1].
 | 
| +    DISPATCH();
 | 
| +  }
 | 
| +
 | 
| +  {
 | 
| +    BYTECODE(AllocateT, 0);
 | 
| +    SP[1] = SP[-0];  // Class object.
 | 
| +    SP[2] = SP[-1];  // Type arguments
 | 
| +    Exit(thread, FP, SP + 3, pc);
 | 
| +    NativeArguments args(thread, 2, SP + 1, SP - 1);
 | 
| +    INVOKE_RUNTIME(DRT_AllocateObject, args);
 | 
| +    SP -= 1;  // Result is in SP - 1.
 | 
| +    DISPATCH();
 | 
| +  }
 | 
| +
 | 
| +  {
 | 
| +    BYTECODE(CreateArrayTOS, 0);
 | 
| +    SP[1] = SP[-0];  // Length.
 | 
| +    SP[2] = SP[-1];  // Type.
 | 
| +    Exit(thread, FP, SP + 3, pc);
 | 
| +    NativeArguments args(thread, 2, SP + 1, SP - 1);
 | 
| +    INVOKE_RUNTIME(DRT_AllocateArray, args);
 | 
| +    SP -= 1;
 | 
| +    DISPATCH();
 | 
| +  }
 | 
| +
 | 
| +  {
 | 
| +    BYTECODE(AssertAssignable, A_D);  // Stack: instance, type args, type, name
 | 
| +    RawObject** args = SP - 3;
 | 
| +    if (args[0] != null_value) {
 | 
| +      RawSubtypeTestCache* cache =
 | 
| +          static_cast<RawSubtypeTestCache*>(LOAD_CONSTANT(rD));
 | 
| +      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, FP, SP + 6, pc);
 | 
| +      NativeArguments args(thread, 5, SP + 1, SP - 3);
 | 
| +      INVOKE_RUNTIME(DRT_TypeCheck, args);
 | 
| +    }
 | 
| +
 | 
| +  AssertAssignableOk:
 | 
| +    SP -= 3;
 | 
| +    DISPATCH();
 | 
| +  }
 | 
| +
 | 
| +  {
 | 
| +    BYTECODE(AssertBoolean, A);
 | 
| +    RawObject* value = SP[0];
 | 
| +    if (rA) {  // Should we perform type check?
 | 
| +      if ((value == true_value) || (value == false_value)) {
 | 
| +        goto AssertBooleanOk;
 | 
| +      }
 | 
| +    } else if (value != null_value) {
 | 
| +      goto AssertBooleanOk;
 | 
| +    }
 | 
| +
 | 
| +    // Assertion failed.
 | 
| +    {
 | 
| +      SP[1] = SP[0];  // instance
 | 
| +      Exit(thread, FP, SP + 2, pc);
 | 
| +      NativeArguments args(thread, 1, SP + 1, SP);
 | 
| +      INVOKE_RUNTIME(DRT_NonBoolTypeError, args);
 | 
| +    }
 | 
| +
 | 
| +  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, FP, SP + 1, pc);
 | 
| +      NativeArguments args(thread, 0, NULL, NULL);
 | 
| +      INVOKE_RUNTIME(DRT_SingleStepHandler, args);
 | 
| +    }
 | 
| +
 | 
| +    SP -= 2;
 | 
| +    if (!SimulatorHelpers::IsStrictEqualWithNumberCheck(SP[1], SP[2])) {
 | 
| +      pc++;
 | 
| +    }
 | 
| +    DISPATCH();
 | 
| +  }
 | 
| +
 | 
| +  {
 | 
| +    BYTECODE(IfNeStrictNumTOS, A_D);
 | 
| +    if (thread->isolate()->single_step()) {
 | 
| +      Exit(thread, FP, SP + 1, pc);
 | 
| +      NativeArguments args(thread, 0, NULL, NULL);
 | 
| +      INVOKE_RUNTIME(DRT_SingleStepHandler, args);
 | 
| +    }
 | 
| +
 | 
| +    SP -= 2;
 | 
| +    if (SimulatorHelpers::IsStrictEqualWithNumberCheck(SP[1], SP[2])) {
 | 
| +      pc++;
 | 
| +    }
 | 
| +    DISPATCH();
 | 
| +  }
 | 
| +
 | 
| +  {
 | 
| +    BYTECODE(Jump, 0);
 | 
| +    const int32_t target = static_cast<int32_t>(op) >> 8;
 | 
| +    pc += (target - 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();
 | 
| +  }
 | 
| +
 | 
| +  // Helper used to handle noSuchMethod on closures.
 | 
| +  {
 | 
| +  ClosureNoSuchMethod:
 | 
| +#if defined(DEBUG)
 | 
| +    function_h ^= FrameFunction(FP);
 | 
| +    ASSERT(function_h.IsClosureFunction());
 | 
| +#endif
 | 
| +
 | 
| +    // Restore caller context as we are going to throw NoSuchMethod.
 | 
| +    pc = SavedCallerPC(FP);
 | 
| +
 | 
| +    const bool has_dart_caller = (reinterpret_cast<uword>(pc) & 2) == 0;
 | 
| +    const intptr_t argc = has_dart_caller
 | 
| +                              ? Bytecode::DecodeArgc(pc[-1])
 | 
| +                              : (reinterpret_cast<uword>(pc) >> 2);
 | 
| +
 | 
| +    SP = FrameArguments(FP, 0);
 | 
| +    RawObject** args = SP - argc;
 | 
| +    FP = SavedCallerFP(FP);
 | 
| +    if (has_dart_caller) {
 | 
| +      pp = FrameCode(FP)->ptr()->object_pool_->ptr();
 | 
| +    }
 | 
| +
 | 
| +    *++SP = null_value;
 | 
| +    *++SP = args[0];  // Closure object.
 | 
| +    *++SP = argdesc;
 | 
| +    *++SP = null_value;  // Array of arguments (will be filled).
 | 
| +
 | 
| +    // Allocate array of arguments.
 | 
| +    {
 | 
| +      SP[1] = Smi::New(argc);  // length
 | 
| +      SP[2] = null_value;      // type
 | 
| +      Exit(thread, FP, SP + 3, pc);
 | 
| +      NativeArguments native_args(thread, 2, SP + 1, SP);
 | 
| +      INVOKE_RUNTIME(DRT_AllocateArray, native_args);
 | 
| +
 | 
| +      // Copy arguments into the newly allocated array.
 | 
| +      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];
 | 
| +      }
 | 
| +    }
 | 
| +
 | 
| +    // Invoke noSuchMethod passing down closure, argument descriptor and
 | 
| +    // array of arguments.
 | 
| +    {
 | 
| +      Exit(thread, FP, SP + 1, pc);
 | 
| +      NativeArguments native_args(thread, 3, SP - 2, SP - 3);
 | 
| +      INVOKE_RUNTIME(DRT_InvokeClosureNoSuchMethod, native_args);
 | 
| +      UNREACHABLE();
 | 
| +    }
 | 
| +
 | 
| +    DISPATCH();
 | 
| +  }
 | 
| +
 | 
| +  // Single dispatch point used by exception handling macros.
 | 
| +  {
 | 
| +  DispatchAfterException:
 | 
| +    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()->fp() > 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());
 | 
| +  sp_ = reinterpret_cast<RawObject**>(sp);
 | 
| +  fp_ = reinterpret_cast<RawObject**>(fp);
 | 
| +  pc_ = pc;
 | 
| +  special_[kExceptionSpecialIndex] = raw_exception;
 | 
| +  special_[kStacktraceSpecialIndex] = raw_stacktrace;
 | 
| +  buf->Longjmp();
 | 
| +  UNREACHABLE();
 | 
| +}
 | 
| +
 | 
| +}  // namespace dart
 | 
| +
 | 
| +
 | 
| +#endif  // defined TARGET_ARCH_DBC
 | 
| 
 |