| Index: runtime/vm/assembler_x64.cc
|
| diff --git a/runtime/vm/assembler_x64.cc b/runtime/vm/assembler_x64.cc
|
| index 05db770a30378888294374759ee56f03b354828b..1887af0bfdb634c20cb4589df119281d8413ddb4 100644
|
| --- a/runtime/vm/assembler_x64.cc
|
| +++ b/runtime/vm/assembler_x64.cc
|
| @@ -8,6 +8,7 @@
|
| #include "vm/assembler.h"
|
| #include "vm/cpu.h"
|
| #include "vm/heap.h"
|
| +#include "vm/locations.h"
|
| #include "vm/memory_region.h"
|
| #include "vm/runtime_entry.h"
|
| #include "vm/stack_frame.h"
|
| @@ -2816,37 +2817,69 @@ void Assembler::ReserveAlignedFrameSpace(intptr_t frame_space) {
|
| }
|
|
|
|
|
| -// TODO(srdjan): Add XMM registers once they are used by the compiler.
|
| -// Based on http://x86-64.org/documentation/abi.pdf Fig. 3.4
|
| -static const intptr_t kNumberOfVolatileCpuRegisters = 9;
|
| -static const Register volatile_cpu_registers[kNumberOfVolatileCpuRegisters] = {
|
| - RAX, RCX, RDX, RSI, RDI, R8, R9, R10, R11
|
| -};
|
| -
|
| -// XMM0 is used only as a scratch register in the optimized code. No need to
|
| -// save it.
|
| -static const intptr_t kNumberOfVolatileXmmRegisters =
|
| - kNumberOfXmmRegisters - 1;
|
| +void Assembler::PushRegisters(intptr_t cpu_register_set,
|
| + intptr_t xmm_register_set) {
|
| + const intptr_t xmm_regs_count = RegisterSet::RegisterCount(xmm_register_set);
|
| + if (xmm_regs_count > 0) {
|
| + AddImmediate(RSP, Immediate(-xmm_regs_count * kFpuRegisterSize), PP);
|
| + // Store XMM registers with the lowest register number at the lowest
|
| + // address.
|
| + intptr_t offset = 0;
|
| + for (intptr_t reg_idx = 0; reg_idx < kNumberOfXmmRegisters; ++reg_idx) {
|
| + XmmRegister xmm_reg = static_cast<XmmRegister>(reg_idx);
|
| + if (RegisterSet::Contains(xmm_register_set, xmm_reg)) {
|
| + movups(Address(RSP, offset), xmm_reg);
|
| + offset += kFpuRegisterSize;
|
| + }
|
| + }
|
| + ASSERT(offset == (xmm_regs_count * kFpuRegisterSize));
|
| + }
|
|
|
| + // Store general purpose registers with the highest register number at the
|
| + // lowest address.
|
| + for (intptr_t reg_idx = 0; reg_idx < kNumberOfCpuRegisters; ++reg_idx) {
|
| + Register reg = static_cast<Register>(reg_idx);
|
| + if (RegisterSet::Contains(cpu_register_set, reg)) {
|
| + pushq(reg);
|
| + }
|
| + }
|
| +}
|
|
|
| -void Assembler::EnterCallRuntimeFrame(intptr_t frame_space) {
|
| - EnterFrame(0);
|
|
|
| - // Preserve volatile CPU registers.
|
| - for (intptr_t i = 0; i < kNumberOfVolatileCpuRegisters; i++) {
|
| - pushq(volatile_cpu_registers[i]);
|
| +void Assembler::PopRegisters(intptr_t cpu_register_set,
|
| + intptr_t xmm_register_set) {
|
| + // General purpose registers have the highest register number at the
|
| + // lowest address.
|
| + for (intptr_t reg_idx = kNumberOfCpuRegisters - 1; reg_idx >= 0; --reg_idx) {
|
| + Register reg = static_cast<Register>(reg_idx);
|
| + if (RegisterSet::Contains(cpu_register_set, reg)) {
|
| + popq(reg);
|
| + }
|
| }
|
|
|
| - // Preserve all XMM registers except XMM0
|
| - subq(RSP, Immediate((kNumberOfXmmRegisters - 1) * kFpuRegisterSize));
|
| - // Store XMM registers with the lowest register number at the lowest
|
| - // address.
|
| - intptr_t offset = 0;
|
| - for (intptr_t reg_idx = 1; reg_idx < kNumberOfXmmRegisters; ++reg_idx) {
|
| - XmmRegister xmm_reg = static_cast<XmmRegister>(reg_idx);
|
| - movups(Address(RSP, offset), xmm_reg);
|
| - offset += kFpuRegisterSize;
|
| + const intptr_t xmm_regs_count = RegisterSet::RegisterCount(xmm_register_set);
|
| + if (xmm_regs_count > 0) {
|
| + // XMM registers have the lowest register number at the lowest address.
|
| + intptr_t offset = 0;
|
| + for (intptr_t reg_idx = 0; reg_idx < kNumberOfXmmRegisters; ++reg_idx) {
|
| + XmmRegister xmm_reg = static_cast<XmmRegister>(reg_idx);
|
| + if (RegisterSet::Contains(xmm_register_set, xmm_reg)) {
|
| + movups(xmm_reg, Address(RSP, offset));
|
| + offset += kFpuRegisterSize;
|
| + }
|
| + }
|
| + ASSERT(offset == (xmm_regs_count * kFpuRegisterSize));
|
| + AddImmediate(RSP, Immediate(offset), PP);
|
| }
|
| +}
|
| +
|
| +
|
| +void Assembler::EnterCallRuntimeFrame(intptr_t frame_space) {
|
| + EnterFrame(0);
|
| +
|
| + // TODO(vegorov): avoid saving FpuTMP, it is used only as scratch.
|
| + PushRegisters(CallingConventions::kVolatileCpuRegisters,
|
| + CallingConventions::kVolatileXmmRegisters);
|
|
|
| ReserveAlignedFrameSpace(frame_space);
|
| }
|
| @@ -2856,27 +2889,38 @@ void Assembler::LeaveCallRuntimeFrame() {
|
| // RSP might have been modified to reserve space for arguments
|
| // and ensure proper alignment of the stack frame.
|
| // We need to restore it before restoring registers.
|
| + const intptr_t kPushedCpuRegistersCount =
|
| + RegisterSet::RegisterCount(CallingConventions::kVolatileCpuRegisters);
|
| + const intptr_t kPushedXmmRegistersCount =
|
| + RegisterSet::RegisterCount(CallingConventions::kVolatileXmmRegisters);
|
| const intptr_t kPushedRegistersSize =
|
| - kNumberOfVolatileCpuRegisters * kWordSize +
|
| - kNumberOfVolatileXmmRegisters * kFpuRegisterSize;
|
| + kPushedCpuRegistersCount * kWordSize +
|
| + kPushedXmmRegistersCount * kFpuRegisterSize;
|
| leaq(RSP, Address(RBP, -kPushedRegistersSize));
|
|
|
| - // Restore all XMM registers except XMM0
|
| - // XMM registers have the lowest register number at the lowest address.
|
| - intptr_t offset = 0;
|
| - for (intptr_t reg_idx = 1; reg_idx < kNumberOfXmmRegisters; ++reg_idx) {
|
| - XmmRegister xmm_reg = static_cast<XmmRegister>(reg_idx);
|
| - movups(xmm_reg, Address(RSP, offset));
|
| - offset += kFpuRegisterSize;
|
| - }
|
| - addq(RSP, Immediate(offset));
|
| + // TODO(vegorov): avoid saving FpuTMP, it is used only as scratch.
|
| + PopRegisters(CallingConventions::kVolatileCpuRegisters,
|
| + CallingConventions::kVolatileXmmRegisters);
|
| +
|
| + leave();
|
| +}
|
|
|
| - // Restore volatile CPU registers.
|
| - for (intptr_t i = kNumberOfVolatileCpuRegisters - 1; i >= 0; i--) {
|
| - popq(volatile_cpu_registers[i]);
|
| +
|
| +void Assembler::CallCFunction(const ExternalLabel* label) {
|
| + // Reserve shadow space for outgoing arguments.
|
| + if (CallingConventions::kShadowSpaceBytes != 0) {
|
| + subq(RSP, Immediate(CallingConventions::kShadowSpaceBytes));
|
| }
|
| + call(label);
|
| +}
|
|
|
| - leave();
|
| +
|
| +void Assembler::CallCFunction(Register reg) {
|
| + // Reserve shadow space for outgoing arguments.
|
| + if (CallingConventions::kShadowSpaceBytes != 0) {
|
| + subq(RSP, Immediate(CallingConventions::kShadowSpaceBytes));
|
| + }
|
| + call(reg);
|
| }
|
|
|
|
|
|
|