| 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_ARM) | 9 #if defined(TARGET_ARCH_ARM) |
| 10 | 10 |
| 11 // Only build the simulator if not compiling for real ARM hardware. | 11 // Only build the simulator if not compiling for real ARM 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_arm.h" | 17 #include "vm/constants_arm.h" |
| 18 #include "vm/cpu.h" | 18 #include "vm/cpu.h" |
| 19 #include "vm/disassembler.h" | 19 #include "vm/disassembler.h" |
| 20 #include "vm/lockers.h" | 20 #include "vm/lockers.h" |
| 21 #include "vm/native_arguments.h" | 21 #include "vm/native_arguments.h" |
| 22 #include "vm/stack_frame.h" | 22 #include "vm/stack_frame.h" |
| 23 #include "vm/os_thread.h" | 23 #include "vm/os_thread.h" |
| 24 | 24 |
| 25 namespace dart { | 25 namespace dart { |
| 26 | 26 |
| 27 DEFINE_FLAG(uint64_t, trace_sim_after, ULLONG_MAX, | 27 DEFINE_FLAG(uint64_t, |
| 28 trace_sim_after, |
| 29 ULLONG_MAX, |
| 28 "Trace simulator execution after instruction count reached."); | 30 "Trace simulator execution after instruction count reached."); |
| 29 DEFINE_FLAG(uint64_t, stop_sim_at, ULLONG_MAX, | 31 DEFINE_FLAG(uint64_t, |
| 32 stop_sim_at, |
| 33 ULLONG_MAX, |
| 30 "Instruction address or instruction count to stop simulator at."); | 34 "Instruction address or instruction count to stop simulator at."); |
| 31 | 35 |
| 32 | 36 |
| 33 // This macro provides a platform independent use of sscanf. The reason for | 37 // This macro provides a platform independent use of sscanf. The reason for |
| 34 // SScanF not being implemented in a platform independent way through | 38 // SScanF not being implemented in a platform independent way through |
| 35 // OS in the same way as SNPrint is that the Windows C Run-Time | 39 // OS in the same way as SNPrint is that the Windows C Run-Time |
| 36 // Library does not provide vsscanf. | 40 // Library does not provide vsscanf. |
| 37 #define SScanF sscanf // NOLINT | 41 #define SScanF sscanf // NOLINT |
| 38 | 42 |
| 39 | 43 |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 89 | 93 |
| 90 private: | 94 private: |
| 91 Simulator* sim_; | 95 Simulator* sim_; |
| 92 | 96 |
| 93 bool GetValue(char* desc, uint32_t* value); | 97 bool GetValue(char* desc, uint32_t* value); |
| 94 bool GetFValue(char* desc, float* value); | 98 bool GetFValue(char* desc, float* value); |
| 95 bool GetDValue(char* desc, double* value); | 99 bool GetDValue(char* desc, double* value); |
| 96 | 100 |
| 97 static TokenPosition GetApproximateTokenIndex(const Code& code, uword pc); | 101 static TokenPosition GetApproximateTokenIndex(const Code& code, uword pc); |
| 98 | 102 |
| 99 static void PrintDartFrame(uword pc, uword fp, uword sp, | 103 static void PrintDartFrame(uword pc, |
| 104 uword fp, |
| 105 uword sp, |
| 100 const Function& function, | 106 const Function& function, |
| 101 TokenPosition token_pos, | 107 TokenPosition token_pos, |
| 102 bool is_optimized, | 108 bool is_optimized, |
| 103 bool is_inlined); | 109 bool is_inlined); |
| 104 void PrintBacktrace(); | 110 void PrintBacktrace(); |
| 105 | 111 |
| 106 // Set or delete a breakpoint. Returns true if successful. | 112 // Set or delete a breakpoint. Returns true if successful. |
| 107 bool SetBreakpoint(Instr* breakpc); | 113 bool SetBreakpoint(Instr* breakpc); |
| 108 bool DeleteBreakpoint(Instr* breakpc); | 114 bool DeleteBreakpoint(Instr* breakpc); |
| 109 | 115 |
| 110 // Undo and redo all breakpoints. This is needed to bracket disassembly and | 116 // Undo and redo all breakpoints. This is needed to bracket disassembly and |
| 111 // execution to skip past breakpoints when run from the debugger. | 117 // execution to skip past breakpoints when run from the debugger. |
| 112 void UndoBreakpoints(); | 118 void UndoBreakpoints(); |
| 113 void RedoBreakpoints(); | 119 void RedoBreakpoints(); |
| 114 }; | 120 }; |
| 115 | 121 |
| 116 | 122 |
| 117 SimulatorDebugger::SimulatorDebugger(Simulator* sim) { | 123 SimulatorDebugger::SimulatorDebugger(Simulator* sim) { |
| 118 sim_ = sim; | 124 sim_ = sim; |
| 119 } | 125 } |
| 120 | 126 |
| 121 | 127 |
| 122 SimulatorDebugger::~SimulatorDebugger() { | 128 SimulatorDebugger::~SimulatorDebugger() {} |
| 123 } | |
| 124 | 129 |
| 125 | 130 |
| 126 void SimulatorDebugger::Stop(Instr* instr, const char* message) { | 131 void SimulatorDebugger::Stop(Instr* instr, const char* message) { |
| 127 OS::Print("Simulator hit %s\n", message); | 132 OS::Print("Simulator hit %s\n", message); |
| 128 Debug(); | 133 Debug(); |
| 129 } | 134 } |
| 130 | 135 |
| 131 | 136 |
| 132 static Register LookupCpuRegisterByName(const char* name) { | 137 static Register LookupCpuRegisterByName(const char* name) { |
| 133 static const char* kNames[] = { | 138 static const char* kNames[] = {"r0", "r1", "r2", "r3", "r4", "r5", |
| 134 "r0", "r1", "r2", "r3", | 139 "r6", "r7", "r8", "r9", "r10", "r11", |
| 135 "r4", "r5", "r6", "r7", | 140 "r12", "r13", "r14", "r15", "pc", "lr", |
| 136 "r8", "r9", "r10", "r11", | 141 "sp", "ip", "fp", "pp", "ctx"}; |
| 137 "r12", "r13", "r14", "r15", | 142 static const Register kRegisters[] = {R0, R1, R2, R3, R4, R5, R6, R7, |
| 138 "pc", "lr", "sp", "ip", | 143 R8, R9, R10, R11, R12, R13, R14, R15, |
| 139 "fp", "pp", "ctx" | 144 PC, LR, SP, IP, FP, PP, CTX}; |
| 140 }; | |
| 141 static const Register kRegisters[] = { | |
| 142 R0, R1, R2, R3, | |
| 143 R4, R5, R6, R7, | |
| 144 R8, R9, R10, R11, | |
| 145 R12, R13, R14, R15, | |
| 146 PC, LR, SP, IP, | |
| 147 FP, PP, CTX | |
| 148 }; | |
| 149 ASSERT(ARRAY_SIZE(kNames) == ARRAY_SIZE(kRegisters)); | 145 ASSERT(ARRAY_SIZE(kNames) == ARRAY_SIZE(kRegisters)); |
| 150 for (unsigned i = 0; i < ARRAY_SIZE(kNames); i++) { | 146 for (unsigned i = 0; i < ARRAY_SIZE(kNames); i++) { |
| 151 if (strcmp(kNames[i], name) == 0) { | 147 if (strcmp(kNames[i], name) == 0) { |
| 152 return kRegisters[i]; | 148 return kRegisters[i]; |
| 153 } | 149 } |
| 154 } | 150 } |
| 155 return kNoRegister; | 151 return kNoRegister; |
| 156 } | 152 } |
| 157 | 153 |
| 158 | 154 |
| (...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 238 } | 234 } |
| 239 *value = *(reinterpret_cast<double*>(addr)); | 235 *value = *(reinterpret_cast<double*>(addr)); |
| 240 return true; | 236 return true; |
| 241 } | 237 } |
| 242 } | 238 } |
| 243 return false; | 239 return false; |
| 244 } | 240 } |
| 245 | 241 |
| 246 | 242 |
| 247 TokenPosition SimulatorDebugger::GetApproximateTokenIndex(const Code& code, | 243 TokenPosition SimulatorDebugger::GetApproximateTokenIndex(const Code& code, |
| 248 uword pc) { | 244 uword pc) { |
| 249 TokenPosition token_pos = TokenPosition::kNoSource; | 245 TokenPosition token_pos = TokenPosition::kNoSource; |
| 250 uword pc_offset = pc - code.PayloadStart(); | 246 uword pc_offset = pc - code.PayloadStart(); |
| 251 const PcDescriptors& descriptors = | 247 const PcDescriptors& descriptors = |
| 252 PcDescriptors::Handle(code.pc_descriptors()); | 248 PcDescriptors::Handle(code.pc_descriptors()); |
| 253 PcDescriptors::Iterator iter(descriptors, RawPcDescriptors::kAnyKind); | 249 PcDescriptors::Iterator iter(descriptors, RawPcDescriptors::kAnyKind); |
| 254 while (iter.MoveNext()) { | 250 while (iter.MoveNext()) { |
| 255 if (iter.PcOffset() == pc_offset) { | 251 if (iter.PcOffset() == pc_offset) { |
| 256 return iter.TokenPos(); | 252 return iter.TokenPos(); |
| 257 } else if (!token_pos.IsReal() && (iter.PcOffset() > pc_offset)) { | 253 } else if (!token_pos.IsReal() && (iter.PcOffset() > pc_offset)) { |
| 258 token_pos = iter.TokenPos(); | 254 token_pos = iter.TokenPos(); |
| 259 } | 255 } |
| 260 } | 256 } |
| 261 return token_pos; | 257 return token_pos; |
| 262 } | 258 } |
| 263 | 259 |
| 264 | 260 |
| 265 void SimulatorDebugger::PrintDartFrame(uword pc, uword fp, uword sp, | 261 void SimulatorDebugger::PrintDartFrame(uword pc, |
| 262 uword fp, |
| 263 uword sp, |
| 266 const Function& function, | 264 const Function& function, |
| 267 TokenPosition token_pos, | 265 TokenPosition token_pos, |
| 268 bool is_optimized, | 266 bool is_optimized, |
| 269 bool is_inlined) { | 267 bool is_inlined) { |
| 270 const Script& script = Script::Handle(function.script()); | 268 const Script& script = Script::Handle(function.script()); |
| 271 const String& func_name = String::Handle(function.QualifiedScrubbedName()); | 269 const String& func_name = String::Handle(function.QualifiedScrubbedName()); |
| 272 const String& url = String::Handle(script.url()); | 270 const String& url = String::Handle(script.url()); |
| 273 intptr_t line = -1; | 271 intptr_t line = -1; |
| 274 intptr_t column = -1; | 272 intptr_t column = -1; |
| 275 if (token_pos.IsReal()) { | 273 if (token_pos.IsReal()) { |
| 276 script.GetTokenLocation(token_pos, &line, &column); | 274 script.GetTokenLocation(token_pos, &line, &column); |
| 277 } | 275 } |
| 278 OS::Print("pc=0x%" Px " fp=0x%" Px " sp=0x%" Px " %s%s (%s:%" Pd | 276 OS::Print( |
| 279 ":%" Pd ")\n", | 277 "pc=0x%" Px " fp=0x%" Px " sp=0x%" Px " %s%s (%s:%" Pd ":%" Pd ")\n", pc, |
| 280 pc, fp, sp, | 278 fp, sp, is_optimized ? (is_inlined ? "inlined " : "optimized ") : "", |
| 281 is_optimized ? (is_inlined ? "inlined " : "optimized ") : "", | 279 func_name.ToCString(), url.ToCString(), line, column); |
| 282 func_name.ToCString(), | |
| 283 url.ToCString(), | |
| 284 line, column); | |
| 285 } | 280 } |
| 286 | 281 |
| 287 | 282 |
| 288 void SimulatorDebugger::PrintBacktrace() { | 283 void SimulatorDebugger::PrintBacktrace() { |
| 289 StackFrameIterator frames(sim_->get_register(FP), | 284 StackFrameIterator frames(sim_->get_register(FP), sim_->get_register(SP), |
| 290 sim_->get_register(SP), | |
| 291 sim_->get_pc(), | 285 sim_->get_pc(), |
| 292 StackFrameIterator::kDontValidateFrames); | 286 StackFrameIterator::kDontValidateFrames); |
| 293 StackFrame* frame = frames.NextFrame(); | 287 StackFrame* frame = frames.NextFrame(); |
| 294 ASSERT(frame != NULL); | 288 ASSERT(frame != NULL); |
| 295 Function& function = Function::Handle(); | 289 Function& function = Function::Handle(); |
| 296 Function& inlined_function = Function::Handle(); | 290 Function& inlined_function = Function::Handle(); |
| 297 Code& code = Code::Handle(); | 291 Code& code = Code::Handle(); |
| 298 Code& unoptimized_code = Code::Handle(); | 292 Code& unoptimized_code = Code::Handle(); |
| 299 while (frame != NULL) { | 293 while (frame != NULL) { |
| 300 if (frame->IsDartFrame()) { | 294 if (frame->IsDartFrame()) { |
| 301 code = frame->LookupDartCode(); | 295 code = frame->LookupDartCode(); |
| 302 function = code.function(); | 296 function = code.function(); |
| 303 if (code.is_optimized()) { | 297 if (code.is_optimized()) { |
| 304 // For optimized frames, extract all the inlined functions if any | 298 // For optimized frames, extract all the inlined functions if any |
| 305 // into the stack trace. | 299 // into the stack trace. |
| 306 InlinedFunctionsIterator it(code, frame->pc()); | 300 InlinedFunctionsIterator it(code, frame->pc()); |
| 307 while (!it.Done()) { | 301 while (!it.Done()) { |
| 308 // Print each inlined frame with its pc in the corresponding | 302 // Print each inlined frame with its pc in the corresponding |
| 309 // unoptimized frame. | 303 // unoptimized frame. |
| 310 inlined_function = it.function(); | 304 inlined_function = it.function(); |
| 311 unoptimized_code = it.code(); | 305 unoptimized_code = it.code(); |
| 312 uword unoptimized_pc = it.pc(); | 306 uword unoptimized_pc = it.pc(); |
| 313 it.Advance(); | 307 it.Advance(); |
| 314 if (!it.Done()) { | 308 if (!it.Done()) { |
| 315 PrintDartFrame(unoptimized_pc, frame->fp(), frame->sp(), | 309 PrintDartFrame( |
| 316 inlined_function, | 310 unoptimized_pc, frame->fp(), frame->sp(), inlined_function, |
| 317 GetApproximateTokenIndex(unoptimized_code, | 311 GetApproximateTokenIndex(unoptimized_code, unoptimized_pc), |
| 318 unoptimized_pc), | 312 true, true); |
| 319 true, true); | |
| 320 } | 313 } |
| 321 } | 314 } |
| 322 // Print the optimized inlining frame below. | 315 // Print the optimized inlining frame below. |
| 323 } | 316 } |
| 324 PrintDartFrame(frame->pc(), frame->fp(), frame->sp(), | 317 PrintDartFrame(frame->pc(), frame->fp(), frame->sp(), function, |
| 325 function, | |
| 326 GetApproximateTokenIndex(code, frame->pc()), | 318 GetApproximateTokenIndex(code, frame->pc()), |
| 327 code.is_optimized(), false); | 319 code.is_optimized(), false); |
| 328 } else { | 320 } else { |
| 329 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", |
| 330 frame->pc(), frame->fp(), frame->sp(), | 322 frame->pc(), frame->fp(), frame->sp(), |
| 331 frame->IsEntryFrame() ? "entry" : | 323 frame->IsEntryFrame() |
| 332 frame->IsExitFrame() ? "exit" : | 324 ? "entry" |
| 333 frame->IsStubFrame() ? "stub" : "invalid"); | 325 : frame->IsExitFrame() |
| 326 ? "exit" |
| 327 : frame->IsStubFrame() ? "stub" : "invalid"); |
| 334 } | 328 } |
| 335 frame = frames.NextFrame(); | 329 frame = frames.NextFrame(); |
| 336 } | 330 } |
| 337 } | 331 } |
| 338 | 332 |
| 339 | 333 |
| 340 bool SimulatorDebugger::SetBreakpoint(Instr* breakpc) { | 334 bool SimulatorDebugger::SetBreakpoint(Instr* breakpc) { |
| 341 // 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. |
| 342 if (sim_->break_pc_ != NULL) { | 336 if (sim_->break_pc_ != NULL) { |
| 343 return false; | 337 return false; |
| (...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 418 FATAL("ReadLine failed"); | 412 FATAL("ReadLine failed"); |
| 419 } else { | 413 } else { |
| 420 // 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 |
| 421 // moment no command expects more than two parameters. | 415 // moment no command expects more than two parameters. |
| 422 int args = SScanF(line, | 416 int args = SScanF(line, |
| 423 "%" XSTR(COMMAND_SIZE) "s " | 417 "%" XSTR(COMMAND_SIZE) "s " |
| 424 "%" XSTR(ARG_SIZE) "s " | 418 "%" XSTR(ARG_SIZE) "s " |
| 425 "%" XSTR(ARG_SIZE) "s", | 419 "%" XSTR(ARG_SIZE) "s", |
| 426 cmd, arg1, arg2); | 420 cmd, arg1, arg2); |
| 427 if ((strcmp(cmd, "h") == 0) || (strcmp(cmd, "help") == 0)) { | 421 if ((strcmp(cmd, "h") == 0) || (strcmp(cmd, "help") == 0)) { |
| 428 OS::Print("c/cont -- continue execution\n" | 422 OS::Print( |
| 429 "disasm -- disassemble instrs at current pc location\n" | 423 "c/cont -- continue execution\n" |
| 430 " other variants are:\n" | 424 "disasm -- disassemble instrs at current pc location\n" |
| 431 " disasm <address>\n" | 425 " other variants are:\n" |
| 432 " disasm <address> <number_of_instructions>\n" | 426 " disasm <address>\n" |
| 433 " by default 10 instrs are disassembled\n" | 427 " disasm <address> <number_of_instructions>\n" |
| 434 "del -- delete breakpoints\n" | 428 " by default 10 instrs are disassembled\n" |
| 435 "flags -- print flag values\n" | 429 "del -- delete breakpoints\n" |
| 436 "gdb -- transfer control to gdb\n" | 430 "flags -- print flag values\n" |
| 437 "h/help -- print this help string\n" | 431 "gdb -- transfer control to gdb\n" |
| 438 "break <address> -- set break point at specified address\n" | 432 "h/help -- print this help string\n" |
| 439 "p/print <reg or icount or value or *addr> -- print integer\n" | 433 "break <address> -- set break point at specified address\n" |
| 440 "ps/printsingle <sreg or *addr> -- print float value\n" | 434 "p/print <reg or icount or value or *addr> -- print integer\n" |
| 441 "pd/printdouble <dreg or *addr> -- print double value\n" | 435 "ps/printsingle <sreg or *addr> -- print float value\n" |
| 442 "po/printobject <*reg or *addr> -- print object\n" | 436 "pd/printdouble <dreg or *addr> -- print double value\n" |
| 443 "si/stepi -- single step an instruction\n" | 437 "po/printobject <*reg or *addr> -- print object\n" |
| 444 "trace -- toggle execution tracing mode\n" | 438 "si/stepi -- single step an instruction\n" |
| 445 "bt -- print backtrace\n" | 439 "trace -- toggle execution tracing mode\n" |
| 446 "unstop -- if current pc is a stop instr make it a nop\n" | 440 "bt -- print backtrace\n" |
| 447 "q/quit -- Quit the debugger and exit the program\n"); | 441 "unstop -- if current pc is a stop instr make it a nop\n" |
| 442 "q/quit -- Quit the debugger and exit the program\n"); |
| 448 } else if ((strcmp(cmd, "quit") == 0) || (strcmp(cmd, "q") == 0)) { | 443 } else if ((strcmp(cmd, "quit") == 0) || (strcmp(cmd, "q") == 0)) { |
| 449 OS::Print("Quitting\n"); | 444 OS::Print("Quitting\n"); |
| 450 OS::Exit(0); | 445 OS::Exit(0); |
| 451 } else if ((strcmp(cmd, "si") == 0) || (strcmp(cmd, "stepi") == 0)) { | 446 } else if ((strcmp(cmd, "si") == 0) || (strcmp(cmd, "stepi") == 0)) { |
| 452 sim_->InstructionDecode(reinterpret_cast<Instr*>(sim_->get_pc())); | 447 sim_->InstructionDecode(reinterpret_cast<Instr*>(sim_->get_pc())); |
| 453 } else if ((strcmp(cmd, "c") == 0) || (strcmp(cmd, "cont") == 0)) { | 448 } else if ((strcmp(cmd, "c") == 0) || (strcmp(cmd, "cont") == 0)) { |
| 454 // Execute the one instruction we broke at with breakpoints disabled. | 449 // Execute the one instruction we broke at with breakpoints disabled. |
| 455 sim_->InstructionDecode(reinterpret_cast<Instr*>(sim_->get_pc())); | 450 sim_->InstructionDecode(reinterpret_cast<Instr*>(sim_->get_pc())); |
| 456 // Leave the debugger shell. | 451 // Leave the debugger shell. |
| 457 done = true; | 452 done = true; |
| (...skipping 23 matching lines...) Expand all Loading... |
| 481 } | 476 } |
| 482 } else { | 477 } else { |
| 483 OS::Print("printfloat <sreg or *addr>\n"); | 478 OS::Print("printfloat <sreg or *addr>\n"); |
| 484 } | 479 } |
| 485 } else if ((strcmp(cmd, "pd") == 0) || | 480 } else if ((strcmp(cmd, "pd") == 0) || |
| 486 (strcmp(cmd, "printdouble") == 0)) { | 481 (strcmp(cmd, "printdouble") == 0)) { |
| 487 if (args == 2) { | 482 if (args == 2) { |
| 488 double dvalue; | 483 double dvalue; |
| 489 if (GetDValue(arg1, &dvalue)) { | 484 if (GetDValue(arg1, &dvalue)) { |
| 490 uint64_t long_value = bit_cast<uint64_t, double>(dvalue); | 485 uint64_t long_value = bit_cast<uint64_t, double>(dvalue); |
| 491 OS::Print("%s: %llu 0x%llx %.8g\n", | 486 OS::Print("%s: %llu 0x%llx %.8g\n", arg1, long_value, long_value, |
| 492 arg1, long_value, long_value, dvalue); | 487 dvalue); |
| 493 } else { | 488 } else { |
| 494 OS::Print("%s unrecognized\n", arg1); | 489 OS::Print("%s unrecognized\n", arg1); |
| 495 } | 490 } |
| 496 } else { | 491 } else { |
| 497 OS::Print("printdouble <dreg or *addr>\n"); | 492 OS::Print("printdouble <dreg or *addr>\n"); |
| 498 } | 493 } |
| 499 } else if ((strcmp(cmd, "po") == 0) || | 494 } else if ((strcmp(cmd, "po") == 0) || |
| 500 (strcmp(cmd, "printobject") == 0)) { | 495 (strcmp(cmd, "printobject") == 0)) { |
| 501 if (args == 2) { | 496 if (args == 2) { |
| 502 uint32_t value; | 497 uint32_t value; |
| 503 // Make the dereferencing '*' optional. | 498 // Make the dereferencing '*' optional. |
| 504 if (((arg1[0] == '*') && GetValue(arg1 + 1, &value)) || | 499 if (((arg1[0] == '*') && GetValue(arg1 + 1, &value)) || |
| 505 GetValue(arg1, &value)) { | 500 GetValue(arg1, &value)) { |
| 506 if (Isolate::Current()->heap()->Contains(value)) { | 501 if (Isolate::Current()->heap()->Contains(value)) { |
| 507 OS::Print("%s: \n", arg1); | 502 OS::Print("%s: \n", arg1); |
| 508 #if defined(DEBUG) | 503 #if defined(DEBUG) |
| 509 const Object& obj = Object::Handle( | 504 const Object& obj = |
| 510 reinterpret_cast<RawObject*>(value)); | 505 Object::Handle(reinterpret_cast<RawObject*>(value)); |
| 511 obj.Print(); | 506 obj.Print(); |
| 512 #endif // defined(DEBUG) | 507 #endif // defined(DEBUG) |
| 513 } else { | 508 } else { |
| 514 OS::Print("0x%x is not an object reference\n", value); | 509 OS::Print("0x%x is not an object reference\n", value); |
| 515 } | 510 } |
| 516 } else { | 511 } else { |
| 517 OS::Print("%s unrecognized\n", arg1); | 512 OS::Print("%s unrecognized\n", arg1); |
| 518 } | 513 } |
| 519 } else { | 514 } else { |
| 520 OS::Print("printobject <*reg or *addr>\n"); | 515 OS::Print("printobject <*reg or *addr>\n"); |
| (...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 634 OS::Print("%s", prompt); | 629 OS::Print("%s", prompt); |
| 635 while (keep_going) { | 630 while (keep_going) { |
| 636 if (fgets(line_buf, sizeof(line_buf), stdin) == NULL) { | 631 if (fgets(line_buf, sizeof(line_buf), stdin) == NULL) { |
| 637 // fgets got an error. Just give up. | 632 // fgets got an error. Just give up. |
| 638 if (result != NULL) { | 633 if (result != NULL) { |
| 639 delete[] result; | 634 delete[] result; |
| 640 } | 635 } |
| 641 return NULL; | 636 return NULL; |
| 642 } | 637 } |
| 643 intptr_t len = strlen(line_buf); | 638 intptr_t len = strlen(line_buf); |
| 644 if (len > 1 && | 639 if (len > 1 && line_buf[len - 2] == '\\' && line_buf[len - 1] == '\n') { |
| 645 line_buf[len - 2] == '\\' && | |
| 646 line_buf[len - 1] == '\n') { | |
| 647 // When we read a line that ends with a "\" we remove the escape and | 640 // When we read a line that ends with a "\" we remove the escape and |
| 648 // append the remainder. | 641 // append the remainder. |
| 649 line_buf[len - 2] = '\n'; | 642 line_buf[len - 2] = '\n'; |
| 650 line_buf[len - 1] = 0; | 643 line_buf[len - 1] = 0; |
| 651 len -= 1; | 644 len -= 1; |
| 652 } else if ((len > 0) && (line_buf[len - 1] == '\n')) { | 645 } else if ((len > 0) && (line_buf[len - 1] == '\n')) { |
| 653 // Since we read a new line we are done reading the line. This | 646 // Since we read a new line we are done reading the line. This |
| 654 // will exit the loop after copying this buffer into the result. | 647 // will exit the loop after copying this buffer into the result. |
| 655 keep_going = false; | 648 keep_going = false; |
| 656 } | 649 } |
| (...skipping 25 matching lines...) Expand all Loading... |
| 682 offset += len; | 675 offset += len; |
| 683 } | 676 } |
| 684 ASSERT(result != NULL); | 677 ASSERT(result != NULL); |
| 685 result[offset] = '\0'; | 678 result[offset] = '\0'; |
| 686 return result; | 679 return result; |
| 687 } | 680 } |
| 688 | 681 |
| 689 | 682 |
| 690 // Synchronization primitives support. | 683 // Synchronization primitives support. |
| 691 Mutex* Simulator::exclusive_access_lock_ = NULL; | 684 Mutex* Simulator::exclusive_access_lock_ = NULL; |
| 692 Simulator::AddressTag Simulator::exclusive_access_state_[kNumAddressTags] = | 685 Simulator::AddressTag Simulator::exclusive_access_state_[kNumAddressTags] = { |
| 693 {{NULL, 0}}; | 686 {NULL, 0}}; |
| 694 int Simulator::next_address_tag_ = 0; | 687 int Simulator::next_address_tag_ = 0; |
| 695 | 688 |
| 696 | 689 |
| 697 void Simulator::InitOnce() { | 690 void Simulator::InitOnce() { |
| 698 // Setup exclusive access state lock. | 691 // Setup exclusive access state lock. |
| 699 exclusive_access_lock_ = new Mutex(); | 692 exclusive_access_lock_ = new Mutex(); |
| 700 } | 693 } |
| 701 | 694 |
| 702 | 695 |
| 703 Simulator::Simulator() { | 696 Simulator::Simulator() { |
| 704 // Setup simulator support first. Some of this information is needed to | 697 // Setup simulator support first. Some of this information is needed to |
| 705 // setup the architecture state. | 698 // setup the architecture state. |
| 706 // We allocate the stack here, the size is computed as the sum of | 699 // We allocate the stack here, the size is computed as the sum of |
| 707 // the size specified by the user and the buffer space needed for | 700 // the size specified by the user and the buffer space needed for |
| 708 // handling stack overflow exceptions. To be safe in potential | 701 // handling stack overflow exceptions. To be safe in potential |
| 709 // stack underflows we also add some underflow buffer space. | 702 // stack underflows we also add some underflow buffer space. |
| 710 stack_ = new char[(OSThread::GetSpecifiedStackSize() + | 703 stack_ = |
| 711 OSThread::kStackSizeBuffer + | 704 new char[(OSThread::GetSpecifiedStackSize() + OSThread::kStackSizeBuffer + |
| 712 kSimulatorStackUnderflowSize)]; | 705 kSimulatorStackUnderflowSize)]; |
| 713 pc_modified_ = false; | 706 pc_modified_ = false; |
| 714 icount_ = 0; | 707 icount_ = 0; |
| 715 break_pc_ = NULL; | 708 break_pc_ = NULL; |
| 716 break_instr_ = 0; | 709 break_instr_ = 0; |
| 717 last_setjmp_buffer_ = NULL; | 710 last_setjmp_buffer_ = NULL; |
| 718 top_exit_frame_info_ = 0; | 711 top_exit_frame_info_ = 0; |
| 719 | 712 |
| 720 // Setup architecture state. | 713 // Setup architecture state. |
| 721 // All registers are initialized to zero to start with. | 714 // All registers are initialized to zero to start with. |
| 722 for (int i = 0; i < kNumberOfCpuRegisters; i++) { | 715 for (int i = 0; i < kNumberOfCpuRegisters; i++) { |
| (...skipping 11 matching lines...) Expand all Loading... |
| 734 // access violation if the simulator ever tries to execute it. | 727 // access violation if the simulator ever tries to execute it. |
| 735 registers_[PC] = kBadLR; | 728 registers_[PC] = kBadLR; |
| 736 registers_[LR] = kBadLR; | 729 registers_[LR] = kBadLR; |
| 737 | 730 |
| 738 // All double-precision registers are initialized to zero. | 731 // All double-precision registers are initialized to zero. |
| 739 for (int i = 0; i < kNumberOfDRegisters; i++) { | 732 for (int i = 0; i < kNumberOfDRegisters; i++) { |
| 740 dregisters_[i] = 0; | 733 dregisters_[i] = 0; |
| 741 } | 734 } |
| 742 // Since VFP registers are overlapping, single-precision registers should | 735 // Since VFP registers are overlapping, single-precision registers should |
| 743 // already be initialized. | 736 // already be initialized. |
| 744 ASSERT(2*kNumberOfDRegisters >= kNumberOfSRegisters); | 737 ASSERT(2 * kNumberOfDRegisters >= kNumberOfSRegisters); |
| 745 for (int i = 0; i < kNumberOfSRegisters; i++) { | 738 for (int i = 0; i < kNumberOfSRegisters; i++) { |
| 746 ASSERT(sregisters_[i] == 0.0); | 739 ASSERT(sregisters_[i] == 0.0); |
| 747 } | 740 } |
| 748 fp_n_flag_ = false; | 741 fp_n_flag_ = false; |
| 749 fp_z_flag_ = false; | 742 fp_z_flag_ = false; |
| 750 fp_c_flag_ = false; | 743 fp_c_flag_ = false; |
| 751 fp_v_flag_ = false; | 744 fp_v_flag_ = false; |
| 752 } | 745 } |
| 753 | 746 |
| 754 | 747 |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 813 int argument_count) | 806 int argument_count) |
| 814 : external_function_(external_function), | 807 : external_function_(external_function), |
| 815 call_kind_(call_kind), | 808 call_kind_(call_kind), |
| 816 argument_count_(argument_count), | 809 argument_count_(argument_count), |
| 817 svc_instruction_(Instr::kSimulatorRedirectInstruction) { | 810 svc_instruction_(Instr::kSimulatorRedirectInstruction) { |
| 818 // Atomically prepend this element to the front of the global list. | 811 // Atomically prepend this element to the front of the global list. |
| 819 // Note: Since elements are never removed, there is no ABA issue. | 812 // Note: Since elements are never removed, there is no ABA issue. |
| 820 Redirection* list_head = list_; | 813 Redirection* list_head = list_; |
| 821 do { | 814 do { |
| 822 next_ = list_head; | 815 next_ = list_head; |
| 823 list_head = reinterpret_cast<Redirection*>( | 816 list_head = |
| 824 AtomicOperations::CompareAndSwapWord( | 817 reinterpret_cast<Redirection*>(AtomicOperations::CompareAndSwapWord( |
| 825 reinterpret_cast<uword*>(&list_), | 818 reinterpret_cast<uword*>(&list_), reinterpret_cast<uword>(next_), |
| 826 reinterpret_cast<uword>(next_), | |
| 827 reinterpret_cast<uword>(this))); | 819 reinterpret_cast<uword>(this))); |
| 828 } while (list_head != next_); | 820 } while (list_head != next_); |
| 829 } | 821 } |
| 830 | 822 |
| 831 uword external_function_; | 823 uword external_function_; |
| 832 Simulator::CallKind call_kind_; | 824 Simulator::CallKind call_kind_; |
| 833 int argument_count_; | 825 int argument_count_; |
| 834 uint32_t svc_instruction_; | 826 uint32_t svc_instruction_; |
| 835 Redirection* next_; | 827 Redirection* next_; |
| 836 static Redirection* list_; | 828 static Redirection* list_; |
| (...skipping 136 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 973 return dregisters_[reg]; | 965 return dregisters_[reg]; |
| 974 } | 966 } |
| 975 | 967 |
| 976 | 968 |
| 977 void Simulator::HandleIllegalAccess(uword addr, Instr* instr) { | 969 void Simulator::HandleIllegalAccess(uword addr, Instr* instr) { |
| 978 uword fault_pc = get_pc(); | 970 uword fault_pc = get_pc(); |
| 979 // The debugger will not be able to single step past this instruction, but | 971 // The debugger will not be able to single step past this instruction, but |
| 980 // it will be possible to disassemble the code and inspect registers. | 972 // it will be possible to disassemble the code and inspect registers. |
| 981 char buffer[128]; | 973 char buffer[128]; |
| 982 snprintf(buffer, sizeof(buffer), | 974 snprintf(buffer, sizeof(buffer), |
| 983 "illegal memory access at 0x%" Px ", pc=0x%" Px "\n", | 975 "illegal memory access at 0x%" Px ", pc=0x%" Px "\n", addr, |
| 984 addr, fault_pc); | 976 fault_pc); |
| 985 SimulatorDebugger dbg(this); | 977 SimulatorDebugger dbg(this); |
| 986 dbg.Stop(instr, buffer); | 978 dbg.Stop(instr, buffer); |
| 987 // The debugger will return control in non-interactive mode. | 979 // The debugger will return control in non-interactive mode. |
| 988 FATAL("Cannot continue execution after illegal memory access."); | 980 FATAL("Cannot continue execution after illegal memory access."); |
| 989 } | 981 } |
| 990 | 982 |
| 991 | 983 |
| 992 // Processor versions prior to ARMv7 could not do unaligned reads and writes. | 984 // Processor versions prior to ARMv7 could not do unaligned reads and writes. |
| 993 // On some ARM platforms an interrupt is caused. On others it does a funky | 985 // On some ARM platforms an interrupt is caused. On others it does a funky |
| 994 // rotation thing. However, from version v7, unaligned access is supported. | 986 // rotation thing. However, from version v7, unaligned access is supported. |
| 995 // Note that simulator runs have the runtime system running directly on the host | 987 // Note that simulator runs have the runtime system running directly on the host |
| 996 // system and only generated code is executed in the simulator. Since the host | 988 // system and only generated code is executed in the simulator. Since the host |
| 997 // is typically IA32 we will get the correct ARMv7-like behaviour on unaligned | 989 // is typically IA32 we will get the correct ARMv7-like behaviour on unaligned |
| 998 // accesses, but we should actually not generate code accessing unaligned data, | 990 // accesses, but we should actually not generate code accessing unaligned data, |
| 999 // so we still want to know and abort if we encounter such code. | 991 // so we still want to know and abort if we encounter such code. |
| 1000 void Simulator::UnalignedAccess(const char* msg, uword addr, Instr* instr) { | 992 void Simulator::UnalignedAccess(const char* msg, uword addr, Instr* instr) { |
| 1001 // The debugger will not be able to single step past this instruction, but | 993 // The debugger will not be able to single step past this instruction, but |
| 1002 // it will be possible to disassemble the code and inspect registers. | 994 // it will be possible to disassemble the code and inspect registers. |
| 1003 char buffer[64]; | 995 char buffer[64]; |
| 1004 snprintf(buffer, sizeof(buffer), | 996 snprintf(buffer, sizeof(buffer), "unaligned %s at 0x%" Px ", pc=%p\n", msg, |
| 1005 "unaligned %s at 0x%" Px ", pc=%p\n", msg, addr, instr); | 997 addr, instr); |
| 1006 SimulatorDebugger dbg(this); | 998 SimulatorDebugger dbg(this); |
| 1007 dbg.Stop(instr, buffer); | 999 dbg.Stop(instr, buffer); |
| 1008 // The debugger will return control in non-interactive mode. | 1000 // The debugger will return control in non-interactive mode. |
| 1009 FATAL("Cannot continue execution after unaligned access."); | 1001 FATAL("Cannot continue execution after unaligned access."); |
| 1010 } | 1002 } |
| 1011 | 1003 |
| 1012 | 1004 |
| 1013 void Simulator::UnimplementedInstruction(Instr* instr) { | 1005 void Simulator::UnimplementedInstruction(Instr* instr) { |
| 1014 char buffer[64]; | 1006 char buffer[64]; |
| 1015 snprintf(buffer, sizeof(buffer), "Unimplemented instruction: pc=%p\n", instr); | 1007 snprintf(buffer, sizeof(buffer), "Unimplemented instruction: pc=%p\n", instr); |
| (...skipping 171 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1187 static_cast<uword>(new_value)); | 1179 static_cast<uword>(new_value)); |
| 1188 } | 1180 } |
| 1189 | 1181 |
| 1190 | 1182 |
| 1191 // Returns the top of the stack area to enable checking for stack pointer | 1183 // Returns the top of the stack area to enable checking for stack pointer |
| 1192 // validity. | 1184 // validity. |
| 1193 uword Simulator::StackTop() const { | 1185 uword Simulator::StackTop() const { |
| 1194 // To be safe in potential stack underflows we leave some buffer above and | 1186 // To be safe in potential stack underflows we leave some buffer above and |
| 1195 // set the stack top. | 1187 // set the stack top. |
| 1196 return StackBase() + | 1188 return StackBase() + |
| 1197 (OSThread::GetSpecifiedStackSize() + OSThread::kStackSizeBuffer); | 1189 (OSThread::GetSpecifiedStackSize() + OSThread::kStackSizeBuffer); |
| 1198 } | 1190 } |
| 1199 | 1191 |
| 1200 | 1192 |
| 1201 bool Simulator::IsTracingExecution() const { | 1193 bool Simulator::IsTracingExecution() const { |
| 1202 return icount_ > FLAG_trace_sim_after; | 1194 return icount_ > FLAG_trace_sim_after; |
| 1203 } | 1195 } |
| 1204 | 1196 |
| 1205 | 1197 |
| 1206 // Unsupported instructions use Format to print an error and stop execution. | 1198 // Unsupported instructions use Format to print an error and stop execution. |
| 1207 void Simulator::Format(Instr* instr, const char* format) { | 1199 void Simulator::Format(Instr* instr, const char* format) { |
| 1208 OS::Print("Simulator found unsupported instruction:\n 0x%p: %s\n", | 1200 OS::Print("Simulator found unsupported instruction:\n 0x%p: %s\n", instr, |
| 1209 instr, | |
| 1210 format); | 1201 format); |
| 1211 UNIMPLEMENTED(); | 1202 UNIMPLEMENTED(); |
| 1212 } | 1203 } |
| 1213 | 1204 |
| 1214 | 1205 |
| 1215 // Checks if the current instruction should be executed based on its | 1206 // Checks if the current instruction should be executed based on its |
| 1216 // condition bits. | 1207 // condition bits. |
| 1217 bool Simulator::ConditionallyExecute(Instr* instr) { | 1208 bool Simulator::ConditionallyExecute(Instr* instr) { |
| 1218 switch (instr->ConditionField()) { | 1209 switch (instr->ConditionField()) { |
| 1219 case EQ: return z_flag_; | 1210 case EQ: |
| 1220 case NE: return !z_flag_; | 1211 return z_flag_; |
| 1221 case CS: return c_flag_; | 1212 case NE: |
| 1222 case CC: return !c_flag_; | 1213 return !z_flag_; |
| 1223 case MI: return n_flag_; | 1214 case CS: |
| 1224 case PL: return !n_flag_; | 1215 return c_flag_; |
| 1225 case VS: return v_flag_; | 1216 case CC: |
| 1226 case VC: return !v_flag_; | 1217 return !c_flag_; |
| 1227 case HI: return c_flag_ && !z_flag_; | 1218 case MI: |
| 1228 case LS: return !c_flag_ || z_flag_; | 1219 return n_flag_; |
| 1229 case GE: return n_flag_ == v_flag_; | 1220 case PL: |
| 1230 case LT: return n_flag_ != v_flag_; | 1221 return !n_flag_; |
| 1231 case GT: return !z_flag_ && (n_flag_ == v_flag_); | 1222 case VS: |
| 1232 case LE: return z_flag_ || (n_flag_ != v_flag_); | 1223 return v_flag_; |
| 1233 case AL: return true; | 1224 case VC: |
| 1234 default: UNREACHABLE(); | 1225 return !v_flag_; |
| 1226 case HI: |
| 1227 return c_flag_ && !z_flag_; |
| 1228 case LS: |
| 1229 return !c_flag_ || z_flag_; |
| 1230 case GE: |
| 1231 return n_flag_ == v_flag_; |
| 1232 case LT: |
| 1233 return n_flag_ != v_flag_; |
| 1234 case GT: |
| 1235 return !z_flag_ && (n_flag_ == v_flag_); |
| 1236 case LE: |
| 1237 return z_flag_ || (n_flag_ != v_flag_); |
| 1238 case AL: |
| 1239 return true; |
| 1240 default: |
| 1241 UNREACHABLE(); |
| 1235 } | 1242 } |
| 1236 return false; | 1243 return false; |
| 1237 } | 1244 } |
| 1238 | 1245 |
| 1239 | 1246 |
| 1240 // Calculate and set the Negative and Zero flags. | 1247 // Calculate and set the Negative and Zero flags. |
| 1241 void Simulator::SetNZFlags(int32_t val) { | 1248 void Simulator::SetNZFlags(int32_t val) { |
| 1242 n_flag_ = (val < 0); | 1249 n_flag_ = (val < 0); |
| 1243 z_flag_ = (val == 0); | 1250 z_flag_ = (val == 0); |
| 1244 } | 1251 } |
| (...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1334 } | 1341 } |
| 1335 | 1342 |
| 1336 default: { | 1343 default: { |
| 1337 UNREACHABLE(); | 1344 UNREACHABLE(); |
| 1338 break; | 1345 break; |
| 1339 } | 1346 } |
| 1340 } | 1347 } |
| 1341 } else { | 1348 } else { |
| 1342 // by register | 1349 // by register |
| 1343 Register rs = instr->RsField(); | 1350 Register rs = instr->RsField(); |
| 1344 shift_amount = get_register(rs) &0xff; | 1351 shift_amount = get_register(rs) & 0xff; |
| 1345 switch (shift) { | 1352 switch (shift) { |
| 1346 case ASR: { | 1353 case ASR: { |
| 1347 if (shift_amount == 0) { | 1354 if (shift_amount == 0) { |
| 1348 *carry_out = c_flag_; | 1355 *carry_out = c_flag_; |
| 1349 } else if (shift_amount < 32) { | 1356 } else if (shift_amount < 32) { |
| 1350 result >>= (shift_amount - 1); | 1357 result >>= (shift_amount - 1); |
| 1351 *carry_out = (result & 1) == 1; | 1358 *carry_out = (result & 1) == 1; |
| 1352 result >>= 1; | 1359 result >>= 1; |
| 1353 } else { | 1360 } else { |
| 1354 ASSERT(shift_amount >= 32); | 1361 ASSERT(shift_amount >= 32); |
| (...skipping 147 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1502 } | 1509 } |
| 1503 ASSERT(end_address == address); | 1510 ASSERT(end_address == address); |
| 1504 } | 1511 } |
| 1505 } | 1512 } |
| 1506 | 1513 |
| 1507 | 1514 |
| 1508 // Calls into the Dart runtime are based on this interface. | 1515 // Calls into the Dart runtime are based on this interface. |
| 1509 typedef void (*SimulatorRuntimeCall)(NativeArguments arguments); | 1516 typedef void (*SimulatorRuntimeCall)(NativeArguments arguments); |
| 1510 | 1517 |
| 1511 // Calls to leaf Dart runtime functions are based on this interface. | 1518 // Calls to leaf Dart runtime functions are based on this interface. |
| 1512 typedef int32_t (*SimulatorLeafRuntimeCall)( | 1519 typedef int32_t (*SimulatorLeafRuntimeCall)(int32_t r0, |
| 1513 int32_t r0, int32_t r1, int32_t r2, int32_t r3); | 1520 int32_t r1, |
| 1521 int32_t r2, |
| 1522 int32_t r3); |
| 1514 | 1523 |
| 1515 // Calls to leaf float Dart runtime functions are based on this interface. | 1524 // Calls to leaf float Dart runtime functions are based on this interface. |
| 1516 typedef double (*SimulatorLeafFloatRuntimeCall)(double d0, double d1); | 1525 typedef double (*SimulatorLeafFloatRuntimeCall)(double d0, double d1); |
| 1517 | 1526 |
| 1518 // Calls to native Dart functions are based on this interface. | 1527 // Calls to native Dart functions are based on this interface. |
| 1519 typedef void (*SimulatorBootstrapNativeCall)(NativeArguments* arguments); | 1528 typedef void (*SimulatorBootstrapNativeCall)(NativeArguments* arguments); |
| 1520 typedef void (*SimulatorNativeCall)(NativeArguments* arguments, uword target); | 1529 typedef void (*SimulatorNativeCall)(NativeArguments* arguments, uword target); |
| 1521 | 1530 |
| 1522 | 1531 |
| 1523 void Simulator::SupervisorCall(Instr* instr) { | 1532 void Simulator::SupervisorCall(Instr* instr) { |
| (...skipping 11 matching lines...) Expand all Loading... |
| 1535 } | 1544 } |
| 1536 | 1545 |
| 1537 if ((redirection->call_kind() == kRuntimeCall) || | 1546 if ((redirection->call_kind() == kRuntimeCall) || |
| 1538 (redirection->call_kind() == kBootstrapNativeCall) || | 1547 (redirection->call_kind() == kBootstrapNativeCall) || |
| 1539 (redirection->call_kind() == kNativeCall)) { | 1548 (redirection->call_kind() == kNativeCall)) { |
| 1540 // Set the top_exit_frame_info of this simulator to the native stack. | 1549 // Set the top_exit_frame_info of this simulator to the native stack. |
| 1541 set_top_exit_frame_info(Thread::GetCurrentStackPointer()); | 1550 set_top_exit_frame_info(Thread::GetCurrentStackPointer()); |
| 1542 } | 1551 } |
| 1543 if (redirection->call_kind() == kRuntimeCall) { | 1552 if (redirection->call_kind() == kRuntimeCall) { |
| 1544 NativeArguments arguments; | 1553 NativeArguments arguments; |
| 1545 ASSERT(sizeof(NativeArguments) == 4*kWordSize); | 1554 ASSERT(sizeof(NativeArguments) == 4 * kWordSize); |
| 1546 arguments.thread_ = reinterpret_cast<Thread*>(get_register(R0)); | 1555 arguments.thread_ = reinterpret_cast<Thread*>(get_register(R0)); |
| 1547 arguments.argc_tag_ = get_register(R1); | 1556 arguments.argc_tag_ = get_register(R1); |
| 1548 arguments.argv_ = reinterpret_cast<RawObject**>(get_register(R2)); | 1557 arguments.argv_ = reinterpret_cast<RawObject**>(get_register(R2)); |
| 1549 arguments.retval_ = reinterpret_cast<RawObject**>(get_register(R3)); | 1558 arguments.retval_ = reinterpret_cast<RawObject**>(get_register(R3)); |
| 1550 SimulatorRuntimeCall target = | 1559 SimulatorRuntimeCall target = |
| 1551 reinterpret_cast<SimulatorRuntimeCall>(external); | 1560 reinterpret_cast<SimulatorRuntimeCall>(external); |
| 1552 target(arguments); | 1561 target(arguments); |
| 1553 set_register(R0, icount_); // Zap result register from void function. | 1562 set_register(R0, icount_); // Zap result register from void function. |
| 1554 set_register(R1, icount_); | 1563 set_register(R1, icount_); |
| 1555 } else if (redirection->call_kind() == kLeafRuntimeCall) { | 1564 } else if (redirection->call_kind() == kLeafRuntimeCall) { |
| 1556 ASSERT((0 <= redirection->argument_count()) && | 1565 ASSERT((0 <= redirection->argument_count()) && |
| 1557 (redirection->argument_count() <= 4)); | 1566 (redirection->argument_count() <= 4)); |
| 1558 int32_t r0 = get_register(R0); | 1567 int32_t r0 = get_register(R0); |
| 1559 int32_t r1 = get_register(R1); | 1568 int32_t r1 = get_register(R1); |
| 1560 int32_t r2 = get_register(R2); | 1569 int32_t r2 = get_register(R2); |
| 1561 int32_t r3 = get_register(R3); | 1570 int32_t r3 = get_register(R3); |
| 1562 SimulatorLeafRuntimeCall target = | 1571 SimulatorLeafRuntimeCall target = |
| 1563 reinterpret_cast<SimulatorLeafRuntimeCall>(external); | 1572 reinterpret_cast<SimulatorLeafRuntimeCall>(external); |
| 1564 r0 = target(r0, r1, r2, r3); | 1573 r0 = target(r0, r1, r2, r3); |
| 1565 set_register(R0, r0); // Set returned result from function. | 1574 set_register(R0, r0); // Set returned result from function. |
| 1566 set_register(R1, icount_); // Zap unused result register. | 1575 set_register(R1, icount_); // Zap unused result register. |
| 1567 } else if (redirection->call_kind() == kLeafFloatRuntimeCall) { | 1576 } else if (redirection->call_kind() == kLeafFloatRuntimeCall) { |
| 1568 ASSERT((0 <= redirection->argument_count()) && | 1577 ASSERT((0 <= redirection->argument_count()) && |
| 1569 (redirection->argument_count() <= 2)); | 1578 (redirection->argument_count() <= 2)); |
| 1570 SimulatorLeafFloatRuntimeCall target = | 1579 SimulatorLeafFloatRuntimeCall target = |
| 1571 reinterpret_cast<SimulatorLeafFloatRuntimeCall>(external); | 1580 reinterpret_cast<SimulatorLeafFloatRuntimeCall>(external); |
| 1572 if (TargetCPUFeatures::hardfp_supported()) { | 1581 if (TargetCPUFeatures::hardfp_supported()) { |
| 1573 // If we're doing "hardfp", the double arguments are already in the | 1582 // If we're doing "hardfp", the double arguments are already in the |
| 1574 // floating point registers. | 1583 // floating point registers. |
| 1575 double d0 = get_dregister(D0); | 1584 double d0 = get_dregister(D0); |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1620 set_register(R2, icount_); | 1629 set_register(R2, icount_); |
| 1621 set_register(R3, icount_); | 1630 set_register(R3, icount_); |
| 1622 set_register(IP, icount_); | 1631 set_register(IP, icount_); |
| 1623 set_register(LR, icount_); | 1632 set_register(LR, icount_); |
| 1624 if (TargetCPUFeatures::vfp_supported()) { | 1633 if (TargetCPUFeatures::vfp_supported()) { |
| 1625 double zap_dvalue = static_cast<double>(icount_); | 1634 double zap_dvalue = static_cast<double>(icount_); |
| 1626 // Do not zap D0, as it may contain a float result. | 1635 // Do not zap D0, as it may contain a float result. |
| 1627 for (int i = D1; i <= D7; i++) { | 1636 for (int i = D1; i <= D7; i++) { |
| 1628 set_dregister(static_cast<DRegister>(i), zap_dvalue); | 1637 set_dregister(static_cast<DRegister>(i), zap_dvalue); |
| 1629 } | 1638 } |
| 1630 // The above loop also zaps overlapping registers S2-S15. | 1639 // The above loop also zaps overlapping registers S2-S15. |
| 1631 // Registers D8-D15 (overlapping with S16-S31) are preserved. | 1640 // Registers D8-D15 (overlapping with S16-S31) are preserved. |
| 1632 #if defined(VFPv3_D32) | 1641 #if defined(VFPv3_D32) |
| 1633 for (int i = D16; i <= D31; i++) { | 1642 for (int i = D16; i <= D31; i++) { |
| 1634 set_dregister(static_cast<DRegister>(i), zap_dvalue); | 1643 set_dregister(static_cast<DRegister>(i), zap_dvalue); |
| 1635 } | 1644 } |
| 1636 #endif | 1645 #endif |
| 1637 } | 1646 } |
| 1638 | 1647 |
| 1639 // Return. | 1648 // Return. |
| 1640 set_pc(saved_lr); | 1649 set_pc(saved_lr); |
| 1641 } else { | 1650 } else { |
| (...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1712 reinterpret_cast<intptr_t>(instr) - Instr::kInstrSize); | 1721 reinterpret_cast<intptr_t>(instr) - Instr::kInstrSize); |
| 1713 set_pc(get_pc() + Instr::kInstrSize); | 1722 set_pc(get_pc() + Instr::kInstrSize); |
| 1714 dbg.Stop(instr, message); | 1723 dbg.Stop(instr, message); |
| 1715 } else { | 1724 } else { |
| 1716 char buffer[32]; | 1725 char buffer[32]; |
| 1717 snprintf(buffer, sizeof(buffer), "bkpt #0x%x", imm); | 1726 snprintf(buffer, sizeof(buffer), "bkpt #0x%x", imm); |
| 1718 set_pc(get_pc() + Instr::kInstrSize); | 1727 set_pc(get_pc() + Instr::kInstrSize); |
| 1719 dbg.Stop(instr, buffer); | 1728 dbg.Stop(instr, buffer); |
| 1720 } | 1729 } |
| 1721 } else { | 1730 } else { |
| 1722 // Format(instr, "smc'cond"); | 1731 // Format(instr, "smc'cond"); |
| 1723 UnimplementedInstruction(instr); | 1732 UnimplementedInstruction(instr); |
| 1724 } | 1733 } |
| 1725 break; | 1734 break; |
| 1726 } | 1735 } |
| 1727 default: { | 1736 default: { |
| 1728 UnimplementedInstruction(instr); | 1737 UnimplementedInstruction(instr); |
| 1729 break; | 1738 break; |
| 1730 } | 1739 } |
| 1731 } | 1740 } |
| 1732 } else if (instr->IsMultiplyOrSyncPrimitive()) { | 1741 } else if (instr->IsMultiplyOrSyncPrimitive()) { |
| 1733 if (instr->Bit(24) == 0) { | 1742 if (instr->Bit(24) == 0) { |
| 1734 // multiply instructions. | 1743 // multiply instructions. |
| 1735 Register rn = instr->RnField(); | 1744 Register rn = instr->RnField(); |
| 1736 Register rd = instr->RdField(); | 1745 Register rd = instr->RdField(); |
| 1737 Register rs = instr->RsField(); | 1746 Register rs = instr->RsField(); |
| 1738 Register rm = instr->RmField(); | 1747 Register rm = instr->RmField(); |
| 1739 int32_t rm_val = get_register(rm); | 1748 int32_t rm_val = get_register(rm); |
| 1740 int32_t rs_val = get_register(rs); | 1749 int32_t rs_val = get_register(rs); |
| 1741 int32_t rd_val = 0; | 1750 int32_t rd_val = 0; |
| 1742 switch (instr->Bits(21, 3)) { | 1751 switch (instr->Bits(21, 3)) { |
| 1743 case 1: | 1752 case 1: |
| 1744 // Registers rd, rn, rm, ra are encoded as rn, rm, rs, rd. | 1753 // Registers rd, rn, rm, ra are encoded as rn, rm, rs, rd. |
| 1745 // Format(instr, "mla'cond's 'rn, 'rm, 'rs, 'rd"); | 1754 // Format(instr, "mla'cond's 'rn, 'rm, 'rs, 'rd"); |
| 1746 case 3: { | 1755 case 3: { |
| 1747 // Registers rd, rn, rm, ra are encoded as rn, rm, rs, rd. | 1756 // Registers rd, rn, rm, ra are encoded as rn, rm, rs, rd. |
| 1748 // Format(instr, "mls'cond's 'rn, 'rm, 'rs, 'rd"); | 1757 // Format(instr, "mls'cond's 'rn, 'rm, 'rs, 'rd"); |
| 1749 rd_val = get_register(rd); | 1758 rd_val = get_register(rd); |
| 1750 // fall through | 1759 // fall through |
| 1751 } | 1760 } |
| 1752 case 0: { | 1761 case 0: { |
| 1753 // Registers rd, rn, rm are encoded as rn, rm, rs. | 1762 // Registers rd, rn, rm are encoded as rn, rm, rs. |
| 1754 // Format(instr, "mul'cond's 'rn, 'rm, 'rs"); | 1763 // Format(instr, "mul'cond's 'rn, 'rm, 'rs"); |
| 1755 int32_t alu_out = rm_val * rs_val; | 1764 int32_t alu_out = rm_val * rs_val; |
| 1756 if (instr->Bits(21, 3) == 3) { // mls | 1765 if (instr->Bits(21, 3) == 3) { // mls |
| 1757 if (TargetCPUFeatures::arm_version() != ARMv7) { | 1766 if (TargetCPUFeatures::arm_version() != ARMv7) { |
| 1758 UnimplementedInstruction(instr); | 1767 UnimplementedInstruction(instr); |
| 1759 break; | 1768 break; |
| 1760 } | 1769 } |
| 1761 alu_out = -alu_out; | 1770 alu_out = -alu_out; |
| 1762 } | 1771 } |
| 1763 alu_out += rd_val; | 1772 alu_out += rd_val; |
| 1764 set_register(rn, alu_out); | 1773 set_register(rn, alu_out); |
| 1765 if (instr->HasS()) { | 1774 if (instr->HasS()) { |
| 1766 SetNZFlags(alu_out); | 1775 SetNZFlags(alu_out); |
| 1767 } | 1776 } |
| 1768 break; | 1777 break; |
| 1769 } | 1778 } |
| 1770 case 4: | 1779 case 4: |
| 1771 // Registers rd_lo, rd_hi, rn, rm are encoded as rd, rn, rm, rs. | 1780 // Registers rd_lo, rd_hi, rn, rm are encoded as rd, rn, rm, rs. |
| 1772 // Format(instr, "umull'cond's 'rd, 'rn, 'rm, 'rs"); | 1781 // Format(instr, "umull'cond's 'rd, 'rn, 'rm, 'rs"); |
| 1773 case 6: { | 1782 case 6: { |
| 1774 // Registers rd_lo, rd_hi, rn, rm are encoded as rd, rn, rm, rs. | 1783 // Registers rd_lo, rd_hi, rn, rm are encoded as rd, rn, rm, rs. |
| 1775 // Format(instr, "smull'cond's 'rd, 'rn, 'rm, 'rs"); | 1784 // Format(instr, "smull'cond's 'rd, 'rn, 'rm, 'rs"); |
| 1776 int64_t result; | 1785 int64_t result; |
| 1777 if (instr->Bits(21, 3) == 4) { // umull | 1786 if (instr->Bits(21, 3) == 4) { // umull |
| 1778 uint64_t left_op = static_cast<uint32_t>(rm_val); | 1787 uint64_t left_op = static_cast<uint32_t>(rm_val); |
| 1779 uint64_t right_op = static_cast<uint32_t>(rs_val); | 1788 uint64_t right_op = static_cast<uint32_t>(rs_val); |
| 1780 result = left_op * right_op; // Unsigned multiplication. | 1789 result = left_op * right_op; // Unsigned multiplication. |
| 1781 } else { // smull | 1790 } else { // smull |
| 1782 int64_t left_op = static_cast<int32_t>(rm_val); | 1791 int64_t left_op = static_cast<int32_t>(rm_val); |
| 1783 int64_t right_op = static_cast<int32_t>(rs_val); | 1792 int64_t right_op = static_cast<int32_t>(rs_val); |
| 1784 result = left_op * right_op; // Signed multiplication. | 1793 result = left_op * right_op; // Signed multiplication. |
| 1785 } | 1794 } |
| 1786 int32_t hi_res = Utils::High32Bits(result); | 1795 int32_t hi_res = Utils::High32Bits(result); |
| 1787 int32_t lo_res = Utils::Low32Bits(result); | 1796 int32_t lo_res = Utils::Low32Bits(result); |
| 1788 set_register(rd, lo_res); | 1797 set_register(rd, lo_res); |
| 1789 set_register(rn, hi_res); | 1798 set_register(rn, hi_res); |
| 1790 if (instr->HasS()) { | 1799 if (instr->HasS()) { |
| 1791 if (lo_res != 0) { | 1800 if (lo_res != 0) { |
| 1792 // Collapse bits 0..31 into bit 32 so that 32-bit Z check works. | 1801 // Collapse bits 0..31 into bit 32 so that 32-bit Z check works. |
| 1793 hi_res |= 1; | 1802 hi_res |= 1; |
| 1794 } | 1803 } |
| 1795 ASSERT((result == 0) == (hi_res == 0)); // Z bit | 1804 ASSERT((result == 0) == (hi_res == 0)); // Z bit |
| 1796 ASSERT(((result & (1LL << 63)) != 0) == (hi_res < 0)); // N bit | 1805 ASSERT(((result & (1LL << 63)) != 0) == (hi_res < 0)); // N bit |
| 1797 SetNZFlags(hi_res); | 1806 SetNZFlags(hi_res); |
| 1798 } | 1807 } |
| 1799 break; | 1808 break; |
| 1800 } | 1809 } |
| 1801 case 2: | 1810 case 2: |
| 1802 // Registers rd_lo, rd_hi, rn, rm are encoded as rd, rn, rm, rs. | 1811 // Registers rd_lo, rd_hi, rn, rm are encoded as rd, rn, rm, rs. |
| 1803 // Format(instr, "umaal'cond's 'rd, 'rn, 'rm, 'rs"); | 1812 // Format(instr, "umaal'cond's 'rd, 'rn, 'rm, 'rs"); |
| 1804 if (TargetCPUFeatures::arm_version() == ARMv5TE) { | 1813 if (TargetCPUFeatures::arm_version() == ARMv5TE) { |
| 1805 // umaal is only in ARMv6 and above. | 1814 // umaal is only in ARMv6 and above. |
| 1806 UnimplementedInstruction(instr); | 1815 UnimplementedInstruction(instr); |
| 1807 } | 1816 } |
| 1808 case 5: | 1817 case 5: |
| 1809 // Registers rd_lo, rd_hi, rn, rm are encoded as rd, rn, rm, rs. | 1818 // Registers rd_lo, rd_hi, rn, rm are encoded as rd, rn, rm, rs. |
| 1810 // Format(instr, "umlal'cond's 'rd, 'rn, 'rm, 'rs"); | 1819 // Format(instr, "umlal'cond's 'rd, 'rn, 'rm, 'rs"); |
| 1811 case 7: { | 1820 case 7: { |
| 1812 // Registers rd_lo, rd_hi, rn, rm are encoded as rd, rn, rm, rs. | 1821 // Registers rd_lo, rd_hi, rn, rm are encoded as rd, rn, rm, rs. |
| 1813 // Format(instr, "smlal'cond's 'rd, 'rn, 'rm, 'rs"); | 1822 // Format(instr, "smlal'cond's 'rd, 'rn, 'rm, 'rs"); |
| 1814 int32_t rd_lo_val = get_register(rd); | 1823 int32_t rd_lo_val = get_register(rd); |
| 1815 int32_t rd_hi_val = get_register(rn); | 1824 int32_t rd_hi_val = get_register(rn); |
| 1816 uint32_t accum_lo = static_cast<uint32_t>(rd_lo_val); | 1825 uint32_t accum_lo = static_cast<uint32_t>(rd_lo_val); |
| 1817 int32_t accum_hi = static_cast<int32_t>(rd_hi_val); | 1826 int32_t accum_hi = static_cast<int32_t>(rd_hi_val); |
| 1818 int64_t accum = Utils::LowHighTo64Bits(accum_lo, accum_hi); | 1827 int64_t accum = Utils::LowHighTo64Bits(accum_lo, accum_hi); |
| 1819 int64_t result; | 1828 int64_t result; |
| 1820 if (instr->Bits(21, 3) == 5) { // umlal | 1829 if (instr->Bits(21, 3) == 5) { // umlal |
| 1821 uint64_t left_op = static_cast<uint32_t>(rm_val); | 1830 uint64_t left_op = static_cast<uint32_t>(rm_val); |
| 1822 uint64_t right_op = static_cast<uint32_t>(rs_val); | 1831 uint64_t right_op = static_cast<uint32_t>(rs_val); |
| 1823 result = accum + left_op * right_op; // Unsigned multiplication. | 1832 result = accum + left_op * right_op; // Unsigned multiplication. |
| 1824 } else if (instr->Bits(21, 3) == 7) { // smlal | 1833 } else if (instr->Bits(21, 3) == 7) { // smlal |
| 1825 int64_t left_op = static_cast<int32_t>(rm_val); | 1834 int64_t left_op = static_cast<int32_t>(rm_val); |
| 1826 int64_t right_op = static_cast<int32_t>(rs_val); | 1835 int64_t right_op = static_cast<int32_t>(rs_val); |
| 1827 result = accum + left_op * right_op; // Signed multiplication. | 1836 result = accum + left_op * right_op; // Signed multiplication. |
| 1828 } else { | 1837 } else { |
| 1829 ASSERT(instr->Bits(21, 3) == 2); // umaal | 1838 ASSERT(instr->Bits(21, 3) == 2); // umaal |
| 1830 ASSERT(!instr->HasS()); | 1839 ASSERT(!instr->HasS()); |
| 1831 uint64_t left_op = static_cast<uint32_t>(rm_val); | 1840 uint64_t left_op = static_cast<uint32_t>(rm_val); |
| 1832 uint64_t right_op = static_cast<uint32_t>(rs_val); | 1841 uint64_t right_op = static_cast<uint32_t>(rs_val); |
| 1833 result = left_op * right_op + // Unsigned multiplication. | 1842 result = left_op * right_op + // Unsigned multiplication. |
| 1834 static_cast<uint32_t>(rd_lo_val) + | 1843 static_cast<uint32_t>(rd_lo_val) + |
| 1835 static_cast<uint32_t>(rd_hi_val); | 1844 static_cast<uint32_t>(rd_hi_val); |
| 1836 } | 1845 } |
| 1837 int32_t hi_res = Utils::High32Bits(result); | 1846 int32_t hi_res = Utils::High32Bits(result); |
| 1838 int32_t lo_res = Utils::Low32Bits(result); | 1847 int32_t lo_res = Utils::Low32Bits(result); |
| 1839 set_register(rd, lo_res); | 1848 set_register(rd, lo_res); |
| 1840 set_register(rn, hi_res); | 1849 set_register(rn, hi_res); |
| 1841 if (instr->HasS()) { | 1850 if (instr->HasS()) { |
| 1842 if (lo_res != 0) { | 1851 if (lo_res != 0) { |
| 1843 // Collapse bits 0..31 into bit 32 so that 32-bit Z check works. | 1852 // Collapse bits 0..31 into bit 32 so that 32-bit Z check works. |
| 1844 hi_res |= 1; | 1853 hi_res |= 1; |
| 1845 } | 1854 } |
| 1846 ASSERT((result == 0) == (hi_res == 0)); // Z bit | 1855 ASSERT((result == 0) == (hi_res == 0)); // Z bit |
| 1847 ASSERT(((result & (1LL << 63)) != 0) == (hi_res < 0)); // N bit | 1856 ASSERT(((result & (1LL << 63)) != 0) == (hi_res < 0)); // N bit |
| 1848 SetNZFlags(hi_res); | 1857 SetNZFlags(hi_res); |
| 1849 } | 1858 } |
| 1850 break; | 1859 break; |
| 1851 } | 1860 } |
| 1852 default: { | 1861 default: { |
| 1853 UnimplementedInstruction(instr); | 1862 UnimplementedInstruction(instr); |
| 1854 break; | 1863 break; |
| 1855 } | 1864 } |
| 1856 } | 1865 } |
| (...skipping 620 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2477 } | 2486 } |
| 2478 | 2487 |
| 2479 | 2488 |
| 2480 void Simulator::DecodeType5(Instr* instr) { | 2489 void Simulator::DecodeType5(Instr* instr) { |
| 2481 // Format(instr, "b'l'cond 'target"); | 2490 // Format(instr, "b'l'cond 'target"); |
| 2482 int off = (instr->SImmed24Field() << 2) + 8; | 2491 int off = (instr->SImmed24Field() << 2) + 8; |
| 2483 intptr_t pc = get_pc(); | 2492 intptr_t pc = get_pc(); |
| 2484 if (instr->HasLink()) { | 2493 if (instr->HasLink()) { |
| 2485 set_register(LR, pc + Instr::kInstrSize); | 2494 set_register(LR, pc + Instr::kInstrSize); |
| 2486 } | 2495 } |
| 2487 set_pc(pc+off); | 2496 set_pc(pc + off); |
| 2488 } | 2497 } |
| 2489 | 2498 |
| 2490 | 2499 |
| 2491 void Simulator::DecodeType6(Instr* instr) { | 2500 void Simulator::DecodeType6(Instr* instr) { |
| 2492 if (instr->IsVFPDoubleTransfer()) { | 2501 if (instr->IsVFPDoubleTransfer()) { |
| 2493 Register rd = instr->RdField(); | 2502 Register rd = instr->RdField(); |
| 2494 Register rn = instr->RnField(); | 2503 Register rn = instr->RnField(); |
| 2495 if (instr->Bit(8) == 0) { | 2504 if (instr->Bit(8) == 0) { |
| 2496 SRegister sm = instr->SmField(); | 2505 SRegister sm = instr->SmField(); |
| 2497 SRegister sm1 = static_cast<SRegister>(sm + 1); | 2506 SRegister sm1 = static_cast<SRegister>(sm + 1); |
| 2498 ASSERT(sm1 < kNumberOfSRegisters); | 2507 ASSERT(sm1 < kNumberOfSRegisters); |
| 2499 if (instr->Bit(20) == 1) { | 2508 if (instr->Bit(20) == 1) { |
| 2500 // Format(instr, "vmovrrs'cond 'rd, 'rn, {'sm', 'sm1}"); | 2509 // Format(instr, "vmovrrs'cond 'rd, 'rn, {'sm', 'sm1}"); |
| 2501 set_register(rd, get_sregister_bits(sm)); | 2510 set_register(rd, get_sregister_bits(sm)); |
| 2502 set_register(rn, get_sregister_bits(sm1)); | 2511 set_register(rn, get_sregister_bits(sm1)); |
| 2503 } else { | 2512 } else { |
| 2504 // Format(instr, "vmovsrr'cond {'sm, 'sm1}, 'rd', 'rn"); | 2513 // Format(instr, "vmovsrr'cond {'sm, 'sm1}, 'rd', 'rn"); |
| 2505 set_sregister_bits(sm, get_register(rd)); | 2514 set_sregister_bits(sm, get_register(rd)); |
| 2506 set_sregister_bits(sm1, get_register(rn)); | 2515 set_sregister_bits(sm1, get_register(rn)); |
| 2507 } | 2516 } |
| 2508 } else { | 2517 } else { |
| 2509 DRegister dm = instr->DmField(); | 2518 DRegister dm = instr->DmField(); |
| 2510 if (instr->Bit(20) == 1) { | 2519 if (instr->Bit(20) == 1) { |
| 2511 // Format(instr, "vmovrrd'cond 'rd, 'rn, 'dm"); | 2520 // Format(instr, "vmovrrd'cond 'rd, 'rn, 'dm"); |
| 2512 int64_t dm_val = get_dregister_bits(dm); | 2521 int64_t dm_val = get_dregister_bits(dm); |
| 2513 set_register(rd, Utils::Low32Bits(dm_val)); | 2522 set_register(rd, Utils::Low32Bits(dm_val)); |
| 2514 set_register(rn, Utils::High32Bits(dm_val)); | 2523 set_register(rn, Utils::High32Bits(dm_val)); |
| 2515 } else { | 2524 } else { |
| 2516 // Format(instr, "vmovdrr'cond 'dm, 'rd, 'rn"); | 2525 // Format(instr, "vmovdrr'cond 'dm, 'rd, 'rn"); |
| 2517 int64_t dm_val = Utils::LowHighTo64Bits(get_register(rd), | 2526 int64_t dm_val = |
| 2518 get_register(rn)); | 2527 Utils::LowHighTo64Bits(get_register(rd), get_register(rn)); |
| 2519 set_dregister_bits(dm, dm_val); | 2528 set_dregister_bits(dm, dm_val); |
| 2520 } | 2529 } |
| 2521 } | 2530 } |
| 2522 } else if (instr-> IsVFPLoadStore()) { | 2531 } else if (instr->IsVFPLoadStore()) { |
| 2523 Register rn = instr->RnField(); | 2532 Register rn = instr->RnField(); |
| 2524 int32_t addr = get_register(rn); | 2533 int32_t addr = get_register(rn); |
| 2525 int32_t imm_val = instr->Bits(0, 8) << 2; | 2534 int32_t imm_val = instr->Bits(0, 8) << 2; |
| 2526 if (instr->Bit(23) == 1) { | 2535 if (instr->Bit(23) == 1) { |
| 2527 addr += imm_val; | 2536 addr += imm_val; |
| 2528 } else { | 2537 } else { |
| 2529 addr -= imm_val; | 2538 addr -= imm_val; |
| 2530 } | 2539 } |
| 2531 if (IsIllegalAddress(addr)) { | 2540 if (IsIllegalAddress(addr)) { |
| 2532 HandleIllegalAccess(addr, instr); | 2541 HandleIllegalAccess(addr, instr); |
| (...skipping 178 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2711 if (instr->Bit(6) == 0) { | 2720 if (instr->Bit(6) == 0) { |
| 2712 // Format(instr, "vaddd'cond 'dd, 'dn, 'dm"); | 2721 // Format(instr, "vaddd'cond 'dd, 'dn, 'dm"); |
| 2713 set_dregister(dd, get_dregister(dn) + get_dregister(dm)); | 2722 set_dregister(dd, get_dregister(dn) + get_dregister(dm)); |
| 2714 } else { | 2723 } else { |
| 2715 // Format(instr, "vsubd'cond 'dd, 'dn, 'dm"); | 2724 // Format(instr, "vsubd'cond 'dd, 'dn, 'dm"); |
| 2716 set_dregister(dd, get_dregister(dn) - get_dregister(dm)); | 2725 set_dregister(dd, get_dregister(dn) - get_dregister(dm)); |
| 2717 } | 2726 } |
| 2718 } | 2727 } |
| 2719 break; | 2728 break; |
| 2720 } | 2729 } |
| 2721 case 0xb: { // Other VFP data-processing instructions | 2730 case 0xb: { // Other VFP data-processing instructions |
| 2722 if (instr->Bit(6) == 0) { // vmov immediate | 2731 if (instr->Bit(6) == 0) { // vmov immediate |
| 2723 if (instr->Bit(8) == 0) { | 2732 if (instr->Bit(8) == 0) { |
| 2724 // Format(instr, "vmovs'cond 'sd, #'immf"); | 2733 // Format(instr, "vmovs'cond 'sd, #'immf"); |
| 2725 set_sregister(sd, instr->ImmFloatField()); | 2734 set_sregister(sd, instr->ImmFloatField()); |
| 2726 } else { | 2735 } else { |
| 2727 // Format(instr, "vmovd'cond 'dd, #'immd"); | 2736 // Format(instr, "vmovd'cond 'dd, #'immd"); |
| 2728 set_dregister(dd, instr->ImmDoubleField()); | 2737 set_dregister(dd, instr->ImmDoubleField()); |
| 2729 } | 2738 } |
| 2730 break; | 2739 break; |
| 2731 } | 2740 } |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2781 } | 2790 } |
| 2782 break; | 2791 break; |
| 2783 } | 2792 } |
| 2784 default: { | 2793 default: { |
| 2785 UnimplementedInstruction(instr); | 2794 UnimplementedInstruction(instr); |
| 2786 break; | 2795 break; |
| 2787 } | 2796 } |
| 2788 } | 2797 } |
| 2789 break; | 2798 break; |
| 2790 } | 2799 } |
| 2791 case 4: // vcmp, vcmpe | 2800 case 4: // vcmp, vcmpe |
| 2792 case 5: { // vcmp #0.0, vcmpe #0.0 | 2801 case 5: { // vcmp #0.0, vcmpe #0.0 |
| 2793 if (instr->Bit(7) == 1) { // vcmpe | 2802 if (instr->Bit(7) == 1) { // vcmpe |
| 2794 UnimplementedInstruction(instr); | 2803 UnimplementedInstruction(instr); |
| 2795 } else { | 2804 } else { |
| 2796 fp_n_flag_ = false; | 2805 fp_n_flag_ = false; |
| 2797 fp_z_flag_ = false; | 2806 fp_z_flag_ = false; |
| 2798 fp_c_flag_ = false; | 2807 fp_c_flag_ = false; |
| 2799 fp_v_flag_ = false; | 2808 fp_v_flag_ = false; |
| 2800 if (instr->Bit(8) == 0) { // vcmps | 2809 if (instr->Bit(8) == 0) { // vcmps |
| 2801 float sd_val = get_sregister(sd); | 2810 float sd_val = get_sregister(sd); |
| 2802 float sm_val; | 2811 float sm_val; |
| (...skipping 142 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2945 } | 2954 } |
| 2946 int32_t sd_val; | 2955 int32_t sd_val; |
| 2947 if (instr->Bit(16) == 0) { | 2956 if (instr->Bit(16) == 0) { |
| 2948 sd_val = static_cast<int32_t>(ud_val); | 2957 sd_val = static_cast<int32_t>(ud_val); |
| 2949 } else { | 2958 } else { |
| 2950 sd_val = id_val; | 2959 sd_val = id_val; |
| 2951 } | 2960 } |
| 2952 set_sregister_bits(sd, sd_val); | 2961 set_sregister_bits(sd, sd_val); |
| 2953 break; | 2962 break; |
| 2954 } | 2963 } |
| 2955 case 2: // vcvtb, vcvtt | 2964 case 2: // vcvtb, vcvtt |
| 2956 case 3: // vcvtb, vcvtt | 2965 case 3: // vcvtb, vcvtt |
| 2957 case 9: // undefined | 2966 case 9: // undefined |
| 2958 case 10: // vcvt between floating-point and fixed-point | 2967 case 10: // vcvt between floating-point and fixed-point |
| 2959 case 11: // vcvt between floating-point and fixed-point | 2968 case 11: // vcvt between floating-point and fixed-point |
| 2960 case 14: // vcvt between floating-point and fixed-point | 2969 case 14: // vcvt between floating-point and fixed-point |
| 2961 case 15: // vcvt between floating-point and fixed-point | 2970 case 15: // vcvt between floating-point and fixed-point |
| 2962 default: { | 2971 default: { |
| 2963 UnimplementedInstruction(instr); | 2972 UnimplementedInstruction(instr); |
| 2964 break; | 2973 break; |
| 2965 } | 2974 } |
| 2966 } | 2975 } |
| 2967 } | 2976 } break; |
| 2968 break; | |
| 2969 } | 2977 } |
| 2970 } else { | 2978 } else { |
| 2971 // 8, 16, or 32-bit Transfer between ARM Core and VFP | 2979 // 8, 16, or 32-bit Transfer between ARM Core and VFP |
| 2972 if ((instr->Bits(21, 3) == 0) && (instr->Bit(8) == 0)) { | 2980 if ((instr->Bits(21, 3) == 0) && (instr->Bit(8) == 0)) { |
| 2973 Register rd = instr->RdField(); | 2981 Register rd = instr->RdField(); |
| 2974 SRegister sn = instr->SnField(); | 2982 SRegister sn = instr->SnField(); |
| 2975 if (instr->Bit(20) == 0) { | 2983 if (instr->Bit(20) == 0) { |
| 2976 // Format(instr, "vmovs'cond 'sn, 'rd"); | 2984 // Format(instr, "vmovs'cond 'sn, 'rd"); |
| 2977 set_sregister_bits(sn, get_register(rd)); | 2985 set_sregister_bits(sn, get_register(rd)); |
| 2978 } else { | 2986 } else { |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3012 } | 3020 } |
| 3013 } | 3021 } |
| 3014 } else { | 3022 } else { |
| 3015 UnimplementedInstruction(instr); | 3023 UnimplementedInstruction(instr); |
| 3016 } | 3024 } |
| 3017 } | 3025 } |
| 3018 | 3026 |
| 3019 | 3027 |
| 3020 static float arm_reciprocal_sqrt_estimate(float a) { | 3028 static float arm_reciprocal_sqrt_estimate(float a) { |
| 3021 // From the ARM Architecture Reference Manual A2-87. | 3029 // From the ARM Architecture Reference Manual A2-87. |
| 3022 if (isinf(a) || (fabs(a) >= exp2f(126))) return 0.0; | 3030 if (isinf(a) || (fabs(a) >= exp2f(126))) |
| 3023 else if (a == 0.0) return kPosInfinity; | 3031 return 0.0; |
| 3024 else if (isnan(a)) return a; | 3032 else if (a == 0.0) |
| 3033 return kPosInfinity; |
| 3034 else if (isnan(a)) |
| 3035 return a; |
| 3025 | 3036 |
| 3026 uint32_t a_bits = bit_cast<uint32_t, float>(a); | 3037 uint32_t a_bits = bit_cast<uint32_t, float>(a); |
| 3027 uint64_t scaled; | 3038 uint64_t scaled; |
| 3028 if (((a_bits >> 23) & 1) != 0) { | 3039 if (((a_bits >> 23) & 1) != 0) { |
| 3029 // scaled = '0 01111111101' : operand<22:0> : Zeros(29) | 3040 // scaled = '0 01111111101' : operand<22:0> : Zeros(29) |
| 3030 scaled = (static_cast<uint64_t>(0x3fd) << 52) | | 3041 scaled = (static_cast<uint64_t>(0x3fd) << 52) | |
| 3031 ((static_cast<uint64_t>(a_bits) & 0x7fffff) << 29); | 3042 ((static_cast<uint64_t>(a_bits) & 0x7fffff) << 29); |
| 3032 } else { | 3043 } else { |
| 3033 // scaled = '0 01111111110' : operand<22:0> : Zeros(29) | 3044 // scaled = '0 01111111110' : operand<22:0> : Zeros(29) |
| 3034 scaled = (static_cast<uint64_t>(0x3fe) << 52) | | 3045 scaled = (static_cast<uint64_t>(0x3fe) << 52) | |
| (...skipping 17 matching lines...) Expand all Loading... |
| 3052 // range 0.5 <= a < 1.0 | 3063 // range 0.5 <= a < 1.0 |
| 3053 | 3064 |
| 3054 // a in units of 1/256 rounded down. | 3065 // a in units of 1/256 rounded down. |
| 3055 int32_t q1 = static_cast<int32_t>(scaled_d * 256.0); | 3066 int32_t q1 = static_cast<int32_t>(scaled_d * 256.0); |
| 3056 // reciprocal root r. | 3067 // reciprocal root r. |
| 3057 r = 1.0 / sqrt((static_cast<double>(q1) + 0.5) / 256.0); | 3068 r = 1.0 / sqrt((static_cast<double>(q1) + 0.5) / 256.0); |
| 3058 } | 3069 } |
| 3059 // r in units of 1/256 rounded to nearest. | 3070 // r in units of 1/256 rounded to nearest. |
| 3060 int32_t s = static_cast<int>(256.0 * r + 0.5); | 3071 int32_t s = static_cast<int>(256.0 * r + 0.5); |
| 3061 double estimate = static_cast<double>(s) / 256.0; | 3072 double estimate = static_cast<double>(s) / 256.0; |
| 3062 ASSERT((estimate >= 1.0) && (estimate <= (511.0/256.0))); | 3073 ASSERT((estimate >= 1.0) && (estimate <= (511.0 / 256.0))); |
| 3063 | 3074 |
| 3064 // result = 0 : result_exp<7:0> : estimate<51:29> | 3075 // result = 0 : result_exp<7:0> : estimate<51:29> |
| 3065 int32_t result_bits = ((result_exp & 0xff) << 23) | | 3076 int32_t result_bits = |
| 3077 ((result_exp & 0xff) << 23) | |
| 3066 ((bit_cast<uint64_t, double>(estimate) >> 29) & 0x7fffff); | 3078 ((bit_cast<uint64_t, double>(estimate) >> 29) & 0x7fffff); |
| 3067 return bit_cast<float, int32_t>(result_bits); | 3079 return bit_cast<float, int32_t>(result_bits); |
| 3068 } | 3080 } |
| 3069 | 3081 |
| 3070 | 3082 |
| 3071 static float arm_recip_estimate(float a) { | 3083 static float arm_recip_estimate(float a) { |
| 3072 // From the ARM Architecture Reference Manual A2-85. | 3084 // From the ARM Architecture Reference Manual A2-85. |
| 3073 if (isinf(a) || (fabs(a) >= exp2f(126))) return 0.0; | 3085 if (isinf(a) || (fabs(a) >= exp2f(126))) |
| 3074 else if (a == 0.0) return kPosInfinity; | 3086 return 0.0; |
| 3075 else if (isnan(a)) return a; | 3087 else if (a == 0.0) |
| 3088 return kPosInfinity; |
| 3089 else if (isnan(a)) |
| 3090 return a; |
| 3076 | 3091 |
| 3077 uint32_t a_bits = bit_cast<uint32_t, float>(a); | 3092 uint32_t a_bits = bit_cast<uint32_t, float>(a); |
| 3078 // scaled = '0011 1111 1110' : a<22:0> : Zeros(29) | 3093 // scaled = '0011 1111 1110' : a<22:0> : Zeros(29) |
| 3079 uint64_t scaled = (static_cast<uint64_t>(0x3fe) << 52) | | 3094 uint64_t scaled = (static_cast<uint64_t>(0x3fe) << 52) | |
| 3080 ((static_cast<uint64_t>(a_bits) & 0x7fffff) << 29); | 3095 ((static_cast<uint64_t>(a_bits) & 0x7fffff) << 29); |
| 3081 // result_exp = 253 - UInt(a<30:23>) | 3096 // result_exp = 253 - UInt(a<30:23>) |
| 3082 int32_t result_exp = 253 - ((a_bits >> 23) & 0xff); | 3097 int32_t result_exp = 253 - ((a_bits >> 23) & 0xff); |
| 3083 ASSERT((result_exp >= 1) && (result_exp <= 252)); | 3098 ASSERT((result_exp >= 1) && (result_exp <= 252)); |
| 3084 | 3099 |
| 3085 double scaled_d = bit_cast<double, uint64_t>(scaled); | 3100 double scaled_d = bit_cast<double, uint64_t>(scaled); |
| 3086 ASSERT((scaled_d >= 0.5) && (scaled_d < 1.0)); | 3101 ASSERT((scaled_d >= 0.5) && (scaled_d < 1.0)); |
| 3087 | 3102 |
| 3088 // a in units of 1/512 rounded down. | 3103 // a in units of 1/512 rounded down. |
| 3089 int32_t q = static_cast<int32_t>(scaled_d * 512.0); | 3104 int32_t q = static_cast<int32_t>(scaled_d * 512.0); |
| 3090 // reciprocal r. | 3105 // reciprocal r. |
| 3091 double r = 1.0 / ((static_cast<double>(q) + 0.5) / 512.0); | 3106 double r = 1.0 / ((static_cast<double>(q) + 0.5) / 512.0); |
| 3092 // r in units of 1/256 rounded to nearest. | 3107 // r in units of 1/256 rounded to nearest. |
| 3093 int32_t s = static_cast<int32_t>(256.0 * r + 0.5); | 3108 int32_t s = static_cast<int32_t>(256.0 * r + 0.5); |
| 3094 double estimate = static_cast<double>(s) / 256.0; | 3109 double estimate = static_cast<double>(s) / 256.0; |
| 3095 ASSERT((estimate >= 1.0) && (estimate <= (511.0/256.0))); | 3110 ASSERT((estimate >= 1.0) && (estimate <= (511.0 / 256.0))); |
| 3096 | 3111 |
| 3097 // result = sign : result_exp<7:0> : estimate<51:29> | 3112 // result = sign : result_exp<7:0> : estimate<51:29> |
| 3098 int32_t result_bits = | 3113 int32_t result_bits = |
| 3099 (a_bits & 0x80000000) | ((result_exp & 0xff) << 23) | | 3114 (a_bits & 0x80000000) | ((result_exp & 0xff) << 23) | |
| 3100 ((bit_cast<uint64_t, double>(estimate) >> 29) & 0x7fffff); | 3115 ((bit_cast<uint64_t, double>(estimate) >> 29) & 0x7fffff); |
| 3101 return bit_cast<float, int32_t>(result_bits); | 3116 return bit_cast<float, int32_t>(result_bits); |
| 3102 } | 3117 } |
| 3103 | 3118 |
| 3104 | 3119 |
| 3105 static void simd_value_swap(simd_value_t* s1, int i1, | 3120 static void simd_value_swap(simd_value_t* s1, |
| 3106 simd_value_t* s2, int i2) { | 3121 int i1, |
| 3122 simd_value_t* s2, |
| 3123 int i2) { |
| 3107 uint32_t tmp; | 3124 uint32_t tmp; |
| 3108 tmp = s1->data_[i1].u; | 3125 tmp = s1->data_[i1].u; |
| 3109 s1->data_[i1].u = s2->data_[i2].u; | 3126 s1->data_[i1].u = s2->data_[i2].u; |
| 3110 s2->data_[i2].u = tmp; | 3127 s2->data_[i2].u = tmp; |
| 3111 } | 3128 } |
| 3112 | 3129 |
| 3113 | 3130 |
| 3114 void Simulator::DecodeSIMDDataProcessing(Instr* instr) { | 3131 void Simulator::DecodeSIMDDataProcessing(Instr* instr) { |
| 3115 ASSERT(instr->ConditionField() == kSpecialCondition); | 3132 ASSERT(instr->ConditionField() == kSpecialCondition); |
| 3116 | 3133 |
| (...skipping 220 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3337 // Format(instr, "vminqs 'qd, 'qn, 'qm"); | 3354 // Format(instr, "vminqs 'qd, 'qn, 'qm"); |
| 3338 for (int i = 0; i < 4; i++) { | 3355 for (int i = 0; i < 4; i++) { |
| 3339 s8d.data_[i].f = | 3356 s8d.data_[i].f = |
| 3340 s8n.data_[i].f <= s8m.data_[i].f ? s8n.data_[i].f : s8m.data_[i].f; | 3357 s8n.data_[i].f <= s8m.data_[i].f ? s8n.data_[i].f : s8m.data_[i].f; |
| 3341 } | 3358 } |
| 3342 } else if ((instr->Bits(8, 4) == 15) && (instr->Bit(4) == 0) && | 3359 } else if ((instr->Bits(8, 4) == 15) && (instr->Bit(4) == 0) && |
| 3343 (instr->Bits(20, 2) == 0) && (instr->Bits(23, 2) == 0)) { | 3360 (instr->Bits(20, 2) == 0) && (instr->Bits(23, 2) == 0)) { |
| 3344 // Format(instr, "vmaxqs 'qd, 'qn, 'qm"); | 3361 // Format(instr, "vmaxqs 'qd, 'qn, 'qm"); |
| 3345 for (int i = 0; i < 4; i++) { | 3362 for (int i = 0; i < 4; i++) { |
| 3346 s8d.data_[i].f = | 3363 s8d.data_[i].f = |
| 3347 s8n.data_[i].f >= s8m.data_[i].f ? s8n.data_[i].f : s8m.data_[i].f; | 3364 s8n.data_[i].f >= s8m.data_[i].f ? s8n.data_[i].f : s8m.data_[i].f; |
| 3348 } | 3365 } |
| 3349 } else if ((instr->Bits(8, 4) == 7) && (instr->Bit(4) == 0) && | 3366 } else if ((instr->Bits(8, 4) == 7) && (instr->Bit(4) == 0) && |
| 3350 (instr->Bits(20, 2) == 3) && (instr->Bits(23, 2) == 3) && | 3367 (instr->Bits(20, 2) == 3) && (instr->Bits(23, 2) == 3) && |
| 3351 (instr->Bit(7) == 0) && (instr->Bits(16, 4) == 9)) { | 3368 (instr->Bit(7) == 0) && (instr->Bits(16, 4) == 9)) { |
| 3352 // Format(instr, "vabsqs 'qd, 'qm"); | 3369 // Format(instr, "vabsqs 'qd, 'qm"); |
| 3353 for (int i = 0; i < 4; i++) { | 3370 for (int i = 0; i < 4; i++) { |
| 3354 s8d.data_[i].f = fabsf(s8m.data_[i].f); | 3371 s8d.data_[i].f = fabsf(s8m.data_[i].f); |
| 3355 } | 3372 } |
| 3356 } else if ((instr->Bits(8, 4) == 7) && (instr->Bit(4) == 0) && | 3373 } else if ((instr->Bits(8, 4) == 7) && (instr->Bit(4) == 0) && |
| 3357 (instr->Bits(20, 2) == 3) && (instr->Bits(23, 2) == 3) && | 3374 (instr->Bits(20, 2) == 3) && (instr->Bits(23, 2) == 3) && |
| (...skipping 542 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3900 set_register(THR, reinterpret_cast<uword>(thread)); | 3917 set_register(THR, reinterpret_cast<uword>(thread)); |
| 3901 // Set the tag. | 3918 // Set the tag. |
| 3902 thread->set_vm_tag(VMTag::kDartTagId); | 3919 thread->set_vm_tag(VMTag::kDartTagId); |
| 3903 // Clear top exit frame. | 3920 // Clear top exit frame. |
| 3904 thread->set_top_exit_frame_info(0); | 3921 thread->set_top_exit_frame_info(0); |
| 3905 | 3922 |
| 3906 ASSERT(raw_exception != Object::null()); | 3923 ASSERT(raw_exception != Object::null()); |
| 3907 set_register(kExceptionObjectReg, bit_cast<int32_t>(raw_exception)); | 3924 set_register(kExceptionObjectReg, bit_cast<int32_t>(raw_exception)); |
| 3908 set_register(kStackTraceObjectReg, bit_cast<int32_t>(raw_stacktrace)); | 3925 set_register(kStackTraceObjectReg, bit_cast<int32_t>(raw_stacktrace)); |
| 3909 // Restore pool pointer. | 3926 // Restore pool pointer. |
| 3910 int32_t code = *reinterpret_cast<int32_t*>( | 3927 int32_t code = |
| 3911 fp + kPcMarkerSlotFromFp * kWordSize); | 3928 *reinterpret_cast<int32_t*>(fp + kPcMarkerSlotFromFp * kWordSize); |
| 3912 int32_t pp = *reinterpret_cast<int32_t*>( | 3929 int32_t pp = *reinterpret_cast<int32_t*>(code + Code::object_pool_offset() - |
| 3913 code + Code::object_pool_offset() - kHeapObjectTag); | 3930 kHeapObjectTag); |
| 3914 set_register(CODE_REG, code); | 3931 set_register(CODE_REG, code); |
| 3915 set_register(PP, pp); | 3932 set_register(PP, pp); |
| 3916 buf->Longjmp(); | 3933 buf->Longjmp(); |
| 3917 } | 3934 } |
| 3918 | 3935 |
| 3919 } // namespace dart | 3936 } // namespace dart |
| 3920 | 3937 |
| 3921 #endif // defined(USING_SIMULATOR) | 3938 #endif // defined(USING_SIMULATOR) |
| 3922 | 3939 |
| 3923 #endif // defined TARGET_ARCH_ARM | 3940 #endif // defined TARGET_ARCH_ARM |
| OLD | NEW |