michael@0: /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- michael@0: * vim: set ts=8 sts=4 et sw=4 tw=99: michael@0: * This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #ifndef jit_x86_Assembler_x86_h michael@0: #define jit_x86_Assembler_x86_h michael@0: michael@0: #include "mozilla/ArrayUtils.h" michael@0: michael@0: #include "assembler/assembler/X86Assembler.h" michael@0: #include "jit/CompactBuffer.h" michael@0: #include "jit/IonCode.h" michael@0: #include "jit/shared/Assembler-shared.h" michael@0: michael@0: namespace js { michael@0: namespace jit { michael@0: michael@0: static MOZ_CONSTEXPR_VAR Register eax = { JSC::X86Registers::eax }; michael@0: static MOZ_CONSTEXPR_VAR Register ecx = { JSC::X86Registers::ecx }; michael@0: static MOZ_CONSTEXPR_VAR Register edx = { JSC::X86Registers::edx }; michael@0: static MOZ_CONSTEXPR_VAR Register ebx = { JSC::X86Registers::ebx }; michael@0: static MOZ_CONSTEXPR_VAR Register esp = { JSC::X86Registers::esp }; michael@0: static MOZ_CONSTEXPR_VAR Register ebp = { JSC::X86Registers::ebp }; michael@0: static MOZ_CONSTEXPR_VAR Register esi = { JSC::X86Registers::esi }; michael@0: static MOZ_CONSTEXPR_VAR Register edi = { JSC::X86Registers::edi }; michael@0: michael@0: static MOZ_CONSTEXPR_VAR FloatRegister xmm0 = { JSC::X86Registers::xmm0 }; michael@0: static MOZ_CONSTEXPR_VAR FloatRegister xmm1 = { JSC::X86Registers::xmm1 }; michael@0: static MOZ_CONSTEXPR_VAR FloatRegister xmm2 = { JSC::X86Registers::xmm2 }; michael@0: static MOZ_CONSTEXPR_VAR FloatRegister xmm3 = { JSC::X86Registers::xmm3 }; michael@0: static MOZ_CONSTEXPR_VAR FloatRegister xmm4 = { JSC::X86Registers::xmm4 }; michael@0: static MOZ_CONSTEXPR_VAR FloatRegister xmm5 = { JSC::X86Registers::xmm5 }; michael@0: static MOZ_CONSTEXPR_VAR FloatRegister xmm6 = { JSC::X86Registers::xmm6 }; michael@0: static MOZ_CONSTEXPR_VAR FloatRegister xmm7 = { JSC::X86Registers::xmm7 }; michael@0: michael@0: static MOZ_CONSTEXPR_VAR Register InvalidReg = { JSC::X86Registers::invalid_reg }; michael@0: static MOZ_CONSTEXPR_VAR FloatRegister InvalidFloatReg = { JSC::X86Registers::invalid_xmm }; michael@0: michael@0: static MOZ_CONSTEXPR_VAR Register JSReturnReg_Type = ecx; michael@0: static MOZ_CONSTEXPR_VAR Register JSReturnReg_Data = edx; michael@0: static MOZ_CONSTEXPR_VAR Register StackPointer = esp; michael@0: static MOZ_CONSTEXPR_VAR Register FramePointer = ebp; michael@0: static MOZ_CONSTEXPR_VAR Register ReturnReg = eax; michael@0: static MOZ_CONSTEXPR_VAR FloatRegister ReturnFloatReg = xmm0; michael@0: static MOZ_CONSTEXPR_VAR FloatRegister ScratchFloatReg = xmm7; michael@0: michael@0: // Avoid ebp, which is the FramePointer, which is unavailable in some modes. michael@0: static MOZ_CONSTEXPR_VAR Register ArgumentsRectifierReg = esi; michael@0: static MOZ_CONSTEXPR_VAR Register CallTempReg0 = edi; michael@0: static MOZ_CONSTEXPR_VAR Register CallTempReg1 = eax; michael@0: static MOZ_CONSTEXPR_VAR Register CallTempReg2 = ebx; michael@0: static MOZ_CONSTEXPR_VAR Register CallTempReg3 = ecx; michael@0: static MOZ_CONSTEXPR_VAR Register CallTempReg4 = esi; michael@0: static MOZ_CONSTEXPR_VAR Register CallTempReg5 = edx; michael@0: michael@0: // The convention used by the ForkJoinGetSlice stub. None of these can be eax michael@0: // or edx, which the stub also needs for cmpxchg and div, respectively. michael@0: static MOZ_CONSTEXPR_VAR Register ForkJoinGetSliceReg_cx = edi; michael@0: static MOZ_CONSTEXPR_VAR Register ForkJoinGetSliceReg_temp0 = ebx; michael@0: static MOZ_CONSTEXPR_VAR Register ForkJoinGetSliceReg_temp1 = ecx; michael@0: static MOZ_CONSTEXPR_VAR Register ForkJoinGetSliceReg_output = esi; michael@0: michael@0: // We have no arg regs, so our NonArgRegs are just our CallTempReg* michael@0: static MOZ_CONSTEXPR_VAR Register CallTempNonArgRegs[] = { edi, eax, ebx, ecx, esi, edx }; michael@0: static const uint32_t NumCallTempNonArgRegs = michael@0: mozilla::ArrayLength(CallTempNonArgRegs); michael@0: michael@0: class ABIArgGenerator michael@0: { michael@0: uint32_t stackOffset_; michael@0: ABIArg current_; michael@0: michael@0: public: michael@0: ABIArgGenerator(); michael@0: ABIArg next(MIRType argType); michael@0: ABIArg ¤t() { return current_; } michael@0: uint32_t stackBytesConsumedSoFar() const { return stackOffset_; } michael@0: michael@0: // Note: these registers are all guaranteed to be different michael@0: static const Register NonArgReturnVolatileReg0; michael@0: static const Register NonArgReturnVolatileReg1; michael@0: static const Register NonVolatileReg; michael@0: }; michael@0: michael@0: static MOZ_CONSTEXPR_VAR Register OsrFrameReg = edx; michael@0: static MOZ_CONSTEXPR_VAR Register PreBarrierReg = edx; michael@0: michael@0: // Registers used in the GenerateFFIIonExit Enable Activation block. michael@0: static MOZ_CONSTEXPR_VAR Register AsmJSIonExitRegCallee = ecx; michael@0: static MOZ_CONSTEXPR_VAR Register AsmJSIonExitRegE0 = edi; michael@0: static MOZ_CONSTEXPR_VAR Register AsmJSIonExitRegE1 = eax; michael@0: static MOZ_CONSTEXPR_VAR Register AsmJSIonExitRegE2 = ebx; michael@0: static MOZ_CONSTEXPR_VAR Register AsmJSIonExitRegE3 = edx; michael@0: michael@0: // Registers used in the GenerateFFIIonExit Disable Activation block. michael@0: static MOZ_CONSTEXPR_VAR Register AsmJSIonExitRegReturnData = edx; michael@0: static MOZ_CONSTEXPR_VAR Register AsmJSIonExitRegReturnType = ecx; michael@0: static MOZ_CONSTEXPR_VAR Register AsmJSIonExitRegD0 = edi; michael@0: static MOZ_CONSTEXPR_VAR Register AsmJSIonExitRegD1 = eax; michael@0: static MOZ_CONSTEXPR_VAR Register AsmJSIonExitRegD2 = esi; michael@0: michael@0: // GCC stack is aligned on 16 bytes, but we don't maintain the invariant in michael@0: // jitted code. michael@0: #if defined(__GNUC__) michael@0: static const uint32_t StackAlignment = 16; michael@0: #else michael@0: static const uint32_t StackAlignment = 4; michael@0: #endif michael@0: static const bool StackKeptAligned = false; michael@0: static const uint32_t CodeAlignment = 8; michael@0: static const uint32_t NativeFrameSize = sizeof(void*); michael@0: static const uint32_t AlignmentAtPrologue = sizeof(void*); michael@0: static const uint32_t AlignmentMidPrologue = AlignmentAtPrologue; michael@0: struct ImmTag : public Imm32 michael@0: { michael@0: ImmTag(JSValueTag mask) michael@0: : Imm32(int32_t(mask)) michael@0: { } michael@0: }; michael@0: michael@0: struct ImmType : public ImmTag michael@0: { michael@0: ImmType(JSValueType type) michael@0: : ImmTag(JSVAL_TYPE_TO_TAG(type)) michael@0: { } michael@0: }; michael@0: michael@0: static const Scale ScalePointer = TimesFour; michael@0: michael@0: } // namespace jit michael@0: } // namespace js michael@0: michael@0: #include "jit/shared/Assembler-x86-shared.h" michael@0: michael@0: namespace js { michael@0: namespace jit { michael@0: michael@0: static inline void michael@0: PatchJump(CodeLocationJump jump, CodeLocationLabel label) michael@0: { michael@0: #ifdef DEBUG michael@0: // Assert that we're overwriting a jump instruction, either: michael@0: // 0F 80+cc , or michael@0: // E9 michael@0: unsigned char *x = (unsigned char *)jump.raw() - 5; michael@0: JS_ASSERT(((*x >= 0x80 && *x <= 0x8F) && *(x - 1) == 0x0F) || michael@0: (*x == 0xE9)); michael@0: #endif michael@0: JSC::X86Assembler::setRel32(jump.raw(), label.raw()); michael@0: } michael@0: michael@0: // Return operand from a JS -> JS call. michael@0: static const ValueOperand JSReturnOperand = ValueOperand(JSReturnReg_Type, JSReturnReg_Data); michael@0: michael@0: class Assembler : public AssemblerX86Shared michael@0: { michael@0: void writeRelocation(JmpSrc src) { michael@0: jumpRelocations_.writeUnsigned(src.offset()); michael@0: } michael@0: void addPendingJump(JmpSrc src, ImmPtr target, Relocation::Kind kind) { michael@0: enoughMemory_ &= jumps_.append(RelativePatch(src.offset(), target.value, kind)); michael@0: if (kind == Relocation::JITCODE) michael@0: writeRelocation(src); michael@0: } michael@0: michael@0: public: michael@0: using AssemblerX86Shared::movl; michael@0: using AssemblerX86Shared::j; michael@0: using AssemblerX86Shared::jmp; michael@0: using AssemblerX86Shared::movsd; michael@0: using AssemblerX86Shared::movss; michael@0: using AssemblerX86Shared::retarget; michael@0: using AssemblerX86Shared::cmpl; michael@0: using AssemblerX86Shared::call; michael@0: using AssemblerX86Shared::push; michael@0: using AssemblerX86Shared::pop; michael@0: michael@0: static void TraceJumpRelocations(JSTracer *trc, JitCode *code, CompactBufferReader &reader); michael@0: michael@0: // Copy the assembly code to the given buffer, and perform any pending michael@0: // relocations relying on the target address. michael@0: void executableCopy(uint8_t *buffer); michael@0: michael@0: // Actual assembly emitting functions. michael@0: michael@0: void push(const ImmGCPtr &ptr) { michael@0: push(Imm32(ptr.value)); michael@0: writeDataRelocation(ptr); michael@0: } michael@0: void push(const ImmWord imm) { michael@0: push(Imm32(imm.value)); michael@0: } michael@0: void push(const ImmPtr imm) { michael@0: push(ImmWord(uintptr_t(imm.value))); michael@0: } michael@0: void push(const FloatRegister &src) { michael@0: subl(Imm32(sizeof(double)), StackPointer); michael@0: movsd(src, Address(StackPointer, 0)); michael@0: } michael@0: michael@0: CodeOffsetLabel pushWithPatch(const ImmWord &word) { michael@0: push(Imm32(word.value)); michael@0: return masm.currentOffset(); michael@0: } michael@0: michael@0: void pop(const FloatRegister &src) { michael@0: movsd(Address(StackPointer, 0), src); michael@0: addl(Imm32(sizeof(double)), StackPointer); michael@0: } michael@0: michael@0: CodeOffsetLabel movWithPatch(const ImmWord &word, const Register &dest) { michael@0: movl(Imm32(word.value), dest); michael@0: return masm.currentOffset(); michael@0: } michael@0: CodeOffsetLabel movWithPatch(const ImmPtr &imm, const Register &dest) { michael@0: return movWithPatch(ImmWord(uintptr_t(imm.value)), dest); michael@0: } michael@0: michael@0: void movl(const ImmGCPtr &ptr, const Register &dest) { michael@0: masm.movl_i32r(ptr.value, dest.code()); michael@0: writeDataRelocation(ptr); michael@0: } michael@0: void movl(const ImmGCPtr &ptr, const Operand &dest) { michael@0: switch (dest.kind()) { michael@0: case Operand::REG: michael@0: masm.movl_i32r(ptr.value, dest.reg()); michael@0: writeDataRelocation(ptr); michael@0: break; michael@0: case Operand::MEM_REG_DISP: michael@0: masm.movl_i32m(ptr.value, dest.disp(), dest.base()); michael@0: writeDataRelocation(ptr); michael@0: break; michael@0: case Operand::MEM_SCALE: michael@0: masm.movl_i32m(ptr.value, dest.disp(), dest.base(), dest.index(), dest.scale()); michael@0: writeDataRelocation(ptr); michael@0: break; michael@0: default: michael@0: MOZ_ASSUME_UNREACHABLE("unexpected operand kind"); michael@0: } michael@0: } michael@0: void movl(ImmWord imm, Register dest) { michael@0: masm.movl_i32r(imm.value, dest.code()); michael@0: } michael@0: void movl(ImmPtr imm, Register dest) { michael@0: movl(ImmWord(uintptr_t(imm.value)), dest); michael@0: } michael@0: void mov(ImmWord imm, Register dest) { michael@0: // Use xor for setting registers to zero, as it is specially optimized michael@0: // for this purpose on modern hardware. Note that it does clobber FLAGS michael@0: // though. michael@0: if (imm.value == 0) michael@0: xorl(dest, dest); michael@0: else michael@0: movl(imm, dest); michael@0: } michael@0: void mov(ImmPtr imm, Register dest) { michael@0: mov(ImmWord(uintptr_t(imm.value)), dest); michael@0: } michael@0: void mov(AsmJSImmPtr imm, Register dest) { michael@0: masm.movl_i32r(-1, dest.code()); michael@0: enoughMemory_ &= append(AsmJSAbsoluteLink(masm.currentOffset(), imm.kind())); michael@0: } michael@0: void mov(const Operand &src, const Register &dest) { michael@0: movl(src, dest); michael@0: } michael@0: void mov(const Register &src, const Operand &dest) { michael@0: movl(src, dest); michael@0: } michael@0: void mov(Imm32 imm, const Operand &dest) { michael@0: movl(imm, dest); michael@0: } michael@0: void mov(AbsoluteLabel *label, const Register &dest) { michael@0: JS_ASSERT(!label->bound()); michael@0: // Thread the patch list through the unpatched address word in the michael@0: // instruction stream. michael@0: masm.movl_i32r(label->prev(), dest.code()); michael@0: label->setPrev(masm.size()); michael@0: } michael@0: void mov(const Register &src, const Register &dest) { michael@0: movl(src, dest); michael@0: } michael@0: void xchg(const Register &src, const Register &dest) { michael@0: xchgl(src, dest); michael@0: } michael@0: void lea(const Operand &src, const Register &dest) { michael@0: return leal(src, dest); michael@0: } michael@0: michael@0: void fld32(const Operand &dest) { michael@0: switch (dest.kind()) { michael@0: case Operand::MEM_REG_DISP: michael@0: masm.fld32_m(dest.disp(), dest.base()); michael@0: break; michael@0: default: michael@0: MOZ_ASSUME_UNREACHABLE("unexpected operand kind"); michael@0: } michael@0: } michael@0: michael@0: void fstp32(const Operand &src) { michael@0: switch (src.kind()) { michael@0: case Operand::MEM_REG_DISP: michael@0: masm.fstp32_m(src.disp(), src.base()); michael@0: break; michael@0: default: michael@0: MOZ_ASSUME_UNREACHABLE("unexpected operand kind"); michael@0: } michael@0: } michael@0: michael@0: void cmpl(const Register src, ImmWord ptr) { michael@0: masm.cmpl_ir(ptr.value, src.code()); michael@0: } michael@0: void cmpl(const Register src, ImmPtr imm) { michael@0: cmpl(src, ImmWord(uintptr_t(imm.value))); michael@0: } michael@0: void cmpl(const Register src, ImmGCPtr ptr) { michael@0: masm.cmpl_ir(ptr.value, src.code()); michael@0: writeDataRelocation(ptr); michael@0: } michael@0: void cmpl(const Register &lhs, const Register &rhs) { michael@0: masm.cmpl_rr(rhs.code(), lhs.code()); michael@0: } michael@0: void cmpl(const Operand &op, ImmGCPtr imm) { michael@0: switch (op.kind()) { michael@0: case Operand::REG: michael@0: masm.cmpl_ir_force32(imm.value, op.reg()); michael@0: writeDataRelocation(imm); michael@0: break; michael@0: case Operand::MEM_REG_DISP: michael@0: masm.cmpl_im_force32(imm.value, op.disp(), op.base()); michael@0: writeDataRelocation(imm); michael@0: break; michael@0: case Operand::MEM_ADDRESS32: michael@0: masm.cmpl_im(imm.value, op.address()); michael@0: writeDataRelocation(imm); michael@0: break; michael@0: default: michael@0: MOZ_ASSUME_UNREACHABLE("unexpected operand kind"); michael@0: } michael@0: } michael@0: void cmpl(const AsmJSAbsoluteAddress &lhs, const Register &rhs) { michael@0: masm.cmpl_rm_force32(rhs.code(), (void*)-1); michael@0: enoughMemory_ &= append(AsmJSAbsoluteLink(masm.currentOffset(), lhs.kind())); michael@0: } michael@0: CodeOffsetLabel cmplWithPatch(const Register &lhs, Imm32 rhs) { michael@0: masm.cmpl_ir_force32(rhs.value, lhs.code()); michael@0: return masm.currentOffset(); michael@0: } michael@0: michael@0: void jmp(ImmPtr target, Relocation::Kind reloc = Relocation::HARDCODED) { michael@0: JmpSrc src = masm.jmp(); michael@0: addPendingJump(src, target, reloc); michael@0: } michael@0: void j(Condition cond, ImmPtr target, michael@0: Relocation::Kind reloc = Relocation::HARDCODED) { michael@0: JmpSrc src = masm.jCC(static_cast(cond)); michael@0: addPendingJump(src, target, reloc); michael@0: } michael@0: michael@0: void jmp(JitCode *target) { michael@0: jmp(ImmPtr(target->raw()), Relocation::JITCODE); michael@0: } michael@0: void j(Condition cond, JitCode *target) { michael@0: j(cond, ImmPtr(target->raw()), Relocation::JITCODE); michael@0: } michael@0: void call(JitCode *target) { michael@0: JmpSrc src = masm.call(); michael@0: addPendingJump(src, ImmPtr(target->raw()), Relocation::JITCODE); michael@0: } michael@0: void call(ImmWord target) { michael@0: call(ImmPtr((void*)target.value)); michael@0: } michael@0: void call(ImmPtr target) { michael@0: JmpSrc src = masm.call(); michael@0: addPendingJump(src, target, Relocation::HARDCODED); michael@0: } michael@0: void call(AsmJSImmPtr target) { michael@0: // Moving to a register is suboptimal. To fix (use a single michael@0: // call-immediate instruction) we'll need to distinguish a new type of michael@0: // relative patch to an absolute address in AsmJSAbsoluteLink. michael@0: mov(target, eax); michael@0: call(eax); michael@0: } michael@0: michael@0: // Emit a CALL or CMP (nop) instruction. ToggleCall can be used to patch michael@0: // this instruction. michael@0: CodeOffsetLabel toggledCall(JitCode *target, bool enabled) { michael@0: CodeOffsetLabel offset(size()); michael@0: JmpSrc src = enabled ? masm.call() : masm.cmp_eax(); michael@0: addPendingJump(src, ImmPtr(target->raw()), Relocation::JITCODE); michael@0: JS_ASSERT(size() - offset.offset() == ToggledCallSize()); michael@0: return offset; michael@0: } michael@0: michael@0: static size_t ToggledCallSize() { michael@0: // Size of a call instruction. michael@0: return 5; michael@0: } michael@0: michael@0: // Re-routes pending jumps to an external target, flushing the label in the michael@0: // process. michael@0: void retarget(Label *label, ImmPtr target, Relocation::Kind reloc) { michael@0: JSC::MacroAssembler::Label jsclabel; michael@0: if (label->used()) { michael@0: bool more; michael@0: JSC::X86Assembler::JmpSrc jmp(label->offset()); michael@0: do { michael@0: JSC::X86Assembler::JmpSrc next; michael@0: more = masm.nextJump(jmp, &next); michael@0: addPendingJump(jmp, target, reloc); michael@0: jmp = next; michael@0: } while (more); michael@0: } michael@0: label->reset(); michael@0: } michael@0: michael@0: // Move a 32-bit immediate into a register where the immediate can be michael@0: // patched. michael@0: CodeOffsetLabel movlWithPatch(Imm32 imm, Register dest) { michael@0: masm.movl_i32r(imm.value, dest.code()); michael@0: return masm.currentOffset(); michael@0: } michael@0: michael@0: // Load from *(base + disp32) where disp32 can be patched. michael@0: CodeOffsetLabel movsblWithPatch(Address src, Register dest) { michael@0: masm.movsbl_mr_disp32(src.offset, src.base.code(), dest.code()); michael@0: return masm.currentOffset(); michael@0: } michael@0: CodeOffsetLabel movzblWithPatch(Address src, Register dest) { michael@0: masm.movzbl_mr_disp32(src.offset, src.base.code(), dest.code()); michael@0: return masm.currentOffset(); michael@0: } michael@0: CodeOffsetLabel movswlWithPatch(Address src, Register dest) { michael@0: masm.movswl_mr_disp32(src.offset, src.base.code(), dest.code()); michael@0: return masm.currentOffset(); michael@0: } michael@0: CodeOffsetLabel movzwlWithPatch(Address src, Register dest) { michael@0: masm.movzwl_mr_disp32(src.offset, src.base.code(), dest.code()); michael@0: return masm.currentOffset(); michael@0: } michael@0: CodeOffsetLabel movlWithPatch(Address src, Register dest) { michael@0: masm.movl_mr_disp32(src.offset, src.base.code(), dest.code()); michael@0: return masm.currentOffset(); michael@0: } michael@0: CodeOffsetLabel movssWithPatch(Address src, FloatRegister dest) { michael@0: JS_ASSERT(HasSSE2()); michael@0: masm.movss_mr_disp32(src.offset, src.base.code(), dest.code()); michael@0: return masm.currentOffset(); michael@0: } michael@0: CodeOffsetLabel movsdWithPatch(Address src, FloatRegister dest) { michael@0: JS_ASSERT(HasSSE2()); michael@0: masm.movsd_mr_disp32(src.offset, src.base.code(), dest.code()); michael@0: return masm.currentOffset(); michael@0: } michael@0: michael@0: // Store to *(base + disp32) where disp32 can be patched. michael@0: CodeOffsetLabel movbWithPatch(Register src, Address dest) { michael@0: masm.movb_rm_disp32(src.code(), dest.offset, dest.base.code()); michael@0: return masm.currentOffset(); michael@0: } michael@0: CodeOffsetLabel movwWithPatch(Register src, Address dest) { michael@0: masm.movw_rm_disp32(src.code(), dest.offset, dest.base.code()); michael@0: return masm.currentOffset(); michael@0: } michael@0: CodeOffsetLabel movlWithPatch(Register src, Address dest) { michael@0: masm.movl_rm_disp32(src.code(), dest.offset, dest.base.code()); michael@0: return masm.currentOffset(); michael@0: } michael@0: CodeOffsetLabel movssWithPatch(FloatRegister src, Address dest) { michael@0: JS_ASSERT(HasSSE2()); michael@0: masm.movss_rm_disp32(src.code(), dest.offset, dest.base.code()); michael@0: return masm.currentOffset(); michael@0: } michael@0: CodeOffsetLabel movsdWithPatch(FloatRegister src, Address dest) { michael@0: JS_ASSERT(HasSSE2()); michael@0: masm.movsd_rm_disp32(src.code(), dest.offset, dest.base.code()); michael@0: return masm.currentOffset(); michael@0: } michael@0: michael@0: // Load from *(addr + index*scale) where addr can be patched. michael@0: CodeOffsetLabel movlWithPatch(PatchedAbsoluteAddress addr, Register index, Scale scale, michael@0: Register dest) michael@0: { michael@0: masm.movl_mr(addr.addr, index.code(), scale, dest.code()); michael@0: return masm.currentOffset(); michael@0: } michael@0: michael@0: // Load from *src where src can be patched. michael@0: CodeOffsetLabel movsblWithPatch(const PatchedAbsoluteAddress &src, Register dest) { michael@0: masm.movsbl_mr(src.addr, dest.code()); michael@0: return masm.currentOffset(); michael@0: } michael@0: CodeOffsetLabel movzblWithPatch(const PatchedAbsoluteAddress &src, Register dest) { michael@0: masm.movzbl_mr(src.addr, dest.code()); michael@0: return masm.currentOffset(); michael@0: } michael@0: CodeOffsetLabel movswlWithPatch(const PatchedAbsoluteAddress &src, Register dest) { michael@0: masm.movswl_mr(src.addr, dest.code()); michael@0: return masm.currentOffset(); michael@0: } michael@0: CodeOffsetLabel movzwlWithPatch(const PatchedAbsoluteAddress &src, Register dest) { michael@0: masm.movzwl_mr(src.addr, dest.code()); michael@0: return masm.currentOffset(); michael@0: } michael@0: CodeOffsetLabel movlWithPatch(const PatchedAbsoluteAddress &src, Register dest) { michael@0: masm.movl_mr(src.addr, dest.code()); michael@0: return masm.currentOffset(); michael@0: } michael@0: CodeOffsetLabel movssWithPatch(const PatchedAbsoluteAddress &src, FloatRegister dest) { michael@0: JS_ASSERT(HasSSE2()); michael@0: masm.movss_mr(src.addr, dest.code()); michael@0: return masm.currentOffset(); michael@0: } michael@0: CodeOffsetLabel movsdWithPatch(const PatchedAbsoluteAddress &src, FloatRegister dest) { michael@0: JS_ASSERT(HasSSE2()); michael@0: masm.movsd_mr(src.addr, dest.code()); michael@0: return masm.currentOffset(); michael@0: } michael@0: michael@0: // Store to *dest where dest can be patched. michael@0: CodeOffsetLabel movbWithPatch(Register src, const PatchedAbsoluteAddress &dest) { michael@0: masm.movb_rm(src.code(), dest.addr); michael@0: return masm.currentOffset(); michael@0: } michael@0: CodeOffsetLabel movwWithPatch(Register src, const PatchedAbsoluteAddress &dest) { michael@0: masm.movw_rm(src.code(), dest.addr); michael@0: return masm.currentOffset(); michael@0: } michael@0: CodeOffsetLabel movlWithPatch(Register src, const PatchedAbsoluteAddress &dest) { michael@0: masm.movl_rm(src.code(), dest.addr); michael@0: return masm.currentOffset(); michael@0: } michael@0: CodeOffsetLabel movssWithPatch(FloatRegister src, const PatchedAbsoluteAddress &dest) { michael@0: JS_ASSERT(HasSSE2()); michael@0: masm.movss_rm(src.code(), dest.addr); michael@0: return masm.currentOffset(); michael@0: } michael@0: CodeOffsetLabel movsdWithPatch(FloatRegister src, const PatchedAbsoluteAddress &dest) { michael@0: JS_ASSERT(HasSSE2()); michael@0: masm.movsd_rm(src.code(), dest.addr); michael@0: return masm.currentOffset(); michael@0: } michael@0: michael@0: }; michael@0: michael@0: // Get a register in which we plan to put a quantity that will be used as an michael@0: // integer argument. This differs from GetIntArgReg in that if we have no more michael@0: // actual argument registers to use we will fall back on using whatever michael@0: // CallTempReg* don't overlap the argument registers, and only fail once those michael@0: // run out too. michael@0: static inline bool michael@0: GetTempRegForIntArg(uint32_t usedIntArgs, uint32_t usedFloatArgs, Register *out) michael@0: { michael@0: if (usedIntArgs >= NumCallTempNonArgRegs) michael@0: return false; michael@0: *out = CallTempNonArgRegs[usedIntArgs]; michael@0: return true; michael@0: } michael@0: michael@0: } // namespace jit michael@0: } // namespace js michael@0: michael@0: #endif /* jit_x86_Assembler_x86_h */