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