| 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 |