1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/js/src/jit/x64/BaselineIC-x64.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,249 @@ 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/BaselineHelpers.h" 1.11 +#include "jit/BaselineIC.h" 1.12 + 1.13 +using namespace js; 1.14 +using namespace js::jit; 1.15 + 1.16 +namespace js { 1.17 +namespace jit { 1.18 + 1.19 +// ICCompare_Int32 1.20 + 1.21 +bool 1.22 +ICCompare_Int32::Compiler::generateStubCode(MacroAssembler &masm) 1.23 +{ 1.24 + // Guard that R0 is an integer and R1 is an integer. 1.25 + Label failure; 1.26 + masm.branchTestInt32(Assembler::NotEqual, R0, &failure); 1.27 + masm.branchTestInt32(Assembler::NotEqual, R1, &failure); 1.28 + 1.29 + // Directly compare the int32 payload of R0 and R1. 1.30 + Assembler::Condition cond = JSOpToCondition(op, /* signed = */true); 1.31 + masm.mov(ImmWord(0), ScratchReg); 1.32 + masm.cmpl(R0.valueReg(), R1.valueReg()); 1.33 + masm.setCC(cond, ScratchReg); 1.34 + 1.35 + // Box the result and return 1.36 + masm.boxValue(JSVAL_TYPE_BOOLEAN, ScratchReg, R0.valueReg()); 1.37 + EmitReturnFromIC(masm); 1.38 + 1.39 + // Failure case - jump to next stub 1.40 + masm.bind(&failure); 1.41 + EmitStubGuardFailure(masm); 1.42 + 1.43 + return true; 1.44 +} 1.45 + 1.46 +// ICBinaryArith_Int32 1.47 + 1.48 +bool 1.49 +ICBinaryArith_Int32::Compiler::generateStubCode(MacroAssembler &masm) 1.50 +{ 1.51 + // Guard that R0 is an integer and R1 is an integer. 1.52 + Label failure; 1.53 + masm.branchTestInt32(Assembler::NotEqual, R0, &failure); 1.54 + masm.branchTestInt32(Assembler::NotEqual, R1, &failure); 1.55 + 1.56 + Label revertRegister, maybeNegZero; 1.57 + switch(op_) { 1.58 + case JSOP_ADD: 1.59 + masm.unboxInt32(R0, ExtractTemp0); 1.60 + // Just jump to failure on overflow. R0 and R1 are preserved, so we can just jump to 1.61 + // the next stub. 1.62 + masm.addl(R1.valueReg(), ExtractTemp0); 1.63 + masm.j(Assembler::Overflow, &failure); 1.64 + 1.65 + // Box the result 1.66 + masm.boxValue(JSVAL_TYPE_INT32, ExtractTemp0, R0.valueReg()); 1.67 + break; 1.68 + case JSOP_SUB: 1.69 + masm.unboxInt32(R0, ExtractTemp0); 1.70 + masm.subl(R1.valueReg(), ExtractTemp0); 1.71 + masm.j(Assembler::Overflow, &failure); 1.72 + masm.boxValue(JSVAL_TYPE_INT32, ExtractTemp0, R0.valueReg()); 1.73 + break; 1.74 + case JSOP_MUL: 1.75 + masm.unboxInt32(R0, ExtractTemp0); 1.76 + masm.imull(R1.valueReg(), ExtractTemp0); 1.77 + masm.j(Assembler::Overflow, &failure); 1.78 + 1.79 + masm.branchTest32(Assembler::Zero, ExtractTemp0, ExtractTemp0, &maybeNegZero); 1.80 + 1.81 + masm.boxValue(JSVAL_TYPE_INT32, ExtractTemp0, R0.valueReg()); 1.82 + break; 1.83 + case JSOP_DIV: 1.84 + { 1.85 + JS_ASSERT(R2.scratchReg() == rax); 1.86 + JS_ASSERT(R0.valueReg() != rdx); 1.87 + JS_ASSERT(R1.valueReg() != rdx); 1.88 + masm.unboxInt32(R0, eax); 1.89 + masm.unboxInt32(R1, ExtractTemp0); 1.90 + 1.91 + // Prevent division by 0. 1.92 + masm.branchTest32(Assembler::Zero, ExtractTemp0, ExtractTemp0, &failure); 1.93 + 1.94 + // Prevent negative 0 and -2147483648 / -1. 1.95 + masm.branch32(Assembler::Equal, eax, Imm32(INT32_MIN), &failure); 1.96 + 1.97 + Label notZero; 1.98 + masm.branch32(Assembler::NotEqual, eax, Imm32(0), ¬Zero); 1.99 + masm.branchTest32(Assembler::Signed, ExtractTemp0, ExtractTemp0, &failure); 1.100 + masm.bind(¬Zero); 1.101 + 1.102 + // Sign extend eax into edx to make (edx:eax), since idiv is 64-bit. 1.103 + masm.cdq(); 1.104 + masm.idiv(ExtractTemp0); 1.105 + 1.106 + // A remainder implies a double result. 1.107 + masm.branchTest32(Assembler::NonZero, edx, edx, &failure); 1.108 + 1.109 + masm.boxValue(JSVAL_TYPE_INT32, eax, R0.valueReg()); 1.110 + break; 1.111 + } 1.112 + case JSOP_MOD: 1.113 + { 1.114 + JS_ASSERT(R2.scratchReg() == rax); 1.115 + JS_ASSERT(R0.valueReg() != rdx); 1.116 + JS_ASSERT(R1.valueReg() != rdx); 1.117 + masm.unboxInt32(R0, eax); 1.118 + masm.unboxInt32(R1, ExtractTemp0); 1.119 + 1.120 + // x % 0 always results in NaN. 1.121 + masm.branchTest32(Assembler::Zero, ExtractTemp0, ExtractTemp0, &failure); 1.122 + 1.123 + // Prevent negative 0 and -2147483648 % -1. 1.124 + masm.branchTest32(Assembler::Zero, eax, Imm32(0x7fffffff), &failure); 1.125 + 1.126 + // Sign extend eax into edx to make (edx:eax), since idiv is 64-bit. 1.127 + masm.cdq(); 1.128 + masm.idiv(ExtractTemp0); 1.129 + 1.130 + // Fail when we would need a negative remainder. 1.131 + Label done; 1.132 + masm.branchTest32(Assembler::NonZero, edx, edx, &done); 1.133 + masm.orl(ExtractTemp0, eax); 1.134 + masm.branchTest32(Assembler::Signed, eax, eax, &failure); 1.135 + 1.136 + masm.bind(&done); 1.137 + masm.boxValue(JSVAL_TYPE_INT32, edx, R0.valueReg()); 1.138 + break; 1.139 + } 1.140 + case JSOP_BITOR: 1.141 + // We can overide R0, because the instruction is unfailable. 1.142 + // Because the tag bits are the same, we don't need to retag. 1.143 + masm.orq(R1.valueReg(), R0.valueReg()); 1.144 + break; 1.145 + case JSOP_BITXOR: 1.146 + masm.xorl(R1.valueReg(), R0.valueReg()); 1.147 + masm.tagValue(JSVAL_TYPE_INT32, R0.valueReg(), R0); 1.148 + break; 1.149 + case JSOP_BITAND: 1.150 + masm.andq(R1.valueReg(), R0.valueReg()); 1.151 + break; 1.152 + case JSOP_LSH: 1.153 + masm.unboxInt32(R0, ExtractTemp0); 1.154 + masm.unboxInt32(R1, ecx); // Unboxing R1 to ecx, clobbers R0. 1.155 + masm.shll_cl(ExtractTemp0); 1.156 + masm.boxValue(JSVAL_TYPE_INT32, ExtractTemp0, R0.valueReg()); 1.157 + break; 1.158 + case JSOP_RSH: 1.159 + masm.unboxInt32(R0, ExtractTemp0); 1.160 + masm.unboxInt32(R1, ecx); 1.161 + masm.sarl_cl(ExtractTemp0); 1.162 + masm.boxValue(JSVAL_TYPE_INT32, ExtractTemp0, R0.valueReg()); 1.163 + break; 1.164 + case JSOP_URSH: 1.165 + if (!allowDouble_) 1.166 + masm.movq(R0.valueReg(), ScratchReg); 1.167 + 1.168 + masm.unboxInt32(R0, ExtractTemp0); 1.169 + masm.unboxInt32(R1, ecx); // This clobbers R0 1.170 + 1.171 + masm.shrl_cl(ExtractTemp0); 1.172 + masm.testl(ExtractTemp0, ExtractTemp0); 1.173 + if (allowDouble_) { 1.174 + Label toUint; 1.175 + masm.j(Assembler::Signed, &toUint); 1.176 + 1.177 + // Box and return. 1.178 + masm.boxValue(JSVAL_TYPE_INT32, ExtractTemp0, R0.valueReg()); 1.179 + EmitReturnFromIC(masm); 1.180 + 1.181 + masm.bind(&toUint); 1.182 + masm.convertUInt32ToDouble(ExtractTemp0, ScratchFloatReg); 1.183 + masm.boxDouble(ScratchFloatReg, R0); 1.184 + } else { 1.185 + masm.j(Assembler::Signed, &revertRegister); 1.186 + masm.boxValue(JSVAL_TYPE_INT32, ExtractTemp0, R0.valueReg()); 1.187 + } 1.188 + break; 1.189 + default: 1.190 + MOZ_ASSUME_UNREACHABLE("Unhandled op in BinaryArith_Int32"); 1.191 + } 1.192 + 1.193 + // Return from stub. 1.194 + EmitReturnFromIC(masm); 1.195 + 1.196 + if (op_ == JSOP_MUL) { 1.197 + masm.bind(&maybeNegZero); 1.198 + 1.199 + // Result is -0 if exactly one of lhs or rhs is negative. 1.200 + masm.movl(R0.valueReg(), ScratchReg); 1.201 + masm.orl(R1.valueReg(), ScratchReg); 1.202 + masm.j(Assembler::Signed, &failure); 1.203 + 1.204 + // Result is +0. 1.205 + masm.moveValue(Int32Value(0), R0); 1.206 + EmitReturnFromIC(masm); 1.207 + } 1.208 + 1.209 + // Revert the content of R0 in the fallible >>> case. 1.210 + if (op_ == JSOP_URSH && !allowDouble_) { 1.211 + masm.bind(&revertRegister); 1.212 + // Restore tag and payload. 1.213 + masm.movq(ScratchReg, R0.valueReg()); 1.214 + // Fall through to failure. 1.215 + } 1.216 + // Failure case - jump to next stub 1.217 + masm.bind(&failure); 1.218 + EmitStubGuardFailure(masm); 1.219 + 1.220 + return true; 1.221 +} 1.222 + 1.223 +bool 1.224 +ICUnaryArith_Int32::Compiler::generateStubCode(MacroAssembler &masm) 1.225 +{ 1.226 + Label failure; 1.227 + masm.branchTestInt32(Assembler::NotEqual, R0, &failure); 1.228 + 1.229 + switch (op) { 1.230 + case JSOP_BITNOT: 1.231 + masm.notl(R0.valueReg()); 1.232 + break; 1.233 + case JSOP_NEG: 1.234 + // Guard against 0 and MIN_INT, both result in a double. 1.235 + masm.branchTest32(Assembler::Zero, R0.valueReg(), Imm32(0x7fffffff), &failure); 1.236 + masm.negl(R0.valueReg()); 1.237 + break; 1.238 + default: 1.239 + MOZ_ASSUME_UNREACHABLE("Unexpected op"); 1.240 + } 1.241 + 1.242 + masm.tagValue(JSVAL_TYPE_INT32, R0.valueReg(), R0); 1.243 + 1.244 + EmitReturnFromIC(masm); 1.245 + 1.246 + masm.bind(&failure); 1.247 + EmitStubGuardFailure(masm); 1.248 + return true; 1.249 +} 1.250 + 1.251 +} // namespace jit 1.252 +} // namespace js