1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/js/src/jit/x86/BaselineIC-x86.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,266 @@ 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.cmpl(R0.payloadReg(), R1.payloadReg()); 1.35 + masm.setCC(cond, R0.payloadReg()); 1.36 + masm.movzbl(R0.payloadReg(), R0.payloadReg()); 1.37 + 1.38 + // Box the result and return 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 + return true; 1.46 +} 1.47 + 1.48 +// ICBinaryArith_Int32 1.49 + 1.50 +bool 1.51 +ICBinaryArith_Int32::Compiler::generateStubCode(MacroAssembler &masm) 1.52 +{ 1.53 + // Guard that R0 is an integer and R1 is an integer. 1.54 + Label failure; 1.55 + masm.branchTestInt32(Assembler::NotEqual, R0, &failure); 1.56 + masm.branchTestInt32(Assembler::NotEqual, R1, &failure); 1.57 + 1.58 + // Add R0 and R1. Don't need to explicitly unbox, just use the TailCallReg which 1.59 + // should be available. 1.60 + Register scratchReg = BaselineTailCallReg; 1.61 + 1.62 + Label revertRegister, maybeNegZero; 1.63 + switch(op_) { 1.64 + case JSOP_ADD: 1.65 + // Add R0 and R1. Don't need to explicitly unbox. 1.66 + masm.movl(R0.payloadReg(), scratchReg); 1.67 + masm.addl(R1.payloadReg(), scratchReg); 1.68 + 1.69 + // Just jump to failure on overflow. R0 and R1 are preserved, so we can just jump to 1.70 + // the next stub. 1.71 + masm.j(Assembler::Overflow, &failure); 1.72 + 1.73 + // Just overwrite the payload, the tag is still fine. 1.74 + masm.movl(scratchReg, R0.payloadReg()); 1.75 + break; 1.76 + case JSOP_SUB: 1.77 + masm.movl(R0.payloadReg(), scratchReg); 1.78 + masm.subl(R1.payloadReg(), scratchReg); 1.79 + masm.j(Assembler::Overflow, &failure); 1.80 + masm.movl(scratchReg, R0.payloadReg()); 1.81 + break; 1.82 + case JSOP_MUL: 1.83 + masm.movl(R0.payloadReg(), scratchReg); 1.84 + masm.imull(R1.payloadReg(), scratchReg); 1.85 + masm.j(Assembler::Overflow, &failure); 1.86 + 1.87 + masm.testl(scratchReg, scratchReg); 1.88 + masm.j(Assembler::Zero, &maybeNegZero); 1.89 + 1.90 + masm.movl(scratchReg, R0.payloadReg()); 1.91 + break; 1.92 + case JSOP_DIV: 1.93 + { 1.94 + // Prevent division by 0. 1.95 + masm.branchTest32(Assembler::Zero, R1.payloadReg(), R1.payloadReg(), &failure); 1.96 + 1.97 + // Prevent negative 0 and -2147483648 / -1. 1.98 + masm.branch32(Assembler::Equal, R0.payloadReg(), Imm32(INT32_MIN), &failure); 1.99 + 1.100 + Label notZero; 1.101 + masm.branch32(Assembler::NotEqual, R0.payloadReg(), Imm32(0), ¬Zero); 1.102 + masm.branchTest32(Assembler::Signed, R1.payloadReg(), R1.payloadReg(), &failure); 1.103 + masm.bind(¬Zero); 1.104 + 1.105 + // For idiv we need eax. 1.106 + JS_ASSERT(R1.typeReg() == eax); 1.107 + masm.movl(R0.payloadReg(), eax); 1.108 + // Preserve R0.payloadReg()/edx, eax is JSVAL_TYPE_INT32. 1.109 + masm.movl(R0.payloadReg(), scratchReg); 1.110 + // Sign extend eax into edx to make (edx:eax), since idiv is 64-bit. 1.111 + masm.cdq(); 1.112 + masm.idiv(R1.payloadReg()); 1.113 + 1.114 + // A remainder implies a double result. 1.115 + masm.branchTest32(Assembler::NonZero, edx, edx, &revertRegister); 1.116 + 1.117 + masm.movl(eax, R0.payloadReg()); 1.118 + break; 1.119 + } 1.120 + case JSOP_MOD: 1.121 + { 1.122 + // x % 0 always results in NaN. 1.123 + masm.branchTest32(Assembler::Zero, R1.payloadReg(), R1.payloadReg(), &failure); 1.124 + 1.125 + // Prevent negative 0 and -2147483648 % -1. 1.126 + masm.branchTest32(Assembler::Zero, R0.payloadReg(), Imm32(0x7fffffff), &failure); 1.127 + 1.128 + // For idiv we need eax. 1.129 + JS_ASSERT(R1.typeReg() == eax); 1.130 + masm.movl(R0.payloadReg(), eax); 1.131 + // Preserve R0.payloadReg()/edx, eax is JSVAL_TYPE_INT32. 1.132 + masm.movl(R0.payloadReg(), scratchReg); 1.133 + // Sign extend eax into edx to make (edx:eax), since idiv is 64-bit. 1.134 + masm.cdq(); 1.135 + masm.idiv(R1.payloadReg()); 1.136 + 1.137 + // Fail when we would need a negative remainder. 1.138 + Label done; 1.139 + masm.branchTest32(Assembler::NonZero, edx, edx, &done); 1.140 + masm.branchTest32(Assembler::Signed, scratchReg, scratchReg, &revertRegister); 1.141 + masm.branchTest32(Assembler::Signed, R1.payloadReg(), R1.payloadReg(), &revertRegister); 1.142 + 1.143 + masm.bind(&done); 1.144 + // Result is in edx, tag in ecx remains untouched. 1.145 + JS_ASSERT(R0.payloadReg() == edx); 1.146 + JS_ASSERT(R0.typeReg() == ecx); 1.147 + break; 1.148 + } 1.149 + case JSOP_BITOR: 1.150 + // We can overide R0, because the instruction is unfailable. 1.151 + // The R0.typeReg() is also still intact. 1.152 + masm.orl(R1.payloadReg(), R0.payloadReg()); 1.153 + break; 1.154 + case JSOP_BITXOR: 1.155 + masm.xorl(R1.payloadReg(), R0.payloadReg()); 1.156 + break; 1.157 + case JSOP_BITAND: 1.158 + masm.andl(R1.payloadReg(), R0.payloadReg()); 1.159 + break; 1.160 + case JSOP_LSH: 1.161 + // RHS needs to be in ecx for shift operations. 1.162 + JS_ASSERT(R0.typeReg() == ecx); 1.163 + masm.movl(R1.payloadReg(), ecx); 1.164 + masm.shll_cl(R0.payloadReg()); 1.165 + // We need to tag again, because we overwrote it. 1.166 + masm.tagValue(JSVAL_TYPE_INT32, R0.payloadReg(), R0); 1.167 + break; 1.168 + case JSOP_RSH: 1.169 + masm.movl(R1.payloadReg(), ecx); 1.170 + masm.sarl_cl(R0.payloadReg()); 1.171 + masm.tagValue(JSVAL_TYPE_INT32, R0.payloadReg(), R0); 1.172 + break; 1.173 + case JSOP_URSH: 1.174 + if (!allowDouble_) 1.175 + masm.movl(R0.payloadReg(), scratchReg); 1.176 + 1.177 + masm.movl(R1.payloadReg(), ecx); 1.178 + masm.shrl_cl(R0.payloadReg()); 1.179 + masm.testl(R0.payloadReg(), R0.payloadReg()); 1.180 + if (allowDouble_) { 1.181 + Label toUint; 1.182 + masm.j(Assembler::Signed, &toUint); 1.183 + 1.184 + // Box and return. 1.185 + masm.tagValue(JSVAL_TYPE_INT32, R0.payloadReg(), R0); 1.186 + EmitReturnFromIC(masm); 1.187 + 1.188 + masm.bind(&toUint); 1.189 + masm.convertUInt32ToDouble(R0.payloadReg(), ScratchFloatReg); 1.190 + masm.boxDouble(ScratchFloatReg, R0); 1.191 + } else { 1.192 + masm.j(Assembler::Signed, &revertRegister); 1.193 + masm.tagValue(JSVAL_TYPE_INT32, R0.payloadReg(), R0); 1.194 + } 1.195 + break; 1.196 + default: 1.197 + MOZ_ASSUME_UNREACHABLE("Unhandled op for BinaryArith_Int32. "); 1.198 + } 1.199 + 1.200 + // Return. 1.201 + EmitReturnFromIC(masm); 1.202 + 1.203 + switch(op_) { 1.204 + case JSOP_MUL: 1.205 + masm.bind(&maybeNegZero); 1.206 + 1.207 + // Result is -0 if exactly one of lhs or rhs is negative. 1.208 + masm.movl(R0.payloadReg(), scratchReg); 1.209 + masm.orl(R1.payloadReg(), scratchReg); 1.210 + masm.j(Assembler::Signed, &failure); 1.211 + 1.212 + // Result is +0. 1.213 + masm.mov(ImmWord(0), R0.payloadReg()); 1.214 + EmitReturnFromIC(masm); 1.215 + break; 1.216 + case JSOP_DIV: 1.217 + case JSOP_MOD: 1.218 + masm.bind(&revertRegister); 1.219 + masm.movl(scratchReg, R0.payloadReg()); 1.220 + masm.movl(ImmType(JSVAL_TYPE_INT32), R1.typeReg()); 1.221 + break; 1.222 + case JSOP_URSH: 1.223 + // Revert the content of R0 in the fallible >>> case. 1.224 + if (!allowDouble_) { 1.225 + masm.bind(&revertRegister); 1.226 + masm.tagValue(JSVAL_TYPE_INT32, scratchReg, R0); 1.227 + } 1.228 + break; 1.229 + default: 1.230 + // No special failure handling required. 1.231 + // Fall through to failure. 1.232 + break; 1.233 + } 1.234 + 1.235 + // Failure case - jump to next stub 1.236 + masm.bind(&failure); 1.237 + EmitStubGuardFailure(masm); 1.238 + 1.239 + return true; 1.240 +} 1.241 + 1.242 +bool 1.243 +ICUnaryArith_Int32::Compiler::generateStubCode(MacroAssembler &masm) 1.244 +{ 1.245 + Label failure; 1.246 + masm.branchTestInt32(Assembler::NotEqual, R0, &failure); 1.247 + 1.248 + switch (op) { 1.249 + case JSOP_BITNOT: 1.250 + masm.notl(R0.payloadReg()); 1.251 + break; 1.252 + case JSOP_NEG: 1.253 + // Guard against 0 and MIN_INT, both result in a double. 1.254 + masm.branchTest32(Assembler::Zero, R0.payloadReg(), Imm32(0x7fffffff), &failure); 1.255 + masm.negl(R0.payloadReg()); 1.256 + break; 1.257 + default: 1.258 + MOZ_ASSUME_UNREACHABLE("Unexpected op"); 1.259 + } 1.260 + 1.261 + EmitReturnFromIC(masm); 1.262 + 1.263 + masm.bind(&failure); 1.264 + EmitStubGuardFailure(masm); 1.265 + return true; 1.266 +} 1.267 + 1.268 +} // namespace jit 1.269 +} // namespace js