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/BaselineHelpers.h" michael@0: #include "jit/BaselineIC.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: // Directly compare the int32 payload of R0 and R1. michael@0: Assembler::Condition cond = JSOpToCondition(op, /* signed = */true); michael@0: masm.mov(ImmWord(0), ScratchReg); michael@0: masm.cmpl(R0.valueReg(), R1.valueReg()); michael@0: masm.setCC(cond, ScratchReg); michael@0: michael@0: // Box the result and return michael@0: masm.boxValue(JSVAL_TYPE_BOOLEAN, ScratchReg, R0.valueReg()); 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: 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: Label revertRegister, maybeNegZero; michael@0: switch(op_) { michael@0: case JSOP_ADD: michael@0: masm.unboxInt32(R0, ExtractTemp0); 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.addl(R1.valueReg(), ExtractTemp0); michael@0: masm.j(Assembler::Overflow, &failure); michael@0: michael@0: // Box the result michael@0: masm.boxValue(JSVAL_TYPE_INT32, ExtractTemp0, R0.valueReg()); michael@0: break; michael@0: case JSOP_SUB: michael@0: masm.unboxInt32(R0, ExtractTemp0); michael@0: masm.subl(R1.valueReg(), ExtractTemp0); michael@0: masm.j(Assembler::Overflow, &failure); michael@0: masm.boxValue(JSVAL_TYPE_INT32, ExtractTemp0, R0.valueReg()); michael@0: break; michael@0: case JSOP_MUL: michael@0: masm.unboxInt32(R0, ExtractTemp0); michael@0: masm.imull(R1.valueReg(), ExtractTemp0); michael@0: masm.j(Assembler::Overflow, &failure); michael@0: michael@0: masm.branchTest32(Assembler::Zero, ExtractTemp0, ExtractTemp0, &maybeNegZero); michael@0: michael@0: masm.boxValue(JSVAL_TYPE_INT32, ExtractTemp0, R0.valueReg()); michael@0: break; michael@0: case JSOP_DIV: michael@0: { michael@0: JS_ASSERT(R2.scratchReg() == rax); michael@0: JS_ASSERT(R0.valueReg() != rdx); michael@0: JS_ASSERT(R1.valueReg() != rdx); michael@0: masm.unboxInt32(R0, eax); michael@0: masm.unboxInt32(R1, ExtractTemp0); michael@0: michael@0: // Prevent division by 0. michael@0: masm.branchTest32(Assembler::Zero, ExtractTemp0, ExtractTemp0, &failure); michael@0: michael@0: // Prevent negative 0 and -2147483648 / -1. michael@0: masm.branch32(Assembler::Equal, eax, Imm32(INT32_MIN), &failure); michael@0: michael@0: Label notZero; michael@0: masm.branch32(Assembler::NotEqual, eax, Imm32(0), ¬Zero); michael@0: masm.branchTest32(Assembler::Signed, ExtractTemp0, ExtractTemp0, &failure); michael@0: masm.bind(¬Zero); michael@0: michael@0: // Sign extend eax into edx to make (edx:eax), since idiv is 64-bit. michael@0: masm.cdq(); michael@0: masm.idiv(ExtractTemp0); michael@0: michael@0: // A remainder implies a double result. michael@0: masm.branchTest32(Assembler::NonZero, edx, edx, &failure); michael@0: michael@0: masm.boxValue(JSVAL_TYPE_INT32, eax, R0.valueReg()); michael@0: break; michael@0: } michael@0: case JSOP_MOD: michael@0: { michael@0: JS_ASSERT(R2.scratchReg() == rax); michael@0: JS_ASSERT(R0.valueReg() != rdx); michael@0: JS_ASSERT(R1.valueReg() != rdx); michael@0: masm.unboxInt32(R0, eax); michael@0: masm.unboxInt32(R1, ExtractTemp0); michael@0: michael@0: // x % 0 always results in NaN. michael@0: masm.branchTest32(Assembler::Zero, ExtractTemp0, ExtractTemp0, &failure); michael@0: michael@0: // Prevent negative 0 and -2147483648 % -1. michael@0: masm.branchTest32(Assembler::Zero, eax, Imm32(0x7fffffff), &failure); michael@0: michael@0: // Sign extend eax into edx to make (edx:eax), since idiv is 64-bit. michael@0: masm.cdq(); michael@0: masm.idiv(ExtractTemp0); 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.orl(ExtractTemp0, eax); michael@0: masm.branchTest32(Assembler::Signed, eax, eax, &failure); michael@0: michael@0: masm.bind(&done); michael@0: masm.boxValue(JSVAL_TYPE_INT32, edx, R0.valueReg()); michael@0: break; michael@0: } michael@0: case JSOP_BITOR: michael@0: // We can overide R0, because the instruction is unfailable. michael@0: // Because the tag bits are the same, we don't need to retag. michael@0: masm.orq(R1.valueReg(), R0.valueReg()); michael@0: break; michael@0: case JSOP_BITXOR: michael@0: masm.xorl(R1.valueReg(), R0.valueReg()); michael@0: masm.tagValue(JSVAL_TYPE_INT32, R0.valueReg(), R0); michael@0: break; michael@0: case JSOP_BITAND: michael@0: masm.andq(R1.valueReg(), R0.valueReg()); michael@0: break; michael@0: case JSOP_LSH: michael@0: masm.unboxInt32(R0, ExtractTemp0); michael@0: masm.unboxInt32(R1, ecx); // Unboxing R1 to ecx, clobbers R0. michael@0: masm.shll_cl(ExtractTemp0); michael@0: masm.boxValue(JSVAL_TYPE_INT32, ExtractTemp0, R0.valueReg()); michael@0: break; michael@0: case JSOP_RSH: michael@0: masm.unboxInt32(R0, ExtractTemp0); michael@0: masm.unboxInt32(R1, ecx); michael@0: masm.sarl_cl(ExtractTemp0); michael@0: masm.boxValue(JSVAL_TYPE_INT32, ExtractTemp0, R0.valueReg()); michael@0: break; michael@0: case JSOP_URSH: michael@0: if (!allowDouble_) michael@0: masm.movq(R0.valueReg(), ScratchReg); michael@0: michael@0: masm.unboxInt32(R0, ExtractTemp0); michael@0: masm.unboxInt32(R1, ecx); // This clobbers R0 michael@0: michael@0: masm.shrl_cl(ExtractTemp0); michael@0: masm.testl(ExtractTemp0, ExtractTemp0); 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.boxValue(JSVAL_TYPE_INT32, ExtractTemp0, R0.valueReg()); michael@0: EmitReturnFromIC(masm); michael@0: michael@0: masm.bind(&toUint); michael@0: masm.convertUInt32ToDouble(ExtractTemp0, ScratchFloatReg); michael@0: masm.boxDouble(ScratchFloatReg, R0); michael@0: } else { michael@0: masm.j(Assembler::Signed, &revertRegister); michael@0: masm.boxValue(JSVAL_TYPE_INT32, ExtractTemp0, R0.valueReg()); michael@0: } michael@0: break; michael@0: default: michael@0: MOZ_ASSUME_UNREACHABLE("Unhandled op in BinaryArith_Int32"); michael@0: } michael@0: michael@0: // Return from stub. michael@0: EmitReturnFromIC(masm); michael@0: michael@0: if (op_ == 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.valueReg(), ScratchReg); michael@0: masm.orl(R1.valueReg(), ScratchReg); michael@0: masm.j(Assembler::Signed, &failure); michael@0: michael@0: // Result is +0. michael@0: masm.moveValue(Int32Value(0), R0); michael@0: EmitReturnFromIC(masm); michael@0: } michael@0: michael@0: // Revert the content of R0 in the fallible >>> case. michael@0: if (op_ == JSOP_URSH && !allowDouble_) { michael@0: masm.bind(&revertRegister); michael@0: // Restore tag and payload. michael@0: masm.movq(ScratchReg, R0.valueReg()); michael@0: // Fall through to failure. 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.valueReg()); 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.valueReg(), Imm32(0x7fffffff), &failure); michael@0: masm.negl(R0.valueReg()); michael@0: break; michael@0: default: michael@0: MOZ_ASSUME_UNREACHABLE("Unexpected op"); michael@0: } michael@0: michael@0: masm.tagValue(JSVAL_TYPE_INT32, R0.valueReg(), R0); 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