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

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

Powered by Google App Engine
This is Rietveld 408576698