| Index: src/arm/macro-assembler-arm.cc
|
| diff --git a/src/arm/macro-assembler-arm.cc b/src/arm/macro-assembler-arm.cc
|
| index 437b7312c718f0aa3b936c0176b49d4724049958..6d3c9676adedb8acd8d1fb223481f84fd8b9772c 100644
|
| --- a/src/arm/macro-assembler-arm.cc
|
| +++ b/src/arm/macro-assembler-arm.cc
|
| @@ -624,72 +624,134 @@ void MacroAssembler::PopFixedFrame(Register marker_reg) {
|
|
|
| // Push and pop all registers that can hold pointers.
|
| void MacroAssembler::PushSafepointRegisters() {
|
| - // Safepoints expect a block of contiguous register values starting with r0:
|
| - ASSERT(((1 << kNumSafepointSavedRegisters) - 1) == kSafepointSavedRegisters);
|
| - // Safepoints expect a block of kNumSafepointRegisters values on the
|
| - // stack, so adjust the stack for unsaved registers.
|
| - const int num_unsaved = kNumSafepointRegisters - kNumSafepointSavedRegisters;
|
| - ASSERT(num_unsaved >= 0);
|
| - sub(sp, sp, Operand(num_unsaved * kPointerSize));
|
| - stm(db_w, sp, kSafepointSavedRegisters);
|
| + // This function must be called from LCodeGen::GenerateCode where
|
| + // registers_mask and double_registers_mask are set.
|
| + ASSERT(registers_mask() != kRegListEmpty);
|
| + stm(db_w, sp, registers_mask());
|
| }
|
|
|
|
|
| void MacroAssembler::PopSafepointRegisters() {
|
| - const int num_unsaved = kNumSafepointRegisters - kNumSafepointSavedRegisters;
|
| - ldm(ia_w, sp, kSafepointSavedRegisters);
|
| - add(sp, sp, Operand(num_unsaved * kPointerSize));
|
| + // This function must be called from LCodeGen::GenerateCode where
|
| + // registers_mask and double_registers_mask are set.
|
| + ASSERT(registers_mask() != kRegListEmpty);
|
| + ldm(ia_w, sp, registers_mask());
|
| }
|
|
|
|
|
| void MacroAssembler::PushSafepointRegistersAndDoubles() {
|
| - // Number of d-regs not known at snapshot time.
|
| - ASSERT(!Serializer::enabled());
|
| PushSafepointRegisters();
|
| - // Only save allocatable registers.
|
| - ASSERT(kScratchDoubleReg.is(d15) && kDoubleRegZero.is(d14));
|
| - ASSERT(DwVfpRegister::NumReservedRegisters() == 2);
|
| - if (CpuFeatures::IsSupported(VFP32DREGS)) {
|
| - vstm(db_w, sp, d16, d31);
|
| + // The vstm instruction can only save up to 16 doubles. So we save all the
|
| + // doubles registers with up to 2 instructions.
|
| + RegList high_mask = double_registers_mask() & 0xffff0000;
|
| + if (high_mask != 0) {
|
| + for (int i = LowDwVfpRegister::kMaxNumLowRegisters;
|
| + i < DoubleRegister::NumRegisters();
|
| + i++) {
|
| + if ((high_mask & (1 << i)) != 0) {
|
| + int last = i + CompilerIntrinsics::CountSetBits(high_mask) - 1;
|
| + // When double_registers_mask has been initialized, we ensured that
|
| + // there is no holes between the first and the last high registers.
|
| + ASSERT(((((1 << last) - 1) | (1 << last)) & ~((1 << i) - 1)) ==
|
| + high_mask);
|
| + vstm(db_w, sp, DwVfpRegister::from_code(i),
|
| + DwVfpRegister::from_code(last));
|
| + break;
|
| + }
|
| + }
|
| + }
|
| + RegList low_mask = double_registers_mask() & 0xffff;
|
| + if (low_mask != 0) {
|
| + for (int i = 0; i < LowDwVfpRegister::kMaxNumLowRegisters; i++) {
|
| + if ((low_mask & (1 << i)) != 0) {
|
| + int last = i + CompilerIntrinsics::CountSetBits(low_mask) - 1;
|
| + // When double_registers_mask has been initialized, we ensured that
|
| + // there is no holes between the first and the last low registers.
|
| + ASSERT(((((1 << last) - 1) | (1 << last)) & ~((1 << i) - 1)) ==
|
| + low_mask);
|
| + vstm(db_w, sp, LowDwVfpRegister::from_code(i),
|
| + LowDwVfpRegister::from_code(last));
|
| + break;
|
| + }
|
| + }
|
| }
|
| - vstm(db_w, sp, d0, d13);
|
| }
|
|
|
|
|
| void MacroAssembler::PopSafepointRegistersAndDoubles() {
|
| - // Number of d-regs not known at snapshot time.
|
| - ASSERT(!Serializer::enabled());
|
| - // Only save allocatable registers.
|
| - ASSERT(kScratchDoubleReg.is(d15) && kDoubleRegZero.is(d14));
|
| - ASSERT(DwVfpRegister::NumReservedRegisters() == 2);
|
| - vldm(ia_w, sp, d0, d13);
|
| - if (CpuFeatures::IsSupported(VFP32DREGS)) {
|
| - vldm(ia_w, sp, d16, d31);
|
| + // The vldm instruction can only restore up to 16 doubles. So we save all the
|
| + // doubles registers with up to 2 instructions.
|
| + RegList low_mask = double_registers_mask() & 0xffff;
|
| + if (low_mask != 0) {
|
| + for (int i = 0; i < LowDwVfpRegister::kMaxNumLowRegisters; i++) {
|
| + if ((low_mask & (1 << i)) != 0) {
|
| + int last = i + CompilerIntrinsics::CountSetBits(low_mask) - 1;
|
| + // When double_registers_mask has been initialized, we ensured that
|
| + // there is no holes between the first and the last low registers.
|
| + ASSERT(((((1 << last) - 1) | (1 << last)) & ~((1 << i) - 1)) ==
|
| + low_mask);
|
| + vldm(ia_w, sp, LowDwVfpRegister::from_code(i),
|
| + LowDwVfpRegister::from_code(last));
|
| + break;
|
| + }
|
| + }
|
| + }
|
| + RegList high_mask = double_registers_mask() & 0xffff0000;
|
| + if (high_mask != 0) {
|
| + for (int i = LowDwVfpRegister::kMaxNumLowRegisters;
|
| + i < DoubleRegister::NumRegisters();
|
| + i++) {
|
| + if ((high_mask & (1 << i)) != 0) {
|
| + int last = i + CompilerIntrinsics::CountSetBits(high_mask) - 1;
|
| + // When double_registers_mask has been initialized, we ensured that
|
| + // there is no holes between the first and the last high registers.
|
| + ASSERT(((((1 << last) - 1) | (1 << last)) & ~((1 << i) - 1)) ==
|
| + high_mask);
|
| + vldm(ia_w, sp, DwVfpRegister::from_code(i),
|
| + DwVfpRegister::from_code(last));
|
| + break;
|
| + }
|
| + }
|
| }
|
| PopSafepointRegisters();
|
| }
|
|
|
| void MacroAssembler::StoreToSafepointRegistersAndDoublesSlot(Register src,
|
| Register dst) {
|
| + // This function must be called from LCodeGen::GenerateCode where
|
| + // registers_mask and double_registers_mask are set.
|
| + ASSERT((registers_mask() & dst.bit()) != kRegListEmpty);
|
| str(src, SafepointRegistersAndDoublesSlot(dst));
|
| }
|
|
|
|
|
| void MacroAssembler::StoreToSafepointRegisterSlot(Register src, Register dst) {
|
| + // This function must be called from LCodeGen::GenerateCode where
|
| + // registers_mask and double_registers_mask are set.
|
| + ASSERT((registers_mask() & dst.bit()) != kRegListEmpty);
|
| str(src, SafepointRegisterSlot(dst));
|
| }
|
|
|
|
|
| void MacroAssembler::LoadFromSafepointRegisterSlot(Register dst, Register src) {
|
| + // This function must be called from LCodeGen::GenerateCode where
|
| + // registers_mask and double_registers_mask are set.
|
| + ASSERT((registers_mask() & dst.bit()) != kRegListEmpty);
|
| ldr(dst, SafepointRegisterSlot(src));
|
| }
|
|
|
|
|
| int MacroAssembler::SafepointRegisterStackIndex(int reg_code) {
|
| + // This function must be called from LCodeGen::GenerateCode where
|
| + // registers_mask and double_registers_mask are set.
|
| + ASSERT((registers_mask() & (1 << reg_code)) != kRegListEmpty);
|
| // The registers are pushed starting with the highest encoding,
|
| // which means that lowest encodings are closest to the stack pointer.
|
| ASSERT(reg_code >= 0 && reg_code < kNumSafepointRegisters);
|
| - return reg_code;
|
| + ASSERT((registers_mask() & (1 << reg_code)) != 0);
|
| + // Only count registers below reg_code.
|
| + return
|
| + CompilerIntrinsics::CountSetBits(registers_mask() & ((1 << reg_code) - 1));
|
| }
|
|
|
|
|
| @@ -699,10 +761,9 @@ MemOperand MacroAssembler::SafepointRegisterSlot(Register reg) {
|
|
|
|
|
| MemOperand MacroAssembler::SafepointRegistersAndDoublesSlot(Register reg) {
|
| - // Number of d-regs not known at snapshot time.
|
| - ASSERT(!Serializer::enabled());
|
| // General purpose registers are pushed last on the stack.
|
| - int doubles_size = DwVfpRegister::NumAllocatableRegisters() * kDoubleSize;
|
| + int doubles_size =
|
| + CompilerIntrinsics::CountSetBits(double_registers_mask()) * kDoubleSize;
|
| int register_offset = SafepointRegisterStackIndex(reg.code()) * kPointerSize;
|
| return MemOperand(sp, doubles_size + register_offset);
|
| }
|
|
|