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

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