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: #include "jit/BaselineCompiler.h" michael@0: #include "jit/BaselineHelpers.h" michael@0: #include "jit/BaselineIC.h" michael@0: #include "jit/BaselineJIT.h" michael@0: #include "jit/IonLinker.h" michael@0: michael@0: using namespace js; michael@0: using namespace js::jit; michael@0: michael@0: namespace js { michael@0: namespace jit { michael@0: michael@0: // ICCompare_Int32 michael@0: michael@0: bool michael@0: ICCompare_Int32::Compiler::generateStubCode(MacroAssembler &masm) michael@0: { michael@0: // Guard that R0 is an integer and R1 is an integer. michael@0: Label failure; michael@0: masm.branchTestInt32(Assembler::NotEqual, R0, &failure); michael@0: masm.branchTestInt32(Assembler::NotEqual, R1, &failure); michael@0: michael@0: // Compare payload regs of R0 and R1. michael@0: Assembler::Condition cond = JSOpToCondition(op, /* signed = */true); michael@0: masm.cmpl(R0.payloadReg(), R1.payloadReg()); michael@0: masm.setCC(cond, R0.payloadReg()); michael@0: masm.movzbl(R0.payloadReg(), R0.payloadReg()); michael@0: michael@0: // Box the result and return michael@0: masm.tagValue(JSVAL_TYPE_BOOLEAN, R0.payloadReg(), R0); michael@0: EmitReturnFromIC(masm); michael@0: michael@0: // Failure case - jump to next stub michael@0: masm.bind(&failure); michael@0: EmitStubGuardFailure(masm); michael@0: return true; michael@0: } michael@0: michael@0: // ICBinaryArith_Int32 michael@0: michael@0: bool michael@0: ICBinaryArith_Int32::Compiler::generateStubCode(MacroAssembler &masm) michael@0: { michael@0: // Guard that R0 is an integer and R1 is an integer. michael@0: Label failure; michael@0: masm.branchTestInt32(Assembler::NotEqual, R0, &failure); michael@0: masm.branchTestInt32(Assembler::NotEqual, R1, &failure); michael@0: michael@0: // Add R0 and R1. Don't need to explicitly unbox, just use the TailCallReg which michael@0: // should be available. michael@0: Register scratchReg = BaselineTailCallReg; michael@0: michael@0: Label revertRegister, maybeNegZero; michael@0: switch(op_) { michael@0: case JSOP_ADD: michael@0: // Add R0 and R1. Don't need to explicitly unbox. michael@0: masm.movl(R0.payloadReg(), scratchReg); michael@0: masm.addl(R1.payloadReg(), scratchReg); michael@0: michael@0: // Just jump to failure on overflow. R0 and R1 are preserved, so we can just jump to michael@0: // the next stub. michael@0: masm.j(Assembler::Overflow, &failure); michael@0: michael@0: // Just overwrite the payload, the tag is still fine. michael@0: masm.movl(scratchReg, R0.payloadReg()); michael@0: break; michael@0: case JSOP_SUB: michael@0: masm.movl(R0.payloadReg(), scratchReg); michael@0: masm.subl(R1.payloadReg(), scratchReg); michael@0: masm.j(Assembler::Overflow, &failure); michael@0: masm.movl(scratchReg, R0.payloadReg()); michael@0: break; michael@0: case JSOP_MUL: michael@0: masm.movl(R0.payloadReg(), scratchReg); michael@0: masm.imull(R1.payloadReg(), scratchReg); michael@0: masm.j(Assembler::Overflow, &failure); michael@0: michael@0: masm.testl(scratchReg, scratchReg); michael@0: masm.j(Assembler::Zero, &maybeNegZero); michael@0: michael@0: masm.movl(scratchReg, R0.payloadReg()); michael@0: break; michael@0: case JSOP_DIV: michael@0: { michael@0: // Prevent division by 0. michael@0: masm.branchTest32(Assembler::Zero, R1.payloadReg(), R1.payloadReg(), &failure); michael@0: michael@0: // Prevent negative 0 and -2147483648 / -1. michael@0: masm.branch32(Assembler::Equal, R0.payloadReg(), Imm32(INT32_MIN), &failure); michael@0: michael@0: Label notZero; michael@0: masm.branch32(Assembler::NotEqual, R0.payloadReg(), Imm32(0), ¬Zero); michael@0: masm.branchTest32(Assembler::Signed, R1.payloadReg(), R1.payloadReg(), &failure); michael@0: masm.bind(¬Zero); michael@0: michael@0: // For idiv we need eax. michael@0: JS_ASSERT(R1.typeReg() == eax); michael@0: masm.movl(R0.payloadReg(), eax); michael@0: // Preserve R0.payloadReg()/edx, eax is JSVAL_TYPE_INT32. michael@0: masm.movl(R0.payloadReg(), scratchReg); michael@0: // Sign extend eax into edx to make (edx:eax), since idiv is 64-bit. michael@0: masm.cdq(); michael@0: masm.idiv(R1.payloadReg()); michael@0: michael@0: // A remainder implies a double result. michael@0: masm.branchTest32(Assembler::NonZero, edx, edx, &revertRegister); michael@0: michael@0: masm.movl(eax, R0.payloadReg()); michael@0: break; michael@0: } michael@0: case JSOP_MOD: michael@0: { michael@0: // x % 0 always results in NaN. michael@0: masm.branchTest32(Assembler::Zero, R1.payloadReg(), R1.payloadReg(), &failure); michael@0: michael@0: // Prevent negative 0 and -2147483648 % -1. michael@0: masm.branchTest32(Assembler::Zero, R0.payloadReg(), Imm32(0x7fffffff), &failure); michael@0: michael@0: // For idiv we need eax. michael@0: JS_ASSERT(R1.typeReg() == eax); michael@0: masm.movl(R0.payloadReg(), eax); michael@0: // Preserve R0.payloadReg()/edx, eax is JSVAL_TYPE_INT32. michael@0: masm.movl(R0.payloadReg(), scratchReg); michael@0: // Sign extend eax into edx to make (edx:eax), since idiv is 64-bit. michael@0: masm.cdq(); michael@0: masm.idiv(R1.payloadReg()); michael@0: michael@0: // Fail when we would need a negative remainder. michael@0: Label done; michael@0: masm.branchTest32(Assembler::NonZero, edx, edx, &done); michael@0: masm.branchTest32(Assembler::Signed, scratchReg, scratchReg, &revertRegister); michael@0: masm.branchTest32(Assembler::Signed, R1.payloadReg(), R1.payloadReg(), &revertRegister); michael@0: michael@0: masm.bind(&done); michael@0: // Result is in edx, tag in ecx remains untouched. michael@0: JS_ASSERT(R0.payloadReg() == edx); michael@0: JS_ASSERT(R0.typeReg() == ecx); michael@0: break; michael@0: } michael@0: case JSOP_BITOR: michael@0: // We can overide R0, because the instruction is unfailable. michael@0: // The R0.typeReg() is also still intact. michael@0: masm.orl(R1.payloadReg(), R0.payloadReg()); michael@0: break; michael@0: case JSOP_BITXOR: michael@0: masm.xorl(R1.payloadReg(), R0.payloadReg()); michael@0: break; michael@0: case JSOP_BITAND: michael@0: masm.andl(R1.payloadReg(), R0.payloadReg()); michael@0: break; michael@0: case JSOP_LSH: michael@0: // RHS needs to be in ecx for shift operations. michael@0: JS_ASSERT(R0.typeReg() == ecx); michael@0: masm.movl(R1.payloadReg(), ecx); michael@0: masm.shll_cl(R0.payloadReg()); michael@0: // We need to tag again, because we overwrote it. michael@0: masm.tagValue(JSVAL_TYPE_INT32, R0.payloadReg(), R0); michael@0: break; michael@0: case JSOP_RSH: michael@0: masm.movl(R1.payloadReg(), ecx); michael@0: masm.sarl_cl(R0.payloadReg()); michael@0: masm.tagValue(JSVAL_TYPE_INT32, R0.payloadReg(), R0); michael@0: break; michael@0: case JSOP_URSH: michael@0: if (!allowDouble_) michael@0: masm.movl(R0.payloadReg(), scratchReg); michael@0: michael@0: masm.movl(R1.payloadReg(), ecx); michael@0: masm.shrl_cl(R0.payloadReg()); michael@0: masm.testl(R0.payloadReg(), R0.payloadReg()); michael@0: if (allowDouble_) { michael@0: Label toUint; michael@0: masm.j(Assembler::Signed, &toUint); michael@0: michael@0: // Box and return. michael@0: masm.tagValue(JSVAL_TYPE_INT32, R0.payloadReg(), R0); michael@0: EmitReturnFromIC(masm); michael@0: michael@0: masm.bind(&toUint); michael@0: masm.convertUInt32ToDouble(R0.payloadReg(), ScratchFloatReg); michael@0: masm.boxDouble(ScratchFloatReg, R0); michael@0: } else { michael@0: masm.j(Assembler::Signed, &revertRegister); michael@0: masm.tagValue(JSVAL_TYPE_INT32, R0.payloadReg(), R0); michael@0: } michael@0: break; michael@0: default: michael@0: MOZ_ASSUME_UNREACHABLE("Unhandled op for BinaryArith_Int32. "); michael@0: } michael@0: michael@0: // Return. michael@0: EmitReturnFromIC(masm); michael@0: michael@0: switch(op_) { michael@0: case JSOP_MUL: michael@0: masm.bind(&maybeNegZero); michael@0: michael@0: // Result is -0 if exactly one of lhs or rhs is negative. michael@0: masm.movl(R0.payloadReg(), scratchReg); michael@0: masm.orl(R1.payloadReg(), scratchReg); michael@0: masm.j(Assembler::Signed, &failure); michael@0: michael@0: // Result is +0. michael@0: masm.mov(ImmWord(0), R0.payloadReg()); michael@0: EmitReturnFromIC(masm); michael@0: break; michael@0: case JSOP_DIV: michael@0: case JSOP_MOD: michael@0: masm.bind(&revertRegister); michael@0: masm.movl(scratchReg, R0.payloadReg()); michael@0: masm.movl(ImmType(JSVAL_TYPE_INT32), R1.typeReg()); michael@0: break; michael@0: case JSOP_URSH: michael@0: // Revert the content of R0 in the fallible >>> case. michael@0: if (!allowDouble_) { michael@0: masm.bind(&revertRegister); michael@0: masm.tagValue(JSVAL_TYPE_INT32, scratchReg, R0); michael@0: } michael@0: break; michael@0: default: michael@0: // No special failure handling required. michael@0: // Fall through to failure. michael@0: break; michael@0: } michael@0: michael@0: // Failure case - jump to next stub michael@0: masm.bind(&failure); michael@0: EmitStubGuardFailure(masm); michael@0: michael@0: return true; michael@0: } michael@0: michael@0: bool michael@0: ICUnaryArith_Int32::Compiler::generateStubCode(MacroAssembler &masm) michael@0: { michael@0: Label failure; michael@0: masm.branchTestInt32(Assembler::NotEqual, R0, &failure); michael@0: michael@0: switch (op) { michael@0: case JSOP_BITNOT: michael@0: masm.notl(R0.payloadReg()); michael@0: break; michael@0: case JSOP_NEG: michael@0: // Guard against 0 and MIN_INT, both result in a double. michael@0: masm.branchTest32(Assembler::Zero, R0.payloadReg(), Imm32(0x7fffffff), &failure); michael@0: masm.negl(R0.payloadReg()); michael@0: break; michael@0: default: michael@0: MOZ_ASSUME_UNREACHABLE("Unexpected op"); michael@0: } michael@0: michael@0: EmitReturnFromIC(masm); michael@0: michael@0: masm.bind(&failure); michael@0: EmitStubGuardFailure(masm); michael@0: return true; michael@0: } michael@0: michael@0: } // namespace jit michael@0: } // namespace js