OLD | NEW |
(Empty) | |
| 1 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. |
| 4 |
| 5 #include <setjmp.h> // NOLINT |
| 6 #include <stdlib.h> |
| 7 |
| 8 #include "vm/globals.h" |
| 9 #if defined(TARGET_ARCH_DBC) |
| 10 |
| 11 #if !defined(USING_SIMULATOR) |
| 12 #error "DBC is a simulated architecture" |
| 13 #endif |
| 14 |
| 15 #include "vm/simulator.h" |
| 16 |
| 17 #include "vm/assembler.h" |
| 18 #include "vm/compiler.h" |
| 19 #include "vm/constants_dbc.h" |
| 20 #include "vm/cpu.h" |
| 21 #include "vm/dart_entry.h" |
| 22 #include "vm/debugger.h" |
| 23 #include "vm/disassembler.h" |
| 24 #include "vm/lockers.h" |
| 25 #include "vm/native_arguments.h" |
| 26 #include "vm/native_entry.h" |
| 27 #include "vm/object.h" |
| 28 #include "vm/object_store.h" |
| 29 #include "vm/os_thread.h" |
| 30 #include "vm/stack_frame.h" |
| 31 |
| 32 namespace dart { |
| 33 |
| 34 DEFINE_FLAG(uint64_t, trace_sim_after, ULLONG_MAX, |
| 35 "Trace simulator execution after instruction count reached."); |
| 36 DEFINE_FLAG(uint64_t, stop_sim_at, ULLONG_MAX, |
| 37 "Instruction address or instruction count to stop simulator at."); |
| 38 |
| 39 // SimulatorSetjmpBuffer are linked together, and the last created one |
| 40 // is referenced by the Simulator. When an exception is thrown, the exception |
| 41 // runtime looks at where to jump and finds the corresponding |
| 42 // SimulatorSetjmpBuffer based on the stack pointer of the exception handler. |
| 43 // The runtime then does a Longjmp on that buffer to return to the simulator. |
| 44 class SimulatorSetjmpBuffer { |
| 45 public: |
| 46 void Longjmp() { |
| 47 // "This" is now the last setjmp buffer. |
| 48 simulator_->set_last_setjmp_buffer(this); |
| 49 longjmp(buffer_, 1); |
| 50 } |
| 51 |
| 52 explicit SimulatorSetjmpBuffer(Simulator* sim) { |
| 53 simulator_ = sim; |
| 54 link_ = sim->last_setjmp_buffer(); |
| 55 sim->set_last_setjmp_buffer(this); |
| 56 sp_ = sim->sp_; |
| 57 fp_ = sim->fp_; |
| 58 } |
| 59 |
| 60 ~SimulatorSetjmpBuffer() { |
| 61 ASSERT(simulator_->last_setjmp_buffer() == this); |
| 62 simulator_->set_last_setjmp_buffer(link_); |
| 63 } |
| 64 |
| 65 SimulatorSetjmpBuffer* link() const { return link_; } |
| 66 |
| 67 uword sp() const { return reinterpret_cast<uword>(sp_); } |
| 68 uword fp() const { return reinterpret_cast<uword>(fp_); } |
| 69 |
| 70 jmp_buf buffer_; |
| 71 |
| 72 private: |
| 73 RawObject** sp_; |
| 74 RawObject** fp_; |
| 75 Simulator* simulator_; |
| 76 SimulatorSetjmpBuffer* link_; |
| 77 |
| 78 friend class Simulator; |
| 79 |
| 80 DISALLOW_ALLOCATION(); |
| 81 DISALLOW_COPY_AND_ASSIGN(SimulatorSetjmpBuffer); |
| 82 }; |
| 83 |
| 84 |
| 85 DART_FORCE_INLINE static RawObject** SavedCallerFP(RawObject** FP) { |
| 86 return reinterpret_cast<RawObject**>(FP[kSavedCallerFpSlotFromFp]); |
| 87 } |
| 88 |
| 89 |
| 90 DART_FORCE_INLINE static RawCode* FrameCode(RawObject** FP) { |
| 91 return static_cast<RawCode*>(FP[kPcMarkerSlotFromFp]); |
| 92 } |
| 93 |
| 94 |
| 95 DART_FORCE_INLINE static void SetFrameCode(RawObject** FP, RawCode* code) { |
| 96 FP[kPcMarkerSlotFromFp] = code; |
| 97 } |
| 98 |
| 99 |
| 100 DART_FORCE_INLINE static RawObject** FrameArguments(RawObject** FP, |
| 101 intptr_t argc) { |
| 102 return FP - (kDartFrameFixedSize + argc); |
| 103 } |
| 104 |
| 105 |
| 106 class SimulatorHelpers { |
| 107 public: |
| 108 DART_FORCE_INLINE static RawSmi* GetClassIdAsSmi(RawObject* obj) { |
| 109 return Smi::New(obj->IsHeapObject() ? obj->GetClassId() : kSmiCid); |
| 110 } |
| 111 |
| 112 DART_FORCE_INLINE static intptr_t GetClassId(RawObject* obj) { |
| 113 return obj->IsHeapObject() ? obj->GetClassId() : kSmiCid; |
| 114 } |
| 115 |
| 116 DART_FORCE_INLINE static void IncrementUsageCounter(RawICData* icdata) { |
| 117 reinterpret_cast<RawFunction*>(icdata->ptr()->owner_) |
| 118 ->ptr() |
| 119 ->usage_counter_++; |
| 120 } |
| 121 |
| 122 DART_FORCE_INLINE static bool IsStrictEqualWithNumberCheck(RawObject* lhs, |
| 123 RawObject* rhs) { |
| 124 if (lhs == rhs) { |
| 125 return true; |
| 126 } |
| 127 |
| 128 if (lhs->IsHeapObject() && rhs->IsHeapObject()) { |
| 129 const intptr_t lhs_cid = lhs->GetClassId(); |
| 130 const intptr_t rhs_cid = rhs->GetClassId(); |
| 131 if (lhs_cid == rhs_cid) { |
| 132 switch (lhs_cid) { |
| 133 case kDoubleCid: |
| 134 return (bit_cast<uint64_t, double>( |
| 135 static_cast<RawDouble*>(lhs)->ptr()->value_) == |
| 136 bit_cast<uint64_t, double>( |
| 137 static_cast<RawDouble*>(rhs)->ptr()->value_)); |
| 138 |
| 139 case kMintCid: |
| 140 return (static_cast<RawMint*>(lhs)->ptr()->value_ == |
| 141 static_cast<RawMint*>(rhs)->ptr()->value_); |
| 142 |
| 143 case kBigintCid: |
| 144 return (DLRT_BigintCompare(static_cast<RawBigint*>(lhs), |
| 145 static_cast<RawBigint*>(rhs)) == 0); |
| 146 } |
| 147 } |
| 148 } |
| 149 |
| 150 return false; |
| 151 } |
| 152 |
| 153 template <typename T> |
| 154 DART_FORCE_INLINE static T* Untag(T* tagged) { |
| 155 return tagged->ptr(); |
| 156 } |
| 157 |
| 158 DART_FORCE_INLINE static bool CheckIndex(RawSmi* index, RawSmi* length) { |
| 159 return !index->IsHeapObject() && |
| 160 (reinterpret_cast<intptr_t>(index) >= 0) && |
| 161 (reinterpret_cast<intptr_t>(index) < |
| 162 reinterpret_cast<intptr_t>(length)); |
| 163 } |
| 164 |
| 165 static bool ObjectArraySetIndexed(Thread* thread, |
| 166 RawObject** FP, |
| 167 RawObject** result) { |
| 168 if (thread->isolate()->type_checks()) { |
| 169 return false; |
| 170 } |
| 171 |
| 172 RawObject** args = FrameArguments(FP, 3); |
| 173 RawSmi* index = static_cast<RawSmi*>(args[1]); |
| 174 RawArray* array = static_cast<RawArray*>(args[0]); |
| 175 if (CheckIndex(index, array->ptr()->length_)) { |
| 176 array->StorePointer(array->ptr()->data() + Smi::Value(index), args[2]); |
| 177 return true; |
| 178 } |
| 179 return false; |
| 180 } |
| 181 |
| 182 static bool ObjectArrayGetIndexed(Thread* thread, |
| 183 RawObject** FP, |
| 184 RawObject** result) { |
| 185 RawObject** args = FrameArguments(FP, 2); |
| 186 RawSmi* index = static_cast<RawSmi*>(args[1]); |
| 187 RawArray* array = static_cast<RawArray*>(args[0]); |
| 188 if (CheckIndex(index, array->ptr()->length_)) { |
| 189 *result = array->ptr()->data()[Smi::Value(index)]; |
| 190 return true; |
| 191 } |
| 192 return false; |
| 193 } |
| 194 |
| 195 static bool GrowableArraySetIndexed(Thread* thread, |
| 196 RawObject** FP, |
| 197 RawObject** result) { |
| 198 if (thread->isolate()->type_checks()) { |
| 199 return false; |
| 200 } |
| 201 |
| 202 RawObject** args = FrameArguments(FP, 3); |
| 203 RawSmi* index = static_cast<RawSmi*>(args[1]); |
| 204 RawGrowableObjectArray* array = |
| 205 static_cast<RawGrowableObjectArray*>(args[0]); |
| 206 if (CheckIndex(index, array->ptr()->length_)) { |
| 207 RawArray* data = array->ptr()->data_; |
| 208 data->StorePointer(data->ptr()->data() + Smi::Value(index), args[2]); |
| 209 return true; |
| 210 } |
| 211 return false; |
| 212 } |
| 213 |
| 214 static bool GrowableArrayGetIndexed(Thread* thread, |
| 215 RawObject** FP, |
| 216 RawObject** result) { |
| 217 RawObject** args = FrameArguments(FP, 2); |
| 218 RawSmi* index = static_cast<RawSmi*>(args[1]); |
| 219 RawGrowableObjectArray* array = |
| 220 static_cast<RawGrowableObjectArray*>(args[0]); |
| 221 if (CheckIndex(index, array->ptr()->length_)) { |
| 222 *result = array->ptr()->data_->ptr()->data()[Smi::Value(index)]; |
| 223 return true; |
| 224 } |
| 225 return false; |
| 226 } |
| 227 }; |
| 228 |
| 229 |
| 230 DART_FORCE_INLINE static uint32_t* SavedCallerPC(RawObject** FP) { |
| 231 return reinterpret_cast<uint32_t*>(FP[kSavedCallerPcSlotFromFp]); |
| 232 } |
| 233 |
| 234 |
| 235 DART_FORCE_INLINE static RawFunction* FrameFunction(RawObject** FP) { |
| 236 RawFunction* function = static_cast<RawFunction*>(FP[kFunctionSlotFromFp]); |
| 237 ASSERT(SimulatorHelpers::GetClassId(function) == kFunctionCid); |
| 238 return function; |
| 239 } |
| 240 |
| 241 |
| 242 IntrinsicHandler Simulator::intrinsics_[Simulator::kIntrinsicCount]; |
| 243 |
| 244 |
| 245 // Synchronization primitives support. |
| 246 void Simulator::InitOnce() { |
| 247 for (intptr_t i = 0; i < kIntrinsicCount; i++) { |
| 248 intrinsics_[i] = 0; |
| 249 } |
| 250 |
| 251 intrinsics_[kObjectArraySetIndexedIntrinsic] = |
| 252 SimulatorHelpers::ObjectArraySetIndexed; |
| 253 intrinsics_[kObjectArrayGetIndexedIntrinsic] = |
| 254 SimulatorHelpers::ObjectArrayGetIndexed; |
| 255 intrinsics_[kGrowableArraySetIndexedIntrinsic] = |
| 256 SimulatorHelpers::GrowableArraySetIndexed; |
| 257 intrinsics_[kGrowableArrayGetIndexedIntrinsic] = |
| 258 SimulatorHelpers::GrowableArrayGetIndexed; |
| 259 } |
| 260 |
| 261 |
| 262 Simulator::Simulator() |
| 263 : stack_(NULL), |
| 264 fp_(NULL), |
| 265 sp_(NULL) { |
| 266 // Setup simulator support first. Some of this information is needed to |
| 267 // setup the architecture state. |
| 268 // We allocate the stack here, the size is computed as the sum of |
| 269 // the size specified by the user and the buffer space needed for |
| 270 // handling stack overflow exceptions. To be safe in potential |
| 271 // stack underflows we also add some underflow buffer space. |
| 272 stack_ = new uintptr_t[(OSThread::GetSpecifiedStackSize() + |
| 273 OSThread::kStackSizeBuffer + |
| 274 kSimulatorStackUnderflowSize) / |
| 275 sizeof(uintptr_t)]; |
| 276 last_setjmp_buffer_ = NULL; |
| 277 top_exit_frame_info_ = 0; |
| 278 } |
| 279 |
| 280 |
| 281 Simulator::~Simulator() { |
| 282 delete[] stack_; |
| 283 Isolate* isolate = Isolate::Current(); |
| 284 if (isolate != NULL) { |
| 285 isolate->set_simulator(NULL); |
| 286 } |
| 287 } |
| 288 |
| 289 |
| 290 // Get the active Simulator for the current isolate. |
| 291 Simulator* Simulator::Current() { |
| 292 Simulator* simulator = Isolate::Current()->simulator(); |
| 293 if (simulator == NULL) { |
| 294 simulator = new Simulator(); |
| 295 Isolate::Current()->set_simulator(simulator); |
| 296 } |
| 297 return simulator; |
| 298 } |
| 299 |
| 300 |
| 301 // Returns the top of the stack area to enable checking for stack pointer |
| 302 // validity. |
| 303 uword Simulator::StackTop() const { |
| 304 // To be safe in potential stack underflows we leave some buffer above and |
| 305 // set the stack top. |
| 306 return StackBase() + |
| 307 (OSThread::GetSpecifiedStackSize() + OSThread::kStackSizeBuffer); |
| 308 } |
| 309 |
| 310 |
| 311 // Calls into the Dart runtime are based on this interface. |
| 312 typedef void (*SimulatorRuntimeCall)(NativeArguments arguments); |
| 313 |
| 314 // Calls to leaf Dart runtime functions are based on this interface. |
| 315 typedef int32_t (*SimulatorLeafRuntimeCall)(int32_t r0, |
| 316 int32_t r1, |
| 317 int32_t r2, |
| 318 int32_t r3); |
| 319 |
| 320 // Calls to leaf float Dart runtime functions are based on this interface. |
| 321 typedef double (*SimulatorLeafFloatRuntimeCall)(double d0, double d1); |
| 322 |
| 323 // Calls to native Dart functions are based on this interface. |
| 324 typedef void (*SimulatorBootstrapNativeCall)(NativeArguments* arguments); |
| 325 typedef void (*SimulatorNativeCall)(NativeArguments* arguments, uword target); |
| 326 |
| 327 |
| 328 void Simulator::Exit(Thread* thread, |
| 329 RawObject** base, |
| 330 RawObject** frame, |
| 331 uint32_t* pc) { |
| 332 frame[0] = Function::null(); |
| 333 frame[1] = Code::null(); |
| 334 frame[2] = reinterpret_cast<RawObject*>(pc); |
| 335 frame[3] = reinterpret_cast<RawObject*>(base); |
| 336 fp_ = sp_ = frame + kDartFrameFixedSize; |
| 337 thread->set_top_exit_frame_info(reinterpret_cast<uword>(sp_)); |
| 338 } |
| 339 |
| 340 |
| 341 #if defined(__has_builtin) |
| 342 #if __has_builtin(__builtin_smul_overflow) |
| 343 #define HAS_MUL_OVERFLOW |
| 344 #endif |
| 345 #if __has_builtin(__builtin_sadd_overflow) |
| 346 #define HAS_ADD_OVERFLOW |
| 347 #endif |
| 348 #if __has_builtin(__builtin_ssub_overflow) |
| 349 #define HAS_SUB_OVERFLOW |
| 350 #endif |
| 351 #endif |
| 352 |
| 353 |
| 354 DART_FORCE_INLINE static bool SignedAddWithOverflow(int32_t lhs, |
| 355 int32_t rhs, |
| 356 intptr_t* out) { |
| 357 int32_t res = 1; |
| 358 #if defined(HAS_ADD_OVERFLOW) |
| 359 res = static_cast<int32_t>(__builtin_sadd_overflow(lhs, rhs, out)); |
| 360 #elif defined(__i386__) |
| 361 asm volatile( |
| 362 "add %2, %1\n" |
| 363 "jo 1f;\n" |
| 364 "xor %0, %0\n" |
| 365 "mov %1, 0(%3)\n" |
| 366 "1: " |
| 367 : "+r"(res), "+r"(lhs) |
| 368 : "r"(rhs), "r"(out) |
| 369 : "cc"); |
| 370 #elif defined(__arm__) |
| 371 asm volatile( |
| 372 "adds %1, %1, %2;\n" |
| 373 "bvs 1f;\n" |
| 374 "mov %0, $0;\n" |
| 375 "str %1, [%3, #0]\n" |
| 376 "1:" |
| 377 : "+r"(res), "+r"(lhs) |
| 378 : "r"(rhs), "r"(out) |
| 379 : "cc", "r12"); |
| 380 #else |
| 381 #error "Unsupported platform" |
| 382 #endif |
| 383 return (res != 0); |
| 384 } |
| 385 |
| 386 |
| 387 DART_FORCE_INLINE static bool SignedSubWithOverflow(int32_t lhs, |
| 388 int32_t rhs, |
| 389 intptr_t* out) { |
| 390 int32_t res = 1; |
| 391 #if defined(HAS_SUB_OVERFLOW) |
| 392 res = static_cast<int32_t>(__builtin_ssub_overflow(lhs, rhs, out)); |
| 393 #elif defined(__i386__) |
| 394 asm volatile( |
| 395 "sub %2, %1\n" |
| 396 "jo 1f;\n" |
| 397 "xor %0, %0\n" |
| 398 "mov %1, 0(%3)\n" |
| 399 "1: " |
| 400 : "+r"(res), "+r"(lhs) |
| 401 : "r"(rhs), "r"(out) |
| 402 : "cc"); |
| 403 #elif defined(__arm__) |
| 404 asm volatile( |
| 405 "subs %1, %1, %2;\n" |
| 406 "bvs 1f;\n" |
| 407 "mov %0, $0;\n" |
| 408 "str %1, [%3, #0]\n" |
| 409 "1:" |
| 410 : "+r"(res), "+r"(lhs) |
| 411 : "r"(rhs), "r"(out) |
| 412 : "cc", "r12"); |
| 413 #else |
| 414 #error "Unsupported platform" |
| 415 #endif |
| 416 return (res != 0); |
| 417 } |
| 418 |
| 419 |
| 420 DART_FORCE_INLINE static bool SignedMulWithOverflow(int32_t lhs, |
| 421 int32_t rhs, |
| 422 intptr_t* out) { |
| 423 int32_t res = 1; |
| 424 #if defined(HAS_MUL_OVERFLOW) |
| 425 res = static_cast<int32_t>(__builtin_smul_overflow(lhs, rhs, out)); |
| 426 #elif defined(__i386__) |
| 427 asm volatile( |
| 428 "imul %2, %1\n" |
| 429 "jo 1f;\n" |
| 430 "xor %0, %0\n" |
| 431 "mov %1, 0(%3)\n" |
| 432 "1: " |
| 433 : "+r"(res), "+r"(lhs) |
| 434 : "r"(rhs), "r"(out) |
| 435 : "cc"); |
| 436 #elif defined(__arm__) |
| 437 asm volatile( |
| 438 "smull %1, ip, %1, %2;\n" |
| 439 "cmp ip, %1, ASR #31;\n" |
| 440 "bne 1f;\n" |
| 441 "mov %0, $0;\n" |
| 442 "str %1, [%3, #0]\n" |
| 443 "1:" |
| 444 : "+r"(res), "+r"(lhs) |
| 445 : "r"(rhs), "r"(out) |
| 446 : "cc", "r12"); |
| 447 #else |
| 448 #error "Unsupported platform" |
| 449 #endif |
| 450 return (res != 0); |
| 451 } |
| 452 |
| 453 |
| 454 #define LIKELY(cond) __builtin_expect((cond), 1) |
| 455 |
| 456 |
| 457 DART_FORCE_INLINE static bool AreBothSmis(intptr_t a, intptr_t b) { |
| 458 return ((a | b) & kHeapObjectTag) == 0; |
| 459 } |
| 460 |
| 461 |
| 462 #define SMI_MUL(lhs, rhs, pres) SignedMulWithOverflow((lhs), (rhs) >> 1, pres) |
| 463 #define SMI_COND(cond, lhs, rhs, pres) \ |
| 464 ((*(pres) = ((lhs cond rhs) ? true_value : false_value)), false) |
| 465 #define SMI_EQ(lhs, rhs, pres) SMI_COND(==, lhs, rhs, pres) |
| 466 #define SMI_LT(lhs, rhs, pres) SMI_COND(<, lhs, rhs, pres) |
| 467 #define SMI_GT(lhs, rhs, pres) SMI_COND(>, lhs, rhs, pres) |
| 468 #define SMI_BITOR(lhs, rhs, pres) ((*(pres) = (lhs | rhs)), false) |
| 469 #define SMI_BITAND(lhs, rhs, pres) ((*(pres) = (lhs & rhs)), false) |
| 470 |
| 471 |
| 472 void Simulator::CallRuntime(Thread* thread, |
| 473 RawObject** base, |
| 474 RawObject** exit_frame, |
| 475 uint32_t* pc, |
| 476 intptr_t argc_tag, |
| 477 RawObject** args, |
| 478 RawObject** result, |
| 479 uword target) { |
| 480 Exit(thread, base, exit_frame, pc); |
| 481 NativeArguments native_args(thread, argc_tag, args, result); |
| 482 reinterpret_cast<RuntimeFunction>(target)(native_args); |
| 483 } |
| 484 |
| 485 |
| 486 DART_FORCE_INLINE void Simulator::Invoke(Thread* thread, |
| 487 RawObject** call_base, |
| 488 RawObject** call_top, |
| 489 RawObjectPool** pp, |
| 490 uint32_t** pc, |
| 491 RawObject*** FP, |
| 492 RawObject*** SP) { |
| 493 RawObject** callee_fp = call_top + kDartFrameFixedSize; |
| 494 |
| 495 RawFunction* function = FrameFunction(callee_fp); |
| 496 RawCode* code = function->ptr()->code_; |
| 497 callee_fp[kPcMarkerSlotFromFp] = code; |
| 498 callee_fp[kSavedCallerPcSlotFromFp] = reinterpret_cast<RawObject*>(*pc); |
| 499 callee_fp[kSavedCallerFpSlotFromFp] = reinterpret_cast<RawObject*>(*FP); |
| 500 *pp = code->ptr()->object_pool_->ptr(); |
| 501 *pc = reinterpret_cast<uint32_t*>(code->ptr()->entry_point_); |
| 502 *FP = callee_fp; |
| 503 *SP = *FP - 1; |
| 504 } |
| 505 |
| 506 |
| 507 void Simulator::InlineCacheMiss(int checked_args, |
| 508 Thread* thread, |
| 509 RawICData* icdata, |
| 510 RawObject** args, |
| 511 RawObject** top, |
| 512 uint32_t* pc, |
| 513 RawObject** FP, |
| 514 RawObject** SP) { |
| 515 RawObject** result = top; |
| 516 RawObject** miss_handler_args = top + 1; |
| 517 for (intptr_t i = 0; i < checked_args; i++) { |
| 518 miss_handler_args[i] = args[i]; |
| 519 } |
| 520 miss_handler_args[checked_args] = icdata; |
| 521 RuntimeFunction handler = NULL; |
| 522 switch (checked_args) { |
| 523 case 1: |
| 524 handler = DRT_InlineCacheMissHandlerOneArg; |
| 525 break; |
| 526 case 2: |
| 527 handler = DRT_InlineCacheMissHandlerTwoArgs; |
| 528 break; |
| 529 case 3: |
| 530 handler = DRT_InlineCacheMissHandlerThreeArgs; |
| 531 break; |
| 532 default: |
| 533 UNREACHABLE(); |
| 534 break; |
| 535 } |
| 536 |
| 537 // Handler arguments: arguments to check and an ICData object. |
| 538 const intptr_t miss_handler_argc = checked_args + 1; |
| 539 RawObject** exit_frame = miss_handler_args + miss_handler_argc; |
| 540 CallRuntime(thread, |
| 541 FP, |
| 542 exit_frame, |
| 543 pc, |
| 544 miss_handler_argc, |
| 545 miss_handler_args, |
| 546 result, |
| 547 reinterpret_cast<uword>(handler)); |
| 548 } |
| 549 |
| 550 |
| 551 DART_FORCE_INLINE void Simulator::InstanceCall1(Thread* thread, |
| 552 RawICData* icdata, |
| 553 RawObject** call_base, |
| 554 RawObject** top, |
| 555 RawArray** argdesc, |
| 556 RawObjectPool** pp, |
| 557 uint32_t** pc, |
| 558 RawObject*** FP, |
| 559 RawObject*** SP) { |
| 560 ASSERT(icdata->GetClassId() == kICDataCid); |
| 561 SimulatorHelpers::IncrementUsageCounter(icdata); |
| 562 |
| 563 const intptr_t kCheckedArgs = 1; |
| 564 RawObject** args = call_base; |
| 565 RawArray* cache = icdata->ptr()->ic_data_->ptr(); |
| 566 |
| 567 RawSmi* receiver_cid = SimulatorHelpers::GetClassIdAsSmi(args[0]); |
| 568 |
| 569 bool found = false; |
| 570 const intptr_t length = Smi::Value(cache->length_); |
| 571 for (intptr_t i = 0; |
| 572 i < (length - (kCheckedArgs + 2)); i += (kCheckedArgs + 2)) { |
| 573 if (cache->data()[i + 0] == receiver_cid) { |
| 574 top[0] = cache->data()[i + kCheckedArgs]; |
| 575 found = true; |
| 576 break; |
| 577 } |
| 578 } |
| 579 |
| 580 if (!found) { |
| 581 InlineCacheMiss( |
| 582 kCheckedArgs, thread, icdata, call_base, top, *pc, *FP, *SP); |
| 583 } |
| 584 |
| 585 *argdesc = icdata->ptr()->args_descriptor_; |
| 586 Invoke(thread, call_base, top, pp, pc, FP, SP); |
| 587 } |
| 588 |
| 589 |
| 590 DART_FORCE_INLINE void Simulator::InstanceCall2(Thread* thread, |
| 591 RawICData* icdata, |
| 592 RawObject** call_base, |
| 593 RawObject** top, |
| 594 RawArray** argdesc, |
| 595 RawObjectPool** pp, |
| 596 uint32_t** pc, |
| 597 RawObject*** FP, |
| 598 RawObject*** SP) { |
| 599 ASSERT(icdata->GetClassId() == kICDataCid); |
| 600 SimulatorHelpers::IncrementUsageCounter(icdata); |
| 601 |
| 602 const intptr_t kCheckedArgs = 2; |
| 603 RawObject** args = call_base; |
| 604 RawArray* cache = icdata->ptr()->ic_data_->ptr(); |
| 605 |
| 606 RawSmi* receiver_cid = SimulatorHelpers::GetClassIdAsSmi(args[0]); |
| 607 RawSmi* arg0_cid = SimulatorHelpers::GetClassIdAsSmi(args[1]); |
| 608 |
| 609 bool found = false; |
| 610 const intptr_t length = Smi::Value(cache->length_); |
| 611 for (intptr_t i = 0; |
| 612 i < (length - (kCheckedArgs + 2)); i += (kCheckedArgs + 2)) { |
| 613 if ((cache->data()[i + 0] == receiver_cid) && |
| 614 (cache->data()[i + 1] == arg0_cid)) { |
| 615 top[0] = cache->data()[i + kCheckedArgs]; |
| 616 found = true; |
| 617 break; |
| 618 } |
| 619 } |
| 620 |
| 621 if (!found) { |
| 622 InlineCacheMiss( |
| 623 kCheckedArgs, thread, icdata, call_base, top, *pc, *FP, *SP); |
| 624 } |
| 625 |
| 626 *argdesc = icdata->ptr()->args_descriptor_; |
| 627 Invoke(thread, call_base, top, pp, pc, FP, SP); |
| 628 } |
| 629 |
| 630 |
| 631 DART_FORCE_INLINE void Simulator::InstanceCall3(Thread* thread, |
| 632 RawICData* icdata, |
| 633 RawObject** call_base, |
| 634 RawObject** top, |
| 635 RawArray** argdesc, |
| 636 RawObjectPool** pp, |
| 637 uint32_t** pc, |
| 638 RawObject*** FP, |
| 639 RawObject*** SP) { |
| 640 ASSERT(icdata->GetClassId() == kICDataCid); |
| 641 SimulatorHelpers::IncrementUsageCounter(icdata); |
| 642 |
| 643 const intptr_t kCheckedArgs = 3; |
| 644 RawObject** args = call_base; |
| 645 RawArray* cache = icdata->ptr()->ic_data_->ptr(); |
| 646 |
| 647 RawSmi* receiver_cid = SimulatorHelpers::GetClassIdAsSmi(args[0]); |
| 648 RawSmi* arg0_cid = SimulatorHelpers::GetClassIdAsSmi(args[1]); |
| 649 RawSmi* arg1_cid = SimulatorHelpers::GetClassIdAsSmi(args[2]); |
| 650 |
| 651 bool found = false; |
| 652 const intptr_t length = Smi::Value(cache->length_); |
| 653 for (intptr_t i = 0; |
| 654 i < (length - (kCheckedArgs + 2)); i += (kCheckedArgs + 2)) { |
| 655 if ((cache->data()[i + 0] == receiver_cid) && |
| 656 (cache->data()[i + 1] == arg0_cid) && |
| 657 (cache->data()[i + 2] == arg1_cid)) { |
| 658 top[0] = cache->data()[i + kCheckedArgs]; |
| 659 found = true; |
| 660 break; |
| 661 } |
| 662 } |
| 663 |
| 664 if (!found) { |
| 665 InlineCacheMiss( |
| 666 kCheckedArgs, thread, icdata, call_base, top, *pc, *FP, *SP); |
| 667 } |
| 668 |
| 669 *argdesc = icdata->ptr()->args_descriptor_; |
| 670 Invoke(thread, call_base, top, pp, pc, FP, SP); |
| 671 } |
| 672 |
| 673 |
| 674 // Note: functions below are marked DART_NOINLINE to recover performance on |
| 675 // ARM where inlining these functions into the interpreter loop seemed to cause |
| 676 // some code quality issues. |
| 677 static DART_NOINLINE bool InvokeRuntime( |
| 678 Thread* thread, |
| 679 Simulator* sim, |
| 680 RuntimeFunction drt, |
| 681 const NativeArguments& args) { |
| 682 SimulatorSetjmpBuffer buffer(sim); |
| 683 if (!setjmp(buffer.buffer_)) { |
| 684 thread->set_vm_tag(reinterpret_cast<uword>(drt)); |
| 685 drt(args); |
| 686 thread->set_vm_tag(VMTag::kDartTagId); |
| 687 return true; |
| 688 } else { |
| 689 return false; |
| 690 } |
| 691 } |
| 692 |
| 693 |
| 694 static DART_NOINLINE bool InvokeNative( |
| 695 Thread* thread, |
| 696 Simulator* sim, |
| 697 SimulatorBootstrapNativeCall f, |
| 698 NativeArguments* args) { |
| 699 SimulatorSetjmpBuffer buffer(sim); |
| 700 if (!setjmp(buffer.buffer_)) { |
| 701 thread->set_vm_tag(reinterpret_cast<uword>(f)); |
| 702 f(args); |
| 703 thread->set_vm_tag(VMTag::kDartTagId); |
| 704 return true; |
| 705 } else { |
| 706 return false; |
| 707 } |
| 708 } |
| 709 |
| 710 |
| 711 static DART_NOINLINE bool InvokeNativeWrapper( |
| 712 Thread* thread, |
| 713 Simulator* sim, |
| 714 Dart_NativeFunction f, |
| 715 NativeArguments* args) { |
| 716 SimulatorSetjmpBuffer buffer(sim); |
| 717 if (!setjmp(buffer.buffer_)) { |
| 718 thread->set_vm_tag(reinterpret_cast<uword>(f)); |
| 719 NativeEntry::NativeCallWrapper(reinterpret_cast<Dart_NativeArguments>(args), |
| 720 f); |
| 721 thread->set_vm_tag(VMTag::kDartTagId); |
| 722 return true; |
| 723 } else { |
| 724 return false; |
| 725 } |
| 726 } |
| 727 |
| 728 // Note: all macro helpers are intended to be used only inside Simulator::Call. |
| 729 |
| 730 // Decode opcode and A part of the given value and dispatch to the |
| 731 // corresponding bytecode handler. |
| 732 #define DISPATCH_OP(val) \ |
| 733 do { \ |
| 734 op = (val); \ |
| 735 rA = ((op >> 8) & 0xFF); \ |
| 736 goto* dispatch[op & 0xFF]; \ |
| 737 } while (0) |
| 738 |
| 739 // Fetch next operation from PC, increment program counter and dispatch. |
| 740 #define DISPATCH() DISPATCH_OP(*pc++) |
| 741 |
| 742 // Define entry point that handles bytecode Name with the given operand format. |
| 743 #define BYTECODE(Name, Operands) \ |
| 744 BYTECODE_HEADER(Name, DECLARE_##Operands, DECODE_##Operands) |
| 745 |
| 746 #define BYTECODE_HEADER(Name, Declare, Decode) \ |
| 747 Declare; \ |
| 748 bc##Name : Decode \ |
| 749 |
| 750 // Helpers to decode common instruction formats. Used in conjunction with |
| 751 // BYTECODE() macro. |
| 752 #define DECLARE_A_B_C uint16_t rB, rC; USE(rB); USE(rC) |
| 753 #define DECODE_A_B_C \ |
| 754 rB = ((op >> Bytecode::kBShift) & Bytecode::kBMask); \ |
| 755 rC = ((op >> Bytecode::kCShift) & Bytecode::kCMask); |
| 756 |
| 757 #define DECLARE_0 |
| 758 #define DECODE_0 |
| 759 |
| 760 #define DECLARE_A |
| 761 #define DECODE_A |
| 762 |
| 763 #define DECLARE___D uint32_t rD; USE(rD) |
| 764 #define DECODE___D rD = (op >> Bytecode::kDShift); |
| 765 |
| 766 #define DECLARE_A_D DECLARE___D |
| 767 #define DECODE_A_D DECODE___D |
| 768 |
| 769 #define DECLARE_A_X int32_t rD; USE(rD) |
| 770 #define DECODE_A_X rD = (static_cast<int32_t>(op) >> Bytecode::kDShift); |
| 771 |
| 772 // Declare bytecode handler for a smi operation (e.g. AddTOS) with the |
| 773 // given result type and the given behavior specified as a function |
| 774 // that takes left and right operands and result slot and returns |
| 775 // true if fast-path succeeds. |
| 776 #define SMI_FASTPATH_TOS(ResultT, Func) \ |
| 777 { \ |
| 778 const intptr_t lhs = reinterpret_cast<intptr_t>(SP[-1]); \ |
| 779 const intptr_t rhs = reinterpret_cast<intptr_t>(SP[-0]); \ |
| 780 ResultT* slot = reinterpret_cast<ResultT*>(SP - 1); \ |
| 781 if (LIKELY(AreBothSmis(lhs, rhs) && !Func(lhs, rhs, slot))) { \ |
| 782 /* Fast path succeeded. Skip the generic call that follows. */ \ |
| 783 pc++; \ |
| 784 /* We dropped 2 arguments and push result */ \ |
| 785 SP--; \ |
| 786 } \ |
| 787 } |
| 788 |
| 789 // Exception handling helper. Gets handler FP and PC from the Simulator where |
| 790 // they were stored by Simulator::Longjmp and proceeds to execute the handler. |
| 791 // Corner case: handler PC can be a fake marker that marks entry frame, which |
| 792 // means exception was not handled in the Dart code. In this case we return |
| 793 // caught exception from Simulator::Call. |
| 794 #define HANDLE_EXCEPTION \ |
| 795 do { \ |
| 796 FP = reinterpret_cast<RawObject**>(fp_); \ |
| 797 pc = reinterpret_cast<uint32_t*>(pc_); \ |
| 798 if ((reinterpret_cast<uword>(pc) & 2) != 0) { /* Entry frame? */ \ |
| 799 fp_ = sp_ = reinterpret_cast<RawObject**>(fp_[0]); \ |
| 800 thread->set_top_exit_frame_info(reinterpret_cast<uword>(sp_)); \ |
| 801 thread->set_top_resource(top_resource); \ |
| 802 thread->set_vm_tag(vm_tag); \ |
| 803 return special_[kExceptionSpecialIndex]; \ |
| 804 } \ |
| 805 pp = FrameCode(FP)->ptr()->object_pool_->ptr(); \ |
| 806 goto DispatchAfterException; \ |
| 807 } while (0) \ |
| 808 |
| 809 // Runtime call helpers: handle invocation and potential exception after return. |
| 810 #define INVOKE_RUNTIME(Func, Args) \ |
| 811 if (!InvokeRuntime(thread, this, Func, Args)) { \ |
| 812 HANDLE_EXCEPTION; \ |
| 813 } \ |
| 814 |
| 815 #define INVOKE_NATIVE(Func, Args) \ |
| 816 if (!InvokeNative(thread, this, Func, &Args)) { \ |
| 817 HANDLE_EXCEPTION; \ |
| 818 } \ |
| 819 |
| 820 #define INVOKE_NATIVE_WRAPPER(Func, Args) \ |
| 821 if (!InvokeNativeWrapper(thread, this, Func, &Args)) { \ |
| 822 HANDLE_EXCEPTION; \ |
| 823 } \ |
| 824 |
| 825 #define LOAD_CONSTANT(index) (pp->data()[(index)].raw_obj_) |
| 826 |
| 827 RawObject* Simulator::Call(const Code& code, |
| 828 const Array& arguments_descriptor, |
| 829 const Array& arguments, |
| 830 Thread* thread) { |
| 831 // Dispatch used to interpret bytecode. Contains addresses of |
| 832 // labels of bytecode handlers. Handlers themselves are defined below. |
| 833 static const void* dispatch[] = { |
| 834 #define TARGET(name, fmt, fmta, fmtb, fmtc) &&bc##name, |
| 835 BYTECODES_LIST(TARGET) |
| 836 #undef TARGET |
| 837 }; |
| 838 |
| 839 // Interpreter state (see constants_dbc.h for high-level overview). |
| 840 uint32_t* pc; // Program Counter: points to the next op to execute. |
| 841 RawObjectPool* pp; // Pool Pointer. |
| 842 RawObject** FP; // Frame Pointer. |
| 843 RawObject** SP; // Stack Pointer. |
| 844 |
| 845 RawArray* argdesc; // Arguments Descriptor: used to pass information between |
| 846 // call instruction and the function entry. |
| 847 |
| 848 uint32_t op; // Currently executing op. |
| 849 uint16_t rA; // A component of the currently executing op. |
| 850 |
| 851 if (sp_ == NULL) { |
| 852 fp_ = sp_ = reinterpret_cast<RawObject**>(stack_); |
| 853 } |
| 854 |
| 855 // Save current VM tag and mark thread as executing Dart code. |
| 856 const uword vm_tag = thread->vm_tag(); |
| 857 thread->set_vm_tag(VMTag::kDartTagId); |
| 858 |
| 859 // Save current top stack resource and reset the list. |
| 860 StackResource* top_resource = thread->top_resource(); |
| 861 thread->set_top_resource(NULL); |
| 862 |
| 863 // Setup entry frame: |
| 864 // |
| 865 // ^ |
| 866 // | previous Dart frames |
| 867 // ~~~~~~~~~~~~~~~ | |
| 868 // | ........... | -+ |
| 869 // fp_ > | | saved top_exit_frame_info |
| 870 // | arg 0 | -+ |
| 871 // ~~~~~~~~~~~~~~~ | |
| 872 // > incoming arguments |
| 873 // ~~~~~~~~~~~~~~~ | |
| 874 // | arg 1 | -+ |
| 875 // | function | -+ |
| 876 // | code | | |
| 877 // | callee PC | ---> special fake PC marking an entry frame |
| 878 // SP > | fp_ | | |
| 879 // FP > | ........... | > normal Dart frame (see stack_frame_dbc.h) |
| 880 // | |
| 881 // v |
| 882 // |
| 883 FP = fp_ + 1 + arguments.Length() + kDartFrameFixedSize; |
| 884 SP = FP - 1; |
| 885 |
| 886 // Save outer top_exit_frame_info. |
| 887 fp_[0] = reinterpret_cast<RawObject*>(thread->top_exit_frame_info()); |
| 888 |
| 889 // Copy arguments and setup the Dart frame. |
| 890 const intptr_t argc = arguments.Length(); |
| 891 for (intptr_t i = 0; i < argc; i++) { |
| 892 fp_[1 + i] = arguments.At(i); |
| 893 } |
| 894 |
| 895 FP[kFunctionSlotFromFp] = code.function(); |
| 896 FP[kPcMarkerSlotFromFp] = code.raw(); |
| 897 FP[kSavedCallerPcSlotFromFp] = reinterpret_cast<RawObject*>((argc << 2) | 2); |
| 898 FP[kSavedCallerFpSlotFromFp] = reinterpret_cast<RawObject*>(fp_); |
| 899 |
| 900 // Load argument descriptor. |
| 901 argdesc = arguments_descriptor.raw(); |
| 902 |
| 903 // Ready to start executing bytecode. Load entry point and corresponding |
| 904 // object pool. |
| 905 pc = reinterpret_cast<uint32_t*>(code.raw()->ptr()->entry_point_); |
| 906 pp = code.object_pool()->ptr(); |
| 907 |
| 908 // Cache some frequently used values in the frame. |
| 909 RawBool* true_value = Bool::True().raw(); |
| 910 RawBool* false_value = Bool::False().raw(); |
| 911 RawObject* null_value = Object::null(); |
| 912 RawObject* empty_context = thread->isolate()->object_store()->empty_context(); |
| 913 |
| 914 #if defined(DEBUG) |
| 915 Function& function_h = Function::Handle(); |
| 916 #endif |
| 917 |
| 918 // Enter the dispatch loop. |
| 919 DISPATCH(); |
| 920 |
| 921 // Bytecode handlers (see constants_dbc.h for bytecode descriptions). |
| 922 { |
| 923 BYTECODE(Entry, A_B_C); |
| 924 const uint8_t num_fixed_params = rA; |
| 925 const uint16_t num_locals = rB; |
| 926 const uint16_t context_reg = rC; |
| 927 |
| 928 // Decode arguments descriptor. |
| 929 const intptr_t pos_count = Smi::Value(*reinterpret_cast<RawSmi**>( |
| 930 reinterpret_cast<uword>(argdesc->ptr()) + |
| 931 Array::element_offset(ArgumentsDescriptor::kPositionalCountIndex))); |
| 932 |
| 933 // Check that we got the right number of positional parameters. |
| 934 if (pos_count != num_fixed_params) { |
| 935 // Mismatch can only occur if current function is a closure. |
| 936 goto ClosureNoSuchMethod; |
| 937 } |
| 938 |
| 939 // Initialize locals with null and set current context variable to |
| 940 // empty context. |
| 941 { |
| 942 RawObject** L = FP; |
| 943 for (intptr_t i = 0; i < num_locals; i++) { |
| 944 L[i] = null_value; |
| 945 } |
| 946 L[context_reg] = empty_context; |
| 947 SP = FP + num_locals - 1; |
| 948 } |
| 949 |
| 950 DISPATCH(); |
| 951 } |
| 952 |
| 953 { |
| 954 BYTECODE(EntryOpt, A_B_C); |
| 955 const uint16_t num_fixed_params = rA; |
| 956 const uint16_t num_opt_pos_params = rB; |
| 957 const uint16_t num_opt_named_params = rC; |
| 958 const intptr_t min_num_pos_args = num_fixed_params; |
| 959 const intptr_t max_num_pos_args = num_fixed_params + num_opt_pos_params; |
| 960 |
| 961 // Decode arguments descriptor. |
| 962 const intptr_t arg_count = Smi::Value(*reinterpret_cast<RawSmi**>( |
| 963 reinterpret_cast<uword>(argdesc->ptr()) + |
| 964 Array::element_offset(ArgumentsDescriptor::kCountIndex))); |
| 965 const intptr_t pos_count = Smi::Value(*reinterpret_cast<RawSmi**>( |
| 966 reinterpret_cast<uword>(argdesc->ptr()) + |
| 967 Array::element_offset(ArgumentsDescriptor::kPositionalCountIndex))); |
| 968 const intptr_t named_count = (arg_count - pos_count); |
| 969 |
| 970 // Check that got the right number of positional parameters. |
| 971 if ((min_num_pos_args > pos_count) || (pos_count > max_num_pos_args)) { |
| 972 goto ClosureNoSuchMethod; |
| 973 } |
| 974 |
| 975 // Copy all passed position arguments. |
| 976 RawObject** first_arg = FrameArguments(FP, arg_count); |
| 977 memmove(FP, first_arg, pos_count * kWordSize); |
| 978 |
| 979 if (num_opt_named_params != 0) { |
| 980 // This is a function with named parameters. |
| 981 // Walk the list of named parameters and their |
| 982 // default values encoded as pairs of LoadConstant instructions that |
| 983 // follows the entry point and find matching values via arguments |
| 984 // descriptor. |
| 985 RawObject** argdesc_data = argdesc->ptr()->data(); |
| 986 |
| 987 intptr_t i = named_count - 1; // argument position |
| 988 intptr_t j = num_opt_named_params - 1; // parameter position |
| 989 while ((j >= 0) && (i >= 0)) { |
| 990 // Fetch formal parameter information: name, default value, target slot. |
| 991 const uint32_t load_name = pc[2 * j]; |
| 992 const uint32_t load_value = pc[2 * j + 1]; |
| 993 ASSERT(Bytecode::DecodeOpcode(load_name) == Bytecode::kLoadConstant); |
| 994 ASSERT(Bytecode::DecodeOpcode(load_value) == Bytecode::kLoadConstant); |
| 995 const uint8_t reg = Bytecode::DecodeA(load_name); |
| 996 ASSERT(reg == Bytecode::DecodeA(load_value)); |
| 997 |
| 998 RawString* name = static_cast<RawString*>( |
| 999 LOAD_CONSTANT(Bytecode::DecodeD(load_name))); |
| 1000 if (name == argdesc_data[ArgumentsDescriptor::name_index(i)]) { |
| 1001 // Parameter was passed. Fetch passed value. |
| 1002 const intptr_t arg_index = Smi::Value(static_cast<RawSmi*>( |
| 1003 argdesc_data[ArgumentsDescriptor::position_index(i)])); |
| 1004 FP[reg] = first_arg[arg_index]; |
| 1005 i--; // Consume passed argument. |
| 1006 } else { |
| 1007 // Parameter was not passed. Fetch default value. |
| 1008 FP[reg] = LOAD_CONSTANT(Bytecode::DecodeD(load_value)); |
| 1009 } |
| 1010 j--; // Next formal parameter. |
| 1011 } |
| 1012 |
| 1013 // If we have unprocessed formal parameters then initialize them all |
| 1014 // using default values. |
| 1015 while (j >= 0) { |
| 1016 const uint32_t load_name = pc[2 * j]; |
| 1017 const uint32_t load_value = pc[2 * j + 1]; |
| 1018 ASSERT(Bytecode::DecodeOpcode(load_name) == Bytecode::kLoadConstant); |
| 1019 ASSERT(Bytecode::DecodeOpcode(load_value) == Bytecode::kLoadConstant); |
| 1020 const uint8_t reg = Bytecode::DecodeA(load_name); |
| 1021 ASSERT(reg == Bytecode::DecodeA(load_value)); |
| 1022 |
| 1023 FP[reg] = LOAD_CONSTANT(Bytecode::DecodeD(load_value)); |
| 1024 j--; |
| 1025 } |
| 1026 |
| 1027 // If we have unprocessed passed arguments that means we have mismatch |
| 1028 // between formal parameters and concrete arguments. This can only |
| 1029 // occur if the current function is a closure. |
| 1030 if (i != -1) { |
| 1031 goto ClosureNoSuchMethod; |
| 1032 } |
| 1033 |
| 1034 // Skip LoadConstant-s encoding information about named parameters. |
| 1035 pc += num_opt_named_params * 2; |
| 1036 |
| 1037 // SP points past copied arguments. |
| 1038 SP = FP + num_fixed_params + num_opt_named_params - 1; |
| 1039 } else { |
| 1040 ASSERT(num_opt_pos_params != 0); |
| 1041 if (named_count != 0) { |
| 1042 // Function can't have both named and optional positional parameters. |
| 1043 // This kind of mismatch can only occur if the current function |
| 1044 // is a closure. |
| 1045 goto ClosureNoSuchMethod; |
| 1046 } |
| 1047 |
| 1048 // Process the list of default values encoded as a sequence of |
| 1049 // LoadConstant instructions after EntryOpt bytecode. |
| 1050 // Execute only those that correspond to parameters the were not passed. |
| 1051 for (intptr_t i = pos_count - num_fixed_params; |
| 1052 i < num_opt_pos_params; |
| 1053 i++) { |
| 1054 const uint32_t load_value = pc[i]; |
| 1055 ASSERT(Bytecode::DecodeOpcode(load_value) == Bytecode::kLoadConstant); |
| 1056 #if defined(DEBUG) |
| 1057 const uint8_t reg = Bytecode::DecodeA(load_value); |
| 1058 ASSERT((num_fixed_params + i) == reg); |
| 1059 #endif |
| 1060 FP[num_fixed_params + i] = LOAD_CONSTANT(Bytecode::DecodeD(load_value)); |
| 1061 } |
| 1062 |
| 1063 // Skip LoadConstant-s encoding default values for optional positional |
| 1064 // parameters. |
| 1065 pc += num_opt_pos_params; |
| 1066 |
| 1067 // SP points past the last copied parameter. |
| 1068 SP = FP + max_num_pos_args - 1; |
| 1069 } |
| 1070 |
| 1071 DISPATCH(); |
| 1072 } |
| 1073 |
| 1074 { |
| 1075 BYTECODE(Frame, A_D); |
| 1076 // Initialize locals with null and increment SP. |
| 1077 const uint16_t num_locals = rD; |
| 1078 for (intptr_t i = 1; i <= num_locals; i++) { |
| 1079 SP[i] = null_value; |
| 1080 } |
| 1081 SP += num_locals; |
| 1082 |
| 1083 DISPATCH(); |
| 1084 } |
| 1085 |
| 1086 { |
| 1087 BYTECODE(SetFrame, A); |
| 1088 SP = FP + rA - 1; |
| 1089 DISPATCH(); |
| 1090 } |
| 1091 |
| 1092 { |
| 1093 BYTECODE(Compile, 0); |
| 1094 FP[0] = FrameFunction(FP); |
| 1095 FP[1] = 0; |
| 1096 Exit(thread, FP, FP + 2, pc); |
| 1097 NativeArguments args(thread, 1, FP, FP + 1); |
| 1098 INVOKE_RUNTIME(DRT_CompileFunction, args); |
| 1099 { |
| 1100 // Function should be compiled now, dispatch to its entry point. |
| 1101 RawCode* code = FrameFunction(FP)->ptr()->code_; |
| 1102 SetFrameCode(FP, code); |
| 1103 pp = code->ptr()->object_pool_->ptr(); |
| 1104 pc = reinterpret_cast<uint32_t*>(code->ptr()->entry_point_); |
| 1105 } |
| 1106 DISPATCH(); |
| 1107 } |
| 1108 |
| 1109 { |
| 1110 BYTECODE(CheckStack, A); |
| 1111 { |
| 1112 if (reinterpret_cast<uword>(SP) >= thread->stack_limit()) { |
| 1113 Exit(thread, FP, SP + 1, pc); |
| 1114 NativeArguments args(thread, 0, NULL, NULL); |
| 1115 INVOKE_RUNTIME(DRT_StackOverflow, args); |
| 1116 } |
| 1117 } |
| 1118 DISPATCH(); |
| 1119 } |
| 1120 |
| 1121 { |
| 1122 BYTECODE(DebugStep, A); |
| 1123 if (thread->isolate()->single_step()) { |
| 1124 Exit(thread, FP, SP + 1, pc); |
| 1125 NativeArguments args(thread, 0, NULL, NULL); |
| 1126 INVOKE_RUNTIME(DRT_SingleStepHandler, args); |
| 1127 } |
| 1128 DISPATCH(); |
| 1129 } |
| 1130 |
| 1131 { |
| 1132 BYTECODE(DebugBreak, A); |
| 1133 { |
| 1134 const uint32_t original_bc = |
| 1135 static_cast<uint32_t>(reinterpret_cast<uintptr_t>( |
| 1136 thread->isolate()->debugger()->GetPatchedStubAddress( |
| 1137 reinterpret_cast<uword>(pc)))); |
| 1138 |
| 1139 SP[1] = null_value; |
| 1140 Exit(thread, FP, SP + 2, pc); |
| 1141 NativeArguments args(thread, 0, NULL, SP + 1); |
| 1142 INVOKE_RUNTIME(DRT_BreakpointRuntimeHandler, args) |
| 1143 DISPATCH_OP(original_bc); |
| 1144 } |
| 1145 DISPATCH(); |
| 1146 } |
| 1147 |
| 1148 { |
| 1149 BYTECODE(InstantiateType, A_D); |
| 1150 RawObject* type = LOAD_CONSTANT(rD); |
| 1151 SP[1] = type; |
| 1152 SP[2] = SP[0]; |
| 1153 SP[0] = null_value; |
| 1154 Exit(thread, FP, SP + 3, pc); |
| 1155 { |
| 1156 NativeArguments args(thread, 2, SP + 1, SP); |
| 1157 INVOKE_RUNTIME(DRT_InstantiateType, args); |
| 1158 } |
| 1159 DISPATCH(); |
| 1160 } |
| 1161 |
| 1162 { |
| 1163 BYTECODE(InstantiateTypeArgumentsTOS, A_D); |
| 1164 RawTypeArguments* type_arguments = |
| 1165 static_cast<RawTypeArguments*>(LOAD_CONSTANT(rD)); |
| 1166 |
| 1167 RawObject* instantiator = SP[0]; |
| 1168 // If the instantiator is null and if the type argument vector |
| 1169 // instantiated from null becomes a vector of dynamic, then use null as |
| 1170 // the type arguments. |
| 1171 if (rA == 0 || null_value != instantiator) { |
| 1172 // First lookup in the cache. |
| 1173 RawArray* instantiations = type_arguments->ptr()->instantiations_; |
| 1174 for (intptr_t i = 0; |
| 1175 instantiations->ptr()->data()[i] != NULL; // kNoInstantiator |
| 1176 i += 2) { |
| 1177 if (instantiations->ptr()->data()[i] == instantiator) { |
| 1178 // Found in the cache. |
| 1179 SP[0] = instantiations->ptr()->data()[i + 1]; |
| 1180 goto InstantiateTypeArgumentsTOSDone; |
| 1181 } |
| 1182 } |
| 1183 |
| 1184 // Cache lookup failed, call runtime. |
| 1185 SP[1] = type_arguments; |
| 1186 SP[2] = instantiator; |
| 1187 |
| 1188 Exit(thread, FP, SP + 3, pc); |
| 1189 NativeArguments args(thread, 2, SP + 1, SP); |
| 1190 INVOKE_RUNTIME(DRT_InstantiateTypeArguments, args); |
| 1191 } |
| 1192 |
| 1193 InstantiateTypeArgumentsTOSDone: |
| 1194 DISPATCH(); |
| 1195 } |
| 1196 |
| 1197 { |
| 1198 BYTECODE(Throw, A); |
| 1199 { |
| 1200 SP[1] = 0; // Space for result. |
| 1201 Exit(thread, FP, SP + 2, pc); |
| 1202 if (rA == 0) { // Throw |
| 1203 NativeArguments args(thread, 1, SP, SP + 1); |
| 1204 INVOKE_RUNTIME(DRT_Throw, args); |
| 1205 } else { // ReThrow |
| 1206 NativeArguments args(thread, 2, SP - 1, SP + 1); |
| 1207 INVOKE_RUNTIME(DRT_ReThrow, args); |
| 1208 } |
| 1209 } |
| 1210 DISPATCH(); |
| 1211 } |
| 1212 |
| 1213 { |
| 1214 BYTECODE(Drop1, 0); |
| 1215 SP--; |
| 1216 DISPATCH(); |
| 1217 } |
| 1218 |
| 1219 { |
| 1220 BYTECODE(Drop, 0); |
| 1221 SP -= rA; |
| 1222 DISPATCH(); |
| 1223 } |
| 1224 |
| 1225 { |
| 1226 BYTECODE(DropR, 0); |
| 1227 RawObject* result = SP[0]; |
| 1228 SP -= rA; |
| 1229 SP[0] = result; |
| 1230 DISPATCH(); |
| 1231 } |
| 1232 |
| 1233 { |
| 1234 BYTECODE(LoadConstant, A_D); |
| 1235 FP[rA] = LOAD_CONSTANT(rD); |
| 1236 DISPATCH(); |
| 1237 } |
| 1238 |
| 1239 { |
| 1240 BYTECODE(PushConstant, __D); |
| 1241 *++SP = LOAD_CONSTANT(rD); |
| 1242 DISPATCH(); |
| 1243 } |
| 1244 |
| 1245 { |
| 1246 BYTECODE(Push, A_X); |
| 1247 *++SP = FP[rD]; |
| 1248 DISPATCH(); |
| 1249 } |
| 1250 |
| 1251 { |
| 1252 BYTECODE(Move, A_X); |
| 1253 FP[rA] = FP[rD]; |
| 1254 DISPATCH(); |
| 1255 } |
| 1256 |
| 1257 { |
| 1258 BYTECODE(StoreLocal, A_X); |
| 1259 FP[rD] = *SP; |
| 1260 DISPATCH(); |
| 1261 } |
| 1262 |
| 1263 { |
| 1264 BYTECODE(PopLocal, A_X); |
| 1265 FP[rD] = *SP--; |
| 1266 DISPATCH(); |
| 1267 } |
| 1268 |
| 1269 { |
| 1270 BYTECODE(MoveSpecial, A_D); |
| 1271 FP[rA] = special_[rD]; |
| 1272 DISPATCH(); |
| 1273 } |
| 1274 |
| 1275 { |
| 1276 BYTECODE(BooleanNegateTOS, 0); |
| 1277 SP[0] = (SP[0] == true_value) ? false_value : true_value; |
| 1278 DISPATCH(); |
| 1279 } |
| 1280 |
| 1281 { |
| 1282 BYTECODE(StaticCall, A_D); |
| 1283 |
| 1284 // Check if single stepping. |
| 1285 if (thread->isolate()->single_step()) { |
| 1286 Exit(thread, FP, SP + 1, pc); |
| 1287 NativeArguments args(thread, 0, NULL, NULL); |
| 1288 INVOKE_RUNTIME(DRT_SingleStepHandler, args); |
| 1289 } |
| 1290 |
| 1291 // Invoke target function. |
| 1292 { |
| 1293 const uint16_t argc = rA; |
| 1294 RawObject** call_base = SP - argc; |
| 1295 RawObject** call_top = SP; // *SP contains function |
| 1296 argdesc = static_cast<RawArray*>(LOAD_CONSTANT(rD)); |
| 1297 Invoke(thread, call_base, call_top, &pp, &pc, &FP, &SP); |
| 1298 } |
| 1299 |
| 1300 DISPATCH(); |
| 1301 } |
| 1302 |
| 1303 { |
| 1304 BYTECODE(InstanceCall, A_D); |
| 1305 |
| 1306 // Check if single stepping. |
| 1307 if (thread->isolate()->single_step()) { |
| 1308 Exit(thread, FP, SP + 1, pc); |
| 1309 NativeArguments args(thread, 0, NULL, NULL); |
| 1310 INVOKE_RUNTIME(DRT_SingleStepHandler, args); |
| 1311 } |
| 1312 |
| 1313 { |
| 1314 const uint16_t argc = rA; |
| 1315 const uint16_t kidx = rD; |
| 1316 |
| 1317 RawObject** call_base = SP - argc + 1; |
| 1318 RawObject** call_top = SP + 1; |
| 1319 InstanceCall1(thread, |
| 1320 static_cast<RawICData*>(LOAD_CONSTANT(kidx)), |
| 1321 call_base, call_top, &argdesc, &pp, &pc, &FP, &SP); |
| 1322 } |
| 1323 |
| 1324 DISPATCH(); |
| 1325 } |
| 1326 |
| 1327 { |
| 1328 BYTECODE(InstanceCall2, A_D); |
| 1329 if (thread->isolate()->single_step()) { |
| 1330 Exit(thread, FP, SP + 1, pc); |
| 1331 NativeArguments args(thread, 0, NULL, NULL); |
| 1332 INVOKE_RUNTIME(DRT_SingleStepHandler, args); |
| 1333 } |
| 1334 |
| 1335 { |
| 1336 const uint16_t argc = rA; |
| 1337 const uint16_t kidx = rD; |
| 1338 |
| 1339 RawObject** call_base = SP - argc + 1; |
| 1340 RawObject** call_top = SP + 1; |
| 1341 InstanceCall2(thread, |
| 1342 static_cast<RawICData*>(LOAD_CONSTANT(kidx)), |
| 1343 call_base, call_top, &argdesc, &pp, &pc, &FP, &SP); |
| 1344 } |
| 1345 |
| 1346 DISPATCH(); |
| 1347 } |
| 1348 |
| 1349 { |
| 1350 BYTECODE(InstanceCall3, A_D); |
| 1351 if (thread->isolate()->single_step()) { |
| 1352 Exit(thread, FP, SP + 1, pc); |
| 1353 NativeArguments args(thread, 0, NULL, NULL); |
| 1354 INVOKE_RUNTIME(DRT_SingleStepHandler, args); |
| 1355 } |
| 1356 |
| 1357 { |
| 1358 const uint16_t argc = rA; |
| 1359 const uint16_t kidx = rD; |
| 1360 |
| 1361 RawObject** call_base = SP - argc + 1; |
| 1362 RawObject** call_top = SP + 1; |
| 1363 InstanceCall3(thread, |
| 1364 static_cast<RawICData*>(LOAD_CONSTANT(kidx)), |
| 1365 call_base, call_top, &argdesc, &pp, &pc, &FP, &SP); |
| 1366 } |
| 1367 |
| 1368 DISPATCH(); |
| 1369 } |
| 1370 |
| 1371 { |
| 1372 BYTECODE(NativeBootstrapCall, 0); |
| 1373 RawFunction* function = FrameFunction(FP); |
| 1374 RawObject** incoming_args = |
| 1375 (function->ptr()->num_optional_parameters_ == 0) |
| 1376 ? FrameArguments(FP, function->ptr()->num_fixed_parameters_) |
| 1377 : FP; |
| 1378 |
| 1379 SimulatorBootstrapNativeCall native_target = |
| 1380 reinterpret_cast<SimulatorBootstrapNativeCall>(SP[-1]); |
| 1381 intptr_t argc_tag = reinterpret_cast<intptr_t>(SP[-0]); |
| 1382 SP[-0] = 0; // Note: argc_tag is not smi-tagged. |
| 1383 SP[-1] = null_value; |
| 1384 Exit(thread, FP, SP + 1, pc); |
| 1385 NativeArguments args(thread, argc_tag, incoming_args, SP - 1); |
| 1386 INVOKE_NATIVE(native_target, args); |
| 1387 SP -= 1; |
| 1388 DISPATCH(); |
| 1389 } |
| 1390 |
| 1391 { |
| 1392 BYTECODE(NativeCall, 0); |
| 1393 RawFunction* function = FrameFunction(FP); |
| 1394 RawObject** incoming_args = |
| 1395 (function->ptr()->num_optional_parameters_ == 0) |
| 1396 ? FrameArguments(FP, function->ptr()->num_fixed_parameters_) |
| 1397 : FP; |
| 1398 |
| 1399 Dart_NativeFunction native_target = |
| 1400 reinterpret_cast<Dart_NativeFunction>(SP[-1]); |
| 1401 intptr_t argc_tag = reinterpret_cast<intptr_t>(SP[-0]); |
| 1402 SP[-0] = 0; // argc_tag is not smi tagged! |
| 1403 SP[-1] = null_value; |
| 1404 Exit(thread, FP, SP + 1, pc); |
| 1405 NativeArguments args(thread, argc_tag, incoming_args, SP - 1); |
| 1406 INVOKE_NATIVE_WRAPPER(native_target, args); |
| 1407 SP -= 1; |
| 1408 DISPATCH(); |
| 1409 } |
| 1410 |
| 1411 { |
| 1412 BYTECODE(AddTOS, A_B_C); |
| 1413 SMI_FASTPATH_TOS(intptr_t, SignedAddWithOverflow); |
| 1414 DISPATCH(); |
| 1415 } |
| 1416 { |
| 1417 BYTECODE(SubTOS, A_B_C); |
| 1418 SMI_FASTPATH_TOS(intptr_t, SignedSubWithOverflow); |
| 1419 DISPATCH(); |
| 1420 } |
| 1421 { |
| 1422 BYTECODE(MulTOS, A_B_C); |
| 1423 SMI_FASTPATH_TOS(intptr_t, SMI_MUL); |
| 1424 DISPATCH(); |
| 1425 } |
| 1426 { |
| 1427 BYTECODE(BitOrTOS, A_B_C); |
| 1428 SMI_FASTPATH_TOS(intptr_t, SMI_BITOR); |
| 1429 DISPATCH(); |
| 1430 } |
| 1431 { |
| 1432 BYTECODE(BitAndTOS, A_B_C); |
| 1433 SMI_FASTPATH_TOS(intptr_t, SMI_BITAND); |
| 1434 DISPATCH(); |
| 1435 } |
| 1436 { |
| 1437 BYTECODE(EqualTOS, A_B_C); |
| 1438 SMI_FASTPATH_TOS(RawObject*, SMI_EQ); |
| 1439 DISPATCH(); |
| 1440 } |
| 1441 { |
| 1442 BYTECODE(LessThanTOS, A_B_C); |
| 1443 SMI_FASTPATH_TOS(RawObject*, SMI_LT); |
| 1444 DISPATCH(); |
| 1445 } |
| 1446 { |
| 1447 BYTECODE(GreaterThanTOS, A_B_C); |
| 1448 SMI_FASTPATH_TOS(RawObject*, SMI_GT); |
| 1449 DISPATCH(); |
| 1450 } |
| 1451 |
| 1452 // Return and return like instructions (Instrinsic). |
| 1453 { |
| 1454 RawObject* result; // result to return to the caller. |
| 1455 |
| 1456 BYTECODE(Intrinsic, A); |
| 1457 // Try invoking intrinsic handler. If it succeeds (returns true) |
| 1458 // then just return the value it returned to the caller. |
| 1459 result = null_value; |
| 1460 if (!intrinsics_[rA](thread, FP, &result)) { |
| 1461 DISPATCH(); |
| 1462 } |
| 1463 goto ReturnImpl; |
| 1464 |
| 1465 BYTECODE(Return, A); |
| 1466 result = FP[rA]; |
| 1467 goto ReturnImpl; |
| 1468 |
| 1469 BYTECODE(ReturnTOS, 0); |
| 1470 result = *SP; |
| 1471 // Fall through to the ReturnImpl. |
| 1472 |
| 1473 ReturnImpl: |
| 1474 // Restore caller PC. |
| 1475 pc = SavedCallerPC(FP); |
| 1476 |
| 1477 // Check if it is a fake PC marking the entry frame. |
| 1478 if ((reinterpret_cast<uword>(pc) & 2) != 0) { |
| 1479 const intptr_t argc = reinterpret_cast<uword>(pc) >> 2; |
| 1480 fp_ = sp_ = |
| 1481 reinterpret_cast<RawObject**>(FrameArguments(FP, argc + 1)[0]); |
| 1482 thread->set_top_exit_frame_info(reinterpret_cast<uword>(sp_)); |
| 1483 thread->set_top_resource(top_resource); |
| 1484 thread->set_vm_tag(vm_tag); |
| 1485 return result; |
| 1486 } |
| 1487 |
| 1488 // Look at the caller to determine how many arguments to pop. |
| 1489 const uint8_t argc = Bytecode::DecodeArgc(pc[-1]); |
| 1490 |
| 1491 // Restore SP, FP and PP. Push result and dispatch. |
| 1492 SP = FrameArguments(FP, argc); |
| 1493 FP = SavedCallerFP(FP); |
| 1494 pp = FrameCode(FP)->ptr()->object_pool_->ptr(); |
| 1495 *SP = result; |
| 1496 DISPATCH(); |
| 1497 } |
| 1498 |
| 1499 { |
| 1500 BYTECODE(StoreStaticTOS, A_D); |
| 1501 RawField* field = reinterpret_cast<RawField*>(LOAD_CONSTANT(rD)); |
| 1502 RawInstance* value = static_cast<RawInstance*>(*SP--); |
| 1503 field->StorePointer(&field->ptr()->value_.static_value_, value); |
| 1504 DISPATCH(); |
| 1505 } |
| 1506 |
| 1507 { |
| 1508 BYTECODE(PushStatic, A_D); |
| 1509 RawField* field = reinterpret_cast<RawField*>(LOAD_CONSTANT(rD)); |
| 1510 // Note: field is also on the stack, hence no increment. |
| 1511 *SP = field->ptr()->value_.static_value_; |
| 1512 DISPATCH(); |
| 1513 } |
| 1514 |
| 1515 { |
| 1516 BYTECODE(StoreField, A_B_C); |
| 1517 const uint16_t offset_in_words = rB; |
| 1518 const uint16_t value_reg = rC; |
| 1519 |
| 1520 RawInstance* instance = reinterpret_cast<RawInstance*>(FP[rA]); |
| 1521 RawObject* value = reinterpret_cast<RawObject*>(FP[value_reg]); |
| 1522 |
| 1523 instance->StorePointer( |
| 1524 reinterpret_cast<RawObject**>(instance->ptr()) + offset_in_words, |
| 1525 value); |
| 1526 DISPATCH(); |
| 1527 } |
| 1528 |
| 1529 { |
| 1530 BYTECODE(StoreFieldTOS, A_D); |
| 1531 const uint16_t offset_in_words = rD; |
| 1532 RawInstance* instance = reinterpret_cast<RawInstance*>(SP[-1]); |
| 1533 RawObject* value = reinterpret_cast<RawObject*>(SP[0]); |
| 1534 SP -= 2; // Drop instance and value. |
| 1535 instance->StorePointer( |
| 1536 reinterpret_cast<RawObject**>(instance->ptr()) + offset_in_words, |
| 1537 value); |
| 1538 |
| 1539 DISPATCH(); |
| 1540 } |
| 1541 |
| 1542 { |
| 1543 BYTECODE(LoadField, A_B_C); |
| 1544 const uint16_t instance_reg = rB; |
| 1545 const uint16_t offset_in_words = rC; |
| 1546 RawInstance* instance = reinterpret_cast<RawInstance*>(FP[instance_reg]); |
| 1547 FP[rA] = reinterpret_cast<RawObject**>(instance->ptr())[offset_in_words]; |
| 1548 DISPATCH(); |
| 1549 } |
| 1550 |
| 1551 { |
| 1552 BYTECODE(LoadFieldTOS, A_D); |
| 1553 const uint16_t offset_in_words = rD; |
| 1554 RawInstance* instance = static_cast<RawInstance*>(SP[0]); |
| 1555 SP[0] = reinterpret_cast<RawObject**>(instance->ptr())[offset_in_words]; |
| 1556 DISPATCH(); |
| 1557 } |
| 1558 |
| 1559 { |
| 1560 BYTECODE(InitStaticTOS, A); |
| 1561 RawField* field = static_cast<RawField*>(*SP--); |
| 1562 RawObject* value = field->ptr()->value_.static_value_; |
| 1563 if ((value == Object::sentinel().raw()) || |
| 1564 (value == Object::transition_sentinel().raw())) { |
| 1565 // Note: SP[1] already contains the field object. |
| 1566 SP[2] = 0; |
| 1567 Exit(thread, FP, SP + 3, pc); |
| 1568 NativeArguments args(thread, 1, SP + 1, SP + 2); |
| 1569 INVOKE_RUNTIME(DRT_InitStaticField, args); |
| 1570 } |
| 1571 DISPATCH(); |
| 1572 } |
| 1573 |
| 1574 // TODO(vegorov) allocation bytecodes can benefit from the new-space |
| 1575 // allocation fast-path that does not transition into the runtime system. |
| 1576 { |
| 1577 BYTECODE(AllocateContext, A_D); |
| 1578 const uint16_t num_context_variables = rD; |
| 1579 { |
| 1580 *++SP = 0; |
| 1581 SP[1] = Smi::New(num_context_variables); |
| 1582 Exit(thread, FP, SP + 2, pc); |
| 1583 NativeArguments args(thread, 1, SP + 1, SP); |
| 1584 INVOKE_RUNTIME(DRT_AllocateContext, args); |
| 1585 } |
| 1586 DISPATCH(); |
| 1587 } |
| 1588 |
| 1589 { |
| 1590 BYTECODE(CloneContext, A); |
| 1591 { |
| 1592 SP[1] = SP[0]; // Context to clone. |
| 1593 Exit(thread, FP, SP + 2, pc); |
| 1594 NativeArguments args(thread, 1, SP + 1, SP); |
| 1595 INVOKE_RUNTIME(DRT_CloneContext, args); |
| 1596 } |
| 1597 DISPATCH(); |
| 1598 } |
| 1599 |
| 1600 { |
| 1601 BYTECODE(Allocate, A_D); |
| 1602 SP[1] = 0; // Space for the result. |
| 1603 SP[2] = LOAD_CONSTANT(rD); // Class object. |
| 1604 SP[3] = null_value; // Type arguments. |
| 1605 Exit(thread, FP, SP + 4, pc); |
| 1606 NativeArguments args(thread, 2, SP + 2, SP + 1); |
| 1607 INVOKE_RUNTIME(DRT_AllocateObject, args); |
| 1608 SP++; // Result is in SP[1]. |
| 1609 DISPATCH(); |
| 1610 } |
| 1611 |
| 1612 { |
| 1613 BYTECODE(AllocateT, 0); |
| 1614 SP[1] = SP[-0]; // Class object. |
| 1615 SP[2] = SP[-1]; // Type arguments |
| 1616 Exit(thread, FP, SP + 3, pc); |
| 1617 NativeArguments args(thread, 2, SP + 1, SP - 1); |
| 1618 INVOKE_RUNTIME(DRT_AllocateObject, args); |
| 1619 SP -= 1; // Result is in SP - 1. |
| 1620 DISPATCH(); |
| 1621 } |
| 1622 |
| 1623 { |
| 1624 BYTECODE(CreateArrayTOS, 0); |
| 1625 SP[1] = SP[-0]; // Length. |
| 1626 SP[2] = SP[-1]; // Type. |
| 1627 Exit(thread, FP, SP + 3, pc); |
| 1628 NativeArguments args(thread, 2, SP + 1, SP - 1); |
| 1629 INVOKE_RUNTIME(DRT_AllocateArray, args); |
| 1630 SP -= 1; |
| 1631 DISPATCH(); |
| 1632 } |
| 1633 |
| 1634 { |
| 1635 BYTECODE(AssertAssignable, A_D); // Stack: instance, type args, type, name |
| 1636 RawObject** args = SP - 3; |
| 1637 if (args[0] != null_value) { |
| 1638 RawSubtypeTestCache* cache = |
| 1639 static_cast<RawSubtypeTestCache*>(LOAD_CONSTANT(rD)); |
| 1640 if (cache != null_value) { |
| 1641 RawInstance* instance = static_cast<RawInstance*>(args[0]); |
| 1642 RawTypeArguments* instantiator_type_arguments = |
| 1643 static_cast<RawTypeArguments*>(args[1]); |
| 1644 |
| 1645 const intptr_t cid = SimulatorHelpers::GetClassId(instance); |
| 1646 |
| 1647 RawTypeArguments* instance_type_arguments = |
| 1648 static_cast<RawTypeArguments*>(null_value); |
| 1649 RawObject* instance_cid_or_function; |
| 1650 if (cid == kClosureCid) { |
| 1651 RawClosure* closure = static_cast<RawClosure*>(instance); |
| 1652 instance_type_arguments = closure->ptr()->type_arguments_; |
| 1653 instance_cid_or_function = closure->ptr()->function_; |
| 1654 } else { |
| 1655 instance_cid_or_function = Smi::New(cid); |
| 1656 |
| 1657 RawClass* instance_class = |
| 1658 thread->isolate()->class_table()->At(cid); |
| 1659 if (instance_class->ptr()->num_type_arguments_ < 0) { |
| 1660 goto AssertAssignableCallRuntime; |
| 1661 } else if (instance_class->ptr()->num_type_arguments_ > 0) { |
| 1662 instance_type_arguments = reinterpret_cast<RawTypeArguments**>( |
| 1663 instance |
| 1664 ->ptr())[instance_class->ptr() |
| 1665 ->type_arguments_field_offset_in_words_]; |
| 1666 } |
| 1667 } |
| 1668 |
| 1669 for (RawObject** entries = cache->ptr()->cache_->ptr()->data(); |
| 1670 entries[0] != null_value; |
| 1671 entries += SubtypeTestCache::kTestEntryLength) { |
| 1672 if ((entries[SubtypeTestCache::kInstanceClassIdOrFunction] == |
| 1673 instance_cid_or_function) && |
| 1674 (entries[SubtypeTestCache::kInstanceTypeArguments] == |
| 1675 instance_type_arguments) && |
| 1676 (entries[SubtypeTestCache::kInstantiatorTypeArguments] == |
| 1677 instantiator_type_arguments)) { |
| 1678 if (true_value == entries[SubtypeTestCache::kTestResult]) { |
| 1679 goto AssertAssignableOk; |
| 1680 } else { |
| 1681 break; |
| 1682 } |
| 1683 } |
| 1684 } |
| 1685 } |
| 1686 |
| 1687 AssertAssignableCallRuntime: |
| 1688 SP[1] = args[0]; // instance |
| 1689 SP[2] = args[2]; // type |
| 1690 SP[3] = args[1]; // type args |
| 1691 SP[4] = args[3]; // name |
| 1692 SP[5] = cache; |
| 1693 Exit(thread, FP, SP + 6, pc); |
| 1694 NativeArguments args(thread, 5, SP + 1, SP - 3); |
| 1695 INVOKE_RUNTIME(DRT_TypeCheck, args); |
| 1696 } |
| 1697 |
| 1698 AssertAssignableOk: |
| 1699 SP -= 3; |
| 1700 DISPATCH(); |
| 1701 } |
| 1702 |
| 1703 { |
| 1704 BYTECODE(AssertBoolean, A); |
| 1705 RawObject* value = SP[0]; |
| 1706 if (rA) { // Should we perform type check? |
| 1707 if ((value == true_value) || (value == false_value)) { |
| 1708 goto AssertBooleanOk; |
| 1709 } |
| 1710 } else if (value != null_value) { |
| 1711 goto AssertBooleanOk; |
| 1712 } |
| 1713 |
| 1714 // Assertion failed. |
| 1715 { |
| 1716 SP[1] = SP[0]; // instance |
| 1717 Exit(thread, FP, SP + 2, pc); |
| 1718 NativeArguments args(thread, 1, SP + 1, SP); |
| 1719 INVOKE_RUNTIME(DRT_NonBoolTypeError, args); |
| 1720 } |
| 1721 |
| 1722 AssertBooleanOk: |
| 1723 DISPATCH(); |
| 1724 } |
| 1725 |
| 1726 { |
| 1727 BYTECODE(IfEqStrictTOS, A_D); |
| 1728 SP -= 2; |
| 1729 if (SP[1] != SP[2]) { |
| 1730 pc++; |
| 1731 } |
| 1732 DISPATCH(); |
| 1733 } |
| 1734 |
| 1735 { |
| 1736 BYTECODE(IfNeStrictTOS, A_D); |
| 1737 SP -= 2; |
| 1738 if (SP[1] == SP[2]) { |
| 1739 pc++; |
| 1740 } |
| 1741 DISPATCH(); |
| 1742 } |
| 1743 |
| 1744 { |
| 1745 BYTECODE(IfEqStrictNumTOS, A_D); |
| 1746 if (thread->isolate()->single_step()) { |
| 1747 Exit(thread, FP, SP + 1, pc); |
| 1748 NativeArguments args(thread, 0, NULL, NULL); |
| 1749 INVOKE_RUNTIME(DRT_SingleStepHandler, args); |
| 1750 } |
| 1751 |
| 1752 SP -= 2; |
| 1753 if (!SimulatorHelpers::IsStrictEqualWithNumberCheck(SP[1], SP[2])) { |
| 1754 pc++; |
| 1755 } |
| 1756 DISPATCH(); |
| 1757 } |
| 1758 |
| 1759 { |
| 1760 BYTECODE(IfNeStrictNumTOS, A_D); |
| 1761 if (thread->isolate()->single_step()) { |
| 1762 Exit(thread, FP, SP + 1, pc); |
| 1763 NativeArguments args(thread, 0, NULL, NULL); |
| 1764 INVOKE_RUNTIME(DRT_SingleStepHandler, args); |
| 1765 } |
| 1766 |
| 1767 SP -= 2; |
| 1768 if (SimulatorHelpers::IsStrictEqualWithNumberCheck(SP[1], SP[2])) { |
| 1769 pc++; |
| 1770 } |
| 1771 DISPATCH(); |
| 1772 } |
| 1773 |
| 1774 { |
| 1775 BYTECODE(Jump, 0); |
| 1776 const int32_t target = static_cast<int32_t>(op) >> 8; |
| 1777 pc += (target - 1); |
| 1778 DISPATCH(); |
| 1779 } |
| 1780 |
| 1781 { |
| 1782 BYTECODE(StoreIndexedTOS, 0); |
| 1783 SP -= 3; |
| 1784 RawArray* array = static_cast<RawArray*>(SP[1]); |
| 1785 RawSmi* index = static_cast<RawSmi*>(SP[2]); |
| 1786 RawObject* value = SP[3]; |
| 1787 ASSERT(array->GetClassId() == kArrayCid); |
| 1788 ASSERT(!index->IsHeapObject()); |
| 1789 array->StorePointer(array->ptr()->data() + Smi::Value(index), value); |
| 1790 DISPATCH(); |
| 1791 } |
| 1792 |
| 1793 { |
| 1794 BYTECODE(Trap, 0); |
| 1795 UNIMPLEMENTED(); |
| 1796 DISPATCH(); |
| 1797 } |
| 1798 |
| 1799 // Helper used to handle noSuchMethod on closures. |
| 1800 { |
| 1801 ClosureNoSuchMethod: |
| 1802 #if defined(DEBUG) |
| 1803 function_h ^= FrameFunction(FP); |
| 1804 ASSERT(function_h.IsClosureFunction()); |
| 1805 #endif |
| 1806 |
| 1807 // Restore caller context as we are going to throw NoSuchMethod. |
| 1808 pc = SavedCallerPC(FP); |
| 1809 |
| 1810 const bool has_dart_caller = (reinterpret_cast<uword>(pc) & 2) == 0; |
| 1811 const intptr_t argc = has_dart_caller |
| 1812 ? Bytecode::DecodeArgc(pc[-1]) |
| 1813 : (reinterpret_cast<uword>(pc) >> 2); |
| 1814 |
| 1815 SP = FrameArguments(FP, 0); |
| 1816 RawObject** args = SP - argc; |
| 1817 FP = SavedCallerFP(FP); |
| 1818 if (has_dart_caller) { |
| 1819 pp = FrameCode(FP)->ptr()->object_pool_->ptr(); |
| 1820 } |
| 1821 |
| 1822 *++SP = null_value; |
| 1823 *++SP = args[0]; // Closure object. |
| 1824 *++SP = argdesc; |
| 1825 *++SP = null_value; // Array of arguments (will be filled). |
| 1826 |
| 1827 // Allocate array of arguments. |
| 1828 { |
| 1829 SP[1] = Smi::New(argc); // length |
| 1830 SP[2] = null_value; // type |
| 1831 Exit(thread, FP, SP + 3, pc); |
| 1832 NativeArguments native_args(thread, 2, SP + 1, SP); |
| 1833 INVOKE_RUNTIME(DRT_AllocateArray, native_args); |
| 1834 |
| 1835 // Copy arguments into the newly allocated array. |
| 1836 RawArray* array = static_cast<RawArray*>(SP[0]); |
| 1837 ASSERT(array->GetClassId() == kArrayCid); |
| 1838 for (intptr_t i = 0; i < argc; i++) { |
| 1839 array->ptr()->data()[i] = args[i]; |
| 1840 } |
| 1841 } |
| 1842 |
| 1843 // Invoke noSuchMethod passing down closure, argument descriptor and |
| 1844 // array of arguments. |
| 1845 { |
| 1846 Exit(thread, FP, SP + 1, pc); |
| 1847 NativeArguments native_args(thread, 3, SP - 2, SP - 3); |
| 1848 INVOKE_RUNTIME(DRT_InvokeClosureNoSuchMethod, native_args); |
| 1849 UNREACHABLE(); |
| 1850 } |
| 1851 |
| 1852 DISPATCH(); |
| 1853 } |
| 1854 |
| 1855 // Single dispatch point used by exception handling macros. |
| 1856 { |
| 1857 DispatchAfterException: |
| 1858 DISPATCH(); |
| 1859 } |
| 1860 |
| 1861 UNREACHABLE(); |
| 1862 return 0; |
| 1863 } |
| 1864 |
| 1865 void Simulator::Longjmp(uword pc, |
| 1866 uword sp, |
| 1867 uword fp, |
| 1868 RawObject* raw_exception, |
| 1869 RawObject* raw_stacktrace, |
| 1870 Thread* thread) { |
| 1871 // Walk over all setjmp buffers (simulated --> C++ transitions) |
| 1872 // and try to find the setjmp associated with the simulated stack pointer. |
| 1873 SimulatorSetjmpBuffer* buf = last_setjmp_buffer(); |
| 1874 while ((buf->link() != NULL) && (buf->link()->fp() > fp)) { |
| 1875 buf = buf->link(); |
| 1876 } |
| 1877 ASSERT(buf != NULL); |
| 1878 ASSERT(last_setjmp_buffer() == buf); |
| 1879 |
| 1880 // The C++ caller has not cleaned up the stack memory of C++ frames. |
| 1881 // Prepare for unwinding frames by destroying all the stack resources |
| 1882 // in the previous C++ frames. |
| 1883 StackResource::Unwind(thread); |
| 1884 |
| 1885 // Set the tag. |
| 1886 thread->set_vm_tag(VMTag::kDartTagId); |
| 1887 // Clear top exit frame. |
| 1888 thread->set_top_exit_frame_info(0); |
| 1889 |
| 1890 ASSERT(raw_exception != Object::null()); |
| 1891 sp_ = reinterpret_cast<RawObject**>(sp); |
| 1892 fp_ = reinterpret_cast<RawObject**>(fp); |
| 1893 pc_ = pc; |
| 1894 special_[kExceptionSpecialIndex] = raw_exception; |
| 1895 special_[kStacktraceSpecialIndex] = raw_stacktrace; |
| 1896 buf->Longjmp(); |
| 1897 UNREACHABLE(); |
| 1898 } |
| 1899 |
| 1900 } // namespace dart |
| 1901 |
| 1902 |
| 1903 #endif // defined TARGET_ARCH_DBC |
OLD | NEW |