| OLD | NEW |
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 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 | 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. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 #include <setjmp.h> // NOLINT | 5 #include <setjmp.h> // NOLINT |
| 6 #include <stdlib.h> | 6 #include <stdlib.h> |
| 7 | 7 |
| 8 #include "vm/globals.h" | 8 #include "vm/globals.h" |
| 9 #if defined(TARGET_ARCH_MIPS) | 9 #if defined(TARGET_ARCH_MIPS) |
| 10 | 10 |
| 11 // Only build the simulator if not compiling for real MIPS hardware. | 11 // Only build the simulator if not compiling for real MIPS hardware. |
| 12 #if defined(USING_SIMULATOR) | 12 #if defined(USING_SIMULATOR) |
| 13 | 13 |
| 14 #include "vm/simulator.h" | 14 #include "vm/simulator.h" |
| 15 | 15 |
| 16 #include "vm/assembler.h" | 16 #include "vm/assembler.h" |
| 17 #include "vm/constants_mips.h" | 17 #include "vm/constants_mips.h" |
| 18 #include "vm/disassembler.h" | 18 #include "vm/disassembler.h" |
| 19 #include "vm/lockers.h" | 19 #include "vm/lockers.h" |
| 20 #include "vm/native_arguments.h" | 20 #include "vm/native_arguments.h" |
| 21 #include "vm/stack_frame.h" | 21 #include "vm/stack_frame.h" |
| 22 #include "vm/os_thread.h" | 22 #include "vm/os_thread.h" |
| 23 | 23 |
| 24 namespace dart { | 24 namespace dart { |
| 25 | 25 |
| 26 DEFINE_FLAG(uint64_t, trace_sim_after, ULLONG_MAX, | 26 DEFINE_FLAG(uint64_t, |
| 27 trace_sim_after, |
| 28 ULLONG_MAX, |
| 27 "Trace simulator execution after instruction count reached."); | 29 "Trace simulator execution after instruction count reached."); |
| 28 DEFINE_FLAG(uint64_t, stop_sim_at, ULLONG_MAX, | 30 DEFINE_FLAG(uint64_t, |
| 31 stop_sim_at, |
| 32 ULLONG_MAX, |
| 29 "Instruction address or instruction count to stop simulator at."); | 33 "Instruction address or instruction count to stop simulator at."); |
| 30 | 34 |
| 31 | 35 |
| 32 // This macro provides a platform independent use of sscanf. The reason for | 36 // This macro provides a platform independent use of sscanf. The reason for |
| 33 // SScanF not being implemented in a platform independent way through | 37 // SScanF not being implemented in a platform independent way through |
| 34 // OS in the same way as SNPrint is that the Windows C Run-Time | 38 // OS in the same way as SNPrint is that the Windows C Run-Time |
| 35 // Library does not provide vsscanf. | 39 // Library does not provide vsscanf. |
| 36 #define SScanF sscanf // NOLINT | 40 #define SScanF sscanf // NOLINT |
| 37 | 41 |
| 38 | 42 |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 88 | 92 |
| 89 private: | 93 private: |
| 90 Simulator* sim_; | 94 Simulator* sim_; |
| 91 | 95 |
| 92 bool GetValue(char* desc, uint32_t* value); | 96 bool GetValue(char* desc, uint32_t* value); |
| 93 bool GetFValue(char* desc, double* value); | 97 bool GetFValue(char* desc, double* value); |
| 94 bool GetDValue(char* desc, double* value); | 98 bool GetDValue(char* desc, double* value); |
| 95 | 99 |
| 96 static TokenPosition GetApproximateTokenIndex(const Code& code, uword pc); | 100 static TokenPosition GetApproximateTokenIndex(const Code& code, uword pc); |
| 97 | 101 |
| 98 static void PrintDartFrame(uword pc, uword fp, uword sp, | 102 static void PrintDartFrame(uword pc, |
| 103 uword fp, |
| 104 uword sp, |
| 99 const Function& function, | 105 const Function& function, |
| 100 TokenPosition token_pos, | 106 TokenPosition token_pos, |
| 101 bool is_optimized, | 107 bool is_optimized, |
| 102 bool is_inlined); | 108 bool is_inlined); |
| 103 void PrintBacktrace(); | 109 void PrintBacktrace(); |
| 104 | 110 |
| 105 // Set or delete a breakpoint. Returns true if successful. | 111 // Set or delete a breakpoint. Returns true if successful. |
| 106 bool SetBreakpoint(Instr* breakpc); | 112 bool SetBreakpoint(Instr* breakpc); |
| 107 bool DeleteBreakpoint(Instr* breakpc); | 113 bool DeleteBreakpoint(Instr* breakpc); |
| 108 | 114 |
| 109 // Undo and redo all breakpoints. This is needed to bracket disassembly and | 115 // Undo and redo all breakpoints. This is needed to bracket disassembly and |
| 110 // execution to skip past breakpoints when run from the debugger. | 116 // execution to skip past breakpoints when run from the debugger. |
| 111 void UndoBreakpoints(); | 117 void UndoBreakpoints(); |
| 112 void RedoBreakpoints(); | 118 void RedoBreakpoints(); |
| 113 }; | 119 }; |
| 114 | 120 |
| 115 | 121 |
| 116 SimulatorDebugger::SimulatorDebugger(Simulator* sim) { | 122 SimulatorDebugger::SimulatorDebugger(Simulator* sim) { |
| 117 sim_ = sim; | 123 sim_ = sim; |
| 118 } | 124 } |
| 119 | 125 |
| 120 | 126 |
| 121 SimulatorDebugger::~SimulatorDebugger() { | 127 SimulatorDebugger::~SimulatorDebugger() {} |
| 122 } | |
| 123 | 128 |
| 124 | 129 |
| 125 void SimulatorDebugger::Stop(Instr* instr, const char* message) { | 130 void SimulatorDebugger::Stop(Instr* instr, const char* message) { |
| 126 OS::Print("Simulator hit %s\n", message); | 131 OS::Print("Simulator hit %s\n", message); |
| 127 Debug(); | 132 Debug(); |
| 128 } | 133 } |
| 129 | 134 |
| 130 | 135 |
| 131 static Register LookupCpuRegisterByName(const char* name) { | 136 static Register LookupCpuRegisterByName(const char* name) { |
| 132 static const char* kNames[] = { | 137 static const char* kNames[] = { |
| 133 "r0", "r1", "r2", "r3", | 138 "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", |
| 134 "r4", "r5", "r6", "r7", | 139 "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", |
| 135 "r8", "r9", "r10", "r11", | 140 "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23", |
| 136 "r12", "r13", "r14", "r15", | 141 "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31", |
| 137 "r16", "r17", "r18", "r19", | |
| 138 "r20", "r21", "r22", "r23", | |
| 139 "r24", "r25", "r26", "r27", | |
| 140 "r28", "r29", "r30", "r31", | |
| 141 | 142 |
| 142 "zr", "at", "v0", "v1", | 143 "zr", "at", "v0", "v1", "a0", "a1", "a2", "a3", |
| 143 "a0", "a1", "a2", "a3", | 144 "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", |
| 144 "t0", "t1", "t2", "t3", | 145 "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7", |
| 145 "t4", "t5", "t6", "t7", | 146 "t8", "t9", "k0", "k1", "gp", "sp", "fp", "ra"}; |
| 146 "s0", "s1", "s2", "s3", | |
| 147 "s4", "s5", "s6", "s7", | |
| 148 "t8", "t9", "k0", "k1", | |
| 149 "gp", "sp", "fp", "ra" | |
| 150 }; | |
| 151 static const Register kRegisters[] = { | 147 static const Register kRegisters[] = { |
| 152 R0, R1, R2, R3, | 148 R0, R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, |
| 153 R4, R5, R6, R7, | 149 R11, R12, R13, R14, R15, R16, R17, R18, R19, R20, R21, |
| 154 R8, R9, R10, R11, | 150 R22, R23, R24, R25, R26, R27, R28, R29, R30, R31, |
| 155 R12, R13, R14, R15, | |
| 156 R16, R17, R18, R19, | |
| 157 R20, R21, R22, R23, | |
| 158 R24, R25, R26, R27, | |
| 159 R28, R29, R30, R31, | |
| 160 | 151 |
| 161 ZR, AT, V0, V1, | 152 ZR, AT, V0, V1, A0, A1, A2, A3, T0, T1, T2, |
| 162 A0, A1, A2, A3, | 153 T3, T4, T5, T6, T7, S0, S1, S2, S3, S4, S5, |
| 163 T0, T1, T2, T3, | 154 S6, S7, T8, T9, K0, K1, GP, SP, FP, RA}; |
| 164 T4, T5, T6, T7, | |
| 165 S0, S1, S2, S3, | |
| 166 S4, S5, S6, S7, | |
| 167 T8, T9, K0, K1, | |
| 168 GP, SP, FP, RA | |
| 169 }; | |
| 170 ASSERT(ARRAY_SIZE(kNames) == ARRAY_SIZE(kRegisters)); | 155 ASSERT(ARRAY_SIZE(kNames) == ARRAY_SIZE(kRegisters)); |
| 171 for (unsigned i = 0; i < ARRAY_SIZE(kNames); i++) { | 156 for (unsigned i = 0; i < ARRAY_SIZE(kNames); i++) { |
| 172 if (strcmp(kNames[i], name) == 0) { | 157 if (strcmp(kNames[i], name) == 0) { |
| 173 return kRegisters[i]; | 158 return kRegisters[i]; |
| 174 } | 159 } |
| 175 } | 160 } |
| 176 return kNoRegister; | 161 return kNoRegister; |
| 177 } | 162 } |
| 178 | 163 |
| 179 | 164 |
| (...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 249 } | 234 } |
| 250 *value = *(reinterpret_cast<double*>(addr)); | 235 *value = *(reinterpret_cast<double*>(addr)); |
| 251 return true; | 236 return true; |
| 252 } | 237 } |
| 253 } | 238 } |
| 254 return false; | 239 return false; |
| 255 } | 240 } |
| 256 | 241 |
| 257 | 242 |
| 258 TokenPosition SimulatorDebugger::GetApproximateTokenIndex(const Code& code, | 243 TokenPosition SimulatorDebugger::GetApproximateTokenIndex(const Code& code, |
| 259 uword pc) { | 244 uword pc) { |
| 260 TokenPosition token_pos = TokenPosition::kNoSource; | 245 TokenPosition token_pos = TokenPosition::kNoSource; |
| 261 uword pc_offset = pc - code.PayloadStart(); | 246 uword pc_offset = pc - code.PayloadStart(); |
| 262 const PcDescriptors& descriptors = | 247 const PcDescriptors& descriptors = |
| 263 PcDescriptors::Handle(code.pc_descriptors()); | 248 PcDescriptors::Handle(code.pc_descriptors()); |
| 264 PcDescriptors::Iterator iter(descriptors, RawPcDescriptors::kAnyKind); | 249 PcDescriptors::Iterator iter(descriptors, RawPcDescriptors::kAnyKind); |
| 265 while (iter.MoveNext()) { | 250 while (iter.MoveNext()) { |
| 266 if (iter.PcOffset() == pc_offset) { | 251 if (iter.PcOffset() == pc_offset) { |
| 267 return iter.TokenPos(); | 252 return iter.TokenPos(); |
| 268 } else if (!token_pos.IsReal() && (iter.PcOffset() > pc_offset)) { | 253 } else if (!token_pos.IsReal() && (iter.PcOffset() > pc_offset)) { |
| 269 token_pos = iter.TokenPos(); | 254 token_pos = iter.TokenPos(); |
| 270 } | 255 } |
| 271 } | 256 } |
| 272 return token_pos; | 257 return token_pos; |
| 273 } | 258 } |
| 274 | 259 |
| 275 | 260 |
| 276 void SimulatorDebugger::PrintDartFrame(uword pc, uword fp, uword sp, | 261 void SimulatorDebugger::PrintDartFrame(uword pc, |
| 262 uword fp, |
| 263 uword sp, |
| 277 const Function& function, | 264 const Function& function, |
| 278 TokenPosition token_pos, | 265 TokenPosition token_pos, |
| 279 bool is_optimized, | 266 bool is_optimized, |
| 280 bool is_inlined) { | 267 bool is_inlined) { |
| 281 const Script& script = Script::Handle(function.script()); | 268 const Script& script = Script::Handle(function.script()); |
| 282 const String& func_name = String::Handle(function.QualifiedScrubbedName()); | 269 const String& func_name = String::Handle(function.QualifiedScrubbedName()); |
| 283 const String& url = String::Handle(script.url()); | 270 const String& url = String::Handle(script.url()); |
| 284 intptr_t line = -1; | 271 intptr_t line = -1; |
| 285 intptr_t column = -1; | 272 intptr_t column = -1; |
| 286 if (token_pos.IsReal()) { | 273 if (token_pos.IsReal()) { |
| 287 script.GetTokenLocation(token_pos, &line, &column); | 274 script.GetTokenLocation(token_pos, &line, &column); |
| 288 } | 275 } |
| 289 OS::Print("pc=0x%" Px " fp=0x%" Px " sp=0x%" Px " %s%s (%s:%" Pd | 276 OS::Print( |
| 290 ":%" Pd ")\n", | 277 "pc=0x%" Px " fp=0x%" Px " sp=0x%" Px " %s%s (%s:%" Pd ":%" Pd ")\n", pc, |
| 291 pc, fp, sp, | 278 fp, sp, is_optimized ? (is_inlined ? "inlined " : "optimized ") : "", |
| 292 is_optimized ? (is_inlined ? "inlined " : "optimized ") : "", | 279 func_name.ToCString(), url.ToCString(), line, column); |
| 293 func_name.ToCString(), | |
| 294 url.ToCString(), | |
| 295 line, column); | |
| 296 } | 280 } |
| 297 | 281 |
| 298 | 282 |
| 299 void SimulatorDebugger::PrintBacktrace() { | 283 void SimulatorDebugger::PrintBacktrace() { |
| 300 StackFrameIterator frames(sim_->get_register(FP), | 284 StackFrameIterator frames(sim_->get_register(FP), sim_->get_register(SP), |
| 301 sim_->get_register(SP), | |
| 302 sim_->get_pc(), | 285 sim_->get_pc(), |
| 303 StackFrameIterator::kDontValidateFrames); | 286 StackFrameIterator::kDontValidateFrames); |
| 304 StackFrame* frame = frames.NextFrame(); | 287 StackFrame* frame = frames.NextFrame(); |
| 305 ASSERT(frame != NULL); | 288 ASSERT(frame != NULL); |
| 306 Function& function = Function::Handle(); | 289 Function& function = Function::Handle(); |
| 307 Function& inlined_function = Function::Handle(); | 290 Function& inlined_function = Function::Handle(); |
| 308 Code& code = Code::Handle(); | 291 Code& code = Code::Handle(); |
| 309 Code& unoptimized_code = Code::Handle(); | 292 Code& unoptimized_code = Code::Handle(); |
| 310 while (frame != NULL) { | 293 while (frame != NULL) { |
| 311 if (frame->IsDartFrame()) { | 294 if (frame->IsDartFrame()) { |
| 312 code = frame->LookupDartCode(); | 295 code = frame->LookupDartCode(); |
| 313 function = code.function(); | 296 function = code.function(); |
| 314 if (code.is_optimized()) { | 297 if (code.is_optimized()) { |
| 315 // For optimized frames, extract all the inlined functions if any | 298 // For optimized frames, extract all the inlined functions if any |
| 316 // into the stack trace. | 299 // into the stack trace. |
| 317 InlinedFunctionsIterator it(code, frame->pc()); | 300 InlinedFunctionsIterator it(code, frame->pc()); |
| 318 while (!it.Done()) { | 301 while (!it.Done()) { |
| 319 // Print each inlined frame with its pc in the corresponding | 302 // Print each inlined frame with its pc in the corresponding |
| 320 // unoptimized frame. | 303 // unoptimized frame. |
| 321 inlined_function = it.function(); | 304 inlined_function = it.function(); |
| 322 unoptimized_code = it.code(); | 305 unoptimized_code = it.code(); |
| 323 uword unoptimized_pc = it.pc(); | 306 uword unoptimized_pc = it.pc(); |
| 324 it.Advance(); | 307 it.Advance(); |
| 325 if (!it.Done()) { | 308 if (!it.Done()) { |
| 326 PrintDartFrame(unoptimized_pc, frame->fp(), frame->sp(), | 309 PrintDartFrame( |
| 327 inlined_function, | 310 unoptimized_pc, frame->fp(), frame->sp(), inlined_function, |
| 328 GetApproximateTokenIndex(unoptimized_code, | 311 GetApproximateTokenIndex(unoptimized_code, unoptimized_pc), |
| 329 unoptimized_pc), | 312 true, true); |
| 330 true, true); | |
| 331 } | 313 } |
| 332 } | 314 } |
| 333 // Print the optimized inlining frame below. | 315 // Print the optimized inlining frame below. |
| 334 } | 316 } |
| 335 PrintDartFrame(frame->pc(), frame->fp(), frame->sp(), | 317 PrintDartFrame(frame->pc(), frame->fp(), frame->sp(), function, |
| 336 function, | |
| 337 GetApproximateTokenIndex(code, frame->pc()), | 318 GetApproximateTokenIndex(code, frame->pc()), |
| 338 code.is_optimized(), false); | 319 code.is_optimized(), false); |
| 339 } else { | 320 } else { |
| 340 OS::Print("pc=0x%" Px " fp=0x%" Px " sp=0x%" Px " %s frame\n", | 321 OS::Print("pc=0x%" Px " fp=0x%" Px " sp=0x%" Px " %s frame\n", |
| 341 frame->pc(), frame->fp(), frame->sp(), | 322 frame->pc(), frame->fp(), frame->sp(), |
| 342 frame->IsEntryFrame() ? "entry" : | 323 frame->IsEntryFrame() |
| 343 frame->IsExitFrame() ? "exit" : | 324 ? "entry" |
| 344 frame->IsStubFrame() ? "stub" : "invalid"); | 325 : frame->IsExitFrame() |
| 326 ? "exit" |
| 327 : frame->IsStubFrame() ? "stub" : "invalid"); |
| 345 } | 328 } |
| 346 frame = frames.NextFrame(); | 329 frame = frames.NextFrame(); |
| 347 } | 330 } |
| 348 } | 331 } |
| 349 | 332 |
| 350 | 333 |
| 351 bool SimulatorDebugger::SetBreakpoint(Instr* breakpc) { | 334 bool SimulatorDebugger::SetBreakpoint(Instr* breakpc) { |
| 352 // Check if a breakpoint can be set. If not return without any side-effects. | 335 // Check if a breakpoint can be set. If not return without any side-effects. |
| 353 if (sim_->break_pc_ != NULL) { | 336 if (sim_->break_pc_ != NULL) { |
| 354 return false; | 337 return false; |
| (...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 429 FATAL("ReadLine failed"); | 412 FATAL("ReadLine failed"); |
| 430 } else { | 413 } else { |
| 431 // Use sscanf to parse the individual parts of the command line. At the | 414 // Use sscanf to parse the individual parts of the command line. At the |
| 432 // moment no command expects more than two parameters. | 415 // moment no command expects more than two parameters. |
| 433 int args = SScanF(line, | 416 int args = SScanF(line, |
| 434 "%" XSTR(COMMAND_SIZE) "s " | 417 "%" XSTR(COMMAND_SIZE) "s " |
| 435 "%" XSTR(ARG_SIZE) "s " | 418 "%" XSTR(ARG_SIZE) "s " |
| 436 "%" XSTR(ARG_SIZE) "s", | 419 "%" XSTR(ARG_SIZE) "s", |
| 437 cmd, arg1, arg2); | 420 cmd, arg1, arg2); |
| 438 if ((strcmp(cmd, "h") == 0) || (strcmp(cmd, "help") == 0)) { | 421 if ((strcmp(cmd, "h") == 0) || (strcmp(cmd, "help") == 0)) { |
| 439 OS::Print("c/cont -- continue execution\n" | 422 OS::Print( |
| 440 "disasm -- disassemble instrs at current pc location\n" | 423 "c/cont -- continue execution\n" |
| 441 " other variants are:\n" | 424 "disasm -- disassemble instrs at current pc location\n" |
| 442 " disasm <address>\n" | 425 " other variants are:\n" |
| 443 " disasm <address> <number_of_instructions>\n" | 426 " disasm <address>\n" |
| 444 " by default 10 instrs are disassembled\n" | 427 " disasm <address> <number_of_instructions>\n" |
| 445 "del -- delete breakpoints\n" | 428 " by default 10 instrs are disassembled\n" |
| 446 "gdb -- transfer control to gdb\n" | 429 "del -- delete breakpoints\n" |
| 447 "h/help -- print this help string\n" | 430 "gdb -- transfer control to gdb\n" |
| 448 "break <address> -- set break point at specified address\n" | 431 "h/help -- print this help string\n" |
| 449 "p/print <reg or icount or value or *addr> -- print integer\n" | 432 "break <address> -- set break point at specified address\n" |
| 450 "pf/printfloat <freg or *addr> -- print float value\n" | 433 "p/print <reg or icount or value or *addr> -- print integer\n" |
| 451 "po/printobject <*reg or *addr> -- print object\n" | 434 "pf/printfloat <freg or *addr> -- print float value\n" |
| 452 "si/stepi -- single step an instruction\n" | 435 "po/printobject <*reg or *addr> -- print object\n" |
| 453 "trace -- toggle execution tracing mode\n" | 436 "si/stepi -- single step an instruction\n" |
| 454 "bt -- print backtrace\n" | 437 "trace -- toggle execution tracing mode\n" |
| 455 "unstop -- if current pc is a stop instr make it a nop\n" | 438 "bt -- print backtrace\n" |
| 456 "q/quit -- Quit the debugger and exit the program\n"); | 439 "unstop -- if current pc is a stop instr make it a nop\n" |
| 440 "q/quit -- Quit the debugger and exit the program\n"); |
| 457 } else if ((strcmp(cmd, "quit") == 0) || (strcmp(cmd, "q") == 0)) { | 441 } else if ((strcmp(cmd, "quit") == 0) || (strcmp(cmd, "q") == 0)) { |
| 458 OS::Print("Quitting\n"); | 442 OS::Print("Quitting\n"); |
| 459 OS::Exit(0); | 443 OS::Exit(0); |
| 460 } else if ((strcmp(cmd, "si") == 0) || (strcmp(cmd, "stepi") == 0)) { | 444 } else if ((strcmp(cmd, "si") == 0) || (strcmp(cmd, "stepi") == 0)) { |
| 461 sim_->InstructionDecode(reinterpret_cast<Instr*>(sim_->get_pc())); | 445 sim_->InstructionDecode(reinterpret_cast<Instr*>(sim_->get_pc())); |
| 462 } else if ((strcmp(cmd, "c") == 0) || (strcmp(cmd, "cont") == 0)) { | 446 } else if ((strcmp(cmd, "c") == 0) || (strcmp(cmd, "cont") == 0)) { |
| 463 // Execute the one instruction we broke at with breakpoints disabled. | 447 // Execute the one instruction we broke at with breakpoints disabled. |
| 464 sim_->InstructionDecode(reinterpret_cast<Instr*>(sim_->get_pc())); | 448 sim_->InstructionDecode(reinterpret_cast<Instr*>(sim_->get_pc())); |
| 465 // Leave the debugger shell. | 449 // Leave the debugger shell. |
| 466 done = true; | 450 done = true; |
| 467 } else if ((strcmp(cmd, "p") == 0) || (strcmp(cmd, "print") == 0)) { | 451 } else if ((strcmp(cmd, "p") == 0) || (strcmp(cmd, "print") == 0)) { |
| 468 if (args == 2) { | 452 if (args == 2) { |
| 469 uint32_t value; | 453 uint32_t value; |
| 470 if (strcmp(arg1, "icount") == 0) { | 454 if (strcmp(arg1, "icount") == 0) { |
| 471 const uint64_t icount = sim_->get_icount(); | 455 const uint64_t icount = sim_->get_icount(); |
| 472 OS::Print("icount: %" Pu64 " 0x%" Px64 "\n", icount, icount); | 456 OS::Print("icount: %" Pu64 " 0x%" Px64 "\n", icount, icount); |
| 473 } else if (GetValue(arg1, &value)) { | 457 } else if (GetValue(arg1, &value)) { |
| 474 OS::Print("%s: %u 0x%x\n", arg1, value, value); | 458 OS::Print("%s: %u 0x%x\n", arg1, value, value); |
| 475 } else { | 459 } else { |
| 476 OS::Print("%s unrecognized\n", arg1); | 460 OS::Print("%s unrecognized\n", arg1); |
| 477 } | 461 } |
| 478 } else { | 462 } else { |
| 479 OS::Print("print <reg or icount or value or *addr>\n"); | 463 OS::Print("print <reg or icount or value or *addr>\n"); |
| 480 } | 464 } |
| 481 } else if ((strcmp(cmd, "pf") == 0) || | 465 } else if ((strcmp(cmd, "pf") == 0) || (strcmp(cmd, "printfloat") == 0)) { |
| 482 (strcmp(cmd, "printfloat") == 0)) { | |
| 483 if (args == 2) { | 466 if (args == 2) { |
| 484 double dvalue; | 467 double dvalue; |
| 485 if (GetFValue(arg1, &dvalue)) { | 468 if (GetFValue(arg1, &dvalue)) { |
| 486 uint64_t long_value = bit_cast<uint64_t, double>(dvalue); | 469 uint64_t long_value = bit_cast<uint64_t, double>(dvalue); |
| 487 OS::Print("%s: %llu 0x%llx %.8g\n", | 470 OS::Print("%s: %llu 0x%llx %.8g\n", arg1, long_value, long_value, |
| 488 arg1, long_value, long_value, dvalue); | 471 dvalue); |
| 489 } else { | 472 } else { |
| 490 OS::Print("%s unrecognized\n", arg1); | 473 OS::Print("%s unrecognized\n", arg1); |
| 491 } | 474 } |
| 492 } else { | 475 } else { |
| 493 OS::Print("printfloat <dreg or *addr>\n"); | 476 OS::Print("printfloat <dreg or *addr>\n"); |
| 494 } | 477 } |
| 495 } else if ((strcmp(cmd, "pd") == 0) || | 478 } else if ((strcmp(cmd, "pd") == 0) || |
| 496 (strcmp(cmd, "printdouble") == 0)) { | 479 (strcmp(cmd, "printdouble") == 0)) { |
| 497 if (args == 2) { | 480 if (args == 2) { |
| 498 double dvalue; | 481 double dvalue; |
| 499 if (GetDValue(arg1, &dvalue)) { | 482 if (GetDValue(arg1, &dvalue)) { |
| 500 uint64_t long_value = bit_cast<uint64_t, double>(dvalue); | 483 uint64_t long_value = bit_cast<uint64_t, double>(dvalue); |
| 501 OS::Print("%s: %llu 0x%llx %.8g\n", | 484 OS::Print("%s: %llu 0x%llx %.8g\n", arg1, long_value, long_value, |
| 502 arg1, long_value, long_value, dvalue); | 485 dvalue); |
| 503 } else { | 486 } else { |
| 504 OS::Print("%s unrecognized\n", arg1); | 487 OS::Print("%s unrecognized\n", arg1); |
| 505 } | 488 } |
| 506 } else { | 489 } else { |
| 507 OS::Print("printfloat <dreg or *addr>\n"); | 490 OS::Print("printfloat <dreg or *addr>\n"); |
| 508 } | 491 } |
| 509 } else if ((strcmp(cmd, "po") == 0) || | 492 } else if ((strcmp(cmd, "po") == 0) || |
| 510 (strcmp(cmd, "printobject") == 0)) { | 493 (strcmp(cmd, "printobject") == 0)) { |
| 511 if (args == 2) { | 494 if (args == 2) { |
| 512 uint32_t value; | 495 uint32_t value; |
| 513 // Make the dereferencing '*' optional. | 496 // Make the dereferencing '*' optional. |
| 514 if (((arg1[0] == '*') && GetValue(arg1 + 1, &value)) || | 497 if (((arg1[0] == '*') && GetValue(arg1 + 1, &value)) || |
| 515 GetValue(arg1, &value)) { | 498 GetValue(arg1, &value)) { |
| 516 if (Isolate::Current()->heap()->Contains(value)) { | 499 if (Isolate::Current()->heap()->Contains(value)) { |
| 517 OS::Print("%s: \n", arg1); | 500 OS::Print("%s: \n", arg1); |
| 518 #if defined(DEBUG) | 501 #if defined(DEBUG) |
| 519 const Object& obj = Object::Handle( | 502 const Object& obj = |
| 520 reinterpret_cast<RawObject*>(value)); | 503 Object::Handle(reinterpret_cast<RawObject*>(value)); |
| 521 obj.Print(); | 504 obj.Print(); |
| 522 #endif // defined(DEBUG) | 505 #endif // defined(DEBUG) |
| 523 } else { | 506 } else { |
| 524 OS::Print("0x%x is not an object reference\n", value); | 507 OS::Print("0x%x is not an object reference\n", value); |
| 525 } | 508 } |
| 526 } else { | 509 } else { |
| 527 OS::Print("%s unrecognized\n", arg1); | 510 OS::Print("%s unrecognized\n", arg1); |
| 528 } | 511 } |
| 529 } else { | 512 } else { |
| 530 OS::Print("printobject <*reg or *addr>\n"); | 513 OS::Print("printobject <*reg or *addr>\n"); |
| (...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 633 OS::Print("%s", prompt); | 616 OS::Print("%s", prompt); |
| 634 while (keep_going) { | 617 while (keep_going) { |
| 635 if (fgets(line_buf, sizeof(line_buf), stdin) == NULL) { | 618 if (fgets(line_buf, sizeof(line_buf), stdin) == NULL) { |
| 636 // fgets got an error. Just give up. | 619 // fgets got an error. Just give up. |
| 637 if (result != NULL) { | 620 if (result != NULL) { |
| 638 delete[] result; | 621 delete[] result; |
| 639 } | 622 } |
| 640 return NULL; | 623 return NULL; |
| 641 } | 624 } |
| 642 intptr_t len = strlen(line_buf); | 625 intptr_t len = strlen(line_buf); |
| 643 if (len > 1 && | 626 if (len > 1 && line_buf[len - 2] == '\\' && line_buf[len - 1] == '\n') { |
| 644 line_buf[len - 2] == '\\' && | |
| 645 line_buf[len - 1] == '\n') { | |
| 646 // When we read a line that ends with a "\" we remove the escape and | 627 // When we read a line that ends with a "\" we remove the escape and |
| 647 // append the remainder. | 628 // append the remainder. |
| 648 line_buf[len - 2] = '\n'; | 629 line_buf[len - 2] = '\n'; |
| 649 line_buf[len - 1] = 0; | 630 line_buf[len - 1] = 0; |
| 650 len -= 1; | 631 len -= 1; |
| 651 } else if ((len > 0) && (line_buf[len - 1] == '\n')) { | 632 } else if ((len > 0) && (line_buf[len - 1] == '\n')) { |
| 652 // Since we read a new line we are done reading the line. This | 633 // Since we read a new line we are done reading the line. This |
| 653 // will exit the loop after copying this buffer into the result. | 634 // will exit the loop after copying this buffer into the result. |
| 654 keep_going = false; | 635 keep_going = false; |
| 655 } | 636 } |
| (...skipping 25 matching lines...) Expand all Loading... |
| 681 offset += len; | 662 offset += len; |
| 682 } | 663 } |
| 683 ASSERT(result != NULL); | 664 ASSERT(result != NULL); |
| 684 result[offset] = '\0'; | 665 result[offset] = '\0'; |
| 685 return result; | 666 return result; |
| 686 } | 667 } |
| 687 | 668 |
| 688 | 669 |
| 689 // Synchronization primitives support. | 670 // Synchronization primitives support. |
| 690 Mutex* Simulator::exclusive_access_lock_ = NULL; | 671 Mutex* Simulator::exclusive_access_lock_ = NULL; |
| 691 Simulator::AddressTag Simulator::exclusive_access_state_[kNumAddressTags] = | 672 Simulator::AddressTag Simulator::exclusive_access_state_[kNumAddressTags] = { |
| 692 {{NULL, 0}}; | 673 {NULL, 0}}; |
| 693 int Simulator::next_address_tag_ = 0; | 674 int Simulator::next_address_tag_ = 0; |
| 694 | 675 |
| 695 | 676 |
| 696 void Simulator::InitOnce() { | 677 void Simulator::InitOnce() { |
| 697 // Setup exclusive access state lock. | 678 // Setup exclusive access state lock. |
| 698 exclusive_access_lock_ = new Mutex(); | 679 exclusive_access_lock_ = new Mutex(); |
| 699 } | 680 } |
| 700 | 681 |
| 701 | 682 |
| 702 Simulator::Simulator() { | 683 Simulator::Simulator() { |
| 703 // Setup simulator support first. Some of this information is needed to | 684 // Setup simulator support first. Some of this information is needed to |
| 704 // setup the architecture state. | 685 // setup the architecture state. |
| 705 // We allocate the stack here, the size is computed as the sum of | 686 // We allocate the stack here, the size is computed as the sum of |
| 706 // the size specified by the user and the buffer space needed for | 687 // the size specified by the user and the buffer space needed for |
| 707 // handling stack overflow exceptions. To be safe in potential | 688 // handling stack overflow exceptions. To be safe in potential |
| 708 // stack underflows we also add some underflow buffer space. | 689 // stack underflows we also add some underflow buffer space. |
| 709 stack_ = new char[(OSThread::GetSpecifiedStackSize() + | 690 stack_ = |
| 710 OSThread::kStackSizeBuffer + | 691 new char[(OSThread::GetSpecifiedStackSize() + OSThread::kStackSizeBuffer + |
| 711 kSimulatorStackUnderflowSize)]; | 692 kSimulatorStackUnderflowSize)]; |
| 712 icount_ = 0; | 693 icount_ = 0; |
| 713 delay_slot_ = false; | 694 delay_slot_ = false; |
| 714 break_pc_ = NULL; | 695 break_pc_ = NULL; |
| 715 break_instr_ = 0; | 696 break_instr_ = 0; |
| 716 last_setjmp_buffer_ = NULL; | 697 last_setjmp_buffer_ = NULL; |
| 717 top_exit_frame_info_ = 0; | 698 top_exit_frame_info_ = 0; |
| 718 | 699 |
| 719 // Setup architecture state. | 700 // Setup architecture state. |
| 720 // All registers are initialized to zero to start with. | 701 // All registers are initialized to zero to start with. |
| 721 for (int i = 0; i < kNumberOfCpuRegisters; i++) { | 702 for (int i = 0; i < kNumberOfCpuRegisters; i++) { |
| (...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 796 : external_function_(external_function), | 777 : external_function_(external_function), |
| 797 call_kind_(call_kind), | 778 call_kind_(call_kind), |
| 798 argument_count_(argument_count), | 779 argument_count_(argument_count), |
| 799 break_instruction_(Instr::kSimulatorRedirectInstruction), | 780 break_instruction_(Instr::kSimulatorRedirectInstruction), |
| 800 next_(list_) { | 781 next_(list_) { |
| 801 // Atomically prepend this element to the front of the global list. | 782 // Atomically prepend this element to the front of the global list. |
| 802 // Note: Since elements are never removed, there is no ABA issue. | 783 // Note: Since elements are never removed, there is no ABA issue. |
| 803 Redirection* list_head = list_; | 784 Redirection* list_head = list_; |
| 804 do { | 785 do { |
| 805 next_ = list_head; | 786 next_ = list_head; |
| 806 list_head = reinterpret_cast<Redirection*>( | 787 list_head = |
| 807 AtomicOperations::CompareAndSwapWord( | 788 reinterpret_cast<Redirection*>(AtomicOperations::CompareAndSwapWord( |
| 808 reinterpret_cast<uword*>(&list_), | 789 reinterpret_cast<uword*>(&list_), reinterpret_cast<uword>(next_), |
| 809 reinterpret_cast<uword>(next_), | |
| 810 reinterpret_cast<uword>(this))); | 790 reinterpret_cast<uword>(this))); |
| 811 } while (list_head != next_); | 791 } while (list_head != next_); |
| 812 } | 792 } |
| 813 | 793 |
| 814 uword external_function_; | 794 uword external_function_; |
| 815 Simulator::CallKind call_kind_; | 795 Simulator::CallKind call_kind_; |
| 816 int argument_count_; | 796 int argument_count_; |
| 817 uint32_t break_instruction_; | 797 uint32_t break_instruction_; |
| 818 Redirection* next_; | 798 Redirection* next_; |
| 819 static Redirection* list_; | 799 static Redirection* list_; |
| (...skipping 149 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 969 FATAL("Cannot continue execution after unimplemented instruction."); | 949 FATAL("Cannot continue execution after unimplemented instruction."); |
| 970 } | 950 } |
| 971 | 951 |
| 972 | 952 |
| 973 void Simulator::HandleIllegalAccess(uword addr, Instr* instr) { | 953 void Simulator::HandleIllegalAccess(uword addr, Instr* instr) { |
| 974 uword fault_pc = get_pc(); | 954 uword fault_pc = get_pc(); |
| 975 // The debugger will not be able to single step past this instruction, but | 955 // The debugger will not be able to single step past this instruction, but |
| 976 // it will be possible to disassemble the code and inspect registers. | 956 // it will be possible to disassemble the code and inspect registers. |
| 977 char buffer[128]; | 957 char buffer[128]; |
| 978 snprintf(buffer, sizeof(buffer), | 958 snprintf(buffer, sizeof(buffer), |
| 979 "illegal memory access at 0x%" Px ", pc=0x%" Px "\n", | 959 "illegal memory access at 0x%" Px ", pc=0x%" Px "\n", addr, |
| 980 addr, fault_pc); | 960 fault_pc); |
| 981 SimulatorDebugger dbg(this); | 961 SimulatorDebugger dbg(this); |
| 982 dbg.Stop(instr, buffer); | 962 dbg.Stop(instr, buffer); |
| 983 // The debugger will return control in non-interactive mode. | 963 // The debugger will return control in non-interactive mode. |
| 984 FATAL("Cannot continue execution after illegal memory access."); | 964 FATAL("Cannot continue execution after illegal memory access."); |
| 985 } | 965 } |
| 986 | 966 |
| 987 | 967 |
| 988 void Simulator::UnalignedAccess(const char* msg, uword addr, Instr* instr) { | 968 void Simulator::UnalignedAccess(const char* msg, uword addr, Instr* instr) { |
| 989 // The debugger will not be able to single step past this instruction, but | 969 // The debugger will not be able to single step past this instruction, but |
| 990 // it will be possible to disassemble the code and inspect registers. | 970 // it will be possible to disassemble the code and inspect registers. |
| 991 char buffer[128]; | 971 char buffer[128]; |
| 992 snprintf(buffer, sizeof(buffer), | 972 snprintf(buffer, sizeof(buffer), "pc=%p, unaligned %s at 0x%" Px "\n", instr, |
| 993 "pc=%p, unaligned %s at 0x%" Px "\n", instr, msg, addr); | 973 msg, addr); |
| 994 SimulatorDebugger dbg(this); | 974 SimulatorDebugger dbg(this); |
| 995 dbg.Stop(instr, buffer); | 975 dbg.Stop(instr, buffer); |
| 996 // The debugger will return control in non-interactive mode. | 976 // The debugger will return control in non-interactive mode. |
| 997 FATAL("Cannot continue execution after unaligned access."); | 977 FATAL("Cannot continue execution after unaligned access."); |
| 998 } | 978 } |
| 999 | 979 |
| 1000 | 980 |
| 1001 // Returns the top of the stack area to enable checking for stack pointer | 981 // Returns the top of the stack area to enable checking for stack pointer |
| 1002 // validity. | 982 // validity. |
| 1003 uword Simulator::StackTop() const { | 983 uword Simulator::StackTop() const { |
| 1004 // To be safe in potential stack underflows we leave some buffer above and | 984 // To be safe in potential stack underflows we leave some buffer above and |
| 1005 // set the stack top. | 985 // set the stack top. |
| 1006 return StackBase() + | 986 return StackBase() + |
| 1007 (OSThread::GetSpecifiedStackSize() + OSThread::kStackSizeBuffer); | 987 (OSThread::GetSpecifiedStackSize() + OSThread::kStackSizeBuffer); |
| 1008 } | 988 } |
| 1009 | 989 |
| 1010 | 990 |
| 1011 bool Simulator::IsTracingExecution() const { | 991 bool Simulator::IsTracingExecution() const { |
| 1012 return icount_ > FLAG_trace_sim_after; | 992 return icount_ > FLAG_trace_sim_after; |
| 1013 } | 993 } |
| 1014 | 994 |
| 1015 | 995 |
| 1016 void Simulator::Format(Instr* instr, const char* format) { | 996 void Simulator::Format(Instr* instr, const char* format) { |
| 1017 OS::PrintErr("Simulator - unknown instruction: %s\n", format); | 997 OS::PrintErr("Simulator - unknown instruction: %s\n", format); |
| (...skipping 187 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1205 return CompareExchange(reinterpret_cast<uword*>(address), | 1185 return CompareExchange(reinterpret_cast<uword*>(address), |
| 1206 static_cast<uword>(compare_value), | 1186 static_cast<uword>(compare_value), |
| 1207 static_cast<uword>(new_value)); | 1187 static_cast<uword>(new_value)); |
| 1208 } | 1188 } |
| 1209 | 1189 |
| 1210 | 1190 |
| 1211 // Calls into the Dart runtime are based on this interface. | 1191 // Calls into the Dart runtime are based on this interface. |
| 1212 typedef void (*SimulatorRuntimeCall)(NativeArguments arguments); | 1192 typedef void (*SimulatorRuntimeCall)(NativeArguments arguments); |
| 1213 | 1193 |
| 1214 // Calls to leaf Dart runtime functions are based on this interface. | 1194 // Calls to leaf Dart runtime functions are based on this interface. |
| 1215 typedef int32_t (*SimulatorLeafRuntimeCall)( | 1195 typedef int32_t (*SimulatorLeafRuntimeCall)(int32_t r0, |
| 1216 int32_t r0, int32_t r1, int32_t r2, int32_t r3); | 1196 int32_t r1, |
| 1197 int32_t r2, |
| 1198 int32_t r3); |
| 1217 | 1199 |
| 1218 // Calls to leaf float Dart runtime functions are based on this interface. | 1200 // Calls to leaf float Dart runtime functions are based on this interface. |
| 1219 typedef double (*SimulatorLeafFloatRuntimeCall)(double d0, double d1); | 1201 typedef double (*SimulatorLeafFloatRuntimeCall)(double d0, double d1); |
| 1220 | 1202 |
| 1221 // Calls to native Dart functions are based on this interface. | 1203 // Calls to native Dart functions are based on this interface. |
| 1222 typedef void (*SimulatorBootstrapNativeCall)(NativeArguments* arguments); | 1204 typedef void (*SimulatorBootstrapNativeCall)(NativeArguments* arguments); |
| 1223 typedef void (*SimulatorNativeCall)(NativeArguments* arguments, uword target); | 1205 typedef void (*SimulatorNativeCall)(NativeArguments* arguments, uword target); |
| 1224 | 1206 |
| 1225 | 1207 |
| 1226 void Simulator::DoBreak(Instr *instr) { | 1208 void Simulator::DoBreak(Instr* instr) { |
| 1227 ASSERT(instr->OpcodeField() == SPECIAL); | 1209 ASSERT(instr->OpcodeField() == SPECIAL); |
| 1228 ASSERT(instr->FunctionField() == BREAK); | 1210 ASSERT(instr->FunctionField() == BREAK); |
| 1229 if (instr->BreakCodeField() == Instr::kStopMessageCode) { | 1211 if (instr->BreakCodeField() == Instr::kStopMessageCode) { |
| 1230 SimulatorDebugger dbg(this); | 1212 SimulatorDebugger dbg(this); |
| 1231 const char* message = *reinterpret_cast<const char**>( | 1213 const char* message = *reinterpret_cast<const char**>( |
| 1232 reinterpret_cast<intptr_t>(instr) - Instr::kInstrSize); | 1214 reinterpret_cast<intptr_t>(instr) - Instr::kInstrSize); |
| 1233 set_pc(get_pc() + Instr::kInstrSize); | 1215 set_pc(get_pc() + Instr::kInstrSize); |
| 1234 dbg.Stop(instr, message); | 1216 dbg.Stop(instr, message); |
| 1235 // Adjust for extra pc increment. | 1217 // Adjust for extra pc increment. |
| 1236 set_pc(get_pc() - Instr::kInstrSize); | 1218 set_pc(get_pc() - Instr::kInstrSize); |
| 1237 } else if (instr->BreakCodeField() == Instr::kSimulatorRedirectCode) { | 1219 } else if (instr->BreakCodeField() == Instr::kSimulatorRedirectCode) { |
| 1238 SimulatorSetjmpBuffer buffer(this); | 1220 SimulatorSetjmpBuffer buffer(this); |
| 1239 | 1221 |
| 1240 if (!setjmp(buffer.buffer_)) { | 1222 if (!setjmp(buffer.buffer_)) { |
| 1241 int32_t saved_ra = get_register(RA); | 1223 int32_t saved_ra = get_register(RA); |
| 1242 Redirection* redirection = Redirection::FromBreakInstruction(instr); | 1224 Redirection* redirection = Redirection::FromBreakInstruction(instr); |
| 1243 uword external = redirection->external_function(); | 1225 uword external = redirection->external_function(); |
| 1244 if (IsTracingExecution()) { | 1226 if (IsTracingExecution()) { |
| 1245 THR_Print("Call to host function at 0x%" Pd "\n", external); | 1227 THR_Print("Call to host function at 0x%" Pd "\n", external); |
| 1246 } | 1228 } |
| 1247 | 1229 |
| 1248 if ((redirection->call_kind() == kRuntimeCall) || | 1230 if ((redirection->call_kind() == kRuntimeCall) || |
| 1249 (redirection->call_kind() == kBootstrapNativeCall) || | 1231 (redirection->call_kind() == kBootstrapNativeCall) || |
| 1250 (redirection->call_kind() == kNativeCall)) { | 1232 (redirection->call_kind() == kNativeCall)) { |
| 1251 // Set the top_exit_frame_info of this simulator to the native stack. | 1233 // Set the top_exit_frame_info of this simulator to the native stack. |
| 1252 set_top_exit_frame_info(Thread::GetCurrentStackPointer()); | 1234 set_top_exit_frame_info(Thread::GetCurrentStackPointer()); |
| 1253 } | 1235 } |
| 1254 if (redirection->call_kind() == kRuntimeCall) { | 1236 if (redirection->call_kind() == kRuntimeCall) { |
| 1255 NativeArguments arguments; | 1237 NativeArguments arguments; |
| 1256 ASSERT(sizeof(NativeArguments) == 4*kWordSize); | 1238 ASSERT(sizeof(NativeArguments) == 4 * kWordSize); |
| 1257 arguments.thread_ = reinterpret_cast<Thread*>(get_register(A0)); | 1239 arguments.thread_ = reinterpret_cast<Thread*>(get_register(A0)); |
| 1258 arguments.argc_tag_ = get_register(A1); | 1240 arguments.argc_tag_ = get_register(A1); |
| 1259 arguments.argv_ = reinterpret_cast<RawObject**>(get_register(A2)); | 1241 arguments.argv_ = reinterpret_cast<RawObject**>(get_register(A2)); |
| 1260 arguments.retval_ = reinterpret_cast<RawObject**>(get_register(A3)); | 1242 arguments.retval_ = reinterpret_cast<RawObject**>(get_register(A3)); |
| 1261 SimulatorRuntimeCall target = | 1243 SimulatorRuntimeCall target = |
| 1262 reinterpret_cast<SimulatorRuntimeCall>(external); | 1244 reinterpret_cast<SimulatorRuntimeCall>(external); |
| 1263 target(arguments); | 1245 target(arguments); |
| 1264 set_register(V0, icount_); // Zap result registers from void function. | 1246 set_register(V0, icount_); // Zap result registers from void function. |
| 1265 set_register(V1, icount_); | 1247 set_register(V1, icount_); |
| 1266 } else if (redirection->call_kind() == kLeafRuntimeCall) { | 1248 } else if (redirection->call_kind() == kLeafRuntimeCall) { |
| 1267 int32_t a0 = get_register(A0); | 1249 int32_t a0 = get_register(A0); |
| 1268 int32_t a1 = get_register(A1); | 1250 int32_t a1 = get_register(A1); |
| 1269 int32_t a2 = get_register(A2); | 1251 int32_t a2 = get_register(A2); |
| 1270 int32_t a3 = get_register(A3); | 1252 int32_t a3 = get_register(A3); |
| 1271 SimulatorLeafRuntimeCall target = | 1253 SimulatorLeafRuntimeCall target = |
| 1272 reinterpret_cast<SimulatorLeafRuntimeCall>(external); | 1254 reinterpret_cast<SimulatorLeafRuntimeCall>(external); |
| 1273 a0 = target(a0, a1, a2, a3); | 1255 a0 = target(a0, a1, a2, a3); |
| 1274 set_register(V0, a0); // Set returned result from function. | 1256 set_register(V0, a0); // Set returned result from function. |
| 1275 set_register(V1, icount_); // Zap second result register. | 1257 set_register(V1, icount_); // Zap second result register. |
| 1276 } else if (redirection->call_kind() == kLeafFloatRuntimeCall) { | 1258 } else if (redirection->call_kind() == kLeafFloatRuntimeCall) { |
| 1277 ASSERT((0 <= redirection->argument_count()) && | 1259 ASSERT((0 <= redirection->argument_count()) && |
| 1278 (redirection->argument_count() <= 2)); | 1260 (redirection->argument_count() <= 2)); |
| 1279 // double values are passed and returned in floating point registers. | 1261 // double values are passed and returned in floating point registers. |
| 1280 SimulatorLeafFloatRuntimeCall target = | 1262 SimulatorLeafFloatRuntimeCall target = |
| 1281 reinterpret_cast<SimulatorLeafFloatRuntimeCall>(external); | 1263 reinterpret_cast<SimulatorLeafFloatRuntimeCall>(external); |
| 1282 double d0 = 0.0; | 1264 double d0 = 0.0; |
| 1283 double d6 = get_fregister_double(F12); | 1265 double d6 = get_fregister_double(F12); |
| 1284 double d7 = get_fregister_double(F14); | 1266 double d7 = get_fregister_double(F14); |
| (...skipping 132 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1417 } | 1399 } |
| 1418 set_lo_register(rs_val / rt_val); | 1400 set_lo_register(rs_val / rt_val); |
| 1419 set_hi_register(rs_val % rt_val); | 1401 set_hi_register(rs_val % rt_val); |
| 1420 break; | 1402 break; |
| 1421 } | 1403 } |
| 1422 case JALR: { | 1404 case JALR: { |
| 1423 ASSERT(instr->RtField() == R0); | 1405 ASSERT(instr->RtField() == R0); |
| 1424 ASSERT(instr->RsField() != instr->RdField()); | 1406 ASSERT(instr->RsField() != instr->RdField()); |
| 1425 ASSERT(!delay_slot_); | 1407 ASSERT(!delay_slot_); |
| 1426 // Format(instr, "jalr'hint 'rd, rs"); | 1408 // Format(instr, "jalr'hint 'rd, rs"); |
| 1427 set_register(instr->RdField(), pc_ + 2*Instr::kInstrSize); | 1409 set_register(instr->RdField(), pc_ + 2 * Instr::kInstrSize); |
| 1428 uword next_pc = get_register(instr->RsField()); | 1410 uword next_pc = get_register(instr->RsField()); |
| 1429 ExecuteDelaySlot(); | 1411 ExecuteDelaySlot(); |
| 1430 // Set return address to be the instruction after the delay slot. | 1412 // Set return address to be the instruction after the delay slot. |
| 1431 pc_ = next_pc - Instr::kInstrSize; // Account for regular PC increment. | 1413 pc_ = next_pc - Instr::kInstrSize; // Account for regular PC increment. |
| 1432 break; | 1414 break; |
| 1433 } | 1415 } |
| 1434 case JR: { | 1416 case JR: { |
| 1435 ASSERT(instr->RtField() == R0); | 1417 ASSERT(instr->RtField() == R0); |
| 1436 ASSERT(instr->RdField() == R0); | 1418 ASSERT(instr->RdField() == R0); |
| 1437 ASSERT(!delay_slot_); | 1419 ASSERT(!delay_slot_); |
| (...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1540 case OR: { | 1522 case OR: { |
| 1541 ASSERT(instr->SaField() == 0); | 1523 ASSERT(instr->SaField() == 0); |
| 1542 // Format(instr, "or 'rd, 'rs, 'rt"); | 1524 // Format(instr, "or 'rd, 'rs, 'rt"); |
| 1543 int32_t rs_val = get_register(instr->RsField()); | 1525 int32_t rs_val = get_register(instr->RsField()); |
| 1544 int32_t rt_val = get_register(instr->RtField()); | 1526 int32_t rt_val = get_register(instr->RtField()); |
| 1545 set_register(instr->RdField(), rs_val | rt_val); | 1527 set_register(instr->RdField(), rs_val | rt_val); |
| 1546 break; | 1528 break; |
| 1547 } | 1529 } |
| 1548 case SLL: { | 1530 case SLL: { |
| 1549 ASSERT(instr->RsField() == 0); | 1531 ASSERT(instr->RsField() == 0); |
| 1550 if ((instr->RdField() == R0) && | 1532 if ((instr->RdField() == R0) && (instr->RtField() == R0) && |
| 1551 (instr->RtField() == R0) && | |
| 1552 (instr->SaField() == 0)) { | 1533 (instr->SaField() == 0)) { |
| 1553 // Format(instr, "nop"); | 1534 // Format(instr, "nop"); |
| 1554 // Nothing to be done for NOP. | 1535 // Nothing to be done for NOP. |
| 1555 } else { | 1536 } else { |
| 1556 int32_t rt_val = get_register(instr->RtField()); | 1537 int32_t rt_val = get_register(instr->RtField()); |
| 1557 int sa = instr->SaField(); | 1538 int sa = instr->SaField(); |
| 1558 set_register(instr->RdField(), rt_val << sa); | 1539 set_register(instr->RdField(), rt_val << sa); |
| 1559 } | 1540 } |
| 1560 break; | 1541 break; |
| 1561 } | 1542 } |
| (...skipping 176 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1738 switch (instr->RegImmFnField()) { | 1719 switch (instr->RegImmFnField()) { |
| 1739 case BGEZ: { | 1720 case BGEZ: { |
| 1740 // Format(instr, "bgez 'rs, 'dest"); | 1721 // Format(instr, "bgez 'rs, 'dest"); |
| 1741 int32_t rs_val = get_register(instr->RsField()); | 1722 int32_t rs_val = get_register(instr->RsField()); |
| 1742 DoBranch(instr, rs_val >= 0, false); | 1723 DoBranch(instr, rs_val >= 0, false); |
| 1743 break; | 1724 break; |
| 1744 } | 1725 } |
| 1745 case BGEZAL: { | 1726 case BGEZAL: { |
| 1746 int32_t rs_val = get_register(instr->RsField()); | 1727 int32_t rs_val = get_register(instr->RsField()); |
| 1747 // Return address is one after the delay slot. | 1728 // Return address is one after the delay slot. |
| 1748 set_register(RA, pc_ + (2*Instr::kInstrSize)); | 1729 set_register(RA, pc_ + (2 * Instr::kInstrSize)); |
| 1749 DoBranch(instr, rs_val >= 0, false); | 1730 DoBranch(instr, rs_val >= 0, false); |
| 1750 break; | 1731 break; |
| 1751 } | 1732 } |
| 1752 case BLTZAL: { | 1733 case BLTZAL: { |
| 1753 int32_t rs_val = get_register(instr->RsField()); | 1734 int32_t rs_val = get_register(instr->RsField()); |
| 1754 // Return address is one after the delay slot. | 1735 // Return address is one after the delay slot. |
| 1755 set_register(RA, pc_ + (2*Instr::kInstrSize)); | 1736 set_register(RA, pc_ + (2 * Instr::kInstrSize)); |
| 1756 DoBranch(instr, rs_val < 0, false); | 1737 DoBranch(instr, rs_val < 0, false); |
| 1757 break; | 1738 break; |
| 1758 } | 1739 } |
| 1759 case BGEZL: { | 1740 case BGEZL: { |
| 1760 // Format(instr, "bgezl 'rs, 'dest"); | 1741 // Format(instr, "bgezl 'rs, 'dest"); |
| 1761 int32_t rs_val = get_register(instr->RsField()); | 1742 int32_t rs_val = get_register(instr->RsField()); |
| 1762 DoBranch(instr, rs_val >= 0, true); | 1743 DoBranch(instr, rs_val >= 0, true); |
| 1763 break; | 1744 break; |
| 1764 } | 1745 } |
| 1765 case BLTZ: { | 1746 case BLTZ: { |
| (...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1851 case COP1_C_EQ: { | 1832 case COP1_C_EQ: { |
| 1852 ASSERT(instr->FormatField() == FMT_D); // Only D supported. | 1833 ASSERT(instr->FormatField() == FMT_D); // Only D supported. |
| 1853 ASSERT(instr->FdField() == F0); | 1834 ASSERT(instr->FdField() == F0); |
| 1854 set_fcsr_bit(fcsr_cc, (fs_val == ft_val)); | 1835 set_fcsr_bit(fcsr_cc, (fs_val == ft_val)); |
| 1855 break; | 1836 break; |
| 1856 } | 1837 } |
| 1857 case COP1_C_UEQ: { | 1838 case COP1_C_UEQ: { |
| 1858 ASSERT(instr->FormatField() == FMT_D); // Only D supported. | 1839 ASSERT(instr->FormatField() == FMT_D); // Only D supported. |
| 1859 ASSERT(instr->FdField() == F0); | 1840 ASSERT(instr->FdField() == F0); |
| 1860 set_fcsr_bit(fcsr_cc, | 1841 set_fcsr_bit(fcsr_cc, |
| 1861 (fs_val == ft_val) || isnan(fs_val) || isnan(ft_val)); | 1842 (fs_val == ft_val) || isnan(fs_val) || isnan(ft_val)); |
| 1862 break; | 1843 break; |
| 1863 } | 1844 } |
| 1864 case COP1_C_OLT: { | 1845 case COP1_C_OLT: { |
| 1865 ASSERT(instr->FormatField() == FMT_D); // Only D supported. | 1846 ASSERT(instr->FormatField() == FMT_D); // Only D supported. |
| 1866 ASSERT(instr->FdField() == F0); | 1847 ASSERT(instr->FdField() == F0); |
| 1867 set_fcsr_bit(fcsr_cc, (fs_val < ft_val)); | 1848 set_fcsr_bit(fcsr_cc, (fs_val < ft_val)); |
| 1868 break; | 1849 break; |
| 1869 } | 1850 } |
| 1870 case COP1_C_ULT: { | 1851 case COP1_C_ULT: { |
| 1871 ASSERT(instr->FormatField() == FMT_D); // Only D supported. | 1852 ASSERT(instr->FormatField() == FMT_D); // Only D supported. |
| 1872 ASSERT(instr->FdField() == F0); | 1853 ASSERT(instr->FdField() == F0); |
| 1873 set_fcsr_bit(fcsr_cc, | 1854 set_fcsr_bit(fcsr_cc, |
| 1874 (fs_val < ft_val) || isnan(fs_val) || isnan(ft_val)); | 1855 (fs_val < ft_val) || isnan(fs_val) || isnan(ft_val)); |
| 1875 break; | 1856 break; |
| 1876 } | 1857 } |
| 1877 case COP1_C_OLE: { | 1858 case COP1_C_OLE: { |
| 1878 ASSERT(instr->FormatField() == FMT_D); // Only D supported. | 1859 ASSERT(instr->FormatField() == FMT_D); // Only D supported. |
| 1879 ASSERT(instr->FdField() == F0); | 1860 ASSERT(instr->FdField() == F0); |
| 1880 set_fcsr_bit(fcsr_cc, (fs_val <= ft_val)); | 1861 set_fcsr_bit(fcsr_cc, (fs_val <= ft_val)); |
| 1881 break; | 1862 break; |
| 1882 } | 1863 } |
| 1883 case COP1_C_ULE: { | 1864 case COP1_C_ULE: { |
| 1884 ASSERT(instr->FormatField() == FMT_D); // Only D supported. | 1865 ASSERT(instr->FormatField() == FMT_D); // Only D supported. |
| 1885 ASSERT(instr->FdField() == F0); | 1866 ASSERT(instr->FdField() == F0); |
| 1886 set_fcsr_bit(fcsr_cc, | 1867 set_fcsr_bit(fcsr_cc, |
| 1887 (fs_val <= ft_val) || isnan(fs_val) || isnan(ft_val)); | 1868 (fs_val <= ft_val) || isnan(fs_val) || isnan(ft_val)); |
| 1888 break; | 1869 break; |
| 1889 } | 1870 } |
| 1890 case COP1_TRUNC_W: { | 1871 case COP1_TRUNC_W: { |
| 1891 switch (instr->FormatField()) { | 1872 switch (instr->FormatField()) { |
| 1892 case FMT_D: { | 1873 case FMT_D: { |
| 1893 double fs_dbl = get_fregister_double(instr->FsField()); | 1874 double fs_dbl = get_fregister_double(instr->FsField()); |
| 1894 int32_t fs_int; | 1875 int32_t fs_int; |
| 1895 if (isnan(fs_dbl) || isinf(fs_dbl) || (fs_dbl > kMaxInt32) || | 1876 if (isnan(fs_dbl) || isinf(fs_dbl) || (fs_dbl > kMaxInt32) || |
| 1896 (fs_dbl < kMinInt32)) { | 1877 (fs_dbl < kMinInt32)) { |
| 1897 fs_int = kMaxInt32; | 1878 fs_int = kMaxInt32; |
| (...skipping 405 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2303 } | 2284 } |
| 2304 case XORI: { | 2285 case XORI: { |
| 2305 // Format(instr, "xori 'rt, 'rs, 'immu"); | 2286 // Format(instr, "xori 'rt, 'rs, 'immu"); |
| 2306 int32_t rs_val = get_register(instr->RsField()); | 2287 int32_t rs_val = get_register(instr->RsField()); |
| 2307 set_register(instr->RtField(), rs_val ^ instr->UImmField()); | 2288 set_register(instr->RtField(), rs_val ^ instr->UImmField()); |
| 2308 break; | 2289 break; |
| 2309 break; | 2290 break; |
| 2310 } | 2291 } |
| 2311 default: { | 2292 default: { |
| 2312 OS::PrintErr("Undecoded instruction: 0x%x at %p\n", | 2293 OS::PrintErr("Undecoded instruction: 0x%x at %p\n", |
| 2313 instr->InstructionBits(), instr); | 2294 instr->InstructionBits(), instr); |
| 2314 UnimplementedInstruction(instr); | 2295 UnimplementedInstruction(instr); |
| 2315 break; | 2296 break; |
| 2316 } | 2297 } |
| 2317 } | 2298 } |
| 2318 pc_ += Instr::kInstrSize; | 2299 pc_ += Instr::kInstrSize; |
| 2319 } | 2300 } |
| 2320 | 2301 |
| 2321 | 2302 |
| 2322 void Simulator::ExecuteDelaySlot() { | 2303 void Simulator::ExecuteDelaySlot() { |
| 2323 ASSERT(pc_ != kEndSimulatingPC); | 2304 ASSERT(pc_ != kEndSimulatingPC); |
| (...skipping 200 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2524 set_register(THR, reinterpret_cast<int32_t>(thread)); | 2505 set_register(THR, reinterpret_cast<int32_t>(thread)); |
| 2525 // Set the tag. | 2506 // Set the tag. |
| 2526 thread->set_vm_tag(VMTag::kDartTagId); | 2507 thread->set_vm_tag(VMTag::kDartTagId); |
| 2527 // Clear top exit frame. | 2508 // Clear top exit frame. |
| 2528 thread->set_top_exit_frame_info(0); | 2509 thread->set_top_exit_frame_info(0); |
| 2529 | 2510 |
| 2530 ASSERT(raw_exception != Object::null()); | 2511 ASSERT(raw_exception != Object::null()); |
| 2531 set_register(kExceptionObjectReg, bit_cast<int32_t>(raw_exception)); | 2512 set_register(kExceptionObjectReg, bit_cast<int32_t>(raw_exception)); |
| 2532 set_register(kStackTraceObjectReg, bit_cast<int32_t>(raw_stacktrace)); | 2513 set_register(kStackTraceObjectReg, bit_cast<int32_t>(raw_stacktrace)); |
| 2533 // Restore pool pointer. | 2514 // Restore pool pointer. |
| 2534 int32_t code = *reinterpret_cast<int32_t*>( | 2515 int32_t code = |
| 2535 fp + kPcMarkerSlotFromFp * kWordSize); | 2516 *reinterpret_cast<int32_t*>(fp + kPcMarkerSlotFromFp * kWordSize); |
| 2536 int32_t pp = *reinterpret_cast<int32_t*>( | 2517 int32_t pp = *reinterpret_cast<int32_t*>(code + Code::object_pool_offset() - |
| 2537 code + Code::object_pool_offset() - kHeapObjectTag); | 2518 kHeapObjectTag); |
| 2538 set_register(CODE_REG, code); | 2519 set_register(CODE_REG, code); |
| 2539 set_register(PP, pp); | 2520 set_register(PP, pp); |
| 2540 buf->Longjmp(); | 2521 buf->Longjmp(); |
| 2541 } | 2522 } |
| 2542 | 2523 |
| 2543 } // namespace dart | 2524 } // namespace dart |
| 2544 | 2525 |
| 2545 #endif // defined(USING_SIMULATOR) | 2526 #endif // defined(USING_SIMULATOR) |
| 2546 | 2527 |
| 2547 #endif // defined TARGET_ARCH_MIPS | 2528 #endif // defined TARGET_ARCH_MIPS |
| OLD | NEW |