| OLD | NEW |
| 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2014, 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_ARM64) | 9 #if defined(TARGET_ARCH_ARM64) |
| 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_arm64.h" | 17 #include "vm/constants_arm64.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 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 89 private: | 93 private: |
| 90 Simulator* sim_; | 94 Simulator* sim_; |
| 91 | 95 |
| 92 bool GetValue(char* desc, uint64_t* value); | 96 bool GetValue(char* desc, uint64_t* value); |
| 93 bool GetSValue(char* desc, uint32_t* value); | 97 bool GetSValue(char* desc, uint32_t* value); |
| 94 bool GetDValue(char* desc, uint64_t* value); | 98 bool GetDValue(char* desc, uint64_t* value); |
| 95 bool GetQValue(char* desc, simd_value_t* value); | 99 bool GetQValue(char* desc, simd_value_t* 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[] = { |
| 134 "r0", "r1", "r2", "r3", | 139 "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", |
| 135 "r4", "r5", "r6", "r7", | 140 "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", |
| 136 "r8", "r9", "r10", "r11", | 141 "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23", |
| 137 "r12", "r13", "r14", "r15", | 142 "r24", "r25", "r26", "r27", "r28", "r29", "r30", |
| 138 "r16", "r17", "r18", "r19", | |
| 139 "r20", "r21", "r22", "r23", | |
| 140 "r24", "r25", "r26", "r27", | |
| 141 "r28", "r29", "r30", | |
| 142 | 143 |
| 143 "ip0", "ip1", "pp", "ctx", "fp", "lr", "sp", "zr", | 144 "ip0", "ip1", "pp", "ctx", "fp", "lr", "sp", "zr", |
| 144 }; | 145 }; |
| 145 static const Register kRegisters[] = { | 146 static const Register kRegisters[] = { |
| 146 R0, R1, R2, R3, R4, R5, R6, R7, | 147 R0, R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, |
| 147 R8, R9, R10, R11, R12, R13, R14, R15, | 148 R11, R12, R13, R14, R15, R16, R17, R18, R19, R20, R21, |
| 148 R16, R17, R18, R19, R20, R21, R22, R23, | 149 R22, R23, R24, R25, R26, R27, R28, R29, R30, |
| 149 R24, R25, R26, R27, R28, R29, R30, | |
| 150 | 150 |
| 151 IP0, IP1, PP, CTX, FP, LR, R31, ZR, | 151 IP0, IP1, PP, CTX, FP, LR, R31, ZR, |
| 152 }; | 152 }; |
| 153 ASSERT(ARRAY_SIZE(kNames) == ARRAY_SIZE(kRegisters)); | 153 ASSERT(ARRAY_SIZE(kNames) == ARRAY_SIZE(kRegisters)); |
| 154 for (unsigned i = 0; i < ARRAY_SIZE(kNames); i++) { | 154 for (unsigned i = 0; i < ARRAY_SIZE(kNames); i++) { |
| 155 if (strcmp(kNames[i], name) == 0) { | 155 if (strcmp(kNames[i], name) == 0) { |
| 156 return kRegisters[i]; | 156 return kRegisters[i]; |
| 157 } | 157 } |
| 158 } | 158 } |
| 159 return kNoRegister; | 159 return kNoRegister; |
| 160 } | 160 } |
| 161 | 161 |
| (...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 256 } | 256 } |
| 257 *value = *(reinterpret_cast<simd_value_t*>(addr)); | 257 *value = *(reinterpret_cast<simd_value_t*>(addr)); |
| 258 return true; | 258 return true; |
| 259 } | 259 } |
| 260 } | 260 } |
| 261 return false; | 261 return false; |
| 262 } | 262 } |
| 263 | 263 |
| 264 | 264 |
| 265 TokenPosition SimulatorDebugger::GetApproximateTokenIndex(const Code& code, | 265 TokenPosition SimulatorDebugger::GetApproximateTokenIndex(const Code& code, |
| 266 uword pc) { | 266 uword pc) { |
| 267 TokenPosition token_pos = TokenPosition::kNoSource; | 267 TokenPosition token_pos = TokenPosition::kNoSource; |
| 268 uword pc_offset = pc - code.PayloadStart(); | 268 uword pc_offset = pc - code.PayloadStart(); |
| 269 const PcDescriptors& descriptors = | 269 const PcDescriptors& descriptors = |
| 270 PcDescriptors::Handle(code.pc_descriptors()); | 270 PcDescriptors::Handle(code.pc_descriptors()); |
| 271 PcDescriptors::Iterator iter(descriptors, RawPcDescriptors::kAnyKind); | 271 PcDescriptors::Iterator iter(descriptors, RawPcDescriptors::kAnyKind); |
| 272 while (iter.MoveNext()) { | 272 while (iter.MoveNext()) { |
| 273 if (iter.PcOffset() == pc_offset) { | 273 if (iter.PcOffset() == pc_offset) { |
| 274 return iter.TokenPos(); | 274 return iter.TokenPos(); |
| 275 } else if (!token_pos.IsReal() && (iter.PcOffset() > pc_offset)) { | 275 } else if (!token_pos.IsReal() && (iter.PcOffset() > pc_offset)) { |
| 276 token_pos = iter.TokenPos(); | 276 token_pos = iter.TokenPos(); |
| 277 } | 277 } |
| 278 } | 278 } |
| 279 return token_pos; | 279 return token_pos; |
| 280 } | 280 } |
| 281 | 281 |
| 282 | 282 |
| 283 void SimulatorDebugger::PrintDartFrame(uword pc, uword fp, uword sp, | 283 void SimulatorDebugger::PrintDartFrame(uword pc, |
| 284 uword fp, |
| 285 uword sp, |
| 284 const Function& function, | 286 const Function& function, |
| 285 TokenPosition token_pos, | 287 TokenPosition token_pos, |
| 286 bool is_optimized, | 288 bool is_optimized, |
| 287 bool is_inlined) { | 289 bool is_inlined) { |
| 288 const Script& script = Script::Handle(function.script()); | 290 const Script& script = Script::Handle(function.script()); |
| 289 const String& func_name = String::Handle(function.QualifiedScrubbedName()); | 291 const String& func_name = String::Handle(function.QualifiedScrubbedName()); |
| 290 const String& url = String::Handle(script.url()); | 292 const String& url = String::Handle(script.url()); |
| 291 intptr_t line = -1; | 293 intptr_t line = -1; |
| 292 intptr_t column = -1; | 294 intptr_t column = -1; |
| 293 if (token_pos.IsReal()) { | 295 if (token_pos.IsReal()) { |
| 294 script.GetTokenLocation(token_pos, &line, &column); | 296 script.GetTokenLocation(token_pos, &line, &column); |
| 295 } | 297 } |
| 296 OS::Print("pc=0x%" Px " fp=0x%" Px " sp=0x%" Px " %s%s (%s:%" Pd | 298 OS::Print( |
| 297 ":%" Pd ")\n", | 299 "pc=0x%" Px " fp=0x%" Px " sp=0x%" Px " %s%s (%s:%" Pd ":%" Pd ")\n", pc, |
| 298 pc, fp, sp, | 300 fp, sp, is_optimized ? (is_inlined ? "inlined " : "optimized ") : "", |
| 299 is_optimized ? (is_inlined ? "inlined " : "optimized ") : "", | 301 func_name.ToCString(), url.ToCString(), line, column); |
| 300 func_name.ToCString(), | |
| 301 url.ToCString(), | |
| 302 line, column); | |
| 303 } | 302 } |
| 304 | 303 |
| 305 | 304 |
| 306 void SimulatorDebugger::PrintBacktrace() { | 305 void SimulatorDebugger::PrintBacktrace() { |
| 307 StackFrameIterator frames(sim_->get_register(FP), | 306 StackFrameIterator frames(sim_->get_register(FP), sim_->get_register(SP), |
| 308 sim_->get_register(SP), | |
| 309 sim_->get_pc(), | 307 sim_->get_pc(), |
| 310 StackFrameIterator::kDontValidateFrames); | 308 StackFrameIterator::kDontValidateFrames); |
| 311 StackFrame* frame = frames.NextFrame(); | 309 StackFrame* frame = frames.NextFrame(); |
| 312 ASSERT(frame != NULL); | 310 ASSERT(frame != NULL); |
| 313 Function& function = Function::Handle(); | 311 Function& function = Function::Handle(); |
| 314 Function& inlined_function = Function::Handle(); | 312 Function& inlined_function = Function::Handle(); |
| 315 Code& code = Code::Handle(); | 313 Code& code = Code::Handle(); |
| 316 Code& unoptimized_code = Code::Handle(); | 314 Code& unoptimized_code = Code::Handle(); |
| 317 while (frame != NULL) { | 315 while (frame != NULL) { |
| 318 if (frame->IsDartFrame()) { | 316 if (frame->IsDartFrame()) { |
| 319 code = frame->LookupDartCode(); | 317 code = frame->LookupDartCode(); |
| 320 function = code.function(); | 318 function = code.function(); |
| 321 if (code.is_optimized()) { | 319 if (code.is_optimized()) { |
| 322 // For optimized frames, extract all the inlined functions if any | 320 // For optimized frames, extract all the inlined functions if any |
| 323 // into the stack trace. | 321 // into the stack trace. |
| 324 InlinedFunctionsIterator it(code, frame->pc()); | 322 InlinedFunctionsIterator it(code, frame->pc()); |
| 325 while (!it.Done()) { | 323 while (!it.Done()) { |
| 326 // Print each inlined frame with its pc in the corresponding | 324 // Print each inlined frame with its pc in the corresponding |
| 327 // unoptimized frame. | 325 // unoptimized frame. |
| 328 inlined_function = it.function(); | 326 inlined_function = it.function(); |
| 329 unoptimized_code = it.code(); | 327 unoptimized_code = it.code(); |
| 330 uword unoptimized_pc = it.pc(); | 328 uword unoptimized_pc = it.pc(); |
| 331 it.Advance(); | 329 it.Advance(); |
| 332 if (!it.Done()) { | 330 if (!it.Done()) { |
| 333 PrintDartFrame(unoptimized_pc, frame->fp(), frame->sp(), | 331 PrintDartFrame( |
| 334 inlined_function, | 332 unoptimized_pc, frame->fp(), frame->sp(), inlined_function, |
| 335 GetApproximateTokenIndex(unoptimized_code, | 333 GetApproximateTokenIndex(unoptimized_code, unoptimized_pc), |
| 336 unoptimized_pc), | 334 true, true); |
| 337 true, true); | |
| 338 } | 335 } |
| 339 } | 336 } |
| 340 // Print the optimized inlining frame below. | 337 // Print the optimized inlining frame below. |
| 341 } | 338 } |
| 342 PrintDartFrame(frame->pc(), frame->fp(), frame->sp(), | 339 PrintDartFrame(frame->pc(), frame->fp(), frame->sp(), function, |
| 343 function, | |
| 344 GetApproximateTokenIndex(code, frame->pc()), | 340 GetApproximateTokenIndex(code, frame->pc()), |
| 345 code.is_optimized(), false); | 341 code.is_optimized(), false); |
| 346 } else { | 342 } else { |
| 347 OS::Print("pc=0x%" Px " fp=0x%" Px " sp=0x%" Px " %s frame\n", | 343 OS::Print("pc=0x%" Px " fp=0x%" Px " sp=0x%" Px " %s frame\n", |
| 348 frame->pc(), frame->fp(), frame->sp(), | 344 frame->pc(), frame->fp(), frame->sp(), |
| 349 frame->IsEntryFrame() ? "entry" : | 345 frame->IsEntryFrame() |
| 350 frame->IsExitFrame() ? "exit" : | 346 ? "entry" |
| 351 frame->IsStubFrame() ? "stub" : "invalid"); | 347 : frame->IsExitFrame() |
| 348 ? "exit" |
| 349 : frame->IsStubFrame() ? "stub" : "invalid"); |
| 352 } | 350 } |
| 353 frame = frames.NextFrame(); | 351 frame = frames.NextFrame(); |
| 354 } | 352 } |
| 355 } | 353 } |
| 356 | 354 |
| 357 | 355 |
| 358 bool SimulatorDebugger::SetBreakpoint(Instr* breakpc) { | 356 bool SimulatorDebugger::SetBreakpoint(Instr* breakpc) { |
| 359 // Check if a breakpoint can be set. If not return without any side-effects. | 357 // Check if a breakpoint can be set. If not return without any side-effects. |
| 360 if (sim_->break_pc_ != NULL) { | 358 if (sim_->break_pc_ != NULL) { |
| 361 return false; | 359 return false; |
| (...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 436 FATAL("ReadLine failed"); | 434 FATAL("ReadLine failed"); |
| 437 } else { | 435 } else { |
| 438 // Use sscanf to parse the individual parts of the command line. At the | 436 // Use sscanf to parse the individual parts of the command line. At the |
| 439 // moment no command expects more than two parameters. | 437 // moment no command expects more than two parameters. |
| 440 int args = SScanF(line, | 438 int args = SScanF(line, |
| 441 "%" XSTR(COMMAND_SIZE) "s " | 439 "%" XSTR(COMMAND_SIZE) "s " |
| 442 "%" XSTR(ARG_SIZE) "s " | 440 "%" XSTR(ARG_SIZE) "s " |
| 443 "%" XSTR(ARG_SIZE) "s", | 441 "%" XSTR(ARG_SIZE) "s", |
| 444 cmd, arg1, arg2); | 442 cmd, arg1, arg2); |
| 445 if ((strcmp(cmd, "h") == 0) || (strcmp(cmd, "help") == 0)) { | 443 if ((strcmp(cmd, "h") == 0) || (strcmp(cmd, "help") == 0)) { |
| 446 OS::Print("c/cont -- continue execution\n" | 444 OS::Print( |
| 447 "disasm -- disassemble instrs at current pc location\n" | 445 "c/cont -- continue execution\n" |
| 448 " other variants are:\n" | 446 "disasm -- disassemble instrs at current pc location\n" |
| 449 " disasm <address>\n" | 447 " other variants are:\n" |
| 450 " disasm <address> <number_of_instructions>\n" | 448 " disasm <address>\n" |
| 451 " by default 10 instrs are disassembled\n" | 449 " disasm <address> <number_of_instructions>\n" |
| 452 "del -- delete breakpoints\n" | 450 " by default 10 instrs are disassembled\n" |
| 453 "flags -- print flag values\n" | 451 "del -- delete breakpoints\n" |
| 454 "gdb -- transfer control to gdb\n" | 452 "flags -- print flag values\n" |
| 455 "h/help -- print this help string\n" | 453 "gdb -- transfer control to gdb\n" |
| 456 "break <address> -- set break point at specified address\n" | 454 "h/help -- print this help string\n" |
| 457 "p/print <reg or icount or value or *addr> -- print integer\n" | 455 "break <address> -- set break point at specified address\n" |
| 458 "pf/printfloat <vreg or *addr> --print float value\n" | 456 "p/print <reg or icount or value or *addr> -- print integer\n" |
| 459 "pd/printdouble <vreg or *addr> -- print double value\n" | 457 "pf/printfloat <vreg or *addr> --print float value\n" |
| 460 "pq/printquad <vreg or *addr> -- print vector register\n" | 458 "pd/printdouble <vreg or *addr> -- print double value\n" |
| 461 "po/printobject <*reg or *addr> -- print object\n" | 459 "pq/printquad <vreg or *addr> -- print vector register\n" |
| 462 "si/stepi -- single step an instruction\n" | 460 "po/printobject <*reg or *addr> -- print object\n" |
| 463 "trace -- toggle execution tracing mode\n" | 461 "si/stepi -- single step an instruction\n" |
| 464 "bt -- print backtrace\n" | 462 "trace -- toggle execution tracing mode\n" |
| 465 "unstop -- if current pc is a stop instr make it a nop\n" | 463 "bt -- print backtrace\n" |
| 466 "q/quit -- Quit the debugger and exit the program\n"); | 464 "unstop -- if current pc is a stop instr make it a nop\n" |
| 465 "q/quit -- Quit the debugger and exit the program\n"); |
| 467 } else if ((strcmp(cmd, "quit") == 0) || (strcmp(cmd, "q") == 0)) { | 466 } else if ((strcmp(cmd, "quit") == 0) || (strcmp(cmd, "q") == 0)) { |
| 468 OS::Print("Quitting\n"); | 467 OS::Print("Quitting\n"); |
| 469 OS::Exit(0); | 468 OS::Exit(0); |
| 470 } else if ((strcmp(cmd, "si") == 0) || (strcmp(cmd, "stepi") == 0)) { | 469 } else if ((strcmp(cmd, "si") == 0) || (strcmp(cmd, "stepi") == 0)) { |
| 471 sim_->InstructionDecode(reinterpret_cast<Instr*>(sim_->get_pc())); | 470 sim_->InstructionDecode(reinterpret_cast<Instr*>(sim_->get_pc())); |
| 472 } else if ((strcmp(cmd, "c") == 0) || (strcmp(cmd, "cont") == 0)) { | 471 } else if ((strcmp(cmd, "c") == 0) || (strcmp(cmd, "cont") == 0)) { |
| 473 // Execute the one instruction we broke at with breakpoints disabled. | 472 // Execute the one instruction we broke at with breakpoints disabled. |
| 474 sim_->InstructionDecode(reinterpret_cast<Instr*>(sim_->get_pc())); | 473 sim_->InstructionDecode(reinterpret_cast<Instr*>(sim_->get_pc())); |
| 475 // Leave the debugger shell. | 474 // Leave the debugger shell. |
| 476 done = true; | 475 done = true; |
| 477 } else if ((strcmp(cmd, "p") == 0) || (strcmp(cmd, "print") == 0)) { | 476 } else if ((strcmp(cmd, "p") == 0) || (strcmp(cmd, "print") == 0)) { |
| 478 if (args == 2) { | 477 if (args == 2) { |
| 479 uint64_t value; | 478 uint64_t value; |
| 480 if (strcmp(arg1, "icount") == 0) { | 479 if (strcmp(arg1, "icount") == 0) { |
| 481 value = sim_->get_icount(); | 480 value = sim_->get_icount(); |
| 482 OS::Print("icount: %" Pu64 " 0x%" Px64 "\n", value, value); | 481 OS::Print("icount: %" Pu64 " 0x%" Px64 "\n", value, value); |
| 483 } else if (GetValue(arg1, &value)) { | 482 } else if (GetValue(arg1, &value)) { |
| 484 OS::Print("%s: %" Pu64 " 0x%" Px64 "\n", arg1, value, value); | 483 OS::Print("%s: %" Pu64 " 0x%" Px64 "\n", arg1, value, value); |
| 485 } else { | 484 } else { |
| 486 OS::Print("%s unrecognized\n", arg1); | 485 OS::Print("%s unrecognized\n", arg1); |
| 487 } | 486 } |
| 488 } else { | 487 } else { |
| 489 OS::Print("print <reg or icount or value or *addr>\n"); | 488 OS::Print("print <reg or icount or value or *addr>\n"); |
| 490 } | 489 } |
| 491 } else if ((strcmp(cmd, "pf") == 0) || | 490 } else if ((strcmp(cmd, "pf") == 0) || (strcmp(cmd, "printfloat") == 0)) { |
| 492 (strcmp(cmd, "printfloat") == 0)) { | |
| 493 if (args == 2) { | 491 if (args == 2) { |
| 494 uint32_t value; | 492 uint32_t value; |
| 495 if (GetSValue(arg1, &value)) { | 493 if (GetSValue(arg1, &value)) { |
| 496 float svalue = bit_cast<float, uint32_t>(value); | 494 float svalue = bit_cast<float, uint32_t>(value); |
| 497 OS::Print("%s: %d 0x%x %.8g\n", | 495 OS::Print("%s: %d 0x%x %.8g\n", arg1, value, value, svalue); |
| 498 arg1, value, value, svalue); | |
| 499 } else { | 496 } else { |
| 500 OS::Print("%s unrecognized\n", arg1); | 497 OS::Print("%s unrecognized\n", arg1); |
| 501 } | 498 } |
| 502 } else { | 499 } else { |
| 503 OS::Print("printfloat <vreg or *addr>\n"); | 500 OS::Print("printfloat <vreg or *addr>\n"); |
| 504 } | 501 } |
| 505 } else if ((strcmp(cmd, "pd") == 0) || | 502 } else if ((strcmp(cmd, "pd") == 0) || |
| 506 (strcmp(cmd, "printdouble") == 0)) { | 503 (strcmp(cmd, "printdouble") == 0)) { |
| 507 if (args == 2) { | 504 if (args == 2) { |
| 508 uint64_t long_value; | 505 uint64_t long_value; |
| 509 if (GetDValue(arg1, &long_value)) { | 506 if (GetDValue(arg1, &long_value)) { |
| 510 double dvalue = bit_cast<double, uint64_t>(long_value); | 507 double dvalue = bit_cast<double, uint64_t>(long_value); |
| 511 OS::Print("%s: %" Pu64 " 0x%" Px64 " %.8g\n", | 508 OS::Print("%s: %" Pu64 " 0x%" Px64 " %.8g\n", arg1, long_value, |
| 512 arg1, long_value, long_value, dvalue); | 509 long_value, dvalue); |
| 513 } else { | 510 } else { |
| 514 OS::Print("%s unrecognized\n", arg1); | 511 OS::Print("%s unrecognized\n", arg1); |
| 515 } | 512 } |
| 516 } else { | 513 } else { |
| 517 OS::Print("printdouble <vreg or *addr>\n"); | 514 OS::Print("printdouble <vreg or *addr>\n"); |
| 518 } | 515 } |
| 519 } else if ((strcmp(cmd, "pq") == 0) || | 516 } else if ((strcmp(cmd, "pq") == 0) || (strcmp(cmd, "printquad") == 0)) { |
| 520 (strcmp(cmd, "printquad") == 0)) { | |
| 521 if (args == 2) { | 517 if (args == 2) { |
| 522 simd_value_t quad_value; | 518 simd_value_t quad_value; |
| 523 if (GetQValue(arg1, &quad_value)) { | 519 if (GetQValue(arg1, &quad_value)) { |
| 524 const int64_t d0 = quad_value.bits.i64[0]; | 520 const int64_t d0 = quad_value.bits.i64[0]; |
| 525 const int64_t d1 = quad_value.bits.i64[1]; | 521 const int64_t d1 = quad_value.bits.i64[1]; |
| 526 const double dval0 = bit_cast<double, int64_t>(d0); | 522 const double dval0 = bit_cast<double, int64_t>(d0); |
| 527 const double dval1 = bit_cast<double, int64_t>(d1); | 523 const double dval1 = bit_cast<double, int64_t>(d1); |
| 528 const int32_t s0 = quad_value.bits.i32[0]; | 524 const int32_t s0 = quad_value.bits.i32[0]; |
| 529 const int32_t s1 = quad_value.bits.i32[1]; | 525 const int32_t s1 = quad_value.bits.i32[1]; |
| 530 const int32_t s2 = quad_value.bits.i32[2]; | 526 const int32_t s2 = quad_value.bits.i32[2]; |
| (...skipping 17 matching lines...) Expand all Loading... |
| 548 } else if ((strcmp(cmd, "po") == 0) || | 544 } else if ((strcmp(cmd, "po") == 0) || |
| 549 (strcmp(cmd, "printobject") == 0)) { | 545 (strcmp(cmd, "printobject") == 0)) { |
| 550 if (args == 2) { | 546 if (args == 2) { |
| 551 uint64_t value; | 547 uint64_t value; |
| 552 // Make the dereferencing '*' optional. | 548 // Make the dereferencing '*' optional. |
| 553 if (((arg1[0] == '*') && GetValue(arg1 + 1, &value)) || | 549 if (((arg1[0] == '*') && GetValue(arg1 + 1, &value)) || |
| 554 GetValue(arg1, &value)) { | 550 GetValue(arg1, &value)) { |
| 555 if (Isolate::Current()->heap()->Contains(value)) { | 551 if (Isolate::Current()->heap()->Contains(value)) { |
| 556 OS::Print("%s: \n", arg1); | 552 OS::Print("%s: \n", arg1); |
| 557 #if defined(DEBUG) | 553 #if defined(DEBUG) |
| 558 const Object& obj = Object::Handle( | 554 const Object& obj = |
| 559 reinterpret_cast<RawObject*>(value)); | 555 Object::Handle(reinterpret_cast<RawObject*>(value)); |
| 560 obj.Print(); | 556 obj.Print(); |
| 561 #endif // defined(DEBUG) | 557 #endif // defined(DEBUG) |
| 562 } else { | 558 } else { |
| 563 OS::Print("0x%" Px64 " is not an object reference\n", value); | 559 OS::Print("0x%" Px64 " is not an object reference\n", value); |
| 564 } | 560 } |
| 565 } else { | 561 } else { |
| 566 OS::Print("%s unrecognized\n", arg1); | 562 OS::Print("%s unrecognized\n", arg1); |
| 567 } | 563 } |
| 568 } else { | 564 } else { |
| 569 OS::Print("printobject <*reg or *addr>\n"); | 565 OS::Print("printobject <*reg or *addr>\n"); |
| (...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 680 OS::Print("%s", prompt); | 676 OS::Print("%s", prompt); |
| 681 while (keep_going) { | 677 while (keep_going) { |
| 682 if (fgets(line_buf, sizeof(line_buf), stdin) == NULL) { | 678 if (fgets(line_buf, sizeof(line_buf), stdin) == NULL) { |
| 683 // fgets got an error. Just give up. | 679 // fgets got an error. Just give up. |
| 684 if (result != NULL) { | 680 if (result != NULL) { |
| 685 delete[] result; | 681 delete[] result; |
| 686 } | 682 } |
| 687 return NULL; | 683 return NULL; |
| 688 } | 684 } |
| 689 intptr_t len = strlen(line_buf); | 685 intptr_t len = strlen(line_buf); |
| 690 if (len > 1 && | 686 if (len > 1 && line_buf[len - 2] == '\\' && line_buf[len - 1] == '\n') { |
| 691 line_buf[len - 2] == '\\' && | |
| 692 line_buf[len - 1] == '\n') { | |
| 693 // When we read a line that ends with a "\" we remove the escape and | 687 // When we read a line that ends with a "\" we remove the escape and |
| 694 // append the remainder. | 688 // append the remainder. |
| 695 line_buf[len - 2] = '\n'; | 689 line_buf[len - 2] = '\n'; |
| 696 line_buf[len - 1] = 0; | 690 line_buf[len - 1] = 0; |
| 697 len -= 1; | 691 len -= 1; |
| 698 } else if ((len > 0) && (line_buf[len - 1] == '\n')) { | 692 } else if ((len > 0) && (line_buf[len - 1] == '\n')) { |
| 699 // Since we read a new line we are done reading the line. This | 693 // Since we read a new line we are done reading the line. This |
| 700 // will exit the loop after copying this buffer into the result. | 694 // will exit the loop after copying this buffer into the result. |
| 701 keep_going = false; | 695 keep_going = false; |
| 702 } | 696 } |
| (...skipping 25 matching lines...) Expand all Loading... |
| 728 offset += len; | 722 offset += len; |
| 729 } | 723 } |
| 730 ASSERT(result != NULL); | 724 ASSERT(result != NULL); |
| 731 result[offset] = '\0'; | 725 result[offset] = '\0'; |
| 732 return result; | 726 return result; |
| 733 } | 727 } |
| 734 | 728 |
| 735 | 729 |
| 736 // Synchronization primitives support. | 730 // Synchronization primitives support. |
| 737 Mutex* Simulator::exclusive_access_lock_ = NULL; | 731 Mutex* Simulator::exclusive_access_lock_ = NULL; |
| 738 Simulator::AddressTag Simulator::exclusive_access_state_[kNumAddressTags] = | 732 Simulator::AddressTag Simulator::exclusive_access_state_[kNumAddressTags] = { |
| 739 {{NULL, 0}}; | 733 {NULL, 0}}; |
| 740 int Simulator::next_address_tag_ = 0; | 734 int Simulator::next_address_tag_ = 0; |
| 741 | 735 |
| 742 | 736 |
| 743 void Simulator::InitOnce() { | 737 void Simulator::InitOnce() { |
| 744 // Setup exclusive access state lock. | 738 // Setup exclusive access state lock. |
| 745 exclusive_access_lock_ = new Mutex(); | 739 exclusive_access_lock_ = new Mutex(); |
| 746 } | 740 } |
| 747 | 741 |
| 748 | 742 |
| 749 Simulator::Simulator() { | 743 Simulator::Simulator() { |
| 750 // Setup simulator support first. Some of this information is needed to | 744 // Setup simulator support first. Some of this information is needed to |
| 751 // setup the architecture state. | 745 // setup the architecture state. |
| 752 // We allocate the stack here, the size is computed as the sum of | 746 // We allocate the stack here, the size is computed as the sum of |
| 753 // the size specified by the user and the buffer space needed for | 747 // the size specified by the user and the buffer space needed for |
| 754 // handling stack overflow exceptions. To be safe in potential | 748 // handling stack overflow exceptions. To be safe in potential |
| 755 // stack underflows we also add some underflow buffer space. | 749 // stack underflows we also add some underflow buffer space. |
| 756 stack_ = new char[(OSThread::GetSpecifiedStackSize() + | 750 stack_ = |
| 757 OSThread::kStackSizeBuffer + | 751 new char[(OSThread::GetSpecifiedStackSize() + OSThread::kStackSizeBuffer + |
| 758 kSimulatorStackUnderflowSize)]; | 752 kSimulatorStackUnderflowSize)]; |
| 759 pc_modified_ = false; | 753 pc_modified_ = false; |
| 760 icount_ = 0; | 754 icount_ = 0; |
| 761 break_pc_ = NULL; | 755 break_pc_ = NULL; |
| 762 break_instr_ = 0; | 756 break_instr_ = 0; |
| 763 last_setjmp_buffer_ = NULL; | 757 last_setjmp_buffer_ = NULL; |
| 764 top_exit_frame_info_ = 0; | 758 top_exit_frame_info_ = 0; |
| 765 | 759 |
| 766 // Setup architecture state. | 760 // Setup architecture state. |
| 767 // All registers are initialized to zero to start with. | 761 // All registers are initialized to zero to start with. |
| 768 for (int i = 0; i < kNumberOfCpuRegisters; i++) { | 762 for (int i = 0; i < kNumberOfCpuRegisters; i++) { |
| (...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 850 : external_function_(external_function), | 844 : external_function_(external_function), |
| 851 call_kind_(call_kind), | 845 call_kind_(call_kind), |
| 852 argument_count_(argument_count), | 846 argument_count_(argument_count), |
| 853 hlt_instruction_(Instr::kSimulatorRedirectInstruction), | 847 hlt_instruction_(Instr::kSimulatorRedirectInstruction), |
| 854 next_(list_) { | 848 next_(list_) { |
| 855 // Atomically prepend this element to the front of the global list. | 849 // Atomically prepend this element to the front of the global list. |
| 856 // Note: Since elements are never removed, there is no ABA issue. | 850 // Note: Since elements are never removed, there is no ABA issue. |
| 857 Redirection* list_head = list_; | 851 Redirection* list_head = list_; |
| 858 do { | 852 do { |
| 859 next_ = list_head; | 853 next_ = list_head; |
| 860 list_head = reinterpret_cast<Redirection*>( | 854 list_head = |
| 861 AtomicOperations::CompareAndSwapWord( | 855 reinterpret_cast<Redirection*>(AtomicOperations::CompareAndSwapWord( |
| 862 reinterpret_cast<uword*>(&list_), | 856 reinterpret_cast<uword*>(&list_), reinterpret_cast<uword>(next_), |
| 863 reinterpret_cast<uword>(next_), | |
| 864 reinterpret_cast<uword>(this))); | 857 reinterpret_cast<uword>(this))); |
| 865 } while (list_head != next_); | 858 } while (list_head != next_); |
| 866 } | 859 } |
| 867 | 860 |
| 868 uword external_function_; | 861 uword external_function_; |
| 869 Simulator::CallKind call_kind_; | 862 Simulator::CallKind call_kind_; |
| 870 int argument_count_; | 863 int argument_count_; |
| 871 uint32_t hlt_instruction_; | 864 uint32_t hlt_instruction_; |
| 872 Redirection* next_; | 865 Redirection* next_; |
| 873 static Redirection* list_; | 866 static Redirection* list_; |
| (...skipping 22 matching lines...) Expand all Loading... |
| 896 Simulator* simulator = Isolate::Current()->simulator(); | 889 Simulator* simulator = Isolate::Current()->simulator(); |
| 897 if (simulator == NULL) { | 890 if (simulator == NULL) { |
| 898 simulator = new Simulator(); | 891 simulator = new Simulator(); |
| 899 Isolate::Current()->set_simulator(simulator); | 892 Isolate::Current()->set_simulator(simulator); |
| 900 } | 893 } |
| 901 return simulator; | 894 return simulator; |
| 902 } | 895 } |
| 903 | 896 |
| 904 | 897 |
| 905 // Sets the register in the architecture state. | 898 // Sets the register in the architecture state. |
| 906 void Simulator::set_register( | 899 void Simulator::set_register(Instr* instr, |
| 907 Instr* instr, Register reg, int64_t value, R31Type r31t) { | 900 Register reg, |
| 901 int64_t value, |
| 902 R31Type r31t) { |
| 908 // Register is in range. | 903 // Register is in range. |
| 909 ASSERT((reg >= 0) && (reg < kNumberOfCpuRegisters)); | 904 ASSERT((reg >= 0) && (reg < kNumberOfCpuRegisters)); |
| 910 ASSERT(instr == NULL || reg != R18); // R18 is globally reserved on iOS. | 905 ASSERT(instr == NULL || reg != R18); // R18 is globally reserved on iOS. |
| 911 if ((reg != R31) || (r31t != R31IsZR)) { | 906 if ((reg != R31) || (r31t != R31IsZR)) { |
| 912 registers_[reg] = value; | 907 registers_[reg] = value; |
| 913 // If we're setting CSP, make sure it is 16-byte aligned. In truth, CSP | 908 // If we're setting CSP, make sure it is 16-byte aligned. In truth, CSP |
| 914 // can store addresses that are not 16-byte aligned, but loads and stores | 909 // can store addresses that are not 16-byte aligned, but loads and stores |
| 915 // are not allowed through CSP when it is not aligned. Thus, this check is | 910 // are not allowed through CSP when it is not aligned. Thus, this check is |
| 916 // more conservative that necessary. However, it will likely be more | 911 // more conservative that necessary. However, it will likely be more |
| 917 // useful to find the program locations where CSP is set to a bad value, | 912 // useful to find the program locations where CSP is set to a bad value, |
| (...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1013 | 1008 |
| 1014 int64_t Simulator::get_last_pc() const { | 1009 int64_t Simulator::get_last_pc() const { |
| 1015 return last_pc_; | 1010 return last_pc_; |
| 1016 } | 1011 } |
| 1017 | 1012 |
| 1018 | 1013 |
| 1019 void Simulator::HandleIllegalAccess(uword addr, Instr* instr) { | 1014 void Simulator::HandleIllegalAccess(uword addr, Instr* instr) { |
| 1020 uword fault_pc = get_pc(); | 1015 uword fault_pc = get_pc(); |
| 1021 uword last_pc = get_last_pc(); | 1016 uword last_pc = get_last_pc(); |
| 1022 char buffer[128]; | 1017 char buffer[128]; |
| 1023 snprintf(buffer, sizeof(buffer), | 1018 snprintf(buffer, sizeof(buffer), "illegal memory access at 0x%" Px |
| 1024 "illegal memory access at 0x%" Px ", pc=0x%" Px ", last_pc=0x%" Px"\n", | 1019 ", pc=0x%" Px ", last_pc=0x%" Px "\n", |
| 1025 addr, fault_pc, last_pc); | 1020 addr, fault_pc, last_pc); |
| 1026 SimulatorDebugger dbg(this); | 1021 SimulatorDebugger dbg(this); |
| 1027 dbg.Stop(instr, buffer); | 1022 dbg.Stop(instr, buffer); |
| 1028 // The debugger will return control in non-interactive mode. | 1023 // The debugger will return control in non-interactive mode. |
| 1029 FATAL("Cannot continue execution after illegal memory access."); | 1024 FATAL("Cannot continue execution after illegal memory access."); |
| 1030 } | 1025 } |
| 1031 | 1026 |
| 1032 | 1027 |
| 1033 // The ARMv8 manual advises that an unaligned access may generate a fault, | 1028 // The ARMv8 manual advises that an unaligned access may generate a fault, |
| 1034 // and if not, will likely take a number of additional cycles to execute, | 1029 // and if not, will likely take a number of additional cycles to execute, |
| 1035 // so let's just not generate any. | 1030 // so let's just not generate any. |
| 1036 void Simulator::UnalignedAccess(const char* msg, uword addr, Instr* instr) { | 1031 void Simulator::UnalignedAccess(const char* msg, uword addr, Instr* instr) { |
| 1037 char buffer[128]; | 1032 char buffer[128]; |
| 1038 snprintf(buffer, sizeof(buffer), | 1033 snprintf(buffer, sizeof(buffer), "unaligned %s at 0x%" Px ", pc=%p\n", msg, |
| 1039 "unaligned %s at 0x%" Px ", pc=%p\n", msg, addr, instr); | 1034 addr, instr); |
| 1040 SimulatorDebugger dbg(this); | 1035 SimulatorDebugger dbg(this); |
| 1041 dbg.Stop(instr, buffer); | 1036 dbg.Stop(instr, buffer); |
| 1042 // The debugger will not be able to single step past this instruction, but | 1037 // The debugger will not be able to single step past this instruction, but |
| 1043 // it will be possible to disassemble the code and inspect registers. | 1038 // it will be possible to disassemble the code and inspect registers. |
| 1044 FATAL("Cannot continue execution after unaligned access."); | 1039 FATAL("Cannot continue execution after unaligned access."); |
| 1045 } | 1040 } |
| 1046 | 1041 |
| 1047 | 1042 |
| 1048 void Simulator::UnimplementedInstruction(Instr* instr) { | 1043 void Simulator::UnimplementedInstruction(Instr* instr) { |
| 1049 char buffer[128]; | 1044 char buffer[128]; |
| 1050 snprintf(buffer, sizeof(buffer), | 1045 snprintf(buffer, sizeof(buffer), |
| 1051 "Unimplemented instruction: at %p, last_pc=0x%" Px64 "\n", | 1046 "Unimplemented instruction: at %p, last_pc=0x%" Px64 "\n", instr, |
| 1052 instr, get_last_pc()); | 1047 get_last_pc()); |
| 1053 SimulatorDebugger dbg(this); | 1048 SimulatorDebugger dbg(this); |
| 1054 dbg.Stop(instr, buffer); | 1049 dbg.Stop(instr, buffer); |
| 1055 FATAL("Cannot continue execution after unimplemented instruction."); | 1050 FATAL("Cannot continue execution after unimplemented instruction."); |
| 1056 } | 1051 } |
| 1057 | 1052 |
| 1058 | 1053 |
| 1059 // Returns the top of the stack area to enable checking for stack pointer | 1054 // Returns the top of the stack area to enable checking for stack pointer |
| 1060 // validity. | 1055 // validity. |
| 1061 uword Simulator::StackTop() const { | 1056 uword Simulator::StackTop() const { |
| 1062 // To be safe in potential stack underflows we leave some buffer above and | 1057 // To be safe in potential stack underflows we leave some buffer above and |
| 1063 // set the stack top. | 1058 // set the stack top. |
| 1064 return StackBase() + | 1059 return StackBase() + |
| 1065 (OSThread::GetSpecifiedStackSize() + OSThread::kStackSizeBuffer); | 1060 (OSThread::GetSpecifiedStackSize() + OSThread::kStackSizeBuffer); |
| 1066 } | 1061 } |
| 1067 | 1062 |
| 1068 | 1063 |
| 1069 bool Simulator::IsTracingExecution() const { | 1064 bool Simulator::IsTracingExecution() const { |
| 1070 return icount_ > FLAG_trace_sim_after; | 1065 return icount_ > FLAG_trace_sim_after; |
| 1071 } | 1066 } |
| 1072 | 1067 |
| 1073 | 1068 |
| 1074 intptr_t Simulator::ReadX(uword addr, Instr* instr) { | 1069 intptr_t Simulator::ReadX(uword addr, Instr* instr) { |
| 1075 if ((addr & 7) == 0) { | 1070 if ((addr & 7) == 0) { |
| (...skipping 199 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1275 } else { | 1270 } else { |
| 1276 // Same effect on exclusive access state as an LDREX. | 1271 // Same effect on exclusive access state as an LDREX. |
| 1277 SetExclusiveAccess(reinterpret_cast<uword>(address)); | 1272 SetExclusiveAccess(reinterpret_cast<uword>(address)); |
| 1278 } | 1273 } |
| 1279 return value; | 1274 return value; |
| 1280 } | 1275 } |
| 1281 | 1276 |
| 1282 | 1277 |
| 1283 // Unsupported instructions use Format to print an error and stop execution. | 1278 // Unsupported instructions use Format to print an error and stop execution. |
| 1284 void Simulator::Format(Instr* instr, const char* format) { | 1279 void Simulator::Format(Instr* instr, const char* format) { |
| 1285 OS::Print("Simulator found unsupported instruction:\n 0x%p: %s\n", | 1280 OS::Print("Simulator found unsupported instruction:\n 0x%p: %s\n", instr, |
| 1286 instr, | |
| 1287 format); | 1281 format); |
| 1288 UNIMPLEMENTED(); | 1282 UNIMPLEMENTED(); |
| 1289 } | 1283 } |
| 1290 | 1284 |
| 1291 | 1285 |
| 1292 // Calculate and set the Negative and Zero flags. | 1286 // Calculate and set the Negative and Zero flags. |
| 1293 void Simulator::SetNZFlagsW(int32_t val) { | 1287 void Simulator::SetNZFlagsW(int32_t val) { |
| 1294 n_flag_ = (val < 0); | 1288 n_flag_ = (val < 0); |
| 1295 z_flag_ = (val == 0); | 1289 z_flag_ = (val == 0); |
| 1296 } | 1290 } |
| (...skipping 17 matching lines...) Expand all Loading... |
| 1314 | 1308 |
| 1315 // Calculate and set the Negative and Zero flags. | 1309 // Calculate and set the Negative and Zero flags. |
| 1316 void Simulator::SetNZFlagsX(int64_t val) { | 1310 void Simulator::SetNZFlagsX(int64_t val) { |
| 1317 n_flag_ = (val < 0); | 1311 n_flag_ = (val < 0); |
| 1318 z_flag_ = (val == 0); | 1312 z_flag_ = (val == 0); |
| 1319 } | 1313 } |
| 1320 | 1314 |
| 1321 | 1315 |
| 1322 // Calculate C flag value for additions and subtractions. | 1316 // Calculate C flag value for additions and subtractions. |
| 1323 bool Simulator::CarryFromX(int64_t alu_out, | 1317 bool Simulator::CarryFromX(int64_t alu_out, |
| 1324 int64_t left, int64_t right, bool addition) { | 1318 int64_t left, |
| 1319 int64_t right, |
| 1320 bool addition) { |
| 1325 if (addition) { | 1321 if (addition) { |
| 1326 return (((left & right) | ((left | right) & ~alu_out)) >> 63) != 0; | 1322 return (((left & right) | ((left | right) & ~alu_out)) >> 63) != 0; |
| 1327 } else { | 1323 } else { |
| 1328 return (((~left & right) | ((~left | right) & alu_out)) >> 63) == 0; | 1324 return (((~left & right) | ((~left | right) & alu_out)) >> 63) == 0; |
| 1329 } | 1325 } |
| 1330 } | 1326 } |
| 1331 | 1327 |
| 1332 | 1328 |
| 1333 // Calculate V flag value for additions and subtractions. | 1329 // Calculate V flag value for additions and subtractions. |
| 1334 bool Simulator::OverflowFromX(int64_t alu_out, | 1330 bool Simulator::OverflowFromX(int64_t alu_out, |
| 1335 int64_t left, int64_t right, bool addition) { | 1331 int64_t left, |
| 1332 int64_t right, |
| 1333 bool addition) { |
| 1336 if (addition) { | 1334 if (addition) { |
| 1337 return (((alu_out ^ left) & (alu_out ^ right)) >> 63) != 0; | 1335 return (((alu_out ^ left) & (alu_out ^ right)) >> 63) != 0; |
| 1338 } else { | 1336 } else { |
| 1339 return (((left ^ right) & (alu_out ^ left)) >> 63) != 0; | 1337 return (((left ^ right) & (alu_out ^ left)) >> 63) != 0; |
| 1340 } | 1338 } |
| 1341 } | 1339 } |
| 1342 | 1340 |
| 1343 | 1341 |
| 1344 // Set the Carry flag. | 1342 // Set the Carry flag. |
| 1345 void Simulator::SetCFlag(bool val) { | 1343 void Simulator::SetCFlag(bool val) { |
| 1346 c_flag_ = val; | 1344 c_flag_ = val; |
| 1347 } | 1345 } |
| 1348 | 1346 |
| 1349 | 1347 |
| 1350 // Set the oVerflow flag. | 1348 // Set the oVerflow flag. |
| 1351 void Simulator::SetVFlag(bool val) { | 1349 void Simulator::SetVFlag(bool val) { |
| 1352 v_flag_ = val; | 1350 v_flag_ = val; |
| 1353 } | 1351 } |
| 1354 | 1352 |
| 1355 | 1353 |
| 1356 void Simulator::DecodeMoveWide(Instr* instr) { | 1354 void Simulator::DecodeMoveWide(Instr* instr) { |
| 1357 const Register rd = instr->RdField(); | 1355 const Register rd = instr->RdField(); |
| 1358 const int hw = instr->HWField(); | 1356 const int hw = instr->HWField(); |
| 1359 const int64_t shift = hw << 4; | 1357 const int64_t shift = hw << 4; |
| 1360 const int64_t shifted_imm = | 1358 const int64_t shifted_imm = static_cast<int64_t>(instr->Imm16Field()) |
| 1361 static_cast<int64_t>(instr->Imm16Field()) << shift; | 1359 << shift; |
| 1362 | 1360 |
| 1363 if (instr->SFField()) { | 1361 if (instr->SFField()) { |
| 1364 if (instr->Bits(29, 2) == 0) { | 1362 if (instr->Bits(29, 2) == 0) { |
| 1365 // Format(instr, "movn'sf 'rd, 'imm16 'hw"); | 1363 // Format(instr, "movn'sf 'rd, 'imm16 'hw"); |
| 1366 set_register(instr, rd, ~shifted_imm, instr->RdMode()); | 1364 set_register(instr, rd, ~shifted_imm, instr->RdMode()); |
| 1367 } else if (instr->Bits(29, 2) == 2) { | 1365 } else if (instr->Bits(29, 2) == 2) { |
| 1368 // Format(instr, "movz'sf 'rd, 'imm16 'hw"); | 1366 // Format(instr, "movz'sf 'rd, 'imm16 'hw"); |
| 1369 set_register(instr, rd, shifted_imm, instr->RdMode()); | 1367 set_register(instr, rd, shifted_imm, instr->RdMode()); |
| 1370 } else if (instr->Bits(29, 2) == 3) { | 1368 } else if (instr->Bits(29, 2) == 3) { |
| 1371 // Format(instr, "movk'sf 'rd, 'imm16 'hw"); | 1369 // Format(instr, "movk'sf 'rd, 'imm16 'hw"); |
| 1372 const int64_t rd_val = get_register(rd, instr->RdMode()); | 1370 const int64_t rd_val = get_register(rd, instr->RdMode()); |
| 1373 const int64_t result = (rd_val & ~(0xffffL << shift)) | shifted_imm; | 1371 const int64_t result = (rd_val & ~(0xffffL << shift)) | shifted_imm; |
| 1374 set_register(instr, rd, result, instr->RdMode()); | 1372 set_register(instr, rd, result, instr->RdMode()); |
| 1375 } else { | 1373 } else { |
| 1376 UnimplementedInstruction(instr); | 1374 UnimplementedInstruction(instr); |
| 1377 } | 1375 } |
| 1378 } else if ((hw & 0x2) == 0) { | 1376 } else if ((hw & 0x2) == 0) { |
| 1379 if (instr->Bits(29, 2) == 0) { | 1377 if (instr->Bits(29, 2) == 0) { |
| 1380 // Format(instr, "movn'sf 'rd, 'imm16 'hw"); | 1378 // Format(instr, "movn'sf 'rd, 'imm16 'hw"); |
| 1381 set_wregister(rd, ~shifted_imm & kWRegMask, instr->RdMode()); | 1379 set_wregister(rd, ~shifted_imm & kWRegMask, instr->RdMode()); |
| 1382 } else if (instr->Bits(29, 2) == 2) { | 1380 } else if (instr->Bits(29, 2) == 2) { |
| 1383 // Format(instr, "movz'sf 'rd, 'imm16 'hw"); | 1381 // Format(instr, "movz'sf 'rd, 'imm16 'hw"); |
| 1384 set_wregister(rd, shifted_imm & kWRegMask, instr->RdMode()); | 1382 set_wregister(rd, shifted_imm & kWRegMask, instr->RdMode()); |
| 1385 } else if (instr->Bits(29, 2) == 3) { | 1383 } else if (instr->Bits(29, 2) == 3) { |
| 1386 // Format(instr, "movk'sf 'rd, 'imm16 'hw"); | 1384 // Format(instr, "movk'sf 'rd, 'imm16 'hw"); |
| 1387 const int32_t rd_val = get_wregister(rd, instr->RdMode()); | 1385 const int32_t rd_val = get_wregister(rd, instr->RdMode()); |
| 1388 const int32_t result = (rd_val & ~(0xffffL << shift)) | shifted_imm; | 1386 const int32_t result = (rd_val & ~(0xffffL << shift)) | shifted_imm; |
| 1389 set_wregister(rd, result, instr->RdMode()); | 1387 set_wregister(rd, result, instr->RdMode()); |
| 1390 } else { | 1388 } else { |
| 1391 UnimplementedInstruction(instr); | 1389 UnimplementedInstruction(instr); |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1431 SetVFlag(OverflowFromW(rn_val, imm, carry_in)); | 1429 SetVFlag(OverflowFromW(rn_val, imm, carry_in)); |
| 1432 } | 1430 } |
| 1433 } | 1431 } |
| 1434 } | 1432 } |
| 1435 | 1433 |
| 1436 | 1434 |
| 1437 void Simulator::DecodeLogicalImm(Instr* instr) { | 1435 void Simulator::DecodeLogicalImm(Instr* instr) { |
| 1438 const int op = instr->Bits(29, 2); | 1436 const int op = instr->Bits(29, 2); |
| 1439 const bool set_flags = op == 3; | 1437 const bool set_flags = op == 3; |
| 1440 const int out_size = ((instr->SFField() == 0) && (instr->NField() == 0)) | 1438 const int out_size = ((instr->SFField() == 0) && (instr->NField() == 0)) |
| 1441 ? kWRegSizeInBits : kXRegSizeInBits; | 1439 ? kWRegSizeInBits |
| 1440 : kXRegSizeInBits; |
| 1442 const Register rn = instr->RnField(); | 1441 const Register rn = instr->RnField(); |
| 1443 const Register rd = instr->RdField(); | 1442 const Register rd = instr->RdField(); |
| 1444 const int64_t rn_val = get_register(rn, instr->RnMode()); | 1443 const int64_t rn_val = get_register(rn, instr->RnMode()); |
| 1445 const uint64_t imm = instr->ImmLogical(); | 1444 const uint64_t imm = instr->ImmLogical(); |
| 1446 if (imm == 0) { | 1445 if (imm == 0) { |
| 1447 UnimplementedInstruction(instr); | 1446 UnimplementedInstruction(instr); |
| 1448 } | 1447 } |
| 1449 | 1448 |
| 1450 int64_t alu_out = 0; | 1449 int64_t alu_out = 0; |
| 1451 switch (op) { | 1450 switch (op) { |
| (...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1537 | 1536 |
| 1538 | 1537 |
| 1539 bool Simulator::ConditionallyExecute(Instr* instr) { | 1538 bool Simulator::ConditionallyExecute(Instr* instr) { |
| 1540 Condition cond; | 1539 Condition cond; |
| 1541 if (instr->IsConditionalSelectOp()) { | 1540 if (instr->IsConditionalSelectOp()) { |
| 1542 cond = instr->SelectConditionField(); | 1541 cond = instr->SelectConditionField(); |
| 1543 } else { | 1542 } else { |
| 1544 cond = instr->ConditionField(); | 1543 cond = instr->ConditionField(); |
| 1545 } | 1544 } |
| 1546 switch (cond) { | 1545 switch (cond) { |
| 1547 case EQ: return z_flag_; | 1546 case EQ: |
| 1548 case NE: return !z_flag_; | 1547 return z_flag_; |
| 1549 case CS: return c_flag_; | 1548 case NE: |
| 1550 case CC: return !c_flag_; | 1549 return !z_flag_; |
| 1551 case MI: return n_flag_; | 1550 case CS: |
| 1552 case PL: return !n_flag_; | 1551 return c_flag_; |
| 1553 case VS: return v_flag_; | 1552 case CC: |
| 1554 case VC: return !v_flag_; | 1553 return !c_flag_; |
| 1555 case HI: return c_flag_ && !z_flag_; | 1554 case MI: |
| 1556 case LS: return !c_flag_ || z_flag_; | 1555 return n_flag_; |
| 1557 case GE: return n_flag_ == v_flag_; | 1556 case PL: |
| 1558 case LT: return n_flag_ != v_flag_; | 1557 return !n_flag_; |
| 1559 case GT: return !z_flag_ && (n_flag_ == v_flag_); | 1558 case VS: |
| 1560 case LE: return z_flag_ || (n_flag_ != v_flag_); | 1559 return v_flag_; |
| 1561 case AL: return true; | 1560 case VC: |
| 1562 default: UNREACHABLE(); | 1561 return !v_flag_; |
| 1562 case HI: |
| 1563 return c_flag_ && !z_flag_; |
| 1564 case LS: |
| 1565 return !c_flag_ || z_flag_; |
| 1566 case GE: |
| 1567 return n_flag_ == v_flag_; |
| 1568 case LT: |
| 1569 return n_flag_ != v_flag_; |
| 1570 case GT: |
| 1571 return !z_flag_ && (n_flag_ == v_flag_); |
| 1572 case LE: |
| 1573 return z_flag_ || (n_flag_ != v_flag_); |
| 1574 case AL: |
| 1575 return true; |
| 1576 default: |
| 1577 UNREACHABLE(); |
| 1563 } | 1578 } |
| 1564 return false; | 1579 return false; |
| 1565 } | 1580 } |
| 1566 | 1581 |
| 1567 | 1582 |
| 1568 void Simulator::DecodeConditionalBranch(Instr* instr) { | 1583 void Simulator::DecodeConditionalBranch(Instr* instr) { |
| 1569 // Format(instr, "b'cond 'dest19"); | 1584 // Format(instr, "b'cond 'dest19"); |
| 1570 if ((instr->Bit(24) != 0) || (instr->Bit(4) != 0)) { | 1585 if ((instr->Bit(24) != 0) || (instr->Bit(4) != 0)) { |
| 1571 UnimplementedInstruction(instr); | 1586 UnimplementedInstruction(instr); |
| 1572 } | 1587 } |
| 1573 const int64_t imm19 = instr->SImm19Field(); | 1588 const int64_t imm19 = instr->SImm19Field(); |
| 1574 const int64_t dest = get_pc() + (imm19 << 2); | 1589 const int64_t dest = get_pc() + (imm19 << 2); |
| 1575 if (ConditionallyExecute(instr)) { | 1590 if (ConditionallyExecute(instr)) { |
| 1576 set_pc(dest); | 1591 set_pc(dest); |
| 1577 } | 1592 } |
| 1578 } | 1593 } |
| 1579 | 1594 |
| 1580 | 1595 |
| 1581 // Calls into the Dart runtime are based on this interface. | 1596 // Calls into the Dart runtime are based on this interface. |
| 1582 typedef void (*SimulatorRuntimeCall)(NativeArguments arguments); | 1597 typedef void (*SimulatorRuntimeCall)(NativeArguments arguments); |
| 1583 | 1598 |
| 1584 // Calls to leaf Dart runtime functions are based on this interface. | 1599 // Calls to leaf Dart runtime functions are based on this interface. |
| 1585 typedef int64_t (*SimulatorLeafRuntimeCall)( | 1600 typedef int64_t (*SimulatorLeafRuntimeCall)(int64_t r0, |
| 1586 int64_t r0, int64_t r1, int64_t r2, int64_t r3, | 1601 int64_t r1, |
| 1587 int64_t r4, int64_t r5, int64_t r6, int64_t r7); | 1602 int64_t r2, |
| 1603 int64_t r3, |
| 1604 int64_t r4, |
| 1605 int64_t r5, |
| 1606 int64_t r6, |
| 1607 int64_t r7); |
| 1588 | 1608 |
| 1589 // Calls to leaf float Dart runtime functions are based on this interface. | 1609 // Calls to leaf float Dart runtime functions are based on this interface. |
| 1590 typedef double (*SimulatorLeafFloatRuntimeCall)( | 1610 typedef double (*SimulatorLeafFloatRuntimeCall)(double d0, |
| 1591 double d0, double d1, double d2, double d3, | 1611 double d1, |
| 1592 double d4, double d5, double d6, double d7); | 1612 double d2, |
| 1613 double d3, |
| 1614 double d4, |
| 1615 double d5, |
| 1616 double d6, |
| 1617 double d7); |
| 1593 | 1618 |
| 1594 // Calls to native Dart functions are based on this interface. | 1619 // Calls to native Dart functions are based on this interface. |
| 1595 typedef void (*SimulatorBootstrapNativeCall)(NativeArguments* arguments); | 1620 typedef void (*SimulatorBootstrapNativeCall)(NativeArguments* arguments); |
| 1596 typedef void (*SimulatorNativeCall)(NativeArguments* arguments, uword target); | 1621 typedef void (*SimulatorNativeCall)(NativeArguments* arguments, uword target); |
| 1597 | 1622 |
| 1598 | 1623 |
| 1599 void Simulator::DoRedirectedCall(Instr* instr) { | 1624 void Simulator::DoRedirectedCall(Instr* instr) { |
| 1600 SimulatorSetjmpBuffer buffer(this); | 1625 SimulatorSetjmpBuffer buffer(this); |
| 1601 if (!setjmp(buffer.buffer_)) { | 1626 if (!setjmp(buffer.buffer_)) { |
| 1602 int64_t saved_lr = get_register(LR); | 1627 int64_t saved_lr = get_register(LR); |
| (...skipping 25 matching lines...) Expand all Loading... |
| 1628 reinterpret_cast<SimulatorLeafRuntimeCall>(external); | 1653 reinterpret_cast<SimulatorLeafRuntimeCall>(external); |
| 1629 const int64_t r0 = get_register(R0); | 1654 const int64_t r0 = get_register(R0); |
| 1630 const int64_t r1 = get_register(R1); | 1655 const int64_t r1 = get_register(R1); |
| 1631 const int64_t r2 = get_register(R2); | 1656 const int64_t r2 = get_register(R2); |
| 1632 const int64_t r3 = get_register(R3); | 1657 const int64_t r3 = get_register(R3); |
| 1633 const int64_t r4 = get_register(R4); | 1658 const int64_t r4 = get_register(R4); |
| 1634 const int64_t r5 = get_register(R5); | 1659 const int64_t r5 = get_register(R5); |
| 1635 const int64_t r6 = get_register(R6); | 1660 const int64_t r6 = get_register(R6); |
| 1636 const int64_t r7 = get_register(R7); | 1661 const int64_t r7 = get_register(R7); |
| 1637 const int64_t res = target(r0, r1, r2, r3, r4, r5, r6, r7); | 1662 const int64_t res = target(r0, r1, r2, r3, r4, r5, r6, r7); |
| 1638 set_register(instr, R0, res); // Set returned result from function. | 1663 set_register(instr, R0, res); // Set returned result from function. |
| 1639 set_register(instr, R1, icount_); // Zap unused result register. | 1664 set_register(instr, R1, icount_); // Zap unused result register. |
| 1640 } else if (redirection->call_kind() == kLeafFloatRuntimeCall) { | 1665 } else if (redirection->call_kind() == kLeafFloatRuntimeCall) { |
| 1641 ASSERT((0 <= redirection->argument_count()) && | 1666 ASSERT((0 <= redirection->argument_count()) && |
| 1642 (redirection->argument_count() <= 8)); | 1667 (redirection->argument_count() <= 8)); |
| 1643 SimulatorLeafFloatRuntimeCall target = | 1668 SimulatorLeafFloatRuntimeCall target = |
| 1644 reinterpret_cast<SimulatorLeafFloatRuntimeCall>(external); | 1669 reinterpret_cast<SimulatorLeafFloatRuntimeCall>(external); |
| 1645 const double d0 = bit_cast<double, int64_t>(get_vregisterd(V0, 0)); | 1670 const double d0 = bit_cast<double, int64_t>(get_vregisterd(V0, 0)); |
| 1646 const double d1 = bit_cast<double, int64_t>(get_vregisterd(V1, 0)); | 1671 const double d1 = bit_cast<double, int64_t>(get_vregisterd(V1, 0)); |
| 1647 const double d2 = bit_cast<double, int64_t>(get_vregisterd(V2, 0)); | 1672 const double d2 = bit_cast<double, int64_t>(get_vregisterd(V2, 0)); |
| 1648 const double d3 = bit_cast<double, int64_t>(get_vregisterd(V3, 0)); | 1673 const double d3 = bit_cast<double, int64_t>(get_vregisterd(V3, 0)); |
| (...skipping 209 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1858 } | 1883 } |
| 1859 } | 1884 } |
| 1860 | 1885 |
| 1861 | 1886 |
| 1862 void Simulator::DecodeLoadStoreReg(Instr* instr) { | 1887 void Simulator::DecodeLoadStoreReg(Instr* instr) { |
| 1863 // Calculate the address. | 1888 // Calculate the address. |
| 1864 const Register rn = instr->RnField(); | 1889 const Register rn = instr->RnField(); |
| 1865 const Register rt = instr->RtField(); | 1890 const Register rt = instr->RtField(); |
| 1866 const VRegister vt = instr->VtField(); | 1891 const VRegister vt = instr->VtField(); |
| 1867 const int64_t rn_val = get_register(rn, R31IsSP); | 1892 const int64_t rn_val = get_register(rn, R31IsSP); |
| 1868 const uint32_t size = | 1893 const uint32_t size = (instr->Bit(26) == 1) |
| 1869 (instr->Bit(26) == 1) ? ((instr->Bit(23) << 2) | instr->SzField()) | 1894 ? ((instr->Bit(23) << 2) | instr->SzField()) |
| 1870 : instr->SzField(); | 1895 : instr->SzField(); |
| 1871 uword address = 0; | 1896 uword address = 0; |
| 1872 uword wb_address = 0; | 1897 uword wb_address = 0; |
| 1873 bool wb = false; | 1898 bool wb = false; |
| 1874 if (instr->Bit(24) == 1) { | 1899 if (instr->Bit(24) == 1) { |
| 1875 // addr = rn + scaled unsigned 12-bit immediate offset. | 1900 // addr = rn + scaled unsigned 12-bit immediate offset. |
| 1876 const uint32_t imm12 = static_cast<uint32_t>(instr->Imm12Field()); | 1901 const uint32_t imm12 = static_cast<uint32_t>(instr->Imm12Field()); |
| 1877 const uint32_t offset = imm12 << size; | 1902 const uint32_t offset = imm12 << size; |
| 1878 address = rn_val + offset; | 1903 address = rn_val + offset; |
| 1879 } else if (instr->Bits(10, 2) == 0) { | 1904 } else if (instr->Bits(10, 2) == 0) { |
| 1880 // addr = rn + signed 9-bit immediate offset. | 1905 // addr = rn + signed 9-bit immediate offset. |
| 1881 wb = false; | 1906 wb = false; |
| 1882 const int64_t offset = static_cast<int64_t>(instr->SImm9Field()); | 1907 const int64_t offset = static_cast<int64_t>(instr->SImm9Field()); |
| 1883 address = rn_val + offset; | 1908 address = rn_val + offset; |
| 1884 wb_address = rn_val; | 1909 wb_address = rn_val; |
| 1885 } else if (instr->Bit(10) == 1) { | 1910 } else if (instr->Bit(10) == 1) { |
| 1886 // addr = rn + signed 9-bit immediate offset. | 1911 // addr = rn + signed 9-bit immediate offset. |
| 1887 wb = true; | 1912 wb = true; |
| 1888 const int64_t offset = static_cast<int64_t>(instr->SImm9Field()); | 1913 const int64_t offset = static_cast<int64_t>(instr->SImm9Field()); |
| 1889 if (instr->Bit(11) == 1) { | 1914 if (instr->Bit(11) == 1) { |
| 1890 // Pre-index. | 1915 // Pre-index. |
| 1891 address = rn_val + offset; | 1916 address = rn_val + offset; |
| 1892 wb_address = address; | 1917 wb_address = address; |
| 1893 } else { | 1918 } else { |
| 1894 // Post-index. | 1919 // Post-index. |
| 1895 address = rn_val; | 1920 address = rn_val; |
| 1896 wb_address = rn_val + offset; | 1921 wb_address = rn_val + offset; |
| 1897 } | 1922 } |
| 1898 } else if (instr->Bits(10, 2) == 2) { | 1923 } else if (instr->Bits(10, 2) == 2) { |
| 1899 // addr = rn + (rm EXT optionally scaled by operand instruction size). | 1924 // addr = rn + (rm EXT optionally scaled by operand instruction size). |
| 1900 const Register rm = instr->RmField(); | 1925 const Register rm = instr->RmField(); |
| 1901 const Extend ext = instr->ExtendTypeField(); | 1926 const Extend ext = instr->ExtendTypeField(); |
| 1902 const uint8_t scale = | 1927 const uint8_t scale = (ext == UXTX) && (instr->Bit(12) == 1) ? size : 0; |
| 1903 (ext == UXTX) && (instr->Bit(12) == 1) ? size : 0; | |
| 1904 const int64_t rm_val = get_register(rm, R31IsZR); | 1928 const int64_t rm_val = get_register(rm, R31IsZR); |
| 1905 const int64_t offset = ExtendOperand(kXRegSizeInBits, rm_val, ext, scale); | 1929 const int64_t offset = ExtendOperand(kXRegSizeInBits, rm_val, ext, scale); |
| 1906 address = rn_val + offset; | 1930 address = rn_val + offset; |
| 1907 } else { | 1931 } else { |
| 1908 UnimplementedInstruction(instr); | 1932 UnimplementedInstruction(instr); |
| 1909 return; | 1933 return; |
| 1910 } | 1934 } |
| 1911 | 1935 |
| 1912 // Check the address. | 1936 // Check the address. |
| 1913 if (IsIllegalAddress(address)) { | 1937 if (IsIllegalAddress(address)) { |
| (...skipping 249 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2163 // Format(instr, "ldrx 'rt, 'pcldr"); | 2187 // Format(instr, "ldrx 'rt, 'pcldr"); |
| 2164 set_register(instr, rt, val, R31IsZR); | 2188 set_register(instr, rt, val, R31IsZR); |
| 2165 } else { | 2189 } else { |
| 2166 // Format(instr, "ldrw 'rt, 'pcldr"); | 2190 // Format(instr, "ldrw 'rt, 'pcldr"); |
| 2167 set_wregister(rt, static_cast<int32_t>(val), R31IsZR); | 2191 set_wregister(rt, static_cast<int32_t>(val), R31IsZR); |
| 2168 } | 2192 } |
| 2169 } | 2193 } |
| 2170 | 2194 |
| 2171 | 2195 |
| 2172 void Simulator::DecodeLoadStoreExclusive(Instr* instr) { | 2196 void Simulator::DecodeLoadStoreExclusive(Instr* instr) { |
| 2173 if ((instr->Bit(23) != 0) || | 2197 if ((instr->Bit(23) != 0) || (instr->Bit(21) != 0) || (instr->Bit(15) != 0)) { |
| 2174 (instr->Bit(21) != 0) || | |
| 2175 (instr->Bit(15) != 0)) { | |
| 2176 UNIMPLEMENTED(); | 2198 UNIMPLEMENTED(); |
| 2177 } | 2199 } |
| 2178 const int32_t size = instr->Bits(30, 2); | 2200 const int32_t size = instr->Bits(30, 2); |
| 2179 if (size != 3) { | 2201 if (size != 3) { |
| 2180 UNIMPLEMENTED(); | 2202 UNIMPLEMENTED(); |
| 2181 } | 2203 } |
| 2182 | 2204 |
| 2183 const Register rs = instr->RsField(); | 2205 const Register rs = instr->RsField(); |
| 2184 const Register rn = instr->RnField(); | 2206 const Register rn = instr->RnField(); |
| 2185 const Register rt = instr->RtField(); | 2207 const Register rt = instr->RtField(); |
| (...skipping 580 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2766 const Register rn = instr->RnField(); | 2788 const Register rn = instr->RnField(); |
| 2767 const Register rd = instr->RdField(); | 2789 const Register rd = instr->RdField(); |
| 2768 if ((op == 0) && (imm4 == 7)) { | 2790 if ((op == 0) && (imm4 == 7)) { |
| 2769 if (Q == 0) { | 2791 if (Q == 0) { |
| 2770 // Format(instr, "vmovrs 'rd, 'vn'idx5"); | 2792 // Format(instr, "vmovrs 'rd, 'vn'idx5"); |
| 2771 set_wregister(rd, get_vregisters(vn, idx5), R31IsZR); | 2793 set_wregister(rd, get_vregisters(vn, idx5), R31IsZR); |
| 2772 } else { | 2794 } else { |
| 2773 // Format(instr, "vmovrd 'rd, 'vn'idx5"); | 2795 // Format(instr, "vmovrd 'rd, 'vn'idx5"); |
| 2774 set_register(instr, rd, get_vregisterd(vn, idx5), R31IsZR); | 2796 set_register(instr, rd, get_vregisterd(vn, idx5), R31IsZR); |
| 2775 } | 2797 } |
| 2776 } else if ((Q == 1) && (op == 0) && (imm4 == 0)) { | 2798 } else if ((Q == 1) && (op == 0) && (imm4 == 0)) { |
| 2777 // Format(instr, "vdup'csz 'vd, 'vn'idx5"); | 2799 // Format(instr, "vdup'csz 'vd, 'vn'idx5"); |
| 2778 if (element_bytes == 4) { | 2800 if (element_bytes == 4) { |
| 2779 for (int i = 0; i < 4; i++) { | 2801 for (int i = 0; i < 4; i++) { |
| 2780 set_vregisters(vd, i, get_vregisters(vn, idx5)); | 2802 set_vregisters(vd, i, get_vregisters(vn, idx5)); |
| 2781 } | 2803 } |
| 2782 } else if (element_bytes == 8) { | 2804 } else if (element_bytes == 8) { |
| 2783 for (int i = 0; i < 2; i++) { | 2805 for (int i = 0; i < 2; i++) { |
| 2784 set_vregisterd(vd, i, get_vregisterd(vn, idx5)); | 2806 set_vregisterd(vd, i, get_vregisterd(vn, idx5)); |
| 2785 } | 2807 } |
| 2786 } else { | 2808 } else { |
| (...skipping 190 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2977 return; | 2999 return; |
| 2978 } | 3000 } |
| 2979 set_vregisterd(vd, idx, res); | 3001 set_vregisterd(vd, idx, res); |
| 2980 } | 3002 } |
| 2981 } | 3003 } |
| 2982 } | 3004 } |
| 2983 | 3005 |
| 2984 | 3006 |
| 2985 static float arm_reciprocal_sqrt_estimate(float a) { | 3007 static float arm_reciprocal_sqrt_estimate(float a) { |
| 2986 // From the ARM Architecture Reference Manual A2-87. | 3008 // From the ARM Architecture Reference Manual A2-87. |
| 2987 if (isinf(a) || (fabs(a) >= exp2f(126))) return 0.0; | 3009 if (isinf(a) || (fabs(a) >= exp2f(126))) |
| 2988 else if (a == 0.0) return kPosInfinity; | 3010 return 0.0; |
| 2989 else if (isnan(a)) return a; | 3011 else if (a == 0.0) |
| 3012 return kPosInfinity; |
| 3013 else if (isnan(a)) |
| 3014 return a; |
| 2990 | 3015 |
| 2991 uint32_t a_bits = bit_cast<uint32_t, float>(a); | 3016 uint32_t a_bits = bit_cast<uint32_t, float>(a); |
| 2992 uint64_t scaled; | 3017 uint64_t scaled; |
| 2993 if (((a_bits >> 23) & 1) != 0) { | 3018 if (((a_bits >> 23) & 1) != 0) { |
| 2994 // scaled = '0 01111111101' : operand<22:0> : Zeros(29) | 3019 // scaled = '0 01111111101' : operand<22:0> : Zeros(29) |
| 2995 scaled = (static_cast<uint64_t>(0x3fd) << 52) | | 3020 scaled = (static_cast<uint64_t>(0x3fd) << 52) | |
| 2996 ((static_cast<uint64_t>(a_bits) & 0x7fffff) << 29); | 3021 ((static_cast<uint64_t>(a_bits) & 0x7fffff) << 29); |
| 2997 } else { | 3022 } else { |
| 2998 // scaled = '0 01111111110' : operand<22:0> : Zeros(29) | 3023 // scaled = '0 01111111110' : operand<22:0> : Zeros(29) |
| 2999 scaled = (static_cast<uint64_t>(0x3fe) << 52) | | 3024 scaled = (static_cast<uint64_t>(0x3fe) << 52) | |
| (...skipping 17 matching lines...) Expand all Loading... |
| 3017 // range 0.5 <= a < 1.0 | 3042 // range 0.5 <= a < 1.0 |
| 3018 | 3043 |
| 3019 // a in units of 1/256 rounded down. | 3044 // a in units of 1/256 rounded down. |
| 3020 int32_t q1 = static_cast<int32_t>(scaled_d * 256.0); | 3045 int32_t q1 = static_cast<int32_t>(scaled_d * 256.0); |
| 3021 // reciprocal root r. | 3046 // reciprocal root r. |
| 3022 r = 1.0 / sqrt((static_cast<double>(q1) + 0.5) / 256.0); | 3047 r = 1.0 / sqrt((static_cast<double>(q1) + 0.5) / 256.0); |
| 3023 } | 3048 } |
| 3024 // r in units of 1/256 rounded to nearest. | 3049 // r in units of 1/256 rounded to nearest. |
| 3025 int32_t s = static_cast<int>(256.0 * r + 0.5); | 3050 int32_t s = static_cast<int>(256.0 * r + 0.5); |
| 3026 double estimate = static_cast<double>(s) / 256.0; | 3051 double estimate = static_cast<double>(s) / 256.0; |
| 3027 ASSERT((estimate >= 1.0) && (estimate <= (511.0/256.0))); | 3052 ASSERT((estimate >= 1.0) && (estimate <= (511.0 / 256.0))); |
| 3028 | 3053 |
| 3029 // result = 0 : result_exp<7:0> : estimate<51:29> | 3054 // result = 0 : result_exp<7:0> : estimate<51:29> |
| 3030 int32_t result_bits = ((result_exp & 0xff) << 23) | | 3055 int32_t result_bits = |
| 3056 ((result_exp & 0xff) << 23) | |
| 3031 ((bit_cast<uint64_t, double>(estimate) >> 29) & 0x7fffff); | 3057 ((bit_cast<uint64_t, double>(estimate) >> 29) & 0x7fffff); |
| 3032 return bit_cast<float, int32_t>(result_bits); | 3058 return bit_cast<float, int32_t>(result_bits); |
| 3033 } | 3059 } |
| 3034 | 3060 |
| 3035 | 3061 |
| 3036 static float arm_recip_estimate(float a) { | 3062 static float arm_recip_estimate(float a) { |
| 3037 // From the ARM Architecture Reference Manual A2-85. | 3063 // From the ARM Architecture Reference Manual A2-85. |
| 3038 if (isinf(a) || (fabs(a) >= exp2f(126))) return 0.0; | 3064 if (isinf(a) || (fabs(a) >= exp2f(126))) |
| 3039 else if (a == 0.0) return kPosInfinity; | 3065 return 0.0; |
| 3040 else if (isnan(a)) return a; | 3066 else if (a == 0.0) |
| 3067 return kPosInfinity; |
| 3068 else if (isnan(a)) |
| 3069 return a; |
| 3041 | 3070 |
| 3042 uint32_t a_bits = bit_cast<uint32_t, float>(a); | 3071 uint32_t a_bits = bit_cast<uint32_t, float>(a); |
| 3043 // scaled = '0011 1111 1110' : a<22:0> : Zeros(29) | 3072 // scaled = '0011 1111 1110' : a<22:0> : Zeros(29) |
| 3044 uint64_t scaled = (static_cast<uint64_t>(0x3fe) << 52) | | 3073 uint64_t scaled = (static_cast<uint64_t>(0x3fe) << 52) | |
| 3045 ((static_cast<uint64_t>(a_bits) & 0x7fffff) << 29); | 3074 ((static_cast<uint64_t>(a_bits) & 0x7fffff) << 29); |
| 3046 // result_exp = 253 - UInt(a<30:23>) | 3075 // result_exp = 253 - UInt(a<30:23>) |
| 3047 int32_t result_exp = 253 - ((a_bits >> 23) & 0xff); | 3076 int32_t result_exp = 253 - ((a_bits >> 23) & 0xff); |
| 3048 ASSERT((result_exp >= 1) && (result_exp <= 252)); | 3077 ASSERT((result_exp >= 1) && (result_exp <= 252)); |
| 3049 | 3078 |
| 3050 double scaled_d = bit_cast<double, uint64_t>(scaled); | 3079 double scaled_d = bit_cast<double, uint64_t>(scaled); |
| 3051 ASSERT((scaled_d >= 0.5) && (scaled_d < 1.0)); | 3080 ASSERT((scaled_d >= 0.5) && (scaled_d < 1.0)); |
| 3052 | 3081 |
| 3053 // a in units of 1/512 rounded down. | 3082 // a in units of 1/512 rounded down. |
| 3054 int32_t q = static_cast<int32_t>(scaled_d * 512.0); | 3083 int32_t q = static_cast<int32_t>(scaled_d * 512.0); |
| 3055 // reciprocal r. | 3084 // reciprocal r. |
| 3056 double r = 1.0 / ((static_cast<double>(q) + 0.5) / 512.0); | 3085 double r = 1.0 / ((static_cast<double>(q) + 0.5) / 512.0); |
| 3057 // r in units of 1/256 rounded to nearest. | 3086 // r in units of 1/256 rounded to nearest. |
| 3058 int32_t s = static_cast<int32_t>(256.0 * r + 0.5); | 3087 int32_t s = static_cast<int32_t>(256.0 * r + 0.5); |
| 3059 double estimate = static_cast<double>(s) / 256.0; | 3088 double estimate = static_cast<double>(s) / 256.0; |
| 3060 ASSERT((estimate >= 1.0) && (estimate <= (511.0/256.0))); | 3089 ASSERT((estimate >= 1.0) && (estimate <= (511.0 / 256.0))); |
| 3061 | 3090 |
| 3062 // result = sign : result_exp<7:0> : estimate<51:29> | 3091 // result = sign : result_exp<7:0> : estimate<51:29> |
| 3063 int32_t result_bits = | 3092 int32_t result_bits = |
| 3064 (a_bits & 0x80000000) | ((result_exp & 0xff) << 23) | | 3093 (a_bits & 0x80000000) | ((result_exp & 0xff) << 23) | |
| 3065 ((bit_cast<uint64_t, double>(estimate) >> 29) & 0x7fffff); | 3094 ((bit_cast<uint64_t, double>(estimate) >> 29) & 0x7fffff); |
| 3066 return bit_cast<float, int32_t>(result_bits); | 3095 return bit_cast<float, int32_t>(result_bits); |
| 3067 } | 3096 } |
| 3068 | 3097 |
| 3069 | 3098 |
| 3070 void Simulator::DecodeSIMDTwoReg(Instr* instr) { | 3099 void Simulator::DecodeSIMDTwoReg(Instr* instr) { |
| (...skipping 139 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3210 | 3239 |
| 3211 if ((instr->Bit(29) != 0) || (instr->Bits(22, 2) != 1) || | 3240 if ((instr->Bit(29) != 0) || (instr->Bits(22, 2) != 1) || |
| 3212 ((instr->SFField() == 0) && (instr->Bits(16, 5) != 2))) { | 3241 ((instr->SFField() == 0) && (instr->Bits(16, 5) != 2))) { |
| 3213 UnimplementedInstruction(instr); | 3242 UnimplementedInstruction(instr); |
| 3214 return; | 3243 return; |
| 3215 } | 3244 } |
| 3216 if (instr->Bits(16, 5) == 2) { | 3245 if (instr->Bits(16, 5) == 2) { |
| 3217 // Format(instr, "scvtfd'sf 'vd, 'rn"); | 3246 // Format(instr, "scvtfd'sf 'vd, 'rn"); |
| 3218 const int64_t rn_val64 = get_register(rn, instr->RnMode()); | 3247 const int64_t rn_val64 = get_register(rn, instr->RnMode()); |
| 3219 const int32_t rn_val32 = get_wregister(rn, instr->RnMode()); | 3248 const int32_t rn_val32 = get_wregister(rn, instr->RnMode()); |
| 3220 const double vn_dbl = (instr->SFField() == 1) ? | 3249 const double vn_dbl = (instr->SFField() == 1) |
| 3221 static_cast<double>(rn_val64) : static_cast<double>(rn_val32); | 3250 ? static_cast<double>(rn_val64) |
| 3251 : static_cast<double>(rn_val32); |
| 3222 set_vregisterd(vd, 0, bit_cast<int64_t, double>(vn_dbl)); | 3252 set_vregisterd(vd, 0, bit_cast<int64_t, double>(vn_dbl)); |
| 3223 set_vregisterd(vd, 1, 0); | 3253 set_vregisterd(vd, 1, 0); |
| 3224 } else if (instr->Bits(16, 5) == 6) { | 3254 } else if (instr->Bits(16, 5) == 6) { |
| 3225 // Format(instr, "fmovrd'sf 'rd, 'vn"); | 3255 // Format(instr, "fmovrd'sf 'rd, 'vn"); |
| 3226 const int64_t vn_val = get_vregisterd(vn, 0); | 3256 const int64_t vn_val = get_vregisterd(vn, 0); |
| 3227 set_register(instr, rd, vn_val, R31IsZR); | 3257 set_register(instr, rd, vn_val, R31IsZR); |
| 3228 } else if (instr->Bits(16, 5) == 7) { | 3258 } else if (instr->Bits(16, 5) == 7) { |
| 3229 // Format(instr, "fmovdr'sf 'vd, 'rn"); | 3259 // Format(instr, "fmovdr'sf 'vd, 'rn"); |
| 3230 const int64_t rn_val = get_register(rn, R31IsZR); | 3260 const int64_t rn_val = get_register(rn, R31IsZR); |
| 3231 set_vregisterd(vd, 0, rn_val); | 3261 set_vregisterd(vd, 0, rn_val); |
| (...skipping 366 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3598 set_register(NULL, THR, reinterpret_cast<int64_t>(thread)); | 3628 set_register(NULL, THR, reinterpret_cast<int64_t>(thread)); |
| 3599 // Set the tag. | 3629 // Set the tag. |
| 3600 thread->set_vm_tag(VMTag::kDartTagId); | 3630 thread->set_vm_tag(VMTag::kDartTagId); |
| 3601 // Clear top exit frame. | 3631 // Clear top exit frame. |
| 3602 thread->set_top_exit_frame_info(0); | 3632 thread->set_top_exit_frame_info(0); |
| 3603 | 3633 |
| 3604 ASSERT(raw_exception != Object::null()); | 3634 ASSERT(raw_exception != Object::null()); |
| 3605 set_register(NULL, kExceptionObjectReg, bit_cast<int64_t>(raw_exception)); | 3635 set_register(NULL, kExceptionObjectReg, bit_cast<int64_t>(raw_exception)); |
| 3606 set_register(NULL, kStackTraceObjectReg, bit_cast<int64_t>(raw_stacktrace)); | 3636 set_register(NULL, kStackTraceObjectReg, bit_cast<int64_t>(raw_stacktrace)); |
| 3607 // Restore pool pointer. | 3637 // Restore pool pointer. |
| 3608 int64_t code = *reinterpret_cast<int64_t*>( | 3638 int64_t code = |
| 3609 fp + kPcMarkerSlotFromFp * kWordSize); | 3639 *reinterpret_cast<int64_t*>(fp + kPcMarkerSlotFromFp * kWordSize); |
| 3610 int64_t pp = *reinterpret_cast<int64_t*>( | 3640 int64_t pp = *reinterpret_cast<int64_t*>(code + Code::object_pool_offset() - |
| 3611 code + Code::object_pool_offset() - kHeapObjectTag); | 3641 kHeapObjectTag); |
| 3612 pp -= kHeapObjectTag; // In the PP register, the pool pointer is untagged. | 3642 pp -= kHeapObjectTag; // In the PP register, the pool pointer is untagged. |
| 3613 set_register(NULL, CODE_REG, code); | 3643 set_register(NULL, CODE_REG, code); |
| 3614 set_register(NULL, PP, pp); | 3644 set_register(NULL, PP, pp); |
| 3615 buf->Longjmp(); | 3645 buf->Longjmp(); |
| 3616 } | 3646 } |
| 3617 | 3647 |
| 3618 } // namespace dart | 3648 } // namespace dart |
| 3619 | 3649 |
| 3620 #endif // !defined(USING_SIMULATOR) | 3650 #endif // !defined(USING_SIMULATOR) |
| 3621 | 3651 |
| 3622 #endif // defined TARGET_ARCH_ARM64 | 3652 #endif // defined TARGET_ARCH_ARM64 |
| OLD | NEW |