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 <math.h> // for isnan. |
| 6 #include <setjmp.h> |
| 7 #include <stdlib.h> |
| 8 |
5 #include "vm/globals.h" | 9 #include "vm/globals.h" |
6 #if defined(TARGET_ARCH_MIPS) | 10 #if defined(TARGET_ARCH_MIPS) |
7 | 11 |
8 // Only build the simulator if not compiling for real MIPS hardware. | 12 // Only build the simulator if not compiling for real MIPS hardware. |
9 #if !defined(HOST_ARCH_MIPS) | 13 #if !defined(HOST_ARCH_MIPS) |
10 | 14 |
11 #include "vm/simulator.h" | 15 #include "vm/simulator.h" |
12 | 16 |
13 #include "vm/assembler.h" | 17 #include "vm/assembler.h" |
14 #include "vm/constants_mips.h" | 18 #include "vm/constants_mips.h" |
15 #include "vm/disassembler.h" | 19 #include "vm/disassembler.h" |
| 20 #include "vm/native_arguments.h" |
| 21 #include "vm/thread.h" |
16 | 22 |
17 namespace dart { | 23 namespace dart { |
18 | 24 |
| 25 DEFINE_FLAG(bool, trace_sim, false, "Trace simulator execution."); |
19 DEFINE_FLAG(int, stop_sim_at, 0, "Address to stop simulator at."); | 26 DEFINE_FLAG(int, stop_sim_at, 0, "Address to stop simulator at."); |
20 | 27 |
21 | 28 |
22 // This macro provides a platform independent use of sscanf. The reason for | 29 // This macro provides a platform independent use of sscanf. The reason for |
23 // SScanF not being implemented in a platform independent way through | 30 // SScanF not being implemented in a platform independent way through |
24 // OS in the same way as SNPrint is that the Windows C Run-Time | 31 // OS in the same way as SNPrint is that the Windows C Run-Time |
25 // Library does not provide vsscanf. | 32 // Library does not provide vsscanf. |
26 #define SScanF sscanf // NOLINT | 33 #define SScanF sscanf // NOLINT |
27 | 34 |
28 | 35 |
| 36 // SimulatorSetjmpBuffer are linked together, and the last created one |
| 37 // is referenced by the Simulator. When an exception is thrown, the exception |
| 38 // runtime looks at where to jump and finds the corresponding |
| 39 // SimulatorSetjmpBuffer based on the stack pointer of the exception handler. |
| 40 // The runtime then does a Longjmp on that buffer to return to the simulator. |
| 41 class SimulatorSetjmpBuffer { |
| 42 public: |
| 43 int Setjmp() { return setjmp(buffer_); } |
| 44 void Longjmp() { |
| 45 // "This" is now the last setjmp buffer. |
| 46 simulator_->set_last_setjmp_buffer(this); |
| 47 longjmp(buffer_, 1); |
| 48 } |
| 49 |
| 50 explicit SimulatorSetjmpBuffer(Simulator* sim) { |
| 51 simulator_ = sim; |
| 52 link_ = sim->last_setjmp_buffer(); |
| 53 sim->set_last_setjmp_buffer(this); |
| 54 sp_ = sim->get_register(SP); |
| 55 } |
| 56 |
| 57 ~SimulatorSetjmpBuffer() { |
| 58 ASSERT(simulator_->last_setjmp_buffer() == this); |
| 59 simulator_->set_last_setjmp_buffer(link_); |
| 60 } |
| 61 |
| 62 SimulatorSetjmpBuffer* link() { return link_; } |
| 63 |
| 64 int32_t sp() { return sp_; } |
| 65 |
| 66 private: |
| 67 int32_t sp_; |
| 68 Simulator* simulator_; |
| 69 SimulatorSetjmpBuffer* link_; |
| 70 jmp_buf buffer_; |
| 71 |
| 72 friend class Simulator; |
| 73 }; |
| 74 |
| 75 |
29 // The SimulatorDebugger class is used by the simulator while debugging | 76 // The SimulatorDebugger class is used by the simulator while debugging |
30 // simulated MIPS code. | 77 // simulated MIPS code. |
31 class SimulatorDebugger { | 78 class SimulatorDebugger { |
32 public: | 79 public: |
33 explicit SimulatorDebugger(Simulator* sim); | 80 explicit SimulatorDebugger(Simulator* sim); |
34 ~SimulatorDebugger(); | 81 ~SimulatorDebugger(); |
35 | 82 |
36 void Stop(Instr* instr, const char* message); | 83 void Stop(Instr* instr, const char* message); |
37 void Debug(); | 84 void Debug(); |
38 char* ReadLine(const char* prompt); | 85 char* ReadLine(const char* prompt); |
(...skipping 464 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
503 | 550 |
504 | 551 |
505 Simulator::~Simulator() { | 552 Simulator::~Simulator() { |
506 Isolate* isolate = Isolate::Current(); | 553 Isolate* isolate = Isolate::Current(); |
507 if (isolate != NULL) { | 554 if (isolate != NULL) { |
508 isolate->set_simulator(NULL); | 555 isolate->set_simulator(NULL); |
509 } | 556 } |
510 } | 557 } |
511 | 558 |
512 | 559 |
| 560 // When the generated code calls an external reference we need to catch that in |
| 561 // the simulator. The external reference will be a function compiled for the |
| 562 // host architecture. We need to call that function instead of trying to |
| 563 // execute it with the simulator. We do that by redirecting the external |
| 564 // reference to a break instruction with code 2 that is handled by |
| 565 // the simulator. We write the original destination of the jump just at a known |
| 566 // offset from the break instruction so the simulator knows what to call. |
| 567 class Redirection { |
| 568 public: |
| 569 uword address_of_break_instruction() { |
| 570 return reinterpret_cast<uword>(&break_instruction_); |
| 571 } |
| 572 |
| 573 uword external_function() const { return external_function_; } |
| 574 |
| 575 Simulator::CallKind call_kind() const { return call_kind_; } |
| 576 |
| 577 static Redirection* Get(uword external_function, |
| 578 Simulator::CallKind call_kind) { |
| 579 Redirection* current; |
| 580 for (current = list_; current != NULL; current = current->next_) { |
| 581 if (current->external_function_ == external_function) return current; |
| 582 } |
| 583 return new Redirection(external_function, call_kind); |
| 584 } |
| 585 |
| 586 static Redirection* FromBreakInstruction(Instr* break_instruction) { |
| 587 char* addr_of_break = reinterpret_cast<char*>(break_instruction); |
| 588 char* addr_of_redirection = |
| 589 addr_of_break - OFFSET_OF(Redirection, break_instruction_); |
| 590 return reinterpret_cast<Redirection*>(addr_of_redirection); |
| 591 } |
| 592 |
| 593 private: |
| 594 static const int32_t kRedirectInstruction = |
| 595 Instr::kBreakPointInstruction | (Instr::kRedirectCode << kBreakCodeShift); |
| 596 |
| 597 Redirection(uword external_function, Simulator::CallKind call_kind) |
| 598 : external_function_(external_function), |
| 599 call_kind_(call_kind), |
| 600 break_instruction_(kRedirectInstruction), |
| 601 next_(list_) { |
| 602 list_ = this; |
| 603 } |
| 604 |
| 605 uword external_function_; |
| 606 Simulator::CallKind call_kind_; |
| 607 uint32_t break_instruction_; |
| 608 Redirection* next_; |
| 609 static Redirection* list_; |
| 610 }; |
| 611 |
| 612 |
| 613 Redirection* Redirection::list_ = NULL; |
| 614 |
| 615 |
| 616 uword Simulator::RedirectExternalReference(uword function, CallKind call_kind) { |
| 617 Redirection* redirection = Redirection::Get(function, call_kind); |
| 618 return redirection->address_of_break_instruction(); |
| 619 } |
| 620 |
| 621 |
513 // Get the active Simulator for the current isolate. | 622 // Get the active Simulator for the current isolate. |
514 Simulator* Simulator::Current() { | 623 Simulator* Simulator::Current() { |
515 Simulator* simulator = Isolate::Current()->simulator(); | 624 Simulator* simulator = Isolate::Current()->simulator(); |
516 if (simulator == NULL) { | 625 if (simulator == NULL) { |
517 simulator = new Simulator(); | 626 simulator = new Simulator(); |
518 Isolate::Current()->set_simulator(simulator); | 627 Isolate::Current()->set_simulator(simulator); |
519 } | 628 } |
520 return simulator; | 629 return simulator; |
521 } | 630 } |
522 | 631 |
(...skipping 161 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
684 } else { | 793 } else { |
685 // Operands have different signs. | 794 // Operands have different signs. |
686 overflow = ((left < 0 && right >= 0) || (left >= 0 && right < 0)) | 795 overflow = ((left < 0 && right >= 0) || (left >= 0 && right < 0)) |
687 // And first operand and result have different signs. | 796 // And first operand and result have different signs. |
688 && ((left < 0 && alu_out >= 0) || (left >= 0 && alu_out < 0)); | 797 && ((left < 0 && alu_out >= 0) || (left >= 0 && alu_out < 0)); |
689 } | 798 } |
690 return overflow; | 799 return overflow; |
691 } | 800 } |
692 | 801 |
693 | 802 |
| 803 // Calls into the Dart runtime are based on this interface. |
| 804 typedef void (*SimulatorRuntimeCall)(NativeArguments arguments); |
| 805 |
| 806 // Calls to leaf Dart runtime functions are based on this interface. |
| 807 typedef int32_t (*SimulatorLeafRuntimeCall)( |
| 808 int32_t r0, int32_t r1, int32_t r2, int32_t r3); |
| 809 |
| 810 // Calls to native Dart functions are based on this interface. |
| 811 typedef void (*SimulatorNativeCall)(NativeArguments* arguments); |
| 812 |
| 813 |
| 814 void Simulator::DoBreak(Instr *instr) { |
| 815 ASSERT(instr->OpcodeField() == SPECIAL); |
| 816 ASSERT(instr->FunctionField() == BREAK); |
| 817 if (instr->BreakCodeField() == Instr::kStopMessageCode) { |
| 818 SimulatorDebugger dbg(this); |
| 819 const char* message = *reinterpret_cast<const char**>( |
| 820 reinterpret_cast<intptr_t>(instr) - Instr::kInstrSize); |
| 821 set_pc(get_pc() + Instr::kInstrSize); |
| 822 dbg.Stop(instr, message); |
| 823 } else if (instr->BreakCodeField() == Instr::kRedirectCode) { |
| 824 SimulatorSetjmpBuffer buffer(this); |
| 825 |
| 826 if (!setjmp(buffer.buffer_)) { |
| 827 int32_t saved_ra = get_register(RA); |
| 828 Redirection* redirection = Redirection::FromBreakInstruction(instr); |
| 829 uword external = redirection->external_function(); |
| 830 if (FLAG_trace_sim) { |
| 831 OS::Print("Call to host function at 0x%"Pd"\n", external); |
| 832 } |
| 833 if (redirection->call_kind() == kRuntimeCall) { |
| 834 NativeArguments arguments; |
| 835 ASSERT(sizeof(NativeArguments) == 4*kWordSize); |
| 836 arguments.isolate_ = reinterpret_cast<Isolate*>(get_register(A0)); |
| 837 arguments.argc_tag_ = get_register(A1); |
| 838 arguments.argv_ = reinterpret_cast<RawObject*(*)[]>(get_register(A2)); |
| 839 arguments.retval_ = reinterpret_cast<RawObject**>(get_register(A3)); |
| 840 SimulatorRuntimeCall target = |
| 841 reinterpret_cast<SimulatorRuntimeCall>(external); |
| 842 target(arguments); |
| 843 set_register(V0, icount_); // Zap result register from void function. |
| 844 } else if (redirection->call_kind() == kLeafRuntimeCall) { |
| 845 int32_t a0 = get_register(A0); |
| 846 int32_t a1 = get_register(A1); |
| 847 int32_t a2 = get_register(A2); |
| 848 int32_t a3 = get_register(A3); |
| 849 SimulatorLeafRuntimeCall target = |
| 850 reinterpret_cast<SimulatorLeafRuntimeCall>(external); |
| 851 a0 = target(a0, a1, a2, a3); |
| 852 set_register(V0, a0); // Set returned result from function. |
| 853 } else { |
| 854 ASSERT(redirection->call_kind() == kNativeCall); |
| 855 NativeArguments* arguments; |
| 856 arguments = reinterpret_cast<NativeArguments*>(get_register(A0)); |
| 857 SimulatorNativeCall target = |
| 858 reinterpret_cast<SimulatorNativeCall>(external); |
| 859 target(arguments); |
| 860 set_register(V0, icount_); // Zap result register from void function. |
| 861 } |
| 862 |
| 863 // Zap caller-saved registers, since the actual runtime call could have |
| 864 // used them. |
| 865 set_register(T0, icount_); |
| 866 set_register(T1, icount_); |
| 867 set_register(T2, icount_); |
| 868 set_register(T3, icount_); |
| 869 set_register(T4, icount_); |
| 870 set_register(T5, icount_); |
| 871 set_register(T6, icount_); |
| 872 set_register(T7, icount_); |
| 873 set_register(T8, icount_); |
| 874 set_register(T9, icount_); |
| 875 |
| 876 set_register(A0, icount_); |
| 877 set_register(A1, icount_); |
| 878 set_register(A2, icount_); |
| 879 set_register(A3, icount_); |
| 880 set_register(TMP, icount_); |
| 881 set_register(RA, icount_); |
| 882 |
| 883 // Zap floating point registers. |
| 884 double zap_dvalue = static_cast<double>(icount_); |
| 885 for (int i = F0; i <= F31; i++) { |
| 886 set_fregister(static_cast<FRegister>(i), zap_dvalue); |
| 887 } |
| 888 |
| 889 // Return. |
| 890 set_pc(saved_ra); |
| 891 } |
| 892 } else { |
| 893 SimulatorDebugger dbg(this); |
| 894 dbg.Stop(instr, "breakpoint"); |
| 895 } |
| 896 } |
| 897 |
| 898 |
694 void Simulator::DecodeSpecial(Instr* instr) { | 899 void Simulator::DecodeSpecial(Instr* instr) { |
695 ASSERT(instr->OpcodeField() == SPECIAL); | 900 ASSERT(instr->OpcodeField() == SPECIAL); |
696 switch (instr->FunctionField()) { | 901 switch (instr->FunctionField()) { |
697 case ADDU: { | 902 case ADDU: { |
698 ASSERT(instr->SaField() == 0); | 903 ASSERT(instr->SaField() == 0); |
699 // Format(instr, "addu 'rd, 'rs, 'rt"); | 904 // Format(instr, "addu 'rd, 'rs, 'rt"); |
700 int32_t rs_val = get_register(instr->RsField()); | 905 int32_t rs_val = get_register(instr->RsField()); |
701 int32_t rt_val = get_register(instr->RtField()); | 906 int32_t rt_val = get_register(instr->RtField()); |
702 set_register(instr->RdField(), rs_val + rt_val); | 907 set_register(instr->RdField(), rs_val + rt_val); |
703 break; | 908 break; |
704 } | 909 } |
705 case AND: { | 910 case AND: { |
706 ASSERT(instr->SaField() == 0); | 911 ASSERT(instr->SaField() == 0); |
707 // Format(instr, "and 'rd, 'rs, 'rt"); | 912 // Format(instr, "and 'rd, 'rs, 'rt"); |
708 int32_t rs_val = get_register(instr->RsField()); | 913 int32_t rs_val = get_register(instr->RsField()); |
709 int32_t rt_val = get_register(instr->RtField()); | 914 int32_t rt_val = get_register(instr->RtField()); |
710 set_register(instr->RdField(), rs_val & rt_val); | 915 set_register(instr->RdField(), rs_val & rt_val); |
711 break; | 916 break; |
712 } | 917 } |
713 case BREAK: { | 918 case BREAK: { |
714 if (instr->BreakCodeField() == Instr::kStopMessageCode) { | 919 DoBreak(instr); |
715 SimulatorDebugger dbg(this); | |
716 const char* message = *reinterpret_cast<const char**>( | |
717 reinterpret_cast<intptr_t>(instr) - Instr::kInstrSize); | |
718 set_pc(get_pc() + Instr::kInstrSize); | |
719 dbg.Stop(instr, message); | |
720 } else { | |
721 SimulatorDebugger dbg(this); | |
722 dbg.Stop(instr, "breakpoint"); | |
723 } | |
724 break; | 920 break; |
725 } | 921 } |
726 case DIV: { | 922 case DIV: { |
727 ASSERT(instr->RdField() == 0); | 923 ASSERT(instr->RdField() == 0); |
728 ASSERT(instr->SaField() == 0); | 924 ASSERT(instr->SaField() == 0); |
729 // Format(instr, "div 'rs, 'rt"); | 925 // Format(instr, "div 'rs, 'rt"); |
730 int32_t rs_val = get_register(instr->RsField()); | 926 int32_t rs_val = get_register(instr->RsField()); |
731 int32_t rt_val = get_register(instr->RtField()); | 927 int32_t rt_val = get_register(instr->RtField()); |
732 if (rt_val == 0) { | 928 if (rt_val == 0) { |
733 // Results are unpredictable. | 929 // Results are unpredictable. |
(...skipping 668 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1402 // Restore the SP register and return R1:R0. | 1598 // Restore the SP register and return R1:R0. |
1403 set_register(SP, sp_before_call); | 1599 set_register(SP, sp_before_call); |
1404 return Utils::LowHighTo64Bits(get_register(V0), get_register(V1)); | 1600 return Utils::LowHighTo64Bits(get_register(V0), get_register(V1)); |
1405 } | 1601 } |
1406 | 1602 |
1407 } // namespace dart | 1603 } // namespace dart |
1408 | 1604 |
1409 #endif // !defined(HOST_ARCH_MIPS) | 1605 #endif // !defined(HOST_ARCH_MIPS) |
1410 | 1606 |
1411 #endif // defined TARGET_ARCH_MIPS | 1607 #endif // defined TARGET_ARCH_MIPS |
OLD | NEW |