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 "vm/globals.h" | 5 #include "vm/globals.h" |
6 #if defined(TARGET_ARCH_X64) | 6 #if defined(TARGET_ARCH_X64) |
7 | 7 |
8 #include "vm/assembler.h" | 8 #include "vm/assembler.h" |
9 #include "vm/cpu.h" | 9 #include "vm/cpu.h" |
10 #include "vm/heap.h" | 10 #include "vm/heap.h" |
| 11 #include "vm/locations.h" |
11 #include "vm/memory_region.h" | 12 #include "vm/memory_region.h" |
12 #include "vm/runtime_entry.h" | 13 #include "vm/runtime_entry.h" |
13 #include "vm/stack_frame.h" | 14 #include "vm/stack_frame.h" |
14 #include "vm/stub_code.h" | 15 #include "vm/stub_code.h" |
15 | 16 |
16 namespace dart { | 17 namespace dart { |
17 | 18 |
18 DEFINE_FLAG(bool, print_stop_message, true, "Print stop message."); | 19 DEFINE_FLAG(bool, print_stop_message, true, "Print stop message."); |
19 DECLARE_FLAG(bool, inline_alloc); | 20 DECLARE_FLAG(bool, inline_alloc); |
20 | 21 |
(...skipping 2788 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2809 // the C++ world. | 2810 // the C++ world. |
2810 if (frame_space != 0) { | 2811 if (frame_space != 0) { |
2811 subq(RSP, Immediate(frame_space)); | 2812 subq(RSP, Immediate(frame_space)); |
2812 } | 2813 } |
2813 if (OS::ActivationFrameAlignment() > 1) { | 2814 if (OS::ActivationFrameAlignment() > 1) { |
2814 andq(RSP, Immediate(~(OS::ActivationFrameAlignment() - 1))); | 2815 andq(RSP, Immediate(~(OS::ActivationFrameAlignment() - 1))); |
2815 } | 2816 } |
2816 } | 2817 } |
2817 | 2818 |
2818 | 2819 |
2819 // TODO(srdjan): Add XMM registers once they are used by the compiler. | 2820 void Assembler::PushRegisters(intptr_t cpu_register_set, |
2820 // Based on http://x86-64.org/documentation/abi.pdf Fig. 3.4 | 2821 intptr_t xmm_register_set) { |
2821 static const intptr_t kNumberOfVolatileCpuRegisters = 9; | 2822 const intptr_t xmm_regs_count = RegisterSet::RegisterCount(xmm_register_set); |
2822 static const Register volatile_cpu_registers[kNumberOfVolatileCpuRegisters] = { | 2823 if (xmm_regs_count > 0) { |
2823 RAX, RCX, RDX, RSI, RDI, R8, R9, R10, R11 | 2824 AddImmediate(RSP, Immediate(-xmm_regs_count * kFpuRegisterSize), PP); |
2824 }; | 2825 // Store XMM registers with the lowest register number at the lowest |
| 2826 // address. |
| 2827 intptr_t offset = 0; |
| 2828 for (intptr_t reg_idx = 0; reg_idx < kNumberOfXmmRegisters; ++reg_idx) { |
| 2829 XmmRegister xmm_reg = static_cast<XmmRegister>(reg_idx); |
| 2830 if (RegisterSet::Contains(xmm_register_set, xmm_reg)) { |
| 2831 movups(Address(RSP, offset), xmm_reg); |
| 2832 offset += kFpuRegisterSize; |
| 2833 } |
| 2834 } |
| 2835 ASSERT(offset == (xmm_regs_count * kFpuRegisterSize)); |
| 2836 } |
2825 | 2837 |
2826 // XMM0 is used only as a scratch register in the optimized code. No need to | 2838 // Store general purpose registers with the highest register number at the |
2827 // save it. | 2839 // lowest address. |
2828 static const intptr_t kNumberOfVolatileXmmRegisters = | 2840 for (intptr_t reg_idx = 0; reg_idx < kNumberOfCpuRegisters; ++reg_idx) { |
2829 kNumberOfXmmRegisters - 1; | 2841 Register reg = static_cast<Register>(reg_idx); |
| 2842 if (RegisterSet::Contains(cpu_register_set, reg)) { |
| 2843 pushq(reg); |
| 2844 } |
| 2845 } |
| 2846 } |
| 2847 |
| 2848 |
| 2849 void Assembler::PopRegisters(intptr_t cpu_register_set, |
| 2850 intptr_t xmm_register_set) { |
| 2851 // General purpose registers have the highest register number at the |
| 2852 // lowest address. |
| 2853 for (intptr_t reg_idx = kNumberOfCpuRegisters - 1; reg_idx >= 0; --reg_idx) { |
| 2854 Register reg = static_cast<Register>(reg_idx); |
| 2855 if (RegisterSet::Contains(cpu_register_set, reg)) { |
| 2856 popq(reg); |
| 2857 } |
| 2858 } |
| 2859 |
| 2860 const intptr_t xmm_regs_count = RegisterSet::RegisterCount(xmm_register_set); |
| 2861 if (xmm_regs_count > 0) { |
| 2862 // XMM registers have the lowest register number at the lowest address. |
| 2863 intptr_t offset = 0; |
| 2864 for (intptr_t reg_idx = 0; reg_idx < kNumberOfXmmRegisters; ++reg_idx) { |
| 2865 XmmRegister xmm_reg = static_cast<XmmRegister>(reg_idx); |
| 2866 if (RegisterSet::Contains(xmm_register_set, xmm_reg)) { |
| 2867 movups(xmm_reg, Address(RSP, offset)); |
| 2868 offset += kFpuRegisterSize; |
| 2869 } |
| 2870 } |
| 2871 ASSERT(offset == (xmm_regs_count * kFpuRegisterSize)); |
| 2872 AddImmediate(RSP, Immediate(offset), PP); |
| 2873 } |
| 2874 } |
2830 | 2875 |
2831 | 2876 |
2832 void Assembler::EnterCallRuntimeFrame(intptr_t frame_space) { | 2877 void Assembler::EnterCallRuntimeFrame(intptr_t frame_space) { |
2833 EnterFrame(0); | 2878 EnterFrame(0); |
2834 | 2879 |
2835 // Preserve volatile CPU registers. | 2880 // TODO(vegorov): avoid saving FpuTMP, it is used only as scratch. |
2836 for (intptr_t i = 0; i < kNumberOfVolatileCpuRegisters; i++) { | 2881 PushRegisters(CallingConventions::kVolatileCpuRegisters, |
2837 pushq(volatile_cpu_registers[i]); | 2882 CallingConventions::kVolatileXmmRegisters); |
2838 } | |
2839 | |
2840 // Preserve all XMM registers except XMM0 | |
2841 subq(RSP, Immediate((kNumberOfXmmRegisters - 1) * kFpuRegisterSize)); | |
2842 // Store XMM registers with the lowest register number at the lowest | |
2843 // address. | |
2844 intptr_t offset = 0; | |
2845 for (intptr_t reg_idx = 1; reg_idx < kNumberOfXmmRegisters; ++reg_idx) { | |
2846 XmmRegister xmm_reg = static_cast<XmmRegister>(reg_idx); | |
2847 movups(Address(RSP, offset), xmm_reg); | |
2848 offset += kFpuRegisterSize; | |
2849 } | |
2850 | 2883 |
2851 ReserveAlignedFrameSpace(frame_space); | 2884 ReserveAlignedFrameSpace(frame_space); |
2852 } | 2885 } |
2853 | 2886 |
2854 | 2887 |
2855 void Assembler::LeaveCallRuntimeFrame() { | 2888 void Assembler::LeaveCallRuntimeFrame() { |
2856 // RSP might have been modified to reserve space for arguments | 2889 // RSP might have been modified to reserve space for arguments |
2857 // and ensure proper alignment of the stack frame. | 2890 // and ensure proper alignment of the stack frame. |
2858 // We need to restore it before restoring registers. | 2891 // We need to restore it before restoring registers. |
| 2892 const intptr_t kPushedCpuRegistersCount = |
| 2893 RegisterSet::RegisterCount(CallingConventions::kVolatileCpuRegisters); |
| 2894 const intptr_t kPushedXmmRegistersCount = |
| 2895 RegisterSet::RegisterCount(CallingConventions::kVolatileXmmRegisters); |
2859 const intptr_t kPushedRegistersSize = | 2896 const intptr_t kPushedRegistersSize = |
2860 kNumberOfVolatileCpuRegisters * kWordSize + | 2897 kPushedCpuRegistersCount * kWordSize + |
2861 kNumberOfVolatileXmmRegisters * kFpuRegisterSize; | 2898 kPushedXmmRegistersCount * kFpuRegisterSize; |
2862 leaq(RSP, Address(RBP, -kPushedRegistersSize)); | 2899 leaq(RSP, Address(RBP, -kPushedRegistersSize)); |
2863 | 2900 |
2864 // Restore all XMM registers except XMM0 | 2901 // TODO(vegorov): avoid saving FpuTMP, it is used only as scratch. |
2865 // XMM registers have the lowest register number at the lowest address. | 2902 PopRegisters(CallingConventions::kVolatileCpuRegisters, |
2866 intptr_t offset = 0; | 2903 CallingConventions::kVolatileXmmRegisters); |
2867 for (intptr_t reg_idx = 1; reg_idx < kNumberOfXmmRegisters; ++reg_idx) { | |
2868 XmmRegister xmm_reg = static_cast<XmmRegister>(reg_idx); | |
2869 movups(xmm_reg, Address(RSP, offset)); | |
2870 offset += kFpuRegisterSize; | |
2871 } | |
2872 addq(RSP, Immediate(offset)); | |
2873 | |
2874 // Restore volatile CPU registers. | |
2875 for (intptr_t i = kNumberOfVolatileCpuRegisters - 1; i >= 0; i--) { | |
2876 popq(volatile_cpu_registers[i]); | |
2877 } | |
2878 | 2904 |
2879 leave(); | 2905 leave(); |
2880 } | 2906 } |
2881 | 2907 |
2882 | 2908 |
| 2909 void Assembler::CallCFunction(const ExternalLabel* label) { |
| 2910 // Reserve shadow space for outgoing arguments. |
| 2911 if (CallingConventions::kShadowSpaceBytes != 0) { |
| 2912 subq(RSP, Immediate(CallingConventions::kShadowSpaceBytes)); |
| 2913 } |
| 2914 call(label); |
| 2915 } |
| 2916 |
| 2917 |
| 2918 void Assembler::CallCFunction(Register reg) { |
| 2919 // Reserve shadow space for outgoing arguments. |
| 2920 if (CallingConventions::kShadowSpaceBytes != 0) { |
| 2921 subq(RSP, Immediate(CallingConventions::kShadowSpaceBytes)); |
| 2922 } |
| 2923 call(reg); |
| 2924 } |
| 2925 |
| 2926 |
2883 void Assembler::CallRuntime(const RuntimeEntry& entry, | 2927 void Assembler::CallRuntime(const RuntimeEntry& entry, |
2884 intptr_t argument_count) { | 2928 intptr_t argument_count) { |
2885 entry.Call(this, argument_count); | 2929 entry.Call(this, argument_count); |
2886 } | 2930 } |
2887 | 2931 |
2888 | 2932 |
2889 void Assembler::LoadPoolPointer(Register pp) { | 2933 void Assembler::LoadPoolPointer(Register pp) { |
2890 Label next; | 2934 Label next; |
2891 call(&next); | 2935 call(&next); |
2892 Bind(&next); | 2936 Bind(&next); |
(...skipping 417 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3310 | 3354 |
3311 | 3355 |
3312 const char* Assembler::FpuRegisterName(FpuRegister reg) { | 3356 const char* Assembler::FpuRegisterName(FpuRegister reg) { |
3313 ASSERT((0 <= reg) && (reg < kNumberOfXmmRegisters)); | 3357 ASSERT((0 <= reg) && (reg < kNumberOfXmmRegisters)); |
3314 return xmm_reg_names[reg]; | 3358 return xmm_reg_names[reg]; |
3315 } | 3359 } |
3316 | 3360 |
3317 } // namespace dart | 3361 } // namespace dart |
3318 | 3362 |
3319 #endif // defined TARGET_ARCH_X64 | 3363 #endif // defined TARGET_ARCH_X64 |
OLD | NEW |