diff --git a/js/src/ion/arm/Assembler-arm.cpp b/js/src/ion/arm/Assembler-arm.cpp index 62b1368eecc..26ccfa56ef0 100644 --- a/js/src/ion/arm/Assembler-arm.cpp +++ b/js/src/ion/arm/Assembler-arm.cpp @@ -181,6 +181,20 @@ InstLDR::asTHIS(Instruction &i) return NULL; } +InstNOP * +InstNOP::asTHIS(Instruction &i) +{ + if (isTHIS(i)) + return (InstNOP*) (&i); + return NULL; +} + +bool +InstNOP::isTHIS(const Instruction &i) +{ + return (i.encode() & 0x0fffffff) == NopInst; +} + bool InstBranchReg::isTHIS(const Instruction &i) { @@ -2471,6 +2485,31 @@ Assembler::ToggleToCmp(CodeLocationLabel inst_) AutoFlushCache::updateTop((uintptr_t)ptr, 4); } +void +Assembler::ToggleCall(CodeLocationLabel inst_, bool enabled) +{ + Instruction *inst = (Instruction *)inst_.raw(); + JS_ASSERT(inst->is()); + + inst = inst->next(); + JS_ASSERT(inst->is()); + + inst = inst->next(); + JS_ASSERT(inst->is() || inst->is()); + + if (enabled == inst->is()) { + // Nothing to do. + return; + } + + if (enabled) + *inst = InstBLXReg(ScratchRegister, Always); + else + *inst = InstNOP(); + + AutoFlushCache::updateTop(uintptr_t(inst), 4); +} + void AutoFlushCache::update(uintptr_t newStart, size_t len) { diff --git a/js/src/ion/arm/Assembler-arm.h b/js/src/ion/arm/Assembler-arm.h index a9709a36564..bd1fb800f76 100644 --- a/js/src/ion/arm/Assembler-arm.h +++ b/js/src/ion/arm/Assembler-arm.h @@ -1698,6 +1698,7 @@ class Assembler static void ToggleToJmp(CodeLocationLabel inst_); static void ToggleToCmp(CodeLocationLabel inst_); + static void ToggleCall(CodeLocationLabel inst_, bool enabled); }; // Assembler // An Instruction is a structure for both encoding and decoding any and all ARM instructions. @@ -1787,6 +1788,20 @@ class InstLDR : public InstDTR }; JS_STATIC_ASSERT(sizeof(InstDTR) == sizeof(InstLDR)); + +class InstNOP : public Instruction +{ + static const uint32_t NopInst = 0x0320f000; + + public: + InstNOP() + : Instruction(NopInst, Assembler::Always) + { } + + static bool isTHIS(const Instruction &i); + static InstNOP *asTHIS(Instruction &i); +}; + // Branching to a register, or calling a register class InstBranchReg : public Instruction { @@ -1798,7 +1813,7 @@ class InstBranchReg : public Instruction }; static const uint32_t IsBRegMask = 0x0ffffff0; InstBranchReg(BranchTag tag, Register rm, Assembler::Condition c) - : Instruction(tag | RM(rm), c) + : Instruction(tag | rm.code(), c) { } public: static bool isTHIS (const Instruction &i); @@ -1841,6 +1856,10 @@ class InstBXReg : public InstBranchReg class InstBLXReg : public InstBranchReg { public: + InstBLXReg(Register reg, Assembler::Condition c) + : InstBranchReg(IsBLX, reg, c) + { } + static bool isTHIS (const Instruction &i); static InstBLXReg *asTHIS (const Instruction &i); }; diff --git a/js/src/ion/arm/MacroAssembler-arm.cpp b/js/src/ion/arm/MacroAssembler-arm.cpp index 8aa5ed98c93..aca07d42e67 100644 --- a/js/src/ion/arm/MacroAssembler-arm.cpp +++ b/js/src/ion/arm/MacroAssembler-arm.cpp @@ -1136,6 +1136,12 @@ MacroAssemblerARM::ma_bl(Label *dest, Assembler::Condition c) as_bl(dest, c); } +void +MacroAssemblerARM::ma_blx(Register reg, Assembler::Condition c) +{ + as_blx(reg, c); +} + // VFP/ALU void MacroAssemblerARM::ma_vadd(FloatRegister src1, FloatRegister src2, FloatRegister dst) @@ -3019,6 +3025,20 @@ MacroAssemblerARMCompat::toggledJump(Label *label) return ret; } +CodeOffsetLabel +MacroAssemblerARMCompat::toggledCall(IonCode *target, bool enabled) +{ + CodeOffsetLabel offset(size()); + BufferOffset bo = m_buffer.nextOffset(); + addPendingJump(bo, target->raw(), Relocation::IONCODE); + ma_movPatchable(Imm32(uint32_t(target->raw())), ScratchRegister, Always, L_MOVWT); + if (enabled) + ma_blx(ScratchRegister); + else + ma_nop(); + return offset; +} + void MacroAssemblerARMCompat::round(FloatRegister input, Register output, Label *bail, FloatRegister tmp) { diff --git a/js/src/ion/arm/MacroAssembler-arm.h b/js/src/ion/arm/MacroAssembler-arm.h index c43b536b8bb..790ec5d6d91 100644 --- a/js/src/ion/arm/MacroAssembler-arm.h +++ b/js/src/ion/arm/MacroAssembler-arm.h @@ -277,6 +277,8 @@ class MacroAssemblerARM : public Assembler // except, possibly in the crazy bailout-table case. void ma_bl(Label *dest, Condition c = Always); + void ma_blx(Register dest, Condition c = Always); + //VFP/ALU void ma_vadd(FloatRegister src1, FloatRegister src2, FloatRegister dst); void ma_vsub(FloatRegister src1, FloatRegister src2, FloatRegister dst); @@ -500,6 +502,10 @@ class MacroAssemblerARMCompat : public MacroAssemblerARM CodeOffsetLabel toggledJump(Label *label); + // Emit a BLX or NOP instruction. ToggleCall can be used to patch + // this instruction. + CodeOffsetLabel toggledCall(IonCode *target, bool enabled); + CodeOffsetLabel pushWithPatch(ImmWord imm) { CodeOffsetLabel label = currentOffset(); ma_movPatchable(Imm32(imm.value), ScratchRegister, Always, L_MOVWT);