1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/js/src/jit/arm/BaselineIC-arm.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,261 @@ 1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- 1.5 + * vim: set ts=8 sts=4 et sw=4 tw=99: 1.6 + * This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +#include "jit/BaselineCompiler.h" 1.11 +#include "jit/BaselineHelpers.h" 1.12 +#include "jit/BaselineIC.h" 1.13 +#include "jit/BaselineJIT.h" 1.14 +#include "jit/IonLinker.h" 1.15 + 1.16 +using namespace js; 1.17 +using namespace js::jit; 1.18 + 1.19 +namespace js { 1.20 +namespace jit { 1.21 + 1.22 +// ICCompare_Int32 1.23 + 1.24 +bool 1.25 +ICCompare_Int32::Compiler::generateStubCode(MacroAssembler &masm) 1.26 +{ 1.27 + // Guard that R0 is an integer and R1 is an integer. 1.28 + Label failure; 1.29 + masm.branchTestInt32(Assembler::NotEqual, R0, &failure); 1.30 + masm.branchTestInt32(Assembler::NotEqual, R1, &failure); 1.31 + 1.32 + // Compare payload regs of R0 and R1. 1.33 + Assembler::Condition cond = JSOpToCondition(op, /* signed = */true); 1.34 + masm.cmp32(R0.payloadReg(), R1.payloadReg()); 1.35 + masm.ma_mov(Imm32(1), R0.payloadReg(), NoSetCond, cond); 1.36 + masm.ma_mov(Imm32(0), R0.payloadReg(), NoSetCond, Assembler::InvertCondition(cond)); 1.37 + 1.38 + // Result is implicitly boxed already. 1.39 + masm.tagValue(JSVAL_TYPE_BOOLEAN, R0.payloadReg(), R0); 1.40 + EmitReturnFromIC(masm); 1.41 + 1.42 + // Failure case - jump to next stub 1.43 + masm.bind(&failure); 1.44 + EmitStubGuardFailure(masm); 1.45 + 1.46 + return true; 1.47 +} 1.48 + 1.49 +bool 1.50 +ICCompare_Double::Compiler::generateStubCode(MacroAssembler &masm) 1.51 +{ 1.52 + Label failure, isNaN; 1.53 + masm.ensureDouble(R0, FloatReg0, &failure); 1.54 + masm.ensureDouble(R1, FloatReg1, &failure); 1.55 + 1.56 + Register dest = R0.scratchReg(); 1.57 + 1.58 + Assembler::DoubleCondition doubleCond = JSOpToDoubleCondition(op); 1.59 + Assembler::Condition cond = Assembler::ConditionFromDoubleCondition(doubleCond); 1.60 + 1.61 + masm.compareDouble(FloatReg0, FloatReg1); 1.62 + masm.ma_mov(Imm32(0), dest); 1.63 + masm.ma_mov(Imm32(1), dest, NoSetCond, cond); 1.64 + 1.65 + masm.tagValue(JSVAL_TYPE_BOOLEAN, dest, R0); 1.66 + EmitReturnFromIC(masm); 1.67 + 1.68 + // Failure case - jump to next stub 1.69 + masm.bind(&failure); 1.70 + EmitStubGuardFailure(masm); 1.71 + return true; 1.72 +} 1.73 + 1.74 +// ICBinaryArith_Int32 1.75 + 1.76 +extern "C" { 1.77 + extern int64_t __aeabi_idivmod(int,int); 1.78 +} 1.79 + 1.80 +bool 1.81 +ICBinaryArith_Int32::Compiler::generateStubCode(MacroAssembler &masm) 1.82 +{ 1.83 + // Guard that R0 is an integer and R1 is an integer. 1.84 + Label failure; 1.85 + masm.branchTestInt32(Assembler::NotEqual, R0, &failure); 1.86 + masm.branchTestInt32(Assembler::NotEqual, R1, &failure); 1.87 + 1.88 + // Add R0 and R1. Don't need to explicitly unbox, just use R2's payloadReg. 1.89 + Register scratchReg = R2.payloadReg(); 1.90 + 1.91 + // DIV and MOD need an extra non-volatile ValueOperand to hold R0. 1.92 + GeneralRegisterSet savedRegs = availableGeneralRegs(2); 1.93 + savedRegs = GeneralRegisterSet::Intersect(GeneralRegisterSet::NonVolatile(), savedRegs); 1.94 + ValueOperand savedValue = savedRegs.takeAnyValue(); 1.95 + 1.96 + Label maybeNegZero, revertRegister; 1.97 + switch(op_) { 1.98 + case JSOP_ADD: 1.99 + masm.ma_add(R0.payloadReg(), R1.payloadReg(), scratchReg, SetCond); 1.100 + 1.101 + // Just jump to failure on overflow. R0 and R1 are preserved, so we can just jump to 1.102 + // the next stub. 1.103 + masm.j(Assembler::Overflow, &failure); 1.104 + 1.105 + // Box the result and return. We know R0.typeReg() already contains the integer 1.106 + // tag, so we just need to move the result value into place. 1.107 + masm.mov(scratchReg, R0.payloadReg()); 1.108 + break; 1.109 + case JSOP_SUB: 1.110 + masm.ma_sub(R0.payloadReg(), R1.payloadReg(), scratchReg, SetCond); 1.111 + masm.j(Assembler::Overflow, &failure); 1.112 + masm.mov(scratchReg, R0.payloadReg()); 1.113 + break; 1.114 + case JSOP_MUL: { 1.115 + Assembler::Condition cond = masm.ma_check_mul(R0.payloadReg(), R1.payloadReg(), scratchReg, 1.116 + Assembler::Overflow); 1.117 + masm.j(cond, &failure); 1.118 + 1.119 + masm.ma_cmp(scratchReg, Imm32(0)); 1.120 + masm.j(Assembler::Equal, &maybeNegZero); 1.121 + 1.122 + masm.mov(scratchReg, R0.payloadReg()); 1.123 + break; 1.124 + } 1.125 + case JSOP_DIV: 1.126 + case JSOP_MOD: { 1.127 + // Check for INT_MIN / -1, it results in a double. 1.128 + masm.ma_cmp(R0.payloadReg(), Imm32(INT_MIN)); 1.129 + masm.ma_cmp(R1.payloadReg(), Imm32(-1), Assembler::Equal); 1.130 + masm.j(Assembler::Equal, &failure); 1.131 + 1.132 + // Check for both division by zero and 0 / X with X < 0 (results in -0). 1.133 + masm.ma_cmp(R1.payloadReg(), Imm32(0)); 1.134 + masm.ma_cmp(R0.payloadReg(), Imm32(0), Assembler::LessThan); 1.135 + masm.j(Assembler::Equal, &failure); 1.136 + 1.137 + // The call will preserve registers r4-r11. Save R0 and the link register. 1.138 + JS_ASSERT(R1 == ValueOperand(r5, r4)); 1.139 + JS_ASSERT(R0 == ValueOperand(r3, r2)); 1.140 + masm.moveValue(R0, savedValue); 1.141 + 1.142 + masm.setupAlignedABICall(2); 1.143 + masm.passABIArg(R0.payloadReg()); 1.144 + masm.passABIArg(R1.payloadReg()); 1.145 + masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, __aeabi_idivmod)); 1.146 + 1.147 + // idivmod returns the quotient in r0, and the remainder in r1. 1.148 + if (op_ == JSOP_DIV) { 1.149 + // Result is a double if the remainder != 0. 1.150 + masm.branch32(Assembler::NotEqual, r1, Imm32(0), &revertRegister); 1.151 + masm.tagValue(JSVAL_TYPE_INT32, r0, R0); 1.152 + } else { 1.153 + // If X % Y == 0 and X < 0, the result is -0. 1.154 + Label done; 1.155 + masm.branch32(Assembler::NotEqual, r1, Imm32(0), &done); 1.156 + masm.branch32(Assembler::LessThan, savedValue.payloadReg(), Imm32(0), &revertRegister); 1.157 + masm.bind(&done); 1.158 + masm.tagValue(JSVAL_TYPE_INT32, r1, R0); 1.159 + } 1.160 + break; 1.161 + } 1.162 + case JSOP_BITOR: 1.163 + masm.ma_orr(R1.payloadReg(), R0.payloadReg(), R0.payloadReg()); 1.164 + break; 1.165 + case JSOP_BITXOR: 1.166 + masm.ma_eor(R1.payloadReg(), R0.payloadReg(), R0.payloadReg()); 1.167 + break; 1.168 + case JSOP_BITAND: 1.169 + masm.ma_and(R1.payloadReg(), R0.payloadReg(), R0.payloadReg()); 1.170 + break; 1.171 + case JSOP_LSH: 1.172 + // ARM will happily try to shift by more than 0x1f. 1.173 + masm.ma_and(Imm32(0x1F), R1.payloadReg(), R1.payloadReg()); 1.174 + masm.ma_lsl(R1.payloadReg(), R0.payloadReg(), R0.payloadReg()); 1.175 + break; 1.176 + case JSOP_RSH: 1.177 + masm.ma_and(Imm32(0x1F), R1.payloadReg(), R1.payloadReg()); 1.178 + masm.ma_asr(R1.payloadReg(), R0.payloadReg(), R0.payloadReg()); 1.179 + break; 1.180 + case JSOP_URSH: 1.181 + masm.ma_and(Imm32(0x1F), R1.payloadReg(), scratchReg); 1.182 + masm.ma_lsr(scratchReg, R0.payloadReg(), scratchReg); 1.183 + masm.ma_cmp(scratchReg, Imm32(0)); 1.184 + if (allowDouble_) { 1.185 + Label toUint; 1.186 + masm.j(Assembler::LessThan, &toUint); 1.187 + 1.188 + // Move result and box for return. 1.189 + masm.mov(scratchReg, R0.payloadReg()); 1.190 + EmitReturnFromIC(masm); 1.191 + 1.192 + masm.bind(&toUint); 1.193 + masm.convertUInt32ToDouble(scratchReg, ScratchFloatReg); 1.194 + masm.boxDouble(ScratchFloatReg, R0); 1.195 + } else { 1.196 + masm.j(Assembler::LessThan, &failure); 1.197 + // Move result for return. 1.198 + masm.mov(scratchReg, R0.payloadReg()); 1.199 + } 1.200 + break; 1.201 + default: 1.202 + MOZ_ASSUME_UNREACHABLE("Unhandled op for BinaryArith_Int32."); 1.203 + } 1.204 + 1.205 + EmitReturnFromIC(masm); 1.206 + 1.207 + switch (op_) { 1.208 + case JSOP_MUL: 1.209 + masm.bind(&maybeNegZero); 1.210 + 1.211 + // Result is -0 if exactly one of lhs or rhs is negative. 1.212 + masm.ma_cmn(R0.payloadReg(), R1.payloadReg()); 1.213 + masm.j(Assembler::Signed, &failure); 1.214 + 1.215 + // Result is +0. 1.216 + masm.ma_mov(Imm32(0), R0.payloadReg()); 1.217 + EmitReturnFromIC(masm); 1.218 + break; 1.219 + case JSOP_DIV: 1.220 + case JSOP_MOD: 1.221 + masm.bind(&revertRegister); 1.222 + masm.moveValue(savedValue, R0); 1.223 + break; 1.224 + default: 1.225 + break; 1.226 + } 1.227 + 1.228 + // Failure case - jump to next stub 1.229 + masm.bind(&failure); 1.230 + EmitStubGuardFailure(masm); 1.231 + 1.232 + return true; 1.233 +} 1.234 + 1.235 +bool 1.236 +ICUnaryArith_Int32::Compiler::generateStubCode(MacroAssembler &masm) 1.237 +{ 1.238 + Label failure; 1.239 + masm.branchTestInt32(Assembler::NotEqual, R0, &failure); 1.240 + 1.241 + switch (op) { 1.242 + case JSOP_BITNOT: 1.243 + masm.ma_mvn(R0.payloadReg(), R0.payloadReg()); 1.244 + break; 1.245 + case JSOP_NEG: 1.246 + // Guard against 0 and MIN_INT, both result in a double. 1.247 + masm.branchTest32(Assembler::Zero, R0.payloadReg(), Imm32(0x7fffffff), &failure); 1.248 + 1.249 + // Compile -x as 0 - x. 1.250 + masm.ma_rsb(R0.payloadReg(), Imm32(0), R0.payloadReg()); 1.251 + break; 1.252 + default: 1.253 + MOZ_ASSUME_UNREACHABLE("Unexpected op"); 1.254 + } 1.255 + 1.256 + EmitReturnFromIC(masm); 1.257 + 1.258 + masm.bind(&failure); 1.259 + EmitStubGuardFailure(masm); 1.260 + return true; 1.261 +} 1.262 + 1.263 +} // namespace jit 1.264 +} // namespace js