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

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

Issue 2858623002: Remove MIPS support (Closed)
Patch Set: Merge and cleanup Created 3 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « runtime/vm/simulator_mips.h ('k') | runtime/vm/snapshot.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 2013, 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_MIPS)
10
11 // Only build the simulator if not compiling for real MIPS hardware.
12 #if defined(USING_SIMULATOR)
13
14 #include "vm/simulator.h"
15
16 #include "vm/assembler.h"
17 #include "vm/constants_mips.h"
18 #include "vm/disassembler.h"
19 #include "vm/lockers.h"
20 #include "vm/native_arguments.h"
21 #include "vm/stack_frame.h"
22 #include "vm/os_thread.h"
23
24 namespace dart {
25
26 DEFINE_FLAG(uint64_t,
27 trace_sim_after,
28 ULLONG_MAX,
29 "Trace simulator execution after instruction count reached.");
30 DEFINE_FLAG(uint64_t,
31 stop_sim_at,
32 ULLONG_MAX,
33 "Instruction address or instruction count to stop simulator at.");
34
35
36 // This macro provides a platform independent use of sscanf. The reason for
37 // SScanF not being implemented in a platform independent way through
38 // OS in the same way as SNPrint is that the Windows C Run-Time
39 // Library does not provide vsscanf.
40 #define SScanF sscanf // NOLINT
41
42
43 // SimulatorSetjmpBuffer are linked together, and the last created one
44 // is referenced by the Simulator. When an exception is thrown, the exception
45 // runtime looks at where to jump and finds the corresponding
46 // SimulatorSetjmpBuffer based on the stack pointer of the exception handler.
47 // The runtime then does a Longjmp on that buffer to return to the simulator.
48 class SimulatorSetjmpBuffer {
49 public:
50 void Longjmp() {
51 // "This" is now the last setjmp buffer.
52 simulator_->set_last_setjmp_buffer(this);
53 longjmp(buffer_, 1);
54 }
55
56 explicit SimulatorSetjmpBuffer(Simulator* sim) {
57 simulator_ = sim;
58 link_ = sim->last_setjmp_buffer();
59 sim->set_last_setjmp_buffer(this);
60 sp_ = static_cast<uword>(sim->get_register(SP));
61 }
62
63 ~SimulatorSetjmpBuffer() {
64 ASSERT(simulator_->last_setjmp_buffer() == this);
65 simulator_->set_last_setjmp_buffer(link_);
66 }
67
68 SimulatorSetjmpBuffer* link() { return link_; }
69
70 uword sp() { return sp_; }
71
72 private:
73 uword sp_;
74 Simulator* simulator_;
75 SimulatorSetjmpBuffer* link_;
76 jmp_buf buffer_;
77
78 friend class Simulator;
79 };
80
81
82 // The SimulatorDebugger class is used by the simulator while debugging
83 // simulated MIPS code.
84 class SimulatorDebugger {
85 public:
86 explicit SimulatorDebugger(Simulator* sim);
87 ~SimulatorDebugger();
88
89 void Stop(Instr* instr, const char* message);
90 void Debug();
91 char* ReadLine(const char* prompt);
92
93 private:
94 Simulator* sim_;
95
96 bool GetValue(char* desc, uint32_t* value);
97 bool GetFValue(char* desc, double* value);
98 bool GetDValue(char* desc, double* value);
99
100 static TokenPosition GetApproximateTokenIndex(const Code& code, uword pc);
101
102 static void PrintDartFrame(uword pc,
103 uword fp,
104 uword sp,
105 const Function& function,
106 TokenPosition token_pos,
107 bool is_optimized,
108 bool is_inlined);
109 void PrintBacktrace();
110
111 // Set or delete a breakpoint. Returns true if successful.
112 bool SetBreakpoint(Instr* breakpc);
113 bool DeleteBreakpoint(Instr* breakpc);
114
115 // Undo and redo all breakpoints. This is needed to bracket disassembly and
116 // execution to skip past breakpoints when run from the debugger.
117 void UndoBreakpoints();
118 void RedoBreakpoints();
119 };
120
121
122 SimulatorDebugger::SimulatorDebugger(Simulator* sim) {
123 sim_ = sim;
124 }
125
126
127 SimulatorDebugger::~SimulatorDebugger() {}
128
129
130 void SimulatorDebugger::Stop(Instr* instr, const char* message) {
131 OS::Print("Simulator hit %s\n", message);
132 Debug();
133 }
134
135
136 static Register LookupCpuRegisterByName(const char* name) {
137 static const char* kNames[] = {
138 "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
139 "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
140 "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
141 "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31",
142
143 "zr", "at", "v0", "v1", "a0", "a1", "a2", "a3",
144 "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7",
145 "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
146 "t8", "t9", "k0", "k1", "gp", "sp", "fp", "ra"};
147 static const Register kRegisters[] = {
148 R0, R1, R2, R3, R4, R5, R6, R7, R8, R9, R10,
149 R11, R12, R13, R14, R15, R16, R17, R18, R19, R20, R21,
150 R22, R23, R24, R25, R26, R27, R28, R29, R30, R31,
151
152 ZR, AT, V0, V1, A0, A1, A2, A3, T0, T1, T2,
153 T3, T4, T5, T6, T7, S0, S1, S2, S3, S4, S5,
154 S6, S7, T8, T9, K0, K1, GP, SP, FP, RA};
155 ASSERT(ARRAY_SIZE(kNames) == ARRAY_SIZE(kRegisters));
156 for (unsigned i = 0; i < ARRAY_SIZE(kNames); i++) {
157 if (strcmp(kNames[i], name) == 0) {
158 return kRegisters[i];
159 }
160 }
161 return kNoRegister;
162 }
163
164
165 static FRegister LookupFRegisterByName(const char* name) {
166 int reg_nr = -1;
167 bool ok = SScanF(name, "f%d", &reg_nr);
168 if (ok && (0 <= reg_nr) && (reg_nr < kNumberOfFRegisters)) {
169 return static_cast<FRegister>(reg_nr);
170 }
171 return kNoFRegister;
172 }
173
174
175 bool SimulatorDebugger::GetValue(char* desc, uint32_t* value) {
176 Register reg = LookupCpuRegisterByName(desc);
177 if (reg != kNoRegister) {
178 *value = sim_->get_register(reg);
179 return true;
180 }
181 if (desc[0] == '*') {
182 uint32_t addr;
183 if (GetValue(desc + 1, &addr)) {
184 if (Simulator::IsIllegalAddress(addr)) {
185 return false;
186 }
187 *value = *(reinterpret_cast<uint32_t*>(addr));
188 return true;
189 }
190 }
191 if (strcmp("pc", desc) == 0) {
192 *value = sim_->get_pc();
193 return true;
194 }
195 bool retval = SScanF(desc, "0x%x", value) == 1;
196 if (!retval) {
197 retval = SScanF(desc, "%x", value) == 1;
198 }
199 return retval;
200 }
201
202
203 bool SimulatorDebugger::GetFValue(char* desc, double* value) {
204 FRegister freg = LookupFRegisterByName(desc);
205 if (freg != kNoFRegister) {
206 *value = sim_->get_fregister(freg);
207 return true;
208 }
209 if (desc[0] == '*') {
210 uint32_t addr;
211 if (GetValue(desc + 1, &addr)) {
212 if (Simulator::IsIllegalAddress(addr)) {
213 return false;
214 }
215 *value = *(reinterpret_cast<float*>(addr));
216 return true;
217 }
218 }
219 return false;
220 }
221
222
223 bool SimulatorDebugger::GetDValue(char* desc, double* value) {
224 FRegister freg = LookupFRegisterByName(desc);
225 if (freg != kNoFRegister) {
226 *value = sim_->get_fregister_double(freg);
227 return true;
228 }
229 if (desc[0] == '*') {
230 uint32_t addr;
231 if (GetValue(desc + 1, &addr)) {
232 if (Simulator::IsIllegalAddress(addr)) {
233 return false;
234 }
235 *value = *(reinterpret_cast<double*>(addr));
236 return true;
237 }
238 }
239 return false;
240 }
241
242
243 TokenPosition SimulatorDebugger::GetApproximateTokenIndex(const Code& code,
244 uword pc) {
245 TokenPosition token_pos = TokenPosition::kNoSource;
246 uword pc_offset = pc - code.PayloadStart();
247 const PcDescriptors& descriptors =
248 PcDescriptors::Handle(code.pc_descriptors());
249 PcDescriptors::Iterator iter(descriptors, RawPcDescriptors::kAnyKind);
250 while (iter.MoveNext()) {
251 if (iter.PcOffset() == pc_offset) {
252 return iter.TokenPos();
253 } else if (!token_pos.IsReal() && (iter.PcOffset() > pc_offset)) {
254 token_pos = iter.TokenPos();
255 }
256 }
257 return token_pos;
258 }
259
260
261 void SimulatorDebugger::PrintDartFrame(uword pc,
262 uword fp,
263 uword sp,
264 const Function& function,
265 TokenPosition token_pos,
266 bool is_optimized,
267 bool is_inlined) {
268 const Script& script = Script::Handle(function.script());
269 const String& func_name = String::Handle(function.QualifiedScrubbedName());
270 const String& url = String::Handle(script.url());
271 intptr_t line = -1;
272 intptr_t column = -1;
273 if (token_pos.IsReal()) {
274 script.GetTokenLocation(token_pos, &line, &column);
275 }
276 OS::Print(
277 "pc=0x%" Px " fp=0x%" Px " sp=0x%" Px " %s%s (%s:%" Pd ":%" Pd ")\n", pc,
278 fp, sp, is_optimized ? (is_inlined ? "inlined " : "optimized ") : "",
279 func_name.ToCString(), url.ToCString(), line, column);
280 }
281
282
283 void SimulatorDebugger::PrintBacktrace() {
284 StackFrameIterator frames(
285 sim_->get_register(FP), sim_->get_register(SP), sim_->get_pc(),
286 StackFrameIterator::kDontValidateFrames, Thread::Current(),
287 StackFrameIterator::kNoCrossThreadIteration);
288 StackFrame* frame = frames.NextFrame();
289 ASSERT(frame != NULL);
290 Function& function = Function::Handle();
291 Function& inlined_function = Function::Handle();
292 Code& code = Code::Handle();
293 Code& unoptimized_code = Code::Handle();
294 while (frame != NULL) {
295 if (frame->IsDartFrame()) {
296 code = frame->LookupDartCode();
297 function = code.function();
298 if (code.is_optimized()) {
299 // For optimized frames, extract all the inlined functions if any
300 // into the stack trace.
301 InlinedFunctionsIterator it(code, frame->pc());
302 while (!it.Done()) {
303 // Print each inlined frame with its pc in the corresponding
304 // unoptimized frame.
305 inlined_function = it.function();
306 unoptimized_code = it.code();
307 uword unoptimized_pc = it.pc();
308 it.Advance();
309 if (!it.Done()) {
310 PrintDartFrame(
311 unoptimized_pc, frame->fp(), frame->sp(), inlined_function,
312 GetApproximateTokenIndex(unoptimized_code, unoptimized_pc),
313 true, true);
314 }
315 }
316 // Print the optimized inlining frame below.
317 }
318 PrintDartFrame(frame->pc(), frame->fp(), frame->sp(), function,
319 GetApproximateTokenIndex(code, frame->pc()),
320 code.is_optimized(), false);
321 } else {
322 OS::Print("pc=0x%" Px " fp=0x%" Px " sp=0x%" Px " %s frame\n",
323 frame->pc(), frame->fp(), frame->sp(),
324 frame->IsEntryFrame()
325 ? "entry"
326 : frame->IsExitFrame()
327 ? "exit"
328 : frame->IsStubFrame() ? "stub" : "invalid");
329 }
330 frame = frames.NextFrame();
331 }
332 }
333
334
335 bool SimulatorDebugger::SetBreakpoint(Instr* breakpc) {
336 // Check if a breakpoint can be set. If not return without any side-effects.
337 if (sim_->break_pc_ != NULL) {
338 return false;
339 }
340
341 // Set the breakpoint.
342 sim_->break_pc_ = breakpc;
343 sim_->break_instr_ = breakpc->InstructionBits();
344 // Not setting the breakpoint instruction in the code itself. It will be set
345 // when the debugger shell continues.
346 return true;
347 }
348
349
350 bool SimulatorDebugger::DeleteBreakpoint(Instr* breakpc) {
351 if (sim_->break_pc_ != NULL) {
352 sim_->break_pc_->SetInstructionBits(sim_->break_instr_);
353 }
354
355 sim_->break_pc_ = NULL;
356 sim_->break_instr_ = 0;
357 return true;
358 }
359
360
361 void SimulatorDebugger::UndoBreakpoints() {
362 if (sim_->break_pc_ != NULL) {
363 sim_->break_pc_->SetInstructionBits(sim_->break_instr_);
364 }
365 }
366
367
368 void SimulatorDebugger::RedoBreakpoints() {
369 if (sim_->break_pc_ != NULL) {
370 sim_->break_pc_->SetInstructionBits(Instr::kSimulatorBreakpointInstruction);
371 }
372 }
373
374
375 void SimulatorDebugger::Debug() {
376 intptr_t last_pc = -1;
377 bool done = false;
378
379 #define COMMAND_SIZE 63
380 #define ARG_SIZE 255
381
382 #define STR(a) #a
383 #define XSTR(a) STR(a)
384
385 char cmd[COMMAND_SIZE + 1];
386 char arg1[ARG_SIZE + 1];
387 char arg2[ARG_SIZE + 1];
388
389 // make sure to have a proper terminating character if reaching the limit
390 cmd[COMMAND_SIZE] = 0;
391 arg1[ARG_SIZE] = 0;
392 arg2[ARG_SIZE] = 0;
393
394 // Undo all set breakpoints while running in the debugger shell. This will
395 // make them invisible to all commands.
396 UndoBreakpoints();
397
398 while (!done) {
399 if (last_pc != sim_->get_pc()) {
400 last_pc = sim_->get_pc();
401 if (Simulator::IsIllegalAddress(last_pc)) {
402 OS::Print("pc is out of bounds: 0x%" Px "\n", last_pc);
403 } else {
404 if (FLAG_support_disassembler) {
405 Disassembler::Disassemble(last_pc, last_pc + Instr::kInstrSize);
406 } else {
407 OS::Print("Disassembler not supported in this mode.\n");
408 }
409 }
410 }
411 char* line = ReadLine("sim> ");
412 if (line == NULL) {
413 FATAL("ReadLine failed");
414 } else {
415 // Use sscanf to parse the individual parts of the command line. At the
416 // moment no command expects more than two parameters.
417 int args = SScanF(line,
418 "%" XSTR(COMMAND_SIZE) "s "
419 "%" XSTR(ARG_SIZE) "s "
420 "%" XSTR(ARG_SIZE) "s",
421 cmd, arg1, arg2);
422 if ((strcmp(cmd, "h") == 0) || (strcmp(cmd, "help") == 0)) {
423 OS::Print(
424 "c/cont -- continue execution\n"
425 "disasm -- disassemble instrs at current pc location\n"
426 " other variants are:\n"
427 " disasm <address>\n"
428 " disasm <address> <number_of_instructions>\n"
429 " by default 10 instrs are disassembled\n"
430 "del -- delete breakpoints\n"
431 "gdb -- transfer control to gdb\n"
432 "h/help -- print this help string\n"
433 "break <address> -- set break point at specified address\n"
434 "p/print <reg or icount or value or *addr> -- print integer\n"
435 "pf/printfloat <freg or *addr> -- print float value\n"
436 "po/printobject <*reg or *addr> -- print object\n"
437 "si/stepi -- single step an instruction\n"
438 "trace -- toggle execution tracing mode\n"
439 "bt -- print backtrace\n"
440 "unstop -- if current pc is a stop instr make it a nop\n"
441 "q/quit -- Quit the debugger and exit the program\n");
442 } else if ((strcmp(cmd, "quit") == 0) || (strcmp(cmd, "q") == 0)) {
443 OS::Print("Quitting\n");
444 OS::Exit(0);
445 } else if ((strcmp(cmd, "si") == 0) || (strcmp(cmd, "stepi") == 0)) {
446 sim_->InstructionDecode(reinterpret_cast<Instr*>(sim_->get_pc()));
447 } else if ((strcmp(cmd, "c") == 0) || (strcmp(cmd, "cont") == 0)) {
448 // Execute the one instruction we broke at with breakpoints disabled.
449 sim_->InstructionDecode(reinterpret_cast<Instr*>(sim_->get_pc()));
450 // Leave the debugger shell.
451 done = true;
452 } else if ((strcmp(cmd, "p") == 0) || (strcmp(cmd, "print") == 0)) {
453 if (args == 2) {
454 uint32_t value;
455 if (strcmp(arg1, "icount") == 0) {
456 const uint64_t icount = sim_->get_icount();
457 OS::Print("icount: %" Pu64 " 0x%" Px64 "\n", icount, icount);
458 } else if (GetValue(arg1, &value)) {
459 OS::Print("%s: %u 0x%x\n", arg1, value, value);
460 } else {
461 OS::Print("%s unrecognized\n", arg1);
462 }
463 } else {
464 OS::Print("print <reg or icount or value or *addr>\n");
465 }
466 } else if ((strcmp(cmd, "pf") == 0) || (strcmp(cmd, "printfloat") == 0)) {
467 if (args == 2) {
468 double dvalue;
469 if (GetFValue(arg1, &dvalue)) {
470 uint64_t long_value = bit_cast<uint64_t, double>(dvalue);
471 OS::Print("%s: %llu 0x%llx %.8g\n", arg1, long_value, long_value,
472 dvalue);
473 } else {
474 OS::Print("%s unrecognized\n", arg1);
475 }
476 } else {
477 OS::Print("printfloat <dreg or *addr>\n");
478 }
479 } else if ((strcmp(cmd, "pd") == 0) ||
480 (strcmp(cmd, "printdouble") == 0)) {
481 if (args == 2) {
482 double dvalue;
483 if (GetDValue(arg1, &dvalue)) {
484 uint64_t long_value = bit_cast<uint64_t, double>(dvalue);
485 OS::Print("%s: %llu 0x%llx %.8g\n", arg1, long_value, long_value,
486 dvalue);
487 } else {
488 OS::Print("%s unrecognized\n", arg1);
489 }
490 } else {
491 OS::Print("printfloat <dreg or *addr>\n");
492 }
493 } else if ((strcmp(cmd, "po") == 0) ||
494 (strcmp(cmd, "printobject") == 0)) {
495 if (args == 2) {
496 uint32_t value;
497 // Make the dereferencing '*' optional.
498 if (((arg1[0] == '*') && GetValue(arg1 + 1, &value)) ||
499 GetValue(arg1, &value)) {
500 if (Isolate::Current()->heap()->Contains(value)) {
501 OS::Print("%s: \n", arg1);
502 #if defined(DEBUG)
503 const Object& obj =
504 Object::Handle(reinterpret_cast<RawObject*>(value));
505 obj.Print();
506 #endif // defined(DEBUG)
507 } else {
508 OS::Print("0x%x is not an object reference\n", value);
509 }
510 } else {
511 OS::Print("%s unrecognized\n", arg1);
512 }
513 } else {
514 OS::Print("printobject <*reg or *addr>\n");
515 }
516 } else if (strcmp(cmd, "disasm") == 0) {
517 uint32_t start = 0;
518 uint32_t end = 0;
519 if (args == 1) {
520 start = sim_->get_pc();
521 end = start + (10 * Instr::kInstrSize);
522 } else if (args == 2) {
523 if (GetValue(arg1, &start)) {
524 // No length parameter passed, assume 10 instructions.
525 if (Simulator::IsIllegalAddress(start)) {
526 // If start isn't a valid address, warn and use PC instead.
527 OS::Print("First argument yields invalid address: 0x%x\n", start);
528 OS::Print("Using PC instead\n");
529 start = sim_->get_pc();
530 }
531 end = start + (10 * Instr::kInstrSize);
532 }
533 } else {
534 uint32_t length;
535 if (GetValue(arg1, &start) && GetValue(arg2, &length)) {
536 if (Simulator::IsIllegalAddress(start)) {
537 // If start isn't a valid address, warn and use PC instead.
538 OS::Print("First argument yields invalid address: 0x%x\n", start);
539 OS::Print("Using PC instead\n");
540 start = sim_->get_pc();
541 }
542 end = start + (length * Instr::kInstrSize);
543 }
544 }
545 if ((start > 0) && (end > start)) {
546 if (FLAG_support_disassembler) {
547 Disassembler::Disassemble(start, end);
548 } else {
549 OS::Print("Disassembler not supported in this mode.\n");
550 }
551 } else {
552 OS::Print("disasm [<address> [<number_of_instructions>]]\n");
553 }
554 } else if (strcmp(cmd, "gdb") == 0) {
555 OS::Print("relinquishing control to gdb\n");
556 OS::DebugBreak();
557 OS::Print("regaining control from gdb\n");
558 } else if (strcmp(cmd, "break") == 0) {
559 if (args == 2) {
560 uint32_t addr;
561 if (GetValue(arg1, &addr)) {
562 if (!SetBreakpoint(reinterpret_cast<Instr*>(addr))) {
563 OS::Print("setting breakpoint failed\n");
564 }
565 } else {
566 OS::Print("%s unrecognized\n", arg1);
567 }
568 } else {
569 OS::Print("break <addr>\n");
570 }
571 } else if (strcmp(cmd, "del") == 0) {
572 if (!DeleteBreakpoint(NULL)) {
573 OS::Print("deleting breakpoint failed\n");
574 }
575 } else if (strcmp(cmd, "unstop") == 0) {
576 intptr_t stop_pc = sim_->get_pc() - Instr::kInstrSize;
577 Instr* stop_instr = reinterpret_cast<Instr*>(stop_pc);
578 if (stop_instr->IsBreakPoint()) {
579 stop_instr->SetInstructionBits(Instr::kNopInstruction);
580 } else {
581 OS::Print("Not at debugger stop.\n");
582 }
583 } else if (strcmp(cmd, "trace") == 0) {
584 if (FLAG_trace_sim_after == ULLONG_MAX) {
585 FLAG_trace_sim_after = sim_->get_icount();
586 OS::Print("execution tracing on\n");
587 } else {
588 FLAG_trace_sim_after = ULLONG_MAX;
589 OS::Print("execution tracing off\n");
590 }
591 } else if (strcmp(cmd, "bt") == 0) {
592 PrintBacktrace();
593 } else {
594 OS::Print("Unknown command: %s\n", cmd);
595 }
596 }
597 delete[] line;
598 }
599
600 // Add all the breakpoints back to stop execution and enter the debugger
601 // shell when hit.
602 RedoBreakpoints();
603
604 #undef COMMAND_SIZE
605 #undef ARG_SIZE
606
607 #undef STR
608 #undef XSTR
609 }
610
611
612 char* SimulatorDebugger::ReadLine(const char* prompt) {
613 char* result = NULL;
614 char line_buf[256];
615 intptr_t offset = 0;
616 bool keep_going = true;
617 OS::Print("%s", prompt);
618 while (keep_going) {
619 if (fgets(line_buf, sizeof(line_buf), stdin) == NULL) {
620 // fgets got an error. Just give up.
621 if (result != NULL) {
622 delete[] result;
623 }
624 return NULL;
625 }
626 intptr_t len = strlen(line_buf);
627 if (len > 1 && line_buf[len - 2] == '\\' && line_buf[len - 1] == '\n') {
628 // When we read a line that ends with a "\" we remove the escape and
629 // append the remainder.
630 line_buf[len - 2] = '\n';
631 line_buf[len - 1] = 0;
632 len -= 1;
633 } else if ((len > 0) && (line_buf[len - 1] == '\n')) {
634 // Since we read a new line we are done reading the line. This
635 // will exit the loop after copying this buffer into the result.
636 keep_going = false;
637 }
638 if (result == NULL) {
639 // Allocate the initial result and make room for the terminating '\0'
640 result = new char[len + 1];
641 if (result == NULL) {
642 // OOM, so cannot readline anymore.
643 return NULL;
644 }
645 } else {
646 // Allocate a new result with enough room for the new addition.
647 intptr_t new_len = offset + len + 1;
648 char* new_result = new char[new_len];
649 if (new_result == NULL) {
650 // OOM, free the buffer allocated so far and return NULL.
651 delete[] result;
652 return NULL;
653 } else {
654 // Copy the existing input into the new array and set the new
655 // array as the result.
656 memmove(new_result, result, offset);
657 delete[] result;
658 result = new_result;
659 }
660 }
661 // Copy the newly read line into the result.
662 memmove(result + offset, line_buf, len);
663 offset += len;
664 }
665 ASSERT(result != NULL);
666 result[offset] = '\0';
667 return result;
668 }
669
670
671 // Synchronization primitives support.
672 Mutex* Simulator::exclusive_access_lock_ = NULL;
673 Simulator::AddressTag Simulator::exclusive_access_state_[kNumAddressTags] = {
674 {NULL, 0}};
675 int Simulator::next_address_tag_ = 0;
676
677
678 void Simulator::InitOnce() {
679 // Setup exclusive access state lock.
680 exclusive_access_lock_ = new Mutex();
681 }
682
683
684 Simulator::Simulator() {
685 // Setup simulator support first. Some of this information is needed to
686 // setup the architecture state.
687 // We allocate the stack here, the size is computed as the sum of
688 // the size specified by the user and the buffer space needed for
689 // handling stack overflow exceptions. To be safe in potential
690 // stack underflows we also add some underflow buffer space.
691 stack_ =
692 new char[(OSThread::GetSpecifiedStackSize() + OSThread::kStackSizeBuffer +
693 kSimulatorStackUnderflowSize)];
694 icount_ = 0;
695 delay_slot_ = false;
696 break_pc_ = NULL;
697 break_instr_ = 0;
698 last_setjmp_buffer_ = NULL;
699 top_exit_frame_info_ = 0;
700
701 // Setup architecture state.
702 // All registers are initialized to zero to start with.
703 for (int i = 0; i < kNumberOfCpuRegisters; i++) {
704 registers_[i] = 0;
705 }
706 pc_ = 0;
707 // The sp is initialized to point to the bottom (high address) of the
708 // allocated stack area.
709 registers_[SP] = StackTop();
710
711 // All double-precision registers are initialized to zero.
712 for (int i = 0; i < kNumberOfFRegisters; i++) {
713 fregisters_[i] = 0.0;
714 }
715 fcsr_ = 0;
716 }
717
718
719 Simulator::~Simulator() {
720 delete[] stack_;
721 Isolate* isolate = Isolate::Current();
722 if (isolate != NULL) {
723 isolate->set_simulator(NULL);
724 }
725 }
726
727
728 // When the generated code calls an external reference we need to catch that in
729 // the simulator. The external reference will be a function compiled for the
730 // host architecture. We need to call that function instead of trying to
731 // execute it with the simulator. We do that by redirecting the external
732 // reference to a break instruction with code 2 that is handled by
733 // the simulator. We write the original destination of the jump just at a known
734 // offset from the break instruction so the simulator knows what to call.
735 class Redirection {
736 public:
737 uword address_of_break_instruction() {
738 return reinterpret_cast<uword>(&break_instruction_);
739 }
740
741 uword external_function() const { return external_function_; }
742
743 Simulator::CallKind call_kind() const { return call_kind_; }
744
745 int argument_count() const { return argument_count_; }
746
747 static Redirection* Get(uword external_function,
748 Simulator::CallKind call_kind,
749 int argument_count) {
750 Redirection* current;
751 for (current = list_; current != NULL; current = current->next_) {
752 if (current->external_function_ == external_function) return current;
753 }
754 return new Redirection(external_function, call_kind, argument_count);
755 }
756
757 static Redirection* FromBreakInstruction(Instr* break_instruction) {
758 char* addr_of_break = reinterpret_cast<char*>(break_instruction);
759 char* addr_of_redirection =
760 addr_of_break - OFFSET_OF(Redirection, break_instruction_);
761 return reinterpret_cast<Redirection*>(addr_of_redirection);
762 }
763
764 static uword FunctionForRedirect(uword address_of_break) {
765 Redirection* current;
766 for (current = list_; current != NULL; current = current->next_) {
767 if (current->address_of_break_instruction() == address_of_break) {
768 return current->external_function_;
769 }
770 }
771 return 0;
772 }
773
774 private:
775 Redirection(uword external_function,
776 Simulator::CallKind call_kind,
777 int argument_count)
778 : external_function_(external_function),
779 call_kind_(call_kind),
780 argument_count_(argument_count),
781 break_instruction_(Instr::kSimulatorRedirectInstruction),
782 next_(list_) {
783 // Atomically prepend this element to the front of the global list.
784 // Note: Since elements are never removed, there is no ABA issue.
785 Redirection* list_head = list_;
786 do {
787 next_ = list_head;
788 list_head =
789 reinterpret_cast<Redirection*>(AtomicOperations::CompareAndSwapWord(
790 reinterpret_cast<uword*>(&list_), reinterpret_cast<uword>(next_),
791 reinterpret_cast<uword>(this)));
792 } while (list_head != next_);
793 }
794
795 uword external_function_;
796 Simulator::CallKind call_kind_;
797 int argument_count_;
798 uint32_t break_instruction_;
799 Redirection* next_;
800 static Redirection* list_;
801 };
802
803
804 Redirection* Redirection::list_ = NULL;
805
806
807 uword Simulator::RedirectExternalReference(uword function,
808 CallKind call_kind,
809 int argument_count) {
810 Redirection* redirection =
811 Redirection::Get(function, call_kind, argument_count);
812 return redirection->address_of_break_instruction();
813 }
814
815
816 uword Simulator::FunctionForRedirect(uword redirect) {
817 return Redirection::FunctionForRedirect(redirect);
818 }
819
820
821 // Get the active Simulator for the current isolate.
822 Simulator* Simulator::Current() {
823 Simulator* simulator = Isolate::Current()->simulator();
824 if (simulator == NULL) {
825 simulator = new Simulator();
826 Isolate::Current()->set_simulator(simulator);
827 }
828 return simulator;
829 }
830
831
832 // Sets the register in the architecture state.
833 void Simulator::set_register(Register reg, int32_t value) {
834 if (reg != R0) {
835 registers_[reg] = value;
836 }
837 }
838
839
840 void Simulator::set_fregister(FRegister reg, int32_t value) {
841 ASSERT(reg >= 0);
842 ASSERT(reg < kNumberOfFRegisters);
843 fregisters_[reg] = value;
844 }
845
846
847 void Simulator::set_fregister_float(FRegister reg, float value) {
848 ASSERT(reg >= 0);
849 ASSERT(reg < kNumberOfFRegisters);
850 fregisters_[reg] = bit_cast<int32_t, float>(value);
851 }
852
853
854 void Simulator::set_fregister_long(FRegister reg, int64_t value) {
855 ASSERT(reg >= 0);
856 ASSERT(reg < kNumberOfFRegisters);
857 ASSERT((reg & 1) == 0);
858 fregisters_[reg] = Utils::Low32Bits(value);
859 fregisters_[reg + 1] = Utils::High32Bits(value);
860 }
861
862
863 void Simulator::set_fregister_double(FRegister reg, double value) {
864 const int64_t ival = bit_cast<int64_t, double>(value);
865 set_fregister_long(reg, ival);
866 }
867
868
869 void Simulator::set_dregister_bits(DRegister reg, int64_t value) {
870 ASSERT(reg >= 0);
871 ASSERT(reg < kNumberOfDRegisters);
872 FRegister lo = static_cast<FRegister>(reg * 2);
873 FRegister hi = static_cast<FRegister>((reg * 2) + 1);
874 set_fregister(lo, Utils::Low32Bits(value));
875 set_fregister(hi, Utils::High32Bits(value));
876 }
877
878
879 void Simulator::set_dregister(DRegister reg, double value) {
880 ASSERT(reg >= 0);
881 ASSERT(reg < kNumberOfDRegisters);
882 set_dregister_bits(reg, bit_cast<int64_t, double>(value));
883 }
884
885
886 // Get the register from the architecture state.
887 int32_t Simulator::get_register(Register reg) const {
888 if (reg == R0) {
889 return 0;
890 }
891 return registers_[reg];
892 }
893
894
895 int32_t Simulator::get_fregister(FRegister reg) const {
896 ASSERT((reg >= 0) && (reg < kNumberOfFRegisters));
897 return fregisters_[reg];
898 }
899
900
901 float Simulator::get_fregister_float(FRegister reg) const {
902 ASSERT(reg >= 0);
903 ASSERT(reg < kNumberOfFRegisters);
904 return bit_cast<float, int32_t>(fregisters_[reg]);
905 }
906
907
908 int64_t Simulator::get_fregister_long(FRegister reg) const {
909 ASSERT(reg >= 0);
910 ASSERT(reg < kNumberOfFRegisters);
911 ASSERT((reg & 1) == 0);
912 const int32_t low = fregisters_[reg];
913 const int32_t high = fregisters_[reg + 1];
914 const int64_t value = Utils::LowHighTo64Bits(low, high);
915 return value;
916 }
917
918
919 double Simulator::get_fregister_double(FRegister reg) const {
920 ASSERT(reg >= 0);
921 ASSERT(reg < kNumberOfFRegisters);
922 ASSERT((reg & 1) == 0);
923 const int64_t value = get_fregister_long(reg);
924 return bit_cast<double, int64_t>(value);
925 }
926
927
928 int64_t Simulator::get_dregister_bits(DRegister reg) const {
929 ASSERT(reg >= 0);
930 ASSERT(reg < kNumberOfDRegisters);
931 FRegister lo = static_cast<FRegister>(reg * 2);
932 FRegister hi = static_cast<FRegister>((reg * 2) + 1);
933 return Utils::LowHighTo64Bits(get_fregister(lo), get_fregister(hi));
934 }
935
936
937 double Simulator::get_dregister(DRegister reg) const {
938 ASSERT(reg >= 0);
939 ASSERT(reg < kNumberOfDRegisters);
940 const int64_t value = get_dregister_bits(reg);
941 return bit_cast<double, int64_t>(value);
942 }
943
944
945 void Simulator::UnimplementedInstruction(Instr* instr) {
946 char buffer[64];
947 snprintf(buffer, sizeof(buffer), "Unimplemented instruction: pc=%p\n", instr);
948 SimulatorDebugger dbg(this);
949 dbg.Stop(instr, buffer);
950 FATAL("Cannot continue execution after unimplemented instruction.");
951 }
952
953
954 void Simulator::HandleIllegalAccess(uword addr, Instr* instr) {
955 uword fault_pc = get_pc();
956 // The debugger will not be able to single step past this instruction, but
957 // it will be possible to disassemble the code and inspect registers.
958 char buffer[128];
959 snprintf(buffer, sizeof(buffer),
960 "illegal memory access at 0x%" Px ", pc=0x%" Px "\n", addr,
961 fault_pc);
962 SimulatorDebugger dbg(this);
963 dbg.Stop(instr, buffer);
964 // The debugger will return control in non-interactive mode.
965 FATAL("Cannot continue execution after illegal memory access.");
966 }
967
968
969 void Simulator::UnalignedAccess(const char* msg, uword addr, Instr* instr) {
970 // The debugger will not be able to single step past this instruction, but
971 // it will be possible to disassemble the code and inspect registers.
972 char buffer[128];
973 snprintf(buffer, sizeof(buffer), "pc=%p, unaligned %s at 0x%" Px "\n", instr,
974 msg, addr);
975 SimulatorDebugger dbg(this);
976 dbg.Stop(instr, buffer);
977 // The debugger will return control in non-interactive mode.
978 FATAL("Cannot continue execution after unaligned access.");
979 }
980
981
982 // Returns the top of the stack area to enable checking for stack pointer
983 // validity.
984 uword Simulator::StackTop() const {
985 // To be safe in potential stack underflows we leave some buffer above and
986 // set the stack top.
987 return StackBase() +
988 (OSThread::GetSpecifiedStackSize() + OSThread::kStackSizeBuffer);
989 }
990
991
992 bool Simulator::IsTracingExecution() const {
993 return icount_ > FLAG_trace_sim_after;
994 }
995
996
997 void Simulator::Format(Instr* instr, const char* format) {
998 OS::PrintErr("Simulator - unknown instruction: %s\n", format);
999 UNIMPLEMENTED();
1000 }
1001
1002
1003 int8_t Simulator::ReadB(uword addr) {
1004 int8_t* ptr = reinterpret_cast<int8_t*>(addr);
1005 return *ptr;
1006 }
1007
1008
1009 uint8_t Simulator::ReadBU(uword addr) {
1010 uint8_t* ptr = reinterpret_cast<uint8_t*>(addr);
1011 return *ptr;
1012 }
1013
1014
1015 int16_t Simulator::ReadH(uword addr, Instr* instr) {
1016 if ((addr & 1) == 0) {
1017 int16_t* ptr = reinterpret_cast<int16_t*>(addr);
1018 return *ptr;
1019 }
1020 UnalignedAccess("signed halfword read", addr, instr);
1021 return 0;
1022 }
1023
1024
1025 uint16_t Simulator::ReadHU(uword addr, Instr* instr) {
1026 if ((addr & 1) == 0) {
1027 uint16_t* ptr = reinterpret_cast<uint16_t*>(addr);
1028 return *ptr;
1029 }
1030 UnalignedAccess("unsigned halfword read", addr, instr);
1031 return 0;
1032 }
1033
1034
1035 intptr_t Simulator::ReadW(uword addr, Instr* instr) {
1036 if ((addr & 3) == 0) {
1037 intptr_t* ptr = reinterpret_cast<intptr_t*>(addr);
1038 return *ptr;
1039 }
1040 UnalignedAccess("read", addr, instr);
1041 return 0;
1042 }
1043
1044
1045 void Simulator::WriteB(uword addr, uint8_t value) {
1046 uint8_t* ptr = reinterpret_cast<uint8_t*>(addr);
1047 *ptr = value;
1048 }
1049
1050
1051 void Simulator::WriteH(uword addr, uint16_t value, Instr* instr) {
1052 if ((addr & 1) == 0) {
1053 uint16_t* ptr = reinterpret_cast<uint16_t*>(addr);
1054 *ptr = value;
1055 return;
1056 }
1057 UnalignedAccess("halfword write", addr, instr);
1058 }
1059
1060
1061 void Simulator::WriteW(uword addr, intptr_t value, Instr* instr) {
1062 if ((addr & 3) == 0) {
1063 intptr_t* ptr = reinterpret_cast<intptr_t*>(addr);
1064 *ptr = value;
1065 return;
1066 }
1067 UnalignedAccess("write", addr, instr);
1068 }
1069
1070
1071 double Simulator::ReadD(uword addr, Instr* instr) {
1072 if ((addr & 7) == 0) {
1073 double* ptr = reinterpret_cast<double*>(addr);
1074 return *ptr;
1075 }
1076 UnalignedAccess("double-precision floating point read", addr, instr);
1077 return 0.0;
1078 }
1079
1080
1081 void Simulator::WriteD(uword addr, double value, Instr* instr) {
1082 if ((addr & 7) == 0) {
1083 double* ptr = reinterpret_cast<double*>(addr);
1084 *ptr = value;
1085 return;
1086 }
1087 UnalignedAccess("double-precision floating point write", addr, instr);
1088 }
1089
1090
1091 // Synchronization primitives support.
1092 void Simulator::SetExclusiveAccess(uword addr) {
1093 Thread* thread = Thread::Current();
1094 ASSERT(thread != NULL);
1095 DEBUG_ASSERT(exclusive_access_lock_->IsOwnedByCurrentThread());
1096 int i = 0;
1097 // Find an entry for this thread in the exclusive access state.
1098 while ((i < kNumAddressTags) &&
1099 (exclusive_access_state_[i].thread != thread)) {
1100 i++;
1101 }
1102 // Round-robin replacement of previously used entries.
1103 if (i == kNumAddressTags) {
1104 i = next_address_tag_;
1105 if (++next_address_tag_ == kNumAddressTags) {
1106 next_address_tag_ = 0;
1107 }
1108 exclusive_access_state_[i].thread = thread;
1109 }
1110 // Remember the address being reserved.
1111 exclusive_access_state_[i].addr = addr;
1112 }
1113
1114
1115 bool Simulator::HasExclusiveAccessAndOpen(uword addr) {
1116 Thread* thread = Thread::Current();
1117 ASSERT(thread != NULL);
1118 ASSERT(addr != 0);
1119 DEBUG_ASSERT(exclusive_access_lock_->IsOwnedByCurrentThread());
1120 bool result = false;
1121 for (int i = 0; i < kNumAddressTags; i++) {
1122 if (exclusive_access_state_[i].thread == thread) {
1123 // Check whether the current thread's address reservation matches.
1124 if (exclusive_access_state_[i].addr == addr) {
1125 result = true;
1126 }
1127 exclusive_access_state_[i].addr = 0;
1128 } else if (exclusive_access_state_[i].addr == addr) {
1129 // Other threads with matching address lose their reservations.
1130 exclusive_access_state_[i].addr = 0;
1131 }
1132 }
1133 return result;
1134 }
1135
1136
1137 void Simulator::ClearExclusive() {
1138 MutexLocker ml(exclusive_access_lock_);
1139 // Remove the reservation for this thread.
1140 SetExclusiveAccess(0);
1141 }
1142
1143
1144 intptr_t Simulator::ReadExclusiveW(uword addr, Instr* instr) {
1145 MutexLocker ml(exclusive_access_lock_);
1146 SetExclusiveAccess(addr);
1147 return ReadW(addr, instr);
1148 }
1149
1150
1151 intptr_t Simulator::WriteExclusiveW(uword addr, intptr_t value, Instr* instr) {
1152 MutexLocker ml(exclusive_access_lock_);
1153 bool write_allowed = HasExclusiveAccessAndOpen(addr);
1154 if (write_allowed) {
1155 WriteW(addr, value, instr);
1156 return 1; // Success.
1157 }
1158 return 0; // Failure.
1159 }
1160
1161
1162 uword Simulator::CompareExchange(uword* address,
1163 uword compare_value,
1164 uword new_value) {
1165 MutexLocker ml(exclusive_access_lock_);
1166 // We do not get a reservation as it would be guaranteed to be found when
1167 // writing below. No other thread is able to make a reservation while we
1168 // hold the lock.
1169 uword value = *address;
1170 if (value == compare_value) {
1171 *address = new_value;
1172 // Same effect on exclusive access state as a successful SC.
1173 HasExclusiveAccessAndOpen(reinterpret_cast<uword>(address));
1174 } else {
1175 // Same effect on exclusive access state as an LL.
1176 SetExclusiveAccess(reinterpret_cast<uword>(address));
1177 }
1178 return value;
1179 }
1180
1181
1182 uint32_t Simulator::CompareExchangeUint32(uint32_t* address,
1183 uint32_t compare_value,
1184 uint32_t new_value) {
1185 COMPILE_ASSERT(sizeof(uword) == sizeof(uint32_t));
1186 return CompareExchange(reinterpret_cast<uword*>(address),
1187 static_cast<uword>(compare_value),
1188 static_cast<uword>(new_value));
1189 }
1190
1191
1192 // Calls into the Dart runtime are based on this interface.
1193 typedef void (*SimulatorRuntimeCall)(NativeArguments arguments);
1194
1195 // Calls to leaf Dart runtime functions are based on this interface.
1196 typedef int32_t (*SimulatorLeafRuntimeCall)(int32_t r0,
1197 int32_t r1,
1198 int32_t r2,
1199 int32_t r3);
1200
1201 // Calls to leaf float Dart runtime functions are based on this interface.
1202 typedef double (*SimulatorLeafFloatRuntimeCall)(double d0, double d1);
1203
1204 // Calls to native Dart functions are based on this interface.
1205 typedef void (*SimulatorBootstrapNativeCall)(NativeArguments* arguments);
1206 typedef void (*SimulatorNativeCall)(NativeArguments* arguments, uword target);
1207
1208
1209 void Simulator::DoBreak(Instr* instr) {
1210 ASSERT(instr->OpcodeField() == SPECIAL);
1211 ASSERT(instr->FunctionField() == BREAK);
1212 if (instr->BreakCodeField() == Instr::kStopMessageCode) {
1213 SimulatorDebugger dbg(this);
1214 const char* message = *reinterpret_cast<const char**>(
1215 reinterpret_cast<intptr_t>(instr) - Instr::kInstrSize);
1216 set_pc(get_pc() + Instr::kInstrSize);
1217 dbg.Stop(instr, message);
1218 // Adjust for extra pc increment.
1219 set_pc(get_pc() - Instr::kInstrSize);
1220 } else if (instr->BreakCodeField() == Instr::kSimulatorRedirectCode) {
1221 SimulatorSetjmpBuffer buffer(this);
1222
1223 if (!setjmp(buffer.buffer_)) {
1224 int32_t saved_ra = get_register(RA);
1225 Redirection* redirection = Redirection::FromBreakInstruction(instr);
1226 uword external = redirection->external_function();
1227 if (IsTracingExecution()) {
1228 THR_Print("Call to host function at 0x%" Pd "\n", external);
1229 }
1230
1231 if ((redirection->call_kind() == kRuntimeCall) ||
1232 (redirection->call_kind() == kBootstrapNativeCall) ||
1233 (redirection->call_kind() == kNativeCall)) {
1234 // Set the top_exit_frame_info of this simulator to the native stack.
1235 set_top_exit_frame_info(Thread::GetCurrentStackPointer());
1236 }
1237 if (redirection->call_kind() == kRuntimeCall) {
1238 NativeArguments arguments;
1239 ASSERT(sizeof(NativeArguments) == 4 * kWordSize);
1240 arguments.thread_ = reinterpret_cast<Thread*>(get_register(A0));
1241 arguments.argc_tag_ = get_register(A1);
1242 arguments.argv_ = reinterpret_cast<RawObject**>(get_register(A2));
1243 arguments.retval_ = reinterpret_cast<RawObject**>(get_register(A3));
1244 SimulatorRuntimeCall target =
1245 reinterpret_cast<SimulatorRuntimeCall>(external);
1246 target(arguments);
1247 set_register(V0, icount_); // Zap result registers from void function.
1248 set_register(V1, icount_);
1249 } else if (redirection->call_kind() == kLeafRuntimeCall) {
1250 int32_t a0 = get_register(A0);
1251 int32_t a1 = get_register(A1);
1252 int32_t a2 = get_register(A2);
1253 int32_t a3 = get_register(A3);
1254 SimulatorLeafRuntimeCall target =
1255 reinterpret_cast<SimulatorLeafRuntimeCall>(external);
1256 a0 = target(a0, a1, a2, a3);
1257 set_register(V0, a0); // Set returned result from function.
1258 set_register(V1, icount_); // Zap second result register.
1259 } else if (redirection->call_kind() == kLeafFloatRuntimeCall) {
1260 ASSERT((0 <= redirection->argument_count()) &&
1261 (redirection->argument_count() <= 2));
1262 // double values are passed and returned in floating point registers.
1263 SimulatorLeafFloatRuntimeCall target =
1264 reinterpret_cast<SimulatorLeafFloatRuntimeCall>(external);
1265 double d0 = 0.0;
1266 double d6 = get_fregister_double(F12);
1267 double d7 = get_fregister_double(F14);
1268 d0 = target(d6, d7);
1269 set_fregister_double(F0, d0);
1270 } else if (redirection->call_kind() == kBootstrapNativeCall) {
1271 ASSERT(redirection->argument_count() == 1);
1272 NativeArguments* arguments;
1273 arguments = reinterpret_cast<NativeArguments*>(get_register(A0));
1274 SimulatorBootstrapNativeCall target =
1275 reinterpret_cast<SimulatorBootstrapNativeCall>(external);
1276 target(arguments);
1277 set_register(V0, icount_); // Zap result register from void function.
1278 set_register(V1, icount_);
1279 } else {
1280 ASSERT(redirection->call_kind() == kNativeCall);
1281 NativeArguments* arguments;
1282 arguments = reinterpret_cast<NativeArguments*>(get_register(A0));
1283 uword target_func = get_register(A1);
1284 SimulatorNativeCall target =
1285 reinterpret_cast<SimulatorNativeCall>(external);
1286 target(arguments, target_func);
1287 set_register(V0, icount_); // Zap result register from void function.
1288 set_register(V1, icount_);
1289 }
1290 set_top_exit_frame_info(0);
1291
1292 // Zap caller-saved registers, since the actual runtime call could have
1293 // used them.
1294 set_register(T0, icount_);
1295 set_register(T1, icount_);
1296 set_register(T2, icount_);
1297 set_register(T3, icount_);
1298 set_register(T4, icount_);
1299 set_register(T5, icount_);
1300 set_register(T6, icount_);
1301 set_register(T7, icount_);
1302 set_register(T8, icount_);
1303 set_register(T9, icount_);
1304
1305 set_register(A0, icount_);
1306 set_register(A1, icount_);
1307 set_register(A2, icount_);
1308 set_register(A3, icount_);
1309 set_register(TMP, icount_);
1310 set_register(RA, icount_);
1311
1312 // Zap floating point registers.
1313 int32_t zap_dvalue = icount_;
1314 for (int i = F4; i <= F18; i++) {
1315 set_fregister(static_cast<FRegister>(i), zap_dvalue);
1316 }
1317
1318 // Return. Subtract to account for pc_ increment after return.
1319 set_pc(saved_ra - Instr::kInstrSize);
1320 } else {
1321 // Coming via long jump from a throw. Continue to exception handler.
1322 set_top_exit_frame_info(0);
1323 // Adjust for extra pc increment.
1324 set_pc(get_pc() - Instr::kInstrSize);
1325 }
1326 } else if (instr->BreakCodeField() == Instr::kSimulatorBreakCode) {
1327 SimulatorDebugger dbg(this);
1328 dbg.Stop(instr, "breakpoint");
1329 // Adjust for extra pc increment.
1330 set_pc(get_pc() - Instr::kInstrSize);
1331 } else {
1332 SimulatorDebugger dbg(this);
1333 set_pc(get_pc() + Instr::kInstrSize);
1334 char buffer[32];
1335 snprintf(buffer, sizeof(buffer), "break #0x%x", instr->BreakCodeField());
1336 dbg.Stop(instr, buffer);
1337 // Adjust for extra pc increment.
1338 set_pc(get_pc() - Instr::kInstrSize);
1339 }
1340 }
1341
1342
1343 void Simulator::DecodeSpecial(Instr* instr) {
1344 ASSERT(instr->OpcodeField() == SPECIAL);
1345 switch (instr->FunctionField()) {
1346 case ADDU: {
1347 ASSERT(instr->SaField() == 0);
1348 // Format(instr, "addu 'rd, 'rs, 'rt");
1349 int32_t rs_val = get_register(instr->RsField());
1350 int32_t rt_val = get_register(instr->RtField());
1351 set_register(instr->RdField(), rs_val + rt_val);
1352 break;
1353 }
1354 case AND: {
1355 ASSERT(instr->SaField() == 0);
1356 // Format(instr, "and 'rd, 'rs, 'rt");
1357 int32_t rs_val = get_register(instr->RsField());
1358 int32_t rt_val = get_register(instr->RtField());
1359 set_register(instr->RdField(), rs_val & rt_val);
1360 break;
1361 }
1362 case BREAK: {
1363 DoBreak(instr);
1364 break;
1365 }
1366 case DIV: {
1367 ASSERT(instr->RdField() == 0);
1368 ASSERT(instr->SaField() == 0);
1369 // Format(instr, "div 'rs, 'rt");
1370 int32_t rs_val = get_register(instr->RsField());
1371 int32_t rt_val = get_register(instr->RtField());
1372 if (rt_val == 0) {
1373 // Results are unpredictable, but there is no arithmetic exception.
1374 set_hi_register(icount_);
1375 set_lo_register(icount_);
1376 break;
1377 }
1378
1379 if ((rs_val == static_cast<int32_t>(0x80000000)) &&
1380 (rt_val == static_cast<int32_t>(0xffffffff))) {
1381 set_lo_register(0x80000000);
1382 set_hi_register(0);
1383 } else {
1384 set_lo_register(rs_val / rt_val);
1385 set_hi_register(rs_val % rt_val);
1386 }
1387 break;
1388 }
1389 case DIVU: {
1390 ASSERT(instr->RdField() == 0);
1391 ASSERT(instr->SaField() == 0);
1392 // Format(instr, "divu 'rs, 'rt");
1393 uint32_t rs_val = get_register(instr->RsField());
1394 uint32_t rt_val = get_register(instr->RtField());
1395 if (rt_val == 0) {
1396 // Results are unpredictable, but there is no arithmetic exception.
1397 set_hi_register(icount_);
1398 set_lo_register(icount_);
1399 break;
1400 }
1401 set_lo_register(rs_val / rt_val);
1402 set_hi_register(rs_val % rt_val);
1403 break;
1404 }
1405 case JALR: {
1406 ASSERT(instr->RtField() == R0);
1407 ASSERT(instr->RsField() != instr->RdField());
1408 ASSERT(!delay_slot_);
1409 // Format(instr, "jalr'hint 'rd, rs");
1410 set_register(instr->RdField(), pc_ + 2 * Instr::kInstrSize);
1411 uword next_pc = get_register(instr->RsField());
1412 ExecuteDelaySlot();
1413 // Set return address to be the instruction after the delay slot.
1414 pc_ = next_pc - Instr::kInstrSize; // Account for regular PC increment.
1415 break;
1416 }
1417 case JR: {
1418 ASSERT(instr->RtField() == R0);
1419 ASSERT(instr->RdField() == R0);
1420 ASSERT(!delay_slot_);
1421 // Format(instr, "jr'hint 'rs");
1422 uword next_pc = get_register(instr->RsField());
1423 ExecuteDelaySlot();
1424 pc_ = next_pc - Instr::kInstrSize; // Account for regular PC increment.
1425 break;
1426 }
1427 case MFHI: {
1428 ASSERT(instr->RsField() == 0);
1429 ASSERT(instr->RtField() == 0);
1430 ASSERT(instr->SaField() == 0);
1431 // Format(instr, "mfhi 'rd");
1432 set_register(instr->RdField(), get_hi_register());
1433 break;
1434 }
1435 case MFLO: {
1436 ASSERT(instr->RsField() == 0);
1437 ASSERT(instr->RtField() == 0);
1438 ASSERT(instr->SaField() == 0);
1439 // Format(instr, "mflo 'rd");
1440 set_register(instr->RdField(), get_lo_register());
1441 break;
1442 }
1443 case MOVCI: {
1444 ASSERT(instr->SaField() == 0);
1445 ASSERT(instr->Bit(17) == 0);
1446 int32_t rs_val = get_register(instr->RsField());
1447 uint32_t cc, fcsr_cc, test, status;
1448 cc = instr->Bits(18, 3);
1449 fcsr_cc = get_fcsr_condition_bit(cc);
1450 test = instr->Bit(16);
1451 status = test_fcsr_bit(fcsr_cc);
1452 if (test == status) {
1453 set_register(instr->RdField(), rs_val);
1454 }
1455 break;
1456 }
1457 case MOVN: {
1458 ASSERT(instr->SaField() == 0);
1459 // Format(instr, "movn 'rd, 'rs, 'rt");
1460 int32_t rt_val = get_register(instr->RtField());
1461 int32_t rs_val = get_register(instr->RsField());
1462 if (rt_val != 0) {
1463 set_register(instr->RdField(), rs_val);
1464 }
1465 break;
1466 }
1467 case MOVZ: {
1468 ASSERT(instr->SaField() == 0);
1469 // Format(instr, "movz 'rd, 'rs, 'rt");
1470 int32_t rt_val = get_register(instr->RtField());
1471 int32_t rs_val = get_register(instr->RsField());
1472 if (rt_val == 0) {
1473 set_register(instr->RdField(), rs_val);
1474 }
1475 break;
1476 }
1477 case MTHI: {
1478 ASSERT(instr->RtField() == 0);
1479 ASSERT(instr->RdField() == 0);
1480 ASSERT(instr->SaField() == 0);
1481 // Format(instr, "mthi 'rd");
1482 set_hi_register(get_register(instr->RsField()));
1483 break;
1484 }
1485 case MTLO: {
1486 ASSERT(instr->RtField() == 0);
1487 ASSERT(instr->RdField() == 0);
1488 ASSERT(instr->SaField() == 0);
1489 // Format(instr, "mflo 'rd");
1490 set_lo_register(get_register(instr->RsField()));
1491 break;
1492 }
1493 case MULT: {
1494 ASSERT(instr->RdField() == 0);
1495 ASSERT(instr->SaField() == 0);
1496 // Format(instr, "mult 'rs, 'rt");
1497 int64_t rs = get_register(instr->RsField());
1498 int64_t rt = get_register(instr->RtField());
1499 int64_t res = rs * rt;
1500 set_hi_register(Utils::High32Bits(res));
1501 set_lo_register(Utils::Low32Bits(res));
1502 break;
1503 }
1504 case MULTU: {
1505 ASSERT(instr->RdField() == 0);
1506 ASSERT(instr->SaField() == 0);
1507 // Format(instr, "multu 'rs, 'rt");
1508 uint64_t rs = static_cast<uint32_t>(get_register(instr->RsField()));
1509 uint64_t rt = static_cast<uint32_t>(get_register(instr->RtField()));
1510 uint64_t res = rs * rt;
1511 set_hi_register(Utils::High32Bits(res));
1512 set_lo_register(Utils::Low32Bits(res));
1513 break;
1514 }
1515 case NOR: {
1516 ASSERT(instr->SaField() == 0);
1517 // Format(instr, "nor 'rd, 'rs, 'rt");
1518 int32_t rs_val = get_register(instr->RsField());
1519 int32_t rt_val = get_register(instr->RtField());
1520 set_register(instr->RdField(), ~(rs_val | rt_val));
1521 break;
1522 }
1523 case OR: {
1524 ASSERT(instr->SaField() == 0);
1525 // Format(instr, "or 'rd, 'rs, 'rt");
1526 int32_t rs_val = get_register(instr->RsField());
1527 int32_t rt_val = get_register(instr->RtField());
1528 set_register(instr->RdField(), rs_val | rt_val);
1529 break;
1530 }
1531 case SLL: {
1532 ASSERT(instr->RsField() == 0);
1533 if ((instr->RdField() == R0) && (instr->RtField() == R0) &&
1534 (instr->SaField() == 0)) {
1535 // Format(instr, "nop");
1536 // Nothing to be done for NOP.
1537 } else {
1538 int32_t rt_val = get_register(instr->RtField());
1539 int sa = instr->SaField();
1540 set_register(instr->RdField(), rt_val << sa);
1541 }
1542 break;
1543 }
1544 case SLLV: {
1545 ASSERT(instr->SaField() == 0);
1546 // Format(instr, "sllv 'rd, 'rt, 'rs");
1547 int32_t rt_val = get_register(instr->RtField());
1548 int32_t rs_val = get_register(instr->RsField());
1549 set_register(instr->RdField(), rt_val << (rs_val & 0x1f));
1550 break;
1551 }
1552 case SLT: {
1553 ASSERT(instr->SaField() == 0);
1554 // Format(instr, "slt 'rd, 'rs, 'rt");
1555 int32_t rs_val = get_register(instr->RsField());
1556 int32_t rt_val = get_register(instr->RtField());
1557 set_register(instr->RdField(), rs_val < rt_val ? 1 : 0);
1558 break;
1559 }
1560 case SLTU: {
1561 ASSERT(instr->SaField() == 0);
1562 // Format(instr, "sltu 'rd, 'rs, 'rt");
1563 uint32_t rs_val = static_cast<uint32_t>(get_register(instr->RsField()));
1564 uint32_t rt_val = static_cast<uint32_t>(get_register(instr->RtField()));
1565 set_register(instr->RdField(), rs_val < rt_val ? 1 : 0);
1566 break;
1567 }
1568 case SRA: {
1569 ASSERT(instr->RsField() == 0);
1570 // Format(instr, "sra 'rd, 'rt, 'sa");
1571 int32_t rt_val = get_register(instr->RtField());
1572 int32_t sa = instr->SaField();
1573 set_register(instr->RdField(), rt_val >> sa);
1574 break;
1575 }
1576 case SRAV: {
1577 ASSERT(instr->SaField() == 0);
1578 // Format(instr, "srav 'rd, 'rt, 'rs");
1579 int32_t rt_val = get_register(instr->RtField());
1580 int32_t rs_val = get_register(instr->RsField());
1581 set_register(instr->RdField(), rt_val >> (rs_val & 0x1f));
1582 break;
1583 }
1584 case SRL: {
1585 ASSERT(instr->RsField() == 0);
1586 // Format(instr, "srl 'rd, 'rt, 'sa");
1587 uint32_t rt_val = get_register(instr->RtField());
1588 uint32_t sa = instr->SaField();
1589 set_register(instr->RdField(), rt_val >> sa);
1590 break;
1591 }
1592 case SRLV: {
1593 ASSERT(instr->SaField() == 0);
1594 // Format(instr, "srlv 'rd, 'rt, 'rs");
1595 uint32_t rt_val = get_register(instr->RtField());
1596 uint32_t rs_val = get_register(instr->RsField());
1597 set_register(instr->RdField(), rt_val >> (rs_val & 0x1f));
1598 break;
1599 }
1600 case SUBU: {
1601 ASSERT(instr->SaField() == 0);
1602 // Format(instr, "subu 'rd, 'rs, 'rt");
1603 int32_t rs_val = get_register(instr->RsField());
1604 int32_t rt_val = get_register(instr->RtField());
1605 set_register(instr->RdField(), rs_val - rt_val);
1606 break;
1607 }
1608 case XOR: {
1609 ASSERT(instr->SaField() == 0);
1610 // Format(instr, "xor 'rd, 'rs, 'rt");
1611 int32_t rs_val = get_register(instr->RsField());
1612 int32_t rt_val = get_register(instr->RtField());
1613 set_register(instr->RdField(), rs_val ^ rt_val);
1614 break;
1615 }
1616 default: {
1617 OS::PrintErr("DecodeSpecial: 0x%x\n", instr->InstructionBits());
1618 UnimplementedInstruction(instr);
1619 break;
1620 }
1621 }
1622 }
1623
1624
1625 void Simulator::DecodeSpecial2(Instr* instr) {
1626 ASSERT(instr->OpcodeField() == SPECIAL2);
1627 switch (instr->FunctionField()) {
1628 case MADD: {
1629 ASSERT(instr->RdField() == 0);
1630 ASSERT(instr->SaField() == 0);
1631 // Format(instr, "madd 'rs, 'rt");
1632 uint32_t lo = get_lo_register();
1633 int32_t hi = get_hi_register();
1634 int64_t accum = Utils::LowHighTo64Bits(lo, hi);
1635 int64_t rs = get_register(instr->RsField());
1636 int64_t rt = get_register(instr->RtField());
1637 int64_t res = accum + rs * rt;
1638 set_hi_register(Utils::High32Bits(res));
1639 set_lo_register(Utils::Low32Bits(res));
1640 break;
1641 }
1642 case MADDU: {
1643 ASSERT(instr->RdField() == 0);
1644 ASSERT(instr->SaField() == 0);
1645 // Format(instr, "maddu 'rs, 'rt");
1646 uint32_t lo = get_lo_register();
1647 uint32_t hi = get_hi_register();
1648 uint64_t accum = Utils::LowHighTo64Bits(lo, hi);
1649 uint64_t rs = static_cast<uint32_t>(get_register(instr->RsField()));
1650 uint64_t rt = static_cast<uint32_t>(get_register(instr->RtField()));
1651 uint64_t res = accum + rs * rt;
1652 set_hi_register(Utils::High32Bits(res));
1653 set_lo_register(Utils::Low32Bits(res));
1654 break;
1655 }
1656 case CLO: {
1657 ASSERT(instr->SaField() == 0);
1658 ASSERT(instr->RtField() == instr->RdField());
1659 // Format(instr, "clo 'rd, 'rs");
1660 int32_t rs_val = get_register(instr->RsField());
1661 int32_t bitcount = 0;
1662 while (rs_val < 0) {
1663 bitcount++;
1664 rs_val <<= 1;
1665 }
1666 set_register(instr->RdField(), bitcount);
1667 break;
1668 }
1669 case CLZ: {
1670 ASSERT(instr->SaField() == 0);
1671 ASSERT(instr->RtField() == instr->RdField());
1672 // Format(instr, "clz 'rd, 'rs");
1673 int32_t rs_val = get_register(instr->RsField());
1674 int32_t bitcount = 0;
1675 if (rs_val != 0) {
1676 while (rs_val > 0) {
1677 bitcount++;
1678 rs_val <<= 1;
1679 }
1680 } else {
1681 bitcount = 32;
1682 }
1683 set_register(instr->RdField(), bitcount);
1684 break;
1685 }
1686 default: {
1687 OS::PrintErr("DecodeSpecial2: 0x%x\n", instr->InstructionBits());
1688 UnimplementedInstruction(instr);
1689 break;
1690 }
1691 }
1692 }
1693
1694
1695 void Simulator::DoBranch(Instr* instr, bool taken, bool likely) {
1696 ASSERT(!delay_slot_);
1697 int32_t imm_val = instr->SImmField() << 2;
1698
1699 uword next_pc;
1700 if (taken) {
1701 // imm_val is added to the address of the instruction following the branch.
1702 next_pc = pc_ + imm_val + Instr::kInstrSize;
1703 if (likely) {
1704 ExecuteDelaySlot();
1705 }
1706 } else {
1707 next_pc = pc_ + (2 * Instr::kInstrSize); // Next after delay slot.
1708 }
1709 if (!likely) {
1710 ExecuteDelaySlot();
1711 }
1712 pc_ = next_pc - Instr::kInstrSize;
1713
1714 return;
1715 }
1716
1717
1718 void Simulator::DecodeRegImm(Instr* instr) {
1719 ASSERT(instr->OpcodeField() == REGIMM);
1720 switch (instr->RegImmFnField()) {
1721 case BGEZ: {
1722 // Format(instr, "bgez 'rs, 'dest");
1723 int32_t rs_val = get_register(instr->RsField());
1724 DoBranch(instr, rs_val >= 0, false);
1725 break;
1726 }
1727 case BGEZAL: {
1728 int32_t rs_val = get_register(instr->RsField());
1729 // Return address is one after the delay slot.
1730 set_register(RA, pc_ + (2 * Instr::kInstrSize));
1731 DoBranch(instr, rs_val >= 0, false);
1732 break;
1733 }
1734 case BLTZAL: {
1735 int32_t rs_val = get_register(instr->RsField());
1736 // Return address is one after the delay slot.
1737 set_register(RA, pc_ + (2 * Instr::kInstrSize));
1738 DoBranch(instr, rs_val < 0, false);
1739 break;
1740 }
1741 case BGEZL: {
1742 // Format(instr, "bgezl 'rs, 'dest");
1743 int32_t rs_val = get_register(instr->RsField());
1744 DoBranch(instr, rs_val >= 0, true);
1745 break;
1746 }
1747 case BLTZ: {
1748 // Format(instr, "bltz 'rs, 'dest");
1749 int32_t rs_val = get_register(instr->RsField());
1750 DoBranch(instr, rs_val < 0, false);
1751 break;
1752 }
1753 case BLTZL: {
1754 // Format(instr, "bltzl 'rs, 'dest");
1755 int32_t rs_val = get_register(instr->RsField());
1756 DoBranch(instr, rs_val < 0, true);
1757 break;
1758 }
1759 default: {
1760 OS::PrintErr("DecodeRegImm: 0x%x\n", instr->InstructionBits());
1761 UnimplementedInstruction(instr);
1762 break;
1763 }
1764 }
1765 }
1766
1767
1768 void Simulator::DecodeCop1(Instr* instr) {
1769 ASSERT(instr->OpcodeField() == COP1);
1770 if (instr->HasFormat()) {
1771 // If the rs field is a valid format, then the function field identifies the
1772 // instruction.
1773 double fs_val = get_fregister_double(instr->FsField());
1774 double ft_val = get_fregister_double(instr->FtField());
1775 uint32_t cc, fcsr_cc;
1776 cc = instr->FpuCCField();
1777 fcsr_cc = get_fcsr_condition_bit(cc);
1778 switch (instr->Cop1FunctionField()) {
1779 case COP1_ADD: {
1780 // Format(instr, "add.'fmt 'fd, 'fs, 'ft");
1781 ASSERT(instr->FormatField() == FMT_D); // Only D supported.
1782 set_fregister_double(instr->FdField(), fs_val + ft_val);
1783 break;
1784 }
1785 case COP1_SUB: {
1786 // Format(instr, "sub.'fmt 'fd, 'fs, 'ft");
1787 ASSERT(instr->FormatField() == FMT_D); // Only D supported.
1788 set_fregister_double(instr->FdField(), fs_val - ft_val);
1789 break;
1790 }
1791 case COP1_MUL: {
1792 // Format(instr, "mul.'fmt 'fd, 'fs, 'ft");
1793 ASSERT(instr->FormatField() == FMT_D); // Only D supported.
1794 set_fregister_double(instr->FdField(), fs_val * ft_val);
1795 break;
1796 }
1797 case COP1_DIV: {
1798 // Format(instr, "div.'fmt 'fd, 'fs, 'ft");
1799 ASSERT(instr->FormatField() == FMT_D); // Only D supported.
1800 set_fregister_double(instr->FdField(), fs_val / ft_val);
1801 break;
1802 }
1803 case COP1_SQRT: {
1804 // Format(instr, "sqrt.'fmt 'fd, 'fs");
1805 ASSERT(instr->FormatField() == FMT_D); // Only D supported.
1806 set_fregister_double(instr->FdField(), sqrt(fs_val));
1807 break;
1808 }
1809 case COP1_MOV: {
1810 // Format(instr, "mov.'fmt 'fd, 'fs");
1811 ASSERT(instr->FormatField() == FMT_D); // Only D supported.
1812 set_fregister_double(instr->FdField(), fs_val);
1813 break;
1814 }
1815 case COP1_NEG: {
1816 // Format(instr, "neg.'fmt 'fd, 'fs");
1817 ASSERT(instr->FormatField() == FMT_D);
1818 set_fregister_double(instr->FdField(), -fs_val);
1819 break;
1820 }
1821 case COP1_C_F: {
1822 ASSERT(instr->FormatField() == FMT_D); // Only D supported.
1823 ASSERT(instr->FdField() == F0);
1824 set_fcsr_bit(fcsr_cc, false);
1825 break;
1826 }
1827 case COP1_C_UN: {
1828 ASSERT(instr->FormatField() == FMT_D); // Only D supported.
1829 ASSERT(instr->FdField() == F0);
1830 set_fcsr_bit(fcsr_cc, isnan(fs_val) || isnan(ft_val));
1831 break;
1832 }
1833 case COP1_C_EQ: {
1834 ASSERT(instr->FormatField() == FMT_D); // Only D supported.
1835 ASSERT(instr->FdField() == F0);
1836 set_fcsr_bit(fcsr_cc, (fs_val == ft_val));
1837 break;
1838 }
1839 case COP1_C_UEQ: {
1840 ASSERT(instr->FormatField() == FMT_D); // Only D supported.
1841 ASSERT(instr->FdField() == F0);
1842 set_fcsr_bit(fcsr_cc,
1843 (fs_val == ft_val) || isnan(fs_val) || isnan(ft_val));
1844 break;
1845 }
1846 case COP1_C_OLT: {
1847 ASSERT(instr->FormatField() == FMT_D); // Only D supported.
1848 ASSERT(instr->FdField() == F0);
1849 set_fcsr_bit(fcsr_cc, (fs_val < ft_val));
1850 break;
1851 }
1852 case COP1_C_ULT: {
1853 ASSERT(instr->FormatField() == FMT_D); // Only D supported.
1854 ASSERT(instr->FdField() == F0);
1855 set_fcsr_bit(fcsr_cc,
1856 (fs_val < ft_val) || isnan(fs_val) || isnan(ft_val));
1857 break;
1858 }
1859 case COP1_C_OLE: {
1860 ASSERT(instr->FormatField() == FMT_D); // Only D supported.
1861 ASSERT(instr->FdField() == F0);
1862 set_fcsr_bit(fcsr_cc, (fs_val <= ft_val));
1863 break;
1864 }
1865 case COP1_C_ULE: {
1866 ASSERT(instr->FormatField() == FMT_D); // Only D supported.
1867 ASSERT(instr->FdField() == F0);
1868 set_fcsr_bit(fcsr_cc,
1869 (fs_val <= ft_val) || isnan(fs_val) || isnan(ft_val));
1870 break;
1871 }
1872 case COP1_TRUNC_W: {
1873 switch (instr->FormatField()) {
1874 case FMT_D: {
1875 double fs_dbl = get_fregister_double(instr->FsField());
1876 int32_t fs_int;
1877 if (isnan(fs_dbl) || isinf(fs_dbl) || (fs_dbl > kMaxInt32) ||
1878 (fs_dbl < kMinInt32)) {
1879 fs_int = kMaxInt32;
1880 } else {
1881 fs_int = static_cast<int32_t>(fs_dbl);
1882 }
1883 set_fregister(instr->FdField(), fs_int);
1884 break;
1885 }
1886 default: {
1887 OS::PrintErr("DecodeCop1: 0x%x\n", instr->InstructionBits());
1888 UnimplementedInstruction(instr);
1889 break;
1890 }
1891 }
1892 break;
1893 }
1894 case COP1_CVT_D: {
1895 switch (instr->FormatField()) {
1896 case FMT_W: {
1897 int32_t fs_int = get_fregister(instr->FsField());
1898 double fs_dbl = static_cast<double>(fs_int);
1899 set_fregister_double(instr->FdField(), fs_dbl);
1900 break;
1901 }
1902 case FMT_S: {
1903 float fs_flt = get_fregister_float(instr->FsField());
1904 double fs_dbl = static_cast<double>(fs_flt);
1905 set_fregister_double(instr->FdField(), fs_dbl);
1906 break;
1907 }
1908 default: {
1909 OS::PrintErr("DecodeCop1: 0x%x\n", instr->InstructionBits());
1910 UnimplementedInstruction(instr);
1911 break;
1912 }
1913 }
1914 break;
1915 }
1916 case COP1_CVT_S: {
1917 switch (instr->FormatField()) {
1918 case FMT_D: {
1919 double fs_dbl = get_fregister_double(instr->FsField());
1920 float fs_flt = static_cast<float>(fs_dbl);
1921 set_fregister_float(instr->FdField(), fs_flt);
1922 break;
1923 }
1924 default: {
1925 OS::PrintErr("DecodeCop1: 0x%x\n", instr->InstructionBits());
1926 UnimplementedInstruction(instr);
1927 break;
1928 }
1929 }
1930 break;
1931 }
1932 default: {
1933 OS::PrintErr("DecodeCop1: 0x%x\n", instr->InstructionBits());
1934 UnimplementedInstruction(instr);
1935 break;
1936 }
1937 }
1938 } else {
1939 // If the rs field isn't a valid format, then it must be a sub-op.
1940 switch (instr->Cop1SubField()) {
1941 case COP1_MF: {
1942 // Format(instr, "mfc1 'rt, 'fs");
1943 ASSERT(instr->Bits(0, 11) == 0);
1944 int32_t fs_val = get_fregister(instr->FsField());
1945 set_register(instr->RtField(), fs_val);
1946 break;
1947 }
1948 case COP1_MT: {
1949 // Format(instr, "mtc1 'rt, 'fs");
1950 ASSERT(instr->Bits(0, 11) == 0);
1951 int32_t rt_val = get_register(instr->RtField());
1952 set_fregister(instr->FsField(), rt_val);
1953 break;
1954 }
1955 case COP1_BC: {
1956 ASSERT(instr->Bit(17) == 0);
1957 uint32_t cc, fcsr_cc;
1958 cc = instr->Bits(18, 3);
1959 fcsr_cc = get_fcsr_condition_bit(cc);
1960 if (instr->Bit(16) == 1) { // Branch on true.
1961 DoBranch(instr, test_fcsr_bit(fcsr_cc), false);
1962 } else { // Branch on false.
1963 DoBranch(instr, !test_fcsr_bit(fcsr_cc), false);
1964 }
1965 break;
1966 }
1967 default: {
1968 OS::PrintErr("DecodeCop1: 0x%x\n", instr->InstructionBits());
1969 UnimplementedInstruction(instr);
1970 break;
1971 }
1972 }
1973 }
1974 }
1975
1976
1977 void Simulator::InstructionDecode(Instr* instr) {
1978 if (IsTracingExecution()) {
1979 THR_Print("%" Pu64 " ", icount_);
1980 const uword start = reinterpret_cast<uword>(instr);
1981 const uword end = start + Instr::kInstrSize;
1982 if (FLAG_support_disassembler) {
1983 Disassembler::Disassemble(start, end);
1984 } else {
1985 THR_Print("Disassembler not supported in this mode.\n");
1986 }
1987 }
1988
1989 switch (instr->OpcodeField()) {
1990 case SPECIAL: {
1991 DecodeSpecial(instr);
1992 break;
1993 }
1994 case SPECIAL2: {
1995 DecodeSpecial2(instr);
1996 break;
1997 }
1998 case REGIMM: {
1999 DecodeRegImm(instr);
2000 break;
2001 }
2002 case COP1: {
2003 DecodeCop1(instr);
2004 break;
2005 }
2006 case ADDIU: {
2007 // Format(instr, "addiu 'rt, 'rs, 'imms");
2008 int32_t rs_val = get_register(instr->RsField());
2009 int32_t imm_val = instr->SImmField();
2010 int32_t res = rs_val + imm_val;
2011 // Rt is set even on overflow.
2012 set_register(instr->RtField(), res);
2013 break;
2014 }
2015 case ANDI: {
2016 // Format(instr, "andi 'rt, 'rs, 'immu");
2017 int32_t rs_val = get_register(instr->RsField());
2018 set_register(instr->RtField(), rs_val & instr->UImmField());
2019 break;
2020 }
2021 case BEQ: {
2022 // Format(instr, "beq 'rs, 'rt, 'dest");
2023 int32_t rs_val = get_register(instr->RsField());
2024 int32_t rt_val = get_register(instr->RtField());
2025 DoBranch(instr, rs_val == rt_val, false);
2026 break;
2027 }
2028 case BEQL: {
2029 // Format(instr, "beql 'rs, 'rt, 'dest");
2030 int32_t rs_val = get_register(instr->RsField());
2031 int32_t rt_val = get_register(instr->RtField());
2032 DoBranch(instr, rs_val == rt_val, true);
2033 break;
2034 }
2035 case BGTZ: {
2036 ASSERT(instr->RtField() == R0);
2037 // Format(instr, "bgtz 'rs, 'dest");
2038 int32_t rs_val = get_register(instr->RsField());
2039 DoBranch(instr, rs_val > 0, false);
2040 break;
2041 }
2042 case BGTZL: {
2043 ASSERT(instr->RtField() == R0);
2044 // Format(instr, "bgtzl 'rs, 'dest");
2045 int32_t rs_val = get_register(instr->RsField());
2046 DoBranch(instr, rs_val > 0, true);
2047 break;
2048 }
2049 case BLEZ: {
2050 ASSERT(instr->RtField() == R0);
2051 // Format(instr, "blez 'rs, 'dest");
2052 int32_t rs_val = get_register(instr->RsField());
2053 DoBranch(instr, rs_val <= 0, false);
2054 break;
2055 }
2056 case BLEZL: {
2057 ASSERT(instr->RtField() == R0);
2058 // Format(instr, "blezl 'rs, 'dest");
2059 int32_t rs_val = get_register(instr->RsField());
2060 DoBranch(instr, rs_val <= 0, true);
2061 break;
2062 }
2063 case BNE: {
2064 // Format(instr, "bne 'rs, 'rt, 'dest");
2065 int32_t rs_val = get_register(instr->RsField());
2066 int32_t rt_val = get_register(instr->RtField());
2067 DoBranch(instr, rs_val != rt_val, false);
2068 break;
2069 }
2070 case BNEL: {
2071 // Format(instr, "bnel 'rs, 'rt, 'dest");
2072 int32_t rs_val = get_register(instr->RsField());
2073 int32_t rt_val = get_register(instr->RtField());
2074 DoBranch(instr, rs_val != rt_val, true);
2075 break;
2076 }
2077 case LB: {
2078 // Format(instr, "lb 'rt, 'imms('rs)");
2079 int32_t base_val = get_register(instr->RsField());
2080 int32_t imm_val = instr->SImmField();
2081 uword addr = base_val + imm_val;
2082 if (Simulator::IsIllegalAddress(addr)) {
2083 HandleIllegalAccess(addr, instr);
2084 } else {
2085 int32_t res = ReadB(addr);
2086 set_register(instr->RtField(), res);
2087 }
2088 break;
2089 }
2090 case LBU: {
2091 // Format(instr, "lbu 'rt, 'imms('rs)");
2092 int32_t base_val = get_register(instr->RsField());
2093 int32_t imm_val = instr->SImmField();
2094 uword addr = base_val + imm_val;
2095 if (Simulator::IsIllegalAddress(addr)) {
2096 HandleIllegalAccess(addr, instr);
2097 } else {
2098 uint32_t res = ReadBU(addr);
2099 set_register(instr->RtField(), res);
2100 }
2101 break;
2102 }
2103 case LDC1: {
2104 // Format(instr, "ldc1 'ft, 'imms('rs)");
2105 int32_t base_val = get_register(instr->RsField());
2106 int32_t imm_val = instr->SImmField();
2107 uword addr = base_val + imm_val;
2108 if (Simulator::IsIllegalAddress(addr)) {
2109 HandleIllegalAccess(addr, instr);
2110 } else {
2111 double value = ReadD(addr, instr);
2112 set_fregister_double(instr->FtField(), value);
2113 }
2114 break;
2115 }
2116 case LH: {
2117 // Format(instr, "lh 'rt, 'imms('rs)");
2118 int32_t base_val = get_register(instr->RsField());
2119 int32_t imm_val = instr->SImmField();
2120 uword addr = base_val + imm_val;
2121 if (Simulator::IsIllegalAddress(addr)) {
2122 HandleIllegalAccess(addr, instr);
2123 } else {
2124 int32_t res = ReadH(addr, instr);
2125 set_register(instr->RtField(), res);
2126 }
2127 break;
2128 }
2129 case LHU: {
2130 // Format(instr, "lhu 'rt, 'imms('rs)");
2131 int32_t base_val = get_register(instr->RsField());
2132 int32_t imm_val = instr->SImmField();
2133 uword addr = base_val + imm_val;
2134 if (Simulator::IsIllegalAddress(addr)) {
2135 HandleIllegalAccess(addr, instr);
2136 } else {
2137 int32_t res = ReadHU(addr, instr);
2138 set_register(instr->RtField(), res);
2139 }
2140 break;
2141 }
2142 case LUI: {
2143 ASSERT(instr->RsField() == 0);
2144 set_register(instr->RtField(), instr->UImmField() << 16);
2145 break;
2146 }
2147 case LL: {
2148 // Format(instr, "ll 'rt, 'imms('rs)");
2149 int32_t base_val = get_register(instr->RsField());
2150 int32_t imm_val = instr->SImmField();
2151 uword addr = base_val + imm_val;
2152 if (Simulator::IsIllegalAddress(addr)) {
2153 HandleIllegalAccess(addr, instr);
2154 } else {
2155 int32_t res = ReadExclusiveW(addr, instr);
2156 set_register(instr->RtField(), res);
2157 }
2158 break;
2159 }
2160 case LW: {
2161 // Format(instr, "lw 'rt, 'imms('rs)");
2162 int32_t base_val = get_register(instr->RsField());
2163 int32_t imm_val = instr->SImmField();
2164 uword addr = base_val + imm_val;
2165 if (Simulator::IsIllegalAddress(addr)) {
2166 HandleIllegalAccess(addr, instr);
2167 } else {
2168 int32_t res = ReadW(addr, instr);
2169 set_register(instr->RtField(), res);
2170 }
2171 break;
2172 }
2173 case LWC1: {
2174 // Format(instr, "lwc1 'ft, 'imms('rs)");
2175 int32_t base_val = get_register(instr->RsField());
2176 int32_t imm_val = instr->SImmField();
2177 uword addr = base_val + imm_val;
2178 if (Simulator::IsIllegalAddress(addr)) {
2179 HandleIllegalAccess(addr, instr);
2180 } else {
2181 int32_t value = ReadW(addr, instr);
2182 set_fregister(instr->FtField(), value);
2183 }
2184 break;
2185 }
2186 case ORI: {
2187 // Format(instr, "ori 'rt, 'rs, 'immu");
2188 int32_t rs_val = get_register(instr->RsField());
2189 set_register(instr->RtField(), rs_val | instr->UImmField());
2190 break;
2191 }
2192 case SB: {
2193 // Format(instr, "sb 'rt, 'imms('rs)");
2194 int32_t rt_val = get_register(instr->RtField());
2195 int32_t base_val = get_register(instr->RsField());
2196 int32_t imm_val = instr->SImmField();
2197 uword addr = base_val + imm_val;
2198 if (Simulator::IsIllegalAddress(addr)) {
2199 HandleIllegalAccess(addr, instr);
2200 } else {
2201 WriteB(addr, rt_val & 0xff);
2202 }
2203 break;
2204 }
2205 case SC: {
2206 // Format(instr, "sc 'rt, 'imms('rs)");
2207 int32_t rt_val = get_register(instr->RtField());
2208 int32_t base_val = get_register(instr->RsField());
2209 int32_t imm_val = instr->SImmField();
2210 uword addr = base_val + imm_val;
2211 if (Simulator::IsIllegalAddress(addr)) {
2212 HandleIllegalAccess(addr, instr);
2213 } else {
2214 intptr_t status = WriteExclusiveW(addr, rt_val, instr);
2215 set_register(instr->RtField(), status);
2216 }
2217 break;
2218 }
2219 case SLTI: {
2220 // Format(instr, "slti 'rt, 'rs, 'imms");
2221 int32_t rs_val = get_register(instr->RsField());
2222 int32_t imm_val = instr->SImmField();
2223 set_register(instr->RtField(), rs_val < imm_val ? 1 : 0);
2224 break;
2225 }
2226 case SLTIU: {
2227 // Format(instr, "sltiu 'rt, 'rs, 'imms");
2228 uint32_t rs_val = get_register(instr->RsField());
2229 int32_t imm_val = instr->SImmField(); // Sign extend to 32-bit.
2230 uint32_t immu_val = static_cast<uint32_t>(imm_val); // Treat as unsigned.
2231 set_register(instr->RtField(), rs_val < immu_val ? 1 : 0);
2232 break;
2233 }
2234 case SDC1: {
2235 // Format(instr, "sdc1 'ft, 'imms('rs)");
2236 int32_t base_val = get_register(instr->RsField());
2237 int32_t imm_val = instr->SImmField();
2238 uword addr = base_val + imm_val;
2239 if (Simulator::IsIllegalAddress(addr)) {
2240 HandleIllegalAccess(addr, instr);
2241 } else {
2242 double value = get_fregister_double(instr->FtField());
2243 WriteD(addr, value, instr);
2244 }
2245 break;
2246 }
2247 case SH: {
2248 // Format(instr, "sh 'rt, 'imms('rs)");
2249 int32_t rt_val = get_register(instr->RtField());
2250 int32_t base_val = get_register(instr->RsField());
2251 int32_t imm_val = instr->SImmField();
2252 uword addr = base_val + imm_val;
2253 if (Simulator::IsIllegalAddress(addr)) {
2254 HandleIllegalAccess(addr, instr);
2255 } else {
2256 WriteH(addr, rt_val & 0xffff, instr);
2257 }
2258 break;
2259 }
2260 case SW: {
2261 // Format(instr, "sw 'rt, 'imms('rs)");
2262 int32_t rt_val = get_register(instr->RtField());
2263 int32_t base_val = get_register(instr->RsField());
2264 int32_t imm_val = instr->SImmField();
2265 uword addr = base_val + imm_val;
2266 if (Simulator::IsIllegalAddress(addr)) {
2267 HandleIllegalAccess(addr, instr);
2268 } else {
2269 WriteW(addr, rt_val, instr);
2270 }
2271 break;
2272 }
2273 case SWC1: {
2274 // Format(instr, "swc1 'ft, 'imms('rs)");
2275 int32_t base_val = get_register(instr->RsField());
2276 int32_t imm_val = instr->SImmField();
2277 uword addr = base_val + imm_val;
2278 if (Simulator::IsIllegalAddress(addr)) {
2279 HandleIllegalAccess(addr, instr);
2280 } else {
2281 int32_t value = get_fregister(instr->FtField());
2282 WriteW(addr, value, instr);
2283 }
2284 break;
2285 }
2286 case XORI: {
2287 // Format(instr, "xori 'rt, 'rs, 'immu");
2288 int32_t rs_val = get_register(instr->RsField());
2289 set_register(instr->RtField(), rs_val ^ instr->UImmField());
2290 break;
2291 break;
2292 }
2293 default: {
2294 OS::PrintErr("Undecoded instruction: 0x%x at %p\n",
2295 instr->InstructionBits(), instr);
2296 UnimplementedInstruction(instr);
2297 break;
2298 }
2299 }
2300 pc_ += Instr::kInstrSize;
2301 }
2302
2303
2304 void Simulator::ExecuteDelaySlot() {
2305 ASSERT(pc_ != kEndSimulatingPC);
2306 delay_slot_ = true;
2307 icount_++;
2308 Instr* instr = Instr::At(pc_ + Instr::kInstrSize);
2309 if (FLAG_stop_sim_at != ULLONG_MAX) {
2310 if (icount_ == FLAG_stop_sim_at) {
2311 SimulatorDebugger dbg(this);
2312 dbg.Stop(instr, "Instruction count reached");
2313 } else if (reinterpret_cast<uint64_t>(instr) == FLAG_stop_sim_at) {
2314 SimulatorDebugger dbg(this);
2315 dbg.Stop(instr, "Instruction address reached");
2316 }
2317 }
2318 InstructionDecode(instr);
2319 delay_slot_ = false;
2320 }
2321
2322
2323 void Simulator::Execute() {
2324 if (FLAG_stop_sim_at == ULLONG_MAX) {
2325 // Fast version of the dispatch loop without checking whether the simulator
2326 // should be stopping at a particular executed instruction.
2327 while (pc_ != kEndSimulatingPC) {
2328 icount_++;
2329 Instr* instr = Instr::At(pc_);
2330 if (IsIllegalAddress(pc_)) {
2331 HandleIllegalAccess(pc_, instr);
2332 } else {
2333 InstructionDecode(instr);
2334 }
2335 }
2336 } else {
2337 // FLAG_stop_sim_at is at the non-default value. Stop in the debugger when
2338 // we reach the particular instruction count or address.
2339 while (pc_ != kEndSimulatingPC) {
2340 Instr* instr = Instr::At(pc_);
2341 icount_++;
2342 if (icount_ == FLAG_stop_sim_at) {
2343 SimulatorDebugger dbg(this);
2344 dbg.Stop(instr, "Instruction count reached");
2345 } else if (reinterpret_cast<uint64_t>(instr) == FLAG_stop_sim_at) {
2346 SimulatorDebugger dbg(this);
2347 dbg.Stop(instr, "Instruction address reached");
2348 } else if (IsIllegalAddress(pc_)) {
2349 HandleIllegalAccess(pc_, instr);
2350 } else {
2351 InstructionDecode(instr);
2352 }
2353 }
2354 }
2355 }
2356
2357
2358 int64_t Simulator::Call(int32_t entry,
2359 int32_t parameter0,
2360 int32_t parameter1,
2361 int32_t parameter2,
2362 int32_t parameter3,
2363 bool fp_return,
2364 bool fp_args) {
2365 // Save the SP register before the call so we can restore it.
2366 int32_t sp_before_call = get_register(SP);
2367
2368 // Setup parameters.
2369 if (fp_args) {
2370 set_fregister(F0, parameter0);
2371 set_fregister(F1, parameter1);
2372 set_fregister(F2, parameter2);
2373 set_fregister(F3, parameter3);
2374 } else {
2375 set_register(A0, parameter0);
2376 set_register(A1, parameter1);
2377 set_register(A2, parameter2);
2378 set_register(A3, parameter3);
2379 }
2380
2381 // Make sure the activation frames are properly aligned.
2382 int32_t stack_pointer = sp_before_call;
2383 if (OS::ActivationFrameAlignment() > 1) {
2384 stack_pointer =
2385 Utils::RoundDown(stack_pointer, OS::ActivationFrameAlignment());
2386 }
2387 set_register(SP, stack_pointer);
2388
2389 // Prepare to execute the code at entry.
2390 set_pc(entry);
2391 // Put down marker for end of simulation. The simulator will stop simulation
2392 // when the PC reaches this value. By saving the "end simulation" value into
2393 // RA the simulation stops when returning to this call point.
2394 set_register(RA, kEndSimulatingPC);
2395
2396 // Remember the values of callee-saved registers.
2397 // The code below assumes that r9 is not used as sb (static base) in
2398 // simulator code and therefore is regarded as a callee-saved register.
2399 int32_t r16_val = get_register(R16);
2400 int32_t r17_val = get_register(R17);
2401 int32_t r18_val = get_register(R18);
2402 int32_t r19_val = get_register(R19);
2403 int32_t r20_val = get_register(R20);
2404 int32_t r21_val = get_register(R21);
2405 int32_t r22_val = get_register(R22);
2406 int32_t r23_val = get_register(R23);
2407
2408 double d10_val = get_dregister(D10);
2409 double d11_val = get_dregister(D11);
2410 double d12_val = get_dregister(D12);
2411 double d13_val = get_dregister(D13);
2412 double d14_val = get_dregister(D14);
2413 double d15_val = get_dregister(D15);
2414
2415 // Setup the callee-saved registers with a known value. To be able to check
2416 // that they are preserved properly across dart execution.
2417 int32_t callee_saved_value = icount_;
2418 set_register(R16, callee_saved_value);
2419 set_register(R17, callee_saved_value);
2420 set_register(R18, callee_saved_value);
2421 set_register(R19, callee_saved_value);
2422 set_register(R20, callee_saved_value);
2423 set_register(R21, callee_saved_value);
2424 set_register(R22, callee_saved_value);
2425 set_register(R23, callee_saved_value);
2426
2427 set_dregister_bits(D10, callee_saved_value);
2428 set_dregister_bits(D11, callee_saved_value);
2429 set_dregister_bits(D12, callee_saved_value);
2430 set_dregister_bits(D13, callee_saved_value);
2431 set_dregister_bits(D14, callee_saved_value);
2432 set_dregister_bits(D15, callee_saved_value);
2433
2434 // Start the simulation
2435 Execute();
2436
2437 // Check that the callee-saved registers have been preserved.
2438 ASSERT(callee_saved_value == get_register(R16));
2439 ASSERT(callee_saved_value == get_register(R17));
2440 ASSERT(callee_saved_value == get_register(R18));
2441 ASSERT(callee_saved_value == get_register(R19));
2442 ASSERT(callee_saved_value == get_register(R20));
2443 ASSERT(callee_saved_value == get_register(R21));
2444 ASSERT(callee_saved_value == get_register(R22));
2445 ASSERT(callee_saved_value == get_register(R23));
2446
2447 ASSERT(callee_saved_value == get_dregister_bits(D10));
2448 ASSERT(callee_saved_value == get_dregister_bits(D11));
2449 ASSERT(callee_saved_value == get_dregister_bits(D12));
2450 ASSERT(callee_saved_value == get_dregister_bits(D13));
2451 ASSERT(callee_saved_value == get_dregister_bits(D14));
2452 ASSERT(callee_saved_value == get_dregister_bits(D15));
2453
2454 // Restore callee-saved registers with the original value.
2455 set_register(R16, r16_val);
2456 set_register(R17, r17_val);
2457 set_register(R18, r18_val);
2458 set_register(R19, r19_val);
2459 set_register(R20, r20_val);
2460 set_register(R21, r21_val);
2461 set_register(R22, r22_val);
2462 set_register(R23, r23_val);
2463
2464 set_dregister(D10, d10_val);
2465 set_dregister(D11, d11_val);
2466 set_dregister(D12, d12_val);
2467 set_dregister(D13, d13_val);
2468 set_dregister(D14, d14_val);
2469 set_dregister(D15, d15_val);
2470
2471 // Restore the SP register and return V1:V0.
2472 set_register(SP, sp_before_call);
2473 int64_t return_value;
2474 if (fp_return) {
2475 return_value = Utils::LowHighTo64Bits(get_fregister(F0), get_fregister(F1));
2476 } else {
2477 return_value = Utils::LowHighTo64Bits(get_register(V0), get_register(V1));
2478 }
2479 return return_value;
2480 }
2481
2482
2483 void Simulator::JumpToFrame(uword pc, uword sp, uword fp, Thread* thread) {
2484 // Walk over all setjmp buffers (simulated --> C++ transitions)
2485 // and try to find the setjmp associated with the simulated stack pointer.
2486 SimulatorSetjmpBuffer* buf = last_setjmp_buffer();
2487 while (buf->link() != NULL && buf->link()->sp() <= sp) {
2488 buf = buf->link();
2489 }
2490 ASSERT(buf != NULL);
2491
2492 // The C++ caller has not cleaned up the stack memory of C++ frames.
2493 // Prepare for unwinding frames by destroying all the stack resources
2494 // in the previous C++ frames.
2495 StackResource::Unwind(thread);
2496
2497 // Unwind the C++ stack and continue simulation in the target frame.
2498 set_pc(static_cast<int32_t>(pc));
2499 set_register(SP, static_cast<int32_t>(sp));
2500 set_register(FP, static_cast<int32_t>(fp));
2501 set_register(THR, reinterpret_cast<int32_t>(thread));
2502 // Set the tag.
2503 thread->set_vm_tag(VMTag::kDartTagId);
2504 // Clear top exit frame.
2505 thread->set_top_exit_frame_info(0);
2506 // Restore pool pointer.
2507 int32_t code =
2508 *reinterpret_cast<int32_t*>(fp + kPcMarkerSlotFromFp * kWordSize);
2509 int32_t pp = *reinterpret_cast<int32_t*>(code + Code::object_pool_offset() -
2510 kHeapObjectTag);
2511 set_register(CODE_REG, code);
2512 set_register(PP, pp);
2513 buf->Longjmp();
2514 }
2515
2516 } // namespace dart
2517
2518 #endif // defined(USING_SIMULATOR)
2519
2520 #endif // defined TARGET_ARCH_MIPS
OLDNEW
« no previous file with comments | « runtime/vm/simulator_mips.h ('k') | runtime/vm/snapshot.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698