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