Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(68)

Side by Side Diff: runtime/vm/simulator_dbc.cc

Issue 1858283002: Initial SIMDBC interpreter. (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Created 4 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « runtime/vm/simulator_dbc.h ('k') | runtime/vm/simulator_mips.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(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 int32_t 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 = __builtin_sadd_overflow(lhs, rhs, out);
zra 2016/04/18 16:50:14 It looks like these builtins return bools: https:
Vyacheslav Egorov (Google) 2016/04/18 19:19:57 Yes, I am intentionally assigning bool to an int a
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;
384 }
385
386
387 DART_FORCE_INLINE static int32_t 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 = __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;
417 }
418
419
420 DART_FORCE_INLINE static int32_t 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 = __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;
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))) { \
zra 2016/04/18 16:50:14 It looks like the functions passed for Func return
Vyacheslav Egorov (Google) 2016/04/18 19:19:56 Not all of them. SMI_GT for example returns boolea
782 /* Fast path succeeded. Skip the generic call that follows. */ \
783 pc++; \
784 /* We dropped 2 arguments and push result */ \
785 SP--; \
786 } \
787 DISPATCH(); \
zra 2016/04/18 16:50:14 I'd pull the DISPATCH() out of the macro to match
Vyacheslav Egorov (Google) 2016/04/18 19:19:56 Done.
788 }
789
790 // Exception handling helper. Gets handler FP and PC from the Simulator where
791 // they were stored by Simulator::Longjmp and proceeds to execute the handler.
792 // Corner case: handler PC can be a fake marker that marks entry frame, which
793 // means exception was not handled in the Dart code. In this case we return
794 // caught exception from Simulator::Call.
795 #define HANDLE_EXCEPTION \
796 do { \
797 FP = reinterpret_cast<RawObject**>(fp_); \
798 pc = reinterpret_cast<uint32_t*>(pc_); \
799 if ((reinterpret_cast<uword>(pc) & 2) != 0) { /* Entry frame? */ \
800 fp_ = sp_ = reinterpret_cast<RawObject**>(fp_[0]); \
801 thread->set_top_exit_frame_info(reinterpret_cast<uword>(sp_)); \
802 thread->set_top_resource(top_resource); \
803 thread->set_vm_tag(vm_tag); \
804 return special_[kExceptionSpecialIndex]; \
805 } \
806 pp = FrameCode(FP)->ptr()->object_pool_->ptr(); \
807 goto DispatchAfterException; \
808 } while (0) \
809
810 // Runtime call helpers: handle invocation and potential exception after return.
811 #define INVOKE_RUNTIME(Func, Args) \
812 if (!InvokeRuntime(thread, this, Func, Args)) { \
813 HANDLE_EXCEPTION; \
814 } \
815
816 #define INVOKE_NATIVE(Func, Args) \
817 if (!InvokeNative(thread, this, Func, &Args)) { \
818 HANDLE_EXCEPTION; \
819 } \
820
821 #define INVOKE_NATIVE_WRAPPER(Func, Args) \
822 if (!InvokeNativeWrapper(thread, this, Func, &Args)) { \
823 HANDLE_EXCEPTION; \
824 } \
825
826 #define LOAD_CONSTANT(index) (pp->data()[(index)].raw_obj_)
827
828 RawObject* Simulator::Call(const Code& code,
829 const Array& arguments_descriptor,
830 const Array& arguments,
831 Thread* thread) {
832 // Dispatch used to interpret bytecode. Contains addresses of
833 // labels of bytecode handlers. Handlers themselves are defined below.
834 static const void* dispatch[] = {
835 #define TARGET(name, fmt, fmta, fmtb, fmtc) &&bc##name,
836 BYTECODES_LIST(TARGET)
837 #undef TARGET
838 };
839
840 // Interpreter state (see constants_dbc.h for high-level overview).
841 uint32_t* pc; // Program Counter: points to the next op to execute.
842 RawObjectPool* pp; // Pool Pointer.
843 RawObject** FP; // Frame Pointer.
844 RawObject** SP; // Stack Pointer.
845
846 RawArray* argdesc; // Arguments Descriptor: used to pass information between
847 // call instruction and the function entry.
848
849 uint32_t op; // Currently executing op.
850 uint16_t rA; // A component of the currently executing op.
851
852 if (sp_ == NULL) {
853 fp_ = sp_ = reinterpret_cast<RawObject**>(stack_);
854 }
855
856 // Save current VM tag and mark thread as executing Dart code.
857 const uword vm_tag = thread->vm_tag();
858 thread->set_vm_tag(VMTag::kDartTagId);
859
860 // Save current top stack resource and reset the list.
861 StackResource* top_resource = thread->top_resource();
862 thread->set_top_resource(NULL);
863
864 // Setup entry frame:
865 //
866 // ^
867 // | previous Dart frames
868 // ~~~~~~~~~~~~~~~ |
869 // | ........... | -+
870 // fp_ > | | saved top_exit_frame_info
871 // | arg 0 | -+
872 // ~~~~~~~~~~~~~~~ |
873 // > incoming arguments
874 // ~~~~~~~~~~~~~~~ |
875 // | arg 1 | -+
876 // | function | -+
877 // | code | |
878 // | callee PC | ---> special fake PC marking an entry frame
879 // SP > | fp_ | |
880 // FP > | ........... | > normal Dart frame (see stack_frame_dbc.h)
881 // |
882 // v
883 //
884 FP = fp_ + 1 + arguments.Length() + kDartFrameFixedSize;
885 SP = FP - 1;
886
887 // Save outer top_exit_frame_info.
888 fp_[0] = reinterpret_cast<RawObject*>(thread->top_exit_frame_info());
889
890 // Copy arguments and setup the Dart frame.
891 const intptr_t argc = arguments.Length();
892 for (intptr_t i = 0; i < argc; i++) {
893 fp_[1 + i] = arguments.At(i);
894 }
895
896 FP[kFunctionSlotFromFp] = code.function();
897 FP[kPcMarkerSlotFromFp] = code.raw();
898 FP[kSavedCallerPcSlotFromFp] = reinterpret_cast<RawObject*>((argc << 2) | 2);
899 FP[kSavedCallerFpSlotFromFp] = reinterpret_cast<RawObject*>(fp_);
900
901 // Load argument descriptor.
902 argdesc = arguments_descriptor.raw();
903
904 // Ready to start executing bytecode. Load entry point and corresponding
905 // object pool.
906 pc = reinterpret_cast<uint32_t*>(code.raw()->ptr()->entry_point_);
907 pp = code.object_pool()->ptr();
908
909 // Cache some frequently used values in the frame.
910 RawBool* true_value = Bool::True().raw();
911 RawBool* false_value = Bool::False().raw();
912 RawObject* null_value = Object::null();
913 RawObject* empty_context = thread->isolate()->object_store()->empty_context();
914
915 #if defined(DEBUG)
916 Function& function_h = Function::Handle();
917 #endif
918
919 // Enter the dispatch loop.
920 DISPATCH();
921
922 // Bytecode handlers (see constants_dbc.h for bytecode descriptions).
923 {
924 BYTECODE(Entry, A_B_C);
925 const uint8_t num_fixed_params = rA;
926 const uint16_t num_locals = rB;
927 const uint16_t context_reg = rC;
928
929 // Decode arguments descriptor.
930 const intptr_t pos_count = Smi::Value(*reinterpret_cast<RawSmi**>(
931 reinterpret_cast<uword>(argdesc->ptr()) +
932 Array::element_offset(ArgumentsDescriptor::kPositionalCountIndex)));
933
934 // Check that we got the right number of positional parameters.
935 if (pos_count != num_fixed_params) {
936 // Mismatch can only occur if current function is a closure.
937 goto ClosureNoSuchMethod;
938 }
939
940 // Initialize locals with null and set current context variable to
941 // empty context.
942 {
943 RawObject** L = FP;
944 for (intptr_t i = 0; i < num_locals; i++) {
945 L[i] = null_value;
946 }
947 L[context_reg] = empty_context;
948 SP = FP + num_locals - 1;
949 }
950
951 DISPATCH();
952 }
953
954 {
955 BYTECODE(EntryOpt, A_B_C);
956 const uint16_t num_fixed_params = rA;
957 const uint16_t num_opt_pos_params = rB;
958 const uint16_t num_opt_named_params = rC;
959 const intptr_t min_num_pos_args = num_fixed_params;
960 const intptr_t max_num_pos_args = num_fixed_params + num_opt_pos_params;
961
962 // Decode arguments descriptor.
963 const intptr_t arg_count = Smi::Value(*reinterpret_cast<RawSmi**>(
964 reinterpret_cast<uword>(argdesc->ptr()) +
965 Array::element_offset(ArgumentsDescriptor::kCountIndex)));
966 const intptr_t pos_count = Smi::Value(*reinterpret_cast<RawSmi**>(
967 reinterpret_cast<uword>(argdesc->ptr()) +
968 Array::element_offset(ArgumentsDescriptor::kPositionalCountIndex)));
969 const intptr_t named_count = (arg_count - pos_count);
970
971 // Check that got the right number of positional parameters.
972 if (!(min_num_pos_args <= pos_count && pos_count <= max_num_pos_args)) {
zra 2016/04/18 16:50:14 parens around comparisons.
Vyacheslav Egorov (Google) 2016/04/18 19:19:57 Done.
973 goto ClosureNoSuchMethod;
974 }
975
976 // Copy all passed position arguments.
977 RawObject** first_arg = FrameArguments(FP, arg_count);
978 memmove(FP, first_arg, pos_count * kWordSize);
979
980 if (num_opt_named_params != 0) {
981 // This is a function with named parameters.
982 // Walk the list of named parameters and their
983 // default values encoded as pairs of LoadConstant instructions that
984 // follows the entry point and find matching values via arguments
985 // descriptor.
986 RawObject** argdesc_data = argdesc->ptr()->data();
987
988 intptr_t i = named_count - 1; // argument position
989 intptr_t j = num_opt_named_params - 1; // parameter position
990 while (j >= 0 && i >= 0) {
zra 2016/04/18 16:50:14 ditto
Vyacheslav Egorov (Google) 2016/04/18 19:19:56 Done.
991 // Fetch formal parameter information: name, default value, target slot.
992 const uint32_t load_name = pc[2 * j];
993 const uint32_t load_value = pc[2 * j + 1];
994 ASSERT(Bytecode::DecodeOpcode(load_name) == Bytecode::kLoadConstant);
995 ASSERT(Bytecode::DecodeOpcode(load_value) == Bytecode::kLoadConstant);
996 const uint8_t reg = Bytecode::DecodeA(load_name);
997 ASSERT(reg == Bytecode::DecodeA(load_value));
998
999 RawString* name = static_cast<RawString*>(
1000 LOAD_CONSTANT(Bytecode::DecodeD(load_name)));
1001 if (name == argdesc_data[ArgumentsDescriptor::name_index(i)]) {
1002 // Parameter was passed. Fetch passed value.
1003 const intptr_t arg_index = Smi::Value(static_cast<RawSmi*>(
1004 argdesc_data[ArgumentsDescriptor::position_index(i)]));
1005 FP[reg] = first_arg[arg_index];
1006 i--; // Consume passed argument.
1007 } else {
1008 // Parameter was not passed. Fetch default value.
1009 FP[reg] = LOAD_CONSTANT(Bytecode::DecodeD(load_value));
1010 }
1011 j--; // Next formal parameter.
1012 }
1013
1014 // If we have unprocessed formal parameters then initialize them all
1015 // using default values.
1016 while (j >= 0) {
1017 const uint32_t load_name = pc[2 * j];
1018 const uint32_t load_value = pc[2 * j + 1];
1019 ASSERT(Bytecode::DecodeOpcode(load_name) == Bytecode::kLoadConstant);
1020 ASSERT(Bytecode::DecodeOpcode(load_value) == Bytecode::kLoadConstant);
1021 const uint8_t reg = Bytecode::DecodeA(load_name);
1022 ASSERT(reg == Bytecode::DecodeA(load_value));
1023
1024 FP[reg] = LOAD_CONSTANT(Bytecode::DecodeD(load_value));
1025 j--;
1026 }
1027
1028 // If we have unprocessed passed arguments that means we have mismatch
1029 // between formal parameters and concrete arguments. This can only
1030 // occur if the current function is a closure.
1031 if (i != -1) {
1032 goto ClosureNoSuchMethod;
1033 }
1034
1035 // Skip LoadConstant-s encoding information about named parameters.
1036 pc += num_opt_named_params * 2;
1037
1038 // SP points past copied arguments.
1039 SP = FP + num_fixed_params + num_opt_named_params - 1;
1040 } else {
1041 ASSERT(num_opt_pos_params != 0);
1042 if (named_count != 0) {
1043 // Function can't have both named and optional positional parameters.
1044 // This kind of mismatch can only occur if the current function
1045 // is a closure.
1046 goto ClosureNoSuchMethod;
1047 }
1048
1049 // Process the list of default values encoded as a sequence of
1050 // LoadConstant instructions after EntryOpt bytecode.
1051 // Execute only those that correspond to parameters the were not passed.
1052 for (intptr_t i = pos_count - num_fixed_params;
1053 i < num_opt_pos_params;
1054 i++) {
1055 const uint32_t load_value = pc[i];
1056 ASSERT(Bytecode::DecodeOpcode(load_value) == Bytecode::kLoadConstant);
1057 #if defined(DEBUG)
1058 const uint8_t reg = Bytecode::DecodeA(load_value);
1059 ASSERT((num_fixed_params + i) == reg);
1060 #endif
1061 FP[num_fixed_params + i] = LOAD_CONSTANT(Bytecode::DecodeD(load_value));
1062 }
1063
1064 // Skip LoadConstant-s encoding default values for optional positional
1065 // parameters.
1066 pc += num_opt_pos_params;
1067
1068 // SP points past the last copied parameter.
1069 SP = FP + max_num_pos_args - 1;
1070 }
1071
1072 DISPATCH();
1073 }
1074
1075 {
1076 BYTECODE(Frame, A_D);
1077 // Initialize locals with null and increment SP.
1078 const uint16_t num_locals = rD;
1079 for (intptr_t i = 1; i <= num_locals; i++) {
1080 SP[i] = null_value;
1081 }
1082 SP += num_locals;
1083
1084 DISPATCH();
1085 }
1086
1087 {
1088 BYTECODE(SetFrame, A);
1089 SP = FP + rA - 1;
1090 DISPATCH();
1091 }
1092
1093 {
1094 BYTECODE(Compile, 0);
1095 FP[0] = FrameFunction(FP);
1096 FP[1] = 0;
1097 Exit(thread, FP, FP + 2, pc);
1098 NativeArguments args(thread, 1, FP, FP + 1);
1099 INVOKE_RUNTIME(DRT_CompileFunction, args);
1100 {
1101 // Function should be compiled now, dispatch to its entry point.
1102 RawCode* code = FrameFunction(FP)->ptr()->code_;
1103 SetFrameCode(FP, code);
1104 pp = code->ptr()->object_pool_->ptr();
1105 pc = reinterpret_cast<uint32_t*>(code->ptr()->entry_point_);
1106 }
1107 DISPATCH();
1108 }
1109
1110 {
1111 BYTECODE(CheckStack, A);
1112 {
1113 if (reinterpret_cast<uword>(SP) >= thread->isolate()->stack_limit()) {
1114 Exit(thread, FP, SP + 1, pc);
1115 NativeArguments args(thread, 0, NULL, NULL);
1116 INVOKE_RUNTIME(DRT_StackOverflow, args);
1117 }
1118 }
1119 DISPATCH();
1120 }
1121
1122 {
1123 BYTECODE(DebugStep, A);
1124 if (thread->isolate()->single_step()) {
1125 Exit(thread, FP, SP + 1, pc);
1126 NativeArguments args(thread, 0, NULL, NULL);
1127 INVOKE_RUNTIME(DRT_SingleStepHandler, args);
1128 }
1129 DISPATCH();
1130 }
1131
1132 {
1133 BYTECODE(DebugBreak, A);
1134 {
1135 const uint32_t original_bc =
1136 static_cast<uint32_t>(reinterpret_cast<uintptr_t>(
1137 thread->isolate()->debugger()->GetPatchedStubAddress(
1138 reinterpret_cast<uword>(pc))));
1139
1140 SP[1] = null_value;
1141 Exit(thread, FP, SP + 2, pc);
1142 NativeArguments args(thread, 0, NULL, SP + 1);
1143 INVOKE_RUNTIME(DRT_BreakpointRuntimeHandler, args)
1144 DISPATCH_OP(original_bc);
1145 }
1146 DISPATCH();
1147 }
1148
1149 {
1150 BYTECODE(InstantiateType, A_D);
1151 RawObject* type = LOAD_CONSTANT(rD);
1152 SP[1] = type;
1153 SP[2] = SP[0];
1154 SP[0] = null_value;
1155 Exit(thread, FP, SP + 3, pc);
1156 {
1157 NativeArguments args(thread, 2, SP + 1, SP);
1158 INVOKE_RUNTIME(DRT_InstantiateType, args);
1159 }
1160 DISPATCH();
1161 }
1162
1163 {
1164 BYTECODE(InstantiateTypeArgumentsTOS, A_D);
1165 RawTypeArguments* type_arguments =
1166 static_cast<RawTypeArguments*>(LOAD_CONSTANT(rD));
1167
1168 RawObject* instantiator = SP[0];
1169 // If the instantiator is null and if the type argument vector
1170 // instantiated from null becomes a vector of dynamic, then use null as
1171 // the type arguments.
1172 if (rA == 0 || null_value != instantiator) {
1173 // First lookup in the cache.
1174 RawArray* instantiations = type_arguments->ptr()->instantiations_;
1175 for (intptr_t i = 0;
1176 instantiations->ptr()->data()[i] != NULL; // kNoInstantiator
1177 i += 2) {
1178 if (instantiations->ptr()->data()[i] == instantiator) {
1179 // Found in the cache.
1180 SP[0] = instantiations->ptr()->data()[i + 1];
1181 goto InstantiateTypeArgumentsTOSDone;
1182 }
1183 }
1184
1185 // Cache lookup failed, call runtime.
1186 SP[1] = type_arguments;
1187 SP[2] = instantiator;
1188
1189 Exit(thread, FP, SP + 3, pc);
1190 NativeArguments args(thread, 2, SP + 1, SP);
1191 INVOKE_RUNTIME(DRT_InstantiateTypeArguments, args);
1192 }
1193
1194 InstantiateTypeArgumentsTOSDone:
1195 DISPATCH();
1196 }
1197
1198 {
1199 BYTECODE(Throw, A);
1200 {
1201 SP[1] = 0; // Space for result.
1202 Exit(thread, FP, SP + 2, pc);
1203 if (rA == 0) { // Throw
1204 NativeArguments args(thread, 1, SP, SP + 1);
1205 INVOKE_RUNTIME(DRT_Throw, args);
1206 } else { // ReThrow
1207 NativeArguments args(thread, 2, SP - 1, SP + 1);
1208 INVOKE_RUNTIME(DRT_ReThrow, args);
1209 }
1210 }
1211 DISPATCH();
1212 }
1213
1214 {
1215 BYTECODE(Drop1, 0);
1216 SP--;
1217 DISPATCH();
1218 }
1219
1220 {
1221 BYTECODE(Drop, 0);
1222 SP -= rA;
1223 DISPATCH();
1224 }
1225
1226 {
1227 BYTECODE(DropR, 0);
1228 RawObject* result = SP[0];
1229 SP -= rA;
1230 SP[0] = result;
1231 DISPATCH();
1232 }
1233
1234 {
1235 BYTECODE(LoadConstant, A_D);
1236 FP[rA] = LOAD_CONSTANT(rD);
1237 DISPATCH();
1238 }
1239
1240 {
1241 BYTECODE(PushConstant, __D);
1242 *++SP = LOAD_CONSTANT(rD);
1243 DISPATCH();
1244 }
1245
1246 {
1247 BYTECODE(Push, A_X);
1248 *++SP = FP[rD];
1249 DISPATCH();
1250 }
1251
1252 {
1253 BYTECODE(Move, A_X);
1254 FP[rA] = FP[rD];
1255 DISPATCH();
1256 }
1257
1258 {
1259 BYTECODE(StoreLocal, A_X);
1260 FP[rD] = *SP;
1261 DISPATCH();
1262 }
1263
1264 {
1265 BYTECODE(PopLocal, A_X);
1266 FP[rD] = *SP--;
1267 DISPATCH();
1268 }
1269
1270 {
1271 BYTECODE(MoveSpecial, A_D);
1272 FP[rA] = special_[rD];
1273 DISPATCH();
1274 }
1275
1276 {
1277 BYTECODE(BooleanNegateTOS, 0);
1278 SP[0] = (SP[0] == true_value) ? false_value : true_value;
1279 DISPATCH();
1280 }
1281
1282 {
1283 BYTECODE(StaticCall, A_D);
1284
1285 // Check if single stepping.
1286 if (thread->isolate()->single_step()) {
1287 Exit(thread, FP, SP + 1, pc);
1288 NativeArguments args(thread, 0, NULL, NULL);
1289 INVOKE_RUNTIME(DRT_SingleStepHandler, args);
1290 }
1291
1292 // Invoke target function.
1293 {
1294 const uint16_t argc = rA;
1295 RawObject** call_base = SP - argc;
1296 RawObject** call_top = SP; // *SP contains function
1297 argdesc = static_cast<RawArray*>(LOAD_CONSTANT(rD));
1298 Invoke(thread, call_base, call_top, &pp, &pc, &FP, &SP);
1299 }
1300
1301 DISPATCH();
1302 }
1303
1304 {
1305 BYTECODE(InstanceCall, A_D);
1306
1307 // Check if single stepping.
1308 if (thread->isolate()->single_step()) {
1309 Exit(thread, FP, SP + 1, pc);
1310 NativeArguments args(thread, 0, NULL, NULL);
1311 INVOKE_RUNTIME(DRT_SingleStepHandler, args);
1312 }
1313
1314 {
1315 const uint16_t argc = rA;
1316 const uint16_t kidx = rD;
1317
1318 RawObject** call_base = SP - argc + 1;
1319 RawObject** call_top = SP + 1;
1320 InstanceCall1(thread,
1321 static_cast<RawICData*>(LOAD_CONSTANT(kidx)),
1322 call_base, call_top, &argdesc, &pp, &pc, &FP, &SP);
1323 }
1324
1325 DISPATCH();
1326 }
1327
1328 {
1329 BYTECODE(InstanceCall2, A_D);
1330 if (thread->isolate()->single_step()) {
1331 Exit(thread, FP, SP + 1, pc);
1332 NativeArguments args(thread, 0, NULL, NULL);
1333 INVOKE_RUNTIME(DRT_SingleStepHandler, args);
1334 }
1335
1336 {
1337 const uint16_t argc = rA;
1338 const uint16_t kidx = rD;
1339
1340 RawObject** call_base = SP - argc + 1;
1341 RawObject** call_top = SP + 1;
1342 InstanceCall2(thread,
1343 static_cast<RawICData*>(LOAD_CONSTANT(kidx)),
1344 call_base, call_top, &argdesc, &pp, &pc, &FP, &SP);
1345 }
1346
1347 DISPATCH();
1348 }
1349
1350 {
1351 BYTECODE(InstanceCall3, A_D);
1352 if (thread->isolate()->single_step()) {
1353 Exit(thread, FP, SP + 1, pc);
1354 NativeArguments args(thread, 0, NULL, NULL);
1355 INVOKE_RUNTIME(DRT_SingleStepHandler, args);
1356 }
1357
1358 {
1359 const uint16_t argc = rA;
1360 const uint16_t kidx = rD;
1361
1362 RawObject** call_base = SP - argc + 1;
1363 RawObject** call_top = SP + 1;
1364 InstanceCall3(thread,
1365 static_cast<RawICData*>(LOAD_CONSTANT(kidx)),
1366 call_base, call_top, &argdesc, &pp, &pc, &FP, &SP);
1367 }
1368
1369 DISPATCH();
1370 }
1371
1372 {
1373 BYTECODE(NativeBootstrapCall, 0);
1374 RawFunction* function = FrameFunction(FP);
1375 RawObject** incoming_args =
1376 function->ptr()->num_optional_parameters_ == 0
zra 2016/04/18 16:50:14 parens
Vyacheslav Egorov (Google) 2016/04/18 19:19:56 Done.
1377 ? FrameArguments(FP, function->ptr()->num_fixed_parameters_)
1378 : FP;
1379
1380 SimulatorBootstrapNativeCall native_target =
1381 reinterpret_cast<SimulatorBootstrapNativeCall>(SP[-1]);
1382 intptr_t argc_tag = reinterpret_cast<intptr_t>(SP[-0]);
1383 SP[-0] = 0; // Note: argc_tag is not smi-tagged.
1384 SP[-1] = null_value;
1385 Exit(thread, FP, SP + 1, pc);
1386 NativeArguments args(thread, argc_tag, incoming_args, SP - 1);
1387 INVOKE_NATIVE(native_target, args);
1388 SP -= 1;
1389 DISPATCH();
1390 }
1391
1392 {
1393 BYTECODE(NativeCall, 0);
1394 RawFunction* function = FrameFunction(FP);
1395 RawObject** incoming_args =
1396 function->ptr()->num_optional_parameters_ == 0
zra 2016/04/18 16:50:14 ditto
Vyacheslav Egorov (Google) 2016/04/18 19:19:56 Done.
1397 ? FrameArguments(FP, function->ptr()->num_fixed_parameters_)
1398 : FP;
1399
1400 Dart_NativeFunction native_target =
1401 reinterpret_cast<Dart_NativeFunction>(SP[-1]);
1402 intptr_t argc_tag = reinterpret_cast<intptr_t>(SP[-0]);
1403 SP[-0] = 0; // argc_tag is not smi tagged!
1404 SP[-1] = null_value;
1405 Exit(thread, FP, SP + 1, pc);
1406 NativeArguments args(thread, argc_tag, incoming_args, SP - 1);
1407 INVOKE_NATIVE_WRAPPER(native_target, args);
1408 SP -= 1;
1409 DISPATCH();
1410 }
1411
1412 {
1413 BYTECODE(AddTOS, A_B_C);
1414 SMI_FASTPATH_TOS(intptr_t, SignedAddWithOverflow);
1415 }
1416 {
1417 BYTECODE(SubTOS, A_B_C);
1418 SMI_FASTPATH_TOS(intptr_t, SignedSubWithOverflow);
1419 }
1420 {
1421 BYTECODE(MulTOS, A_B_C);
1422 SMI_FASTPATH_TOS(intptr_t, SMI_MUL);
1423 }
1424 {
1425 BYTECODE(BitOrTOS, A_B_C);
1426 SMI_FASTPATH_TOS(intptr_t, SMI_BITOR);
1427 }
1428 {
1429 BYTECODE(BitAndTOS, A_B_C);
1430 SMI_FASTPATH_TOS(intptr_t, SMI_BITAND);
1431 }
1432 {
1433 BYTECODE(EqualTOS, A_B_C);
1434 SMI_FASTPATH_TOS(RawObject*, SMI_EQ);
1435 }
1436 {
1437 BYTECODE(LessThanTOS, A_B_C);
1438 SMI_FASTPATH_TOS(RawObject*, SMI_LT);
1439 }
1440 {
1441 BYTECODE(GreaterThanTOS, A_B_C);
1442 SMI_FASTPATH_TOS(RawObject*, SMI_GT);
1443 }
1444
1445 // Return and return like instructions (Instrinsic).
1446 {
1447 RawObject* result; // result to return to the caller.
1448
1449 BYTECODE(Intrinsic, A);
1450 // Try invoking intrinsic handler. If it succeeds (returns true)
1451 // then just return the value it returned to the caller.
1452 result = null_value;
1453 if (!intrinsics_[rA](thread, FP, &result)) {
1454 DISPATCH();
1455 }
1456 goto ReturnImpl;
1457
1458 BYTECODE(Return, A);
1459 result = FP[rA];
1460 goto ReturnImpl;
1461
1462 BYTECODE(ReturnTOS, 0);
1463 result = *SP;
1464 // Fall through to the ReturnImpl.
1465
1466 ReturnImpl:
1467 // Restore caller PC.
1468 pc = SavedCallerPC(FP);
1469
1470 // Check if it is a fake PC marking the entry frame.
1471 if ((reinterpret_cast<uword>(pc) & 2) != 0) {
1472 const intptr_t argc = reinterpret_cast<uword>(pc) >> 2;
1473 fp_ = sp_ =
1474 reinterpret_cast<RawObject**>(FrameArguments(FP, argc + 1)[0]);
1475 thread->set_top_exit_frame_info(reinterpret_cast<uword>(sp_));
1476 thread->set_top_resource(top_resource);
1477 thread->set_vm_tag(vm_tag);
1478 return result;
1479 }
1480
1481 // Look at the caller to determine how many arguments to pop.
1482 const uint8_t argc = Bytecode::DecodeArgc(pc[-1]);
1483
1484 // Restore SP, FP and PP. Push result and dispatch.
1485 SP = FrameArguments(FP, argc);
1486 FP = SavedCallerFP(FP);
1487 pp = FrameCode(FP)->ptr()->object_pool_->ptr();
1488 *SP = result;
1489 DISPATCH();
1490 }
1491
1492 {
1493 BYTECODE(StoreStaticTOS, A_D);
1494 RawField* field = reinterpret_cast<RawField*>(LOAD_CONSTANT(rD));
1495 RawInstance* value = static_cast<RawInstance*>(*SP--);
1496 field->StorePointer(&field->ptr()->value_.static_value_, value);
1497 DISPATCH();
1498 }
1499
1500 {
1501 BYTECODE(PushStatic, A_D);
1502 RawField* field = reinterpret_cast<RawField*>(LOAD_CONSTANT(rD));
1503 // Note: field is also on the stack, hence no increment.
1504 *SP = field->ptr()->value_.static_value_;
1505 DISPATCH();
1506 }
1507
1508 {
1509 BYTECODE(StoreField, A_B_C);
1510 const uint16_t offset_in_words = rB;
1511 const uint16_t value_reg = rC;
1512
1513 RawInstance* instance = reinterpret_cast<RawInstance*>(FP[rA]);
1514 RawObject* value = reinterpret_cast<RawObject*>(FP[value_reg]);
1515
1516 instance->StorePointer(
1517 reinterpret_cast<RawObject**>(instance->ptr()) + offset_in_words,
1518 value);
1519 DISPATCH();
1520 }
1521
1522 {
1523 BYTECODE(StoreFieldTOS, A_D);
1524 const uint16_t offset_in_words = rD;
1525 RawInstance* instance = reinterpret_cast<RawInstance*>(SP[-1]);
1526 RawObject* value = reinterpret_cast<RawObject*>(SP[0]);
1527 SP -= 2; // Drop instance and value.
1528 instance->StorePointer(
1529 reinterpret_cast<RawObject**>(instance->ptr()) + offset_in_words,
1530 value);
1531
1532 DISPATCH();
1533 }
1534
1535 {
1536 BYTECODE(LoadField, A_B_C);
1537 const uint16_t instance_reg = rB;
1538 const uint16_t offset_in_words = rC;
1539 RawInstance* instance = reinterpret_cast<RawInstance*>(FP[instance_reg]);
1540 FP[rA] = reinterpret_cast<RawObject**>(instance->ptr())[offset_in_words];
1541 DISPATCH();
1542 }
1543
1544 {
1545 BYTECODE(LoadFieldTOS, A_D);
1546 const uint16_t offset_in_words = rD;
1547 RawInstance* instance = static_cast<RawInstance*>(SP[0]);
1548 SP[0] = reinterpret_cast<RawObject**>(instance->ptr())[offset_in_words];
1549 DISPATCH();
1550 }
1551
1552 {
1553 BYTECODE(InitStaticTOS, A);
1554 RawField* field = static_cast<RawField*>(*SP--);
1555 RawObject* value = field->ptr()->value_.static_value_;
1556 if ((value == Object::sentinel().raw()) ||
1557 (value == Object::transition_sentinel().raw())) {
1558 // Note: SP[1] already contains the field object.
1559 SP[2] = 0;
1560 Exit(thread, FP, SP + 3, pc);
1561 NativeArguments args(thread, 1, SP + 1, SP + 2);
1562 INVOKE_RUNTIME(DRT_InitStaticField, args);
1563 }
1564 DISPATCH();
1565 }
1566
1567 // TODO(vegorov) allocation bytecodes can benefit from the new-space
1568 // allocation fast-path that does not transition into the runtime system.
1569 {
1570 BYTECODE(AllocateContext, A_D);
1571 const uint16_t num_context_variables = rD;
1572 {
1573 *++SP = 0;
1574 SP[1] = Smi::New(num_context_variables);
1575 Exit(thread, FP, SP + 2, pc);
1576 NativeArguments args(thread, 1, SP + 1, SP);
1577 INVOKE_RUNTIME(DRT_AllocateContext, args);
1578 }
1579 DISPATCH();
1580 }
1581
1582 {
1583 BYTECODE(CloneContext, A);
1584 {
1585 SP[1] = SP[0]; // Context to clone.
1586 Exit(thread, FP, SP + 2, pc);
1587 NativeArguments args(thread, 1, SP + 1, SP);
1588 INVOKE_RUNTIME(DRT_CloneContext, args);
1589 }
1590 DISPATCH();
1591 }
1592
1593 {
1594 BYTECODE(Allocate, A_D);
1595 SP[1] = 0; // Space for the result.
1596 SP[2] = LOAD_CONSTANT(rD); // Class object.
1597 SP[3] = null_value; // Type arguments.
1598 Exit(thread, FP, SP + 4, pc);
1599 NativeArguments args(thread, 2, SP + 2, SP + 1);
1600 INVOKE_RUNTIME(DRT_AllocateObject, args);
1601 SP++; // Result is in SP[1].
1602 DISPATCH();
1603 }
1604
1605 {
1606 BYTECODE(AllocateT, 0);
1607 SP[1] = SP[-0]; // Class object.
1608 SP[2] = SP[-1]; // Type arguments
1609 Exit(thread, FP, SP + 3, pc);
1610 NativeArguments args(thread, 2, SP + 1, SP - 1);
1611 INVOKE_RUNTIME(DRT_AllocateObject, args);
1612 SP -= 1; // Result is in SP - 1.
1613 DISPATCH();
1614 }
1615
1616 {
1617 BYTECODE(CreateArrayTOS, 0);
1618 SP[1] = SP[-0]; // Length.
1619 SP[2] = SP[-1]; // Type.
1620 Exit(thread, FP, SP + 3, pc);
1621 NativeArguments args(thread, 2, SP + 1, SP - 1);
1622 INVOKE_RUNTIME(DRT_AllocateArray, args);
1623 SP -= 1;
1624 DISPATCH();
1625 }
1626
1627 {
1628 BYTECODE(AssertAssignable, A_D); // Stack: instance, type args, type, name
1629 RawObject** args = SP - 3;
1630 if (args[0] != null_value) {
1631 RawSubtypeTestCache* cache =
1632 static_cast<RawSubtypeTestCache*>(LOAD_CONSTANT(rD));
1633 if (cache != null_value) {
1634 RawInstance* instance = static_cast<RawInstance*>(args[0]);
1635 RawTypeArguments* instantiator_type_arguments =
1636 static_cast<RawTypeArguments*>(args[1]);
1637
1638 const intptr_t cid = SimulatorHelpers::GetClassId(instance);
1639
1640 RawTypeArguments* instance_type_arguments =
1641 static_cast<RawTypeArguments*>(null_value);
1642 RawObject* instance_cid_or_function;
1643 if (cid == kClosureCid) {
1644 RawClosure* closure = static_cast<RawClosure*>(instance);
1645 instance_type_arguments = closure->ptr()->type_arguments_;
1646 instance_cid_or_function = closure->ptr()->function_;
1647 } else {
1648 instance_cid_or_function = Smi::New(cid);
1649
1650 RawClass* instance_class =
1651 thread->isolate()->class_table()->At(cid);
1652 if (instance_class->ptr()->num_type_arguments_ < 0) {
1653 goto AssertAssignableCallRuntime;
1654 } else if (instance_class->ptr()->num_type_arguments_ > 0) {
1655 instance_type_arguments = reinterpret_cast<RawTypeArguments**>(
1656 instance
1657 ->ptr())[instance_class->ptr()
1658 ->type_arguments_field_offset_in_words_];
1659 }
1660 }
1661
1662 for (RawObject** entries = cache->ptr()->cache_->ptr()->data();
1663 entries[0] != null_value;
1664 entries += SubtypeTestCache::kTestEntryLength) {
1665 if (entries[SubtypeTestCache::kInstanceClassIdOrFunction] ==
zra 2016/04/18 16:50:14 parens around comparisons
Vyacheslav Egorov (Google) 2016/04/18 19:19:57 Done.
1666 instance_cid_or_function &&
1667 entries[SubtypeTestCache::kInstanceTypeArguments] ==
1668 instance_type_arguments &&
1669 entries[SubtypeTestCache::kInstantiatorTypeArguments] ==
1670 instantiator_type_arguments) {
1671 if (true_value == entries[SubtypeTestCache::kTestResult]) {
1672 goto AssertAssignableOk;
1673 } else {
1674 break;
1675 }
1676 }
1677 }
1678 }
1679
1680 AssertAssignableCallRuntime:
1681 SP[1] = args[0]; // instance
1682 SP[2] = args[2]; // type
1683 SP[3] = args[1]; // type args
1684 SP[4] = args[3]; // name
1685 SP[5] = cache;
1686 Exit(thread, FP, SP + 6, pc);
1687 NativeArguments args(thread, 5, SP + 1, SP - 3);
1688 INVOKE_RUNTIME(DRT_TypeCheck, args);
1689 }
1690
1691 AssertAssignableOk:
1692 SP -= 3;
1693 DISPATCH();
1694 }
1695
1696 {
1697 BYTECODE(AssertBoolean, A);
1698 RawObject* value = SP[0];
1699 if (rA) { // Should we perform type check?
1700 if (value == true_value || value == false_value) {
zra 2016/04/18 16:50:14 ditto
Vyacheslav Egorov (Google) 2016/04/18 19:19:57 Done.
1701 goto AssertBooleanOk;
1702 }
1703 } else if (value != null_value) {
1704 goto AssertBooleanOk;
1705 }
1706
1707 // Assertion failed.
1708 {
1709 SP[1] = SP[0]; // instance
1710 Exit(thread, FP, SP + 2, pc);
1711 NativeArguments args(thread, 1, SP + 1, SP);
1712 INVOKE_RUNTIME(DRT_NonBoolTypeError, args);
1713 }
1714
1715 AssertBooleanOk:
1716 DISPATCH();
1717 }
1718
1719 {
1720 BYTECODE(IfEqStrictTOS, A_D);
1721 SP -= 2;
1722 if (SP[1] != SP[2]) {
1723 pc++;
1724 }
1725 DISPATCH();
1726 }
1727
1728 {
1729 BYTECODE(IfNeStrictTOS, A_D);
1730 SP -= 2;
1731 if (SP[1] == SP[2]) {
1732 pc++;
1733 }
1734 DISPATCH();
1735 }
1736
1737 {
1738 BYTECODE(IfEqStrictNumTOS, A_D);
1739 if (thread->isolate()->single_step()) {
1740 Exit(thread, FP, SP + 1, pc);
1741 NativeArguments args(thread, 0, NULL, NULL);
1742 INVOKE_RUNTIME(DRT_SingleStepHandler, args);
1743 }
1744
1745 SP -= 2;
1746 if (!SimulatorHelpers::IsStrictEqualWithNumberCheck(SP[1], SP[2])) {
1747 pc++;
1748 }
1749 DISPATCH();
1750 }
1751
1752 {
1753 BYTECODE(IfNeStrictNumTOS, A_D);
1754 if (thread->isolate()->single_step()) {
1755 Exit(thread, FP, SP + 1, pc);
1756 NativeArguments args(thread, 0, NULL, NULL);
1757 INVOKE_RUNTIME(DRT_SingleStepHandler, args);
1758 }
1759
1760 SP -= 2;
1761 if (SimulatorHelpers::IsStrictEqualWithNumberCheck(SP[1], SP[2])) {
1762 pc++;
1763 }
1764 DISPATCH();
1765 }
1766
1767 {
1768 BYTECODE(Jump, 0);
1769 const int32_t target = static_cast<int32_t>(op) >> 8;
1770 pc += (target - 1);
1771 DISPATCH();
1772 }
1773
1774 {
1775 BYTECODE(StoreIndexedTOS, 0);
1776 SP -= 3;
1777 RawArray* array = static_cast<RawArray*>(SP[1]);
1778 RawSmi* index = static_cast<RawSmi*>(SP[2]);
1779 RawObject* value = SP[3];
1780 ASSERT(array->GetClassId() == kArrayCid);
1781 ASSERT(!index->IsHeapObject());
1782 array->StorePointer(array->ptr()->data() + Smi::Value(index), value);
1783 DISPATCH();
1784 }
1785
1786 {
1787 BYTECODE(Trap, 0);
1788 UNIMPLEMENTED();
1789 DISPATCH();
1790 }
1791
1792 // Helper used to handle noSuchMethod on closures.
1793 {
1794 ClosureNoSuchMethod:
1795 #if defined(DEBUG)
1796 function_h ^= FrameFunction(FP);
1797 ASSERT(function_h.IsClosureFunction());
1798 #endif
1799
1800 // Restore caller context as we are going to throw NoSuchMethod.
1801 pc = SavedCallerPC(FP);
1802
1803 const bool has_dart_caller = (reinterpret_cast<uword>(pc) & 2) == 0;
1804 const intptr_t argc = has_dart_caller
1805 ? Bytecode::DecodeArgc(pc[-1])
1806 : (reinterpret_cast<uword>(pc) >> 2);
1807
1808 SP = FrameArguments(FP, 0);
1809 RawObject** args = SP - argc;
1810 FP = SavedCallerFP(FP);
1811 if (has_dart_caller) {
1812 pp = FrameCode(FP)->ptr()->object_pool_->ptr();
1813 }
1814
1815 *++SP = null_value;
1816 *++SP = args[0]; // Closure object.
1817 *++SP = argdesc;
1818 *++SP = null_value; // Array of arguments (will be filled).
1819
1820 // Allocate array of arguments.
1821 {
1822 SP[1] = Smi::New(argc); // length
1823 SP[2] = null_value; // type
1824 Exit(thread, FP, SP + 3, pc);
1825 NativeArguments native_args(thread, 2, SP + 1, SP);
1826 INVOKE_RUNTIME(DRT_AllocateArray, native_args);
1827
1828 // Copy arguments into the newly allocated array.
1829 RawArray* array = static_cast<RawArray*>(SP[0]);
1830 ASSERT(array->GetClassId() == kArrayCid);
1831 for (intptr_t i = 0; i < argc; i++) {
1832 array->ptr()->data()[i] = args[i];
1833 }
1834 }
1835
1836 // Invoke noSuchMethod passing down closure, argument descriptor and
1837 // array of arguments.
1838 {
1839 Exit(thread, FP, SP + 1, pc);
1840 NativeArguments native_args(thread, 3, SP - 2, SP - 3);
1841 INVOKE_RUNTIME(DRT_InvokeClosureNoSuchMethod, native_args);
1842 UNREACHABLE();
1843 }
1844
1845 DISPATCH();
1846 }
1847
1848 // Single dispatch point used by exception handling macros.
1849 {
1850 DispatchAfterException:
1851 DISPATCH();
1852 }
1853
1854 UNREACHABLE();
1855 return 0;
1856 }
1857
1858 void Simulator::Longjmp(uword pc,
1859 uword sp,
1860 uword fp,
1861 RawObject* raw_exception,
1862 RawObject* raw_stacktrace,
1863 Thread* thread) {
1864 // Walk over all setjmp buffers (simulated --> C++ transitions)
1865 // and try to find the setjmp associated with the simulated stack pointer.
1866 SimulatorSetjmpBuffer* buf = last_setjmp_buffer();
1867 while ((buf->link() != NULL) && (buf->link()->fp() > fp)) {
1868 buf = buf->link();
1869 }
1870 ASSERT(buf != NULL);
1871 ASSERT(last_setjmp_buffer() == buf);
1872
1873 // The C++ caller has not cleaned up the stack memory of C++ frames.
1874 // Prepare for unwinding frames by destroying all the stack resources
1875 // in the previous C++ frames.
1876 StackResource::Unwind(thread);
1877
1878 // Set the tag.
1879 thread->set_vm_tag(VMTag::kDartTagId);
1880 // Clear top exit frame.
1881 thread->set_top_exit_frame_info(0);
1882
1883 ASSERT(raw_exception != Object::null());
1884 sp_ = reinterpret_cast<RawObject**>(sp);
1885 fp_ = reinterpret_cast<RawObject**>(fp);
1886 pc_ = pc;
1887 special_[kExceptionSpecialIndex] = raw_exception;
1888 special_[kStacktraceSpecialIndex] = raw_stacktrace;
1889 buf->Longjmp();
1890 UNREACHABLE();
1891 }
1892
1893 } // namespace dart
1894
1895
1896 #endif // defined TARGET_ARCH_DBC
OLDNEW
« no previous file with comments | « runtime/vm/simulator_dbc.h ('k') | runtime/vm/simulator_mips.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698