Line data Source code
1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 : * vim: set ts=8 sts=4 et sw=4 tw=99:
3 : * This Source Code Form is subject to the terms of the Mozilla Public
4 : * License, v. 2.0. If a copy of the MPL was not distributed with this
5 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 :
7 : #include "jit/BaselineIC.h"
8 : #include "jit/SharedICHelpers.h"
9 :
10 : #include "jit/MacroAssembler-inl.h"
11 :
12 : using namespace js;
13 : using namespace js::jit;
14 :
15 : namespace js {
16 : namespace jit {
17 :
18 : // ICBinaryArith_Int32
19 :
20 : bool
21 64 : ICBinaryArith_Int32::Compiler::generateStubCode(MacroAssembler& masm)
22 : {
23 : // Guard that R0 is an integer and R1 is an integer.
24 128 : Label failure;
25 64 : masm.branchTestInt32(Assembler::NotEqual, R0, &failure);
26 64 : masm.branchTestInt32(Assembler::NotEqual, R1, &failure);
27 :
28 : // The scratch register is only used in the case of JSOP_URSH.
29 128 : mozilla::Maybe<ScratchRegisterScope> scratch;
30 :
31 128 : Label revertRegister, maybeNegZero;
32 64 : switch(op_) {
33 : case JSOP_ADD:
34 39 : masm.unboxInt32(R0, ExtractTemp0);
35 : // Just jump to failure on overflow. R0 and R1 are preserved, so we can just jump to
36 : // the next stub.
37 39 : masm.addl(R1.valueReg(), ExtractTemp0);
38 39 : masm.j(Assembler::Overflow, &failure);
39 :
40 : // Box the result
41 39 : masm.boxValue(JSVAL_TYPE_INT32, ExtractTemp0, R0.valueReg());
42 39 : break;
43 : case JSOP_SUB:
44 9 : masm.unboxInt32(R0, ExtractTemp0);
45 9 : masm.subl(R1.valueReg(), ExtractTemp0);
46 9 : masm.j(Assembler::Overflow, &failure);
47 9 : masm.boxValue(JSVAL_TYPE_INT32, ExtractTemp0, R0.valueReg());
48 9 : break;
49 : case JSOP_MUL:
50 0 : masm.unboxInt32(R0, ExtractTemp0);
51 0 : masm.imull(R1.valueReg(), ExtractTemp0);
52 0 : masm.j(Assembler::Overflow, &failure);
53 :
54 0 : masm.branchTest32(Assembler::Zero, ExtractTemp0, ExtractTemp0, &maybeNegZero);
55 :
56 0 : masm.boxValue(JSVAL_TYPE_INT32, ExtractTemp0, R0.valueReg());
57 0 : break;
58 : case JSOP_DIV:
59 : {
60 0 : MOZ_ASSERT(R2.scratchReg() == rax);
61 0 : MOZ_ASSERT(R0.valueReg() != rdx);
62 0 : MOZ_ASSERT(R1.valueReg() != rdx);
63 0 : masm.unboxInt32(R0, eax);
64 0 : masm.unboxInt32(R1, ExtractTemp0);
65 :
66 : // Prevent division by 0.
67 0 : masm.branchTest32(Assembler::Zero, ExtractTemp0, ExtractTemp0, &failure);
68 :
69 : // Prevent negative 0 and -2147483648 / -1.
70 0 : masm.branch32(Assembler::Equal, eax, Imm32(INT32_MIN), &failure);
71 :
72 0 : Label notZero;
73 0 : masm.branch32(Assembler::NotEqual, eax, Imm32(0), ¬Zero);
74 0 : masm.branchTest32(Assembler::Signed, ExtractTemp0, ExtractTemp0, &failure);
75 0 : masm.bind(¬Zero);
76 :
77 : // Sign extend eax into edx to make (edx:eax), since idiv is 64-bit.
78 0 : masm.cdq();
79 0 : masm.idiv(ExtractTemp0);
80 :
81 : // A remainder implies a double result.
82 0 : masm.branchTest32(Assembler::NonZero, edx, edx, &failure);
83 :
84 0 : masm.boxValue(JSVAL_TYPE_INT32, eax, R0.valueReg());
85 0 : break;
86 : }
87 : case JSOP_MOD:
88 : {
89 0 : MOZ_ASSERT(R2.scratchReg() == rax);
90 0 : MOZ_ASSERT(R0.valueReg() != rdx);
91 0 : MOZ_ASSERT(R1.valueReg() != rdx);
92 0 : masm.unboxInt32(R0, eax);
93 0 : masm.unboxInt32(R1, ExtractTemp0);
94 :
95 : // x % 0 always results in NaN.
96 0 : masm.branchTest32(Assembler::Zero, ExtractTemp0, ExtractTemp0, &failure);
97 :
98 : // Prevent negative 0 and -2147483648 % -1.
99 0 : masm.branchTest32(Assembler::Zero, eax, Imm32(0x7fffffff), &failure);
100 :
101 : // Sign extend eax into edx to make (edx:eax), since idiv is 64-bit.
102 0 : masm.cdq();
103 0 : masm.idiv(ExtractTemp0);
104 :
105 : // Fail when we would need a negative remainder.
106 0 : Label done;
107 0 : masm.branchTest32(Assembler::NonZero, edx, edx, &done);
108 0 : masm.orl(ExtractTemp0, eax);
109 0 : masm.branchTest32(Assembler::Signed, eax, eax, &failure);
110 :
111 0 : masm.bind(&done);
112 0 : masm.boxValue(JSVAL_TYPE_INT32, edx, R0.valueReg());
113 0 : break;
114 : }
115 : case JSOP_BITOR:
116 : // We can overide R0, because the instruction is unfailable.
117 : // Because the tag bits are the same, we don't need to retag.
118 8 : masm.orq(R1.valueReg(), R0.valueReg());
119 8 : break;
120 : case JSOP_BITXOR:
121 0 : masm.xorl(R1.valueReg(), R0.valueReg());
122 0 : masm.tagValue(JSVAL_TYPE_INT32, R0.valueReg(), R0);
123 0 : break;
124 : case JSOP_BITAND:
125 8 : masm.andq(R1.valueReg(), R0.valueReg());
126 8 : break;
127 : case JSOP_LSH:
128 0 : masm.unboxInt32(R0, ExtractTemp0);
129 0 : masm.unboxInt32(R1, ecx); // Unboxing R1 to ecx, clobbers R0.
130 0 : masm.shll_cl(ExtractTemp0);
131 0 : masm.boxValue(JSVAL_TYPE_INT32, ExtractTemp0, R0.valueReg());
132 0 : break;
133 : case JSOP_RSH:
134 0 : masm.unboxInt32(R0, ExtractTemp0);
135 0 : masm.unboxInt32(R1, ecx);
136 0 : masm.sarl_cl(ExtractTemp0);
137 0 : masm.boxValue(JSVAL_TYPE_INT32, ExtractTemp0, R0.valueReg());
138 0 : break;
139 : case JSOP_URSH:
140 0 : if (!allowDouble_) {
141 0 : scratch.emplace(masm);
142 0 : masm.movq(R0.valueReg(), *scratch);
143 : }
144 :
145 0 : masm.unboxInt32(R0, ExtractTemp0);
146 0 : masm.unboxInt32(R1, ecx); // This clobbers R0
147 :
148 0 : masm.shrl_cl(ExtractTemp0);
149 0 : masm.test32(ExtractTemp0, ExtractTemp0);
150 0 : if (allowDouble_) {
151 0 : Label toUint;
152 0 : masm.j(Assembler::Signed, &toUint);
153 :
154 : // Box and return.
155 0 : masm.boxValue(JSVAL_TYPE_INT32, ExtractTemp0, R0.valueReg());
156 0 : EmitReturnFromIC(masm);
157 :
158 0 : masm.bind(&toUint);
159 0 : ScratchDoubleScope scratchDouble(masm);
160 0 : masm.convertUInt32ToDouble(ExtractTemp0, scratchDouble);
161 0 : masm.boxDouble(scratchDouble, R0);
162 : } else {
163 0 : masm.j(Assembler::Signed, &revertRegister);
164 0 : masm.boxValue(JSVAL_TYPE_INT32, ExtractTemp0, R0.valueReg());
165 : }
166 0 : break;
167 : default:
168 0 : MOZ_CRASH("Unhandled op in BinaryArith_Int32");
169 : }
170 :
171 : // Return from stub.
172 64 : EmitReturnFromIC(masm);
173 :
174 64 : if (op_ == JSOP_MUL) {
175 0 : masm.bind(&maybeNegZero);
176 :
177 : // Result is -0 if exactly one of lhs or rhs is negative.
178 : {
179 0 : ScratchRegisterScope scratch(masm);
180 0 : masm.movl(R0.valueReg(), scratch);
181 0 : masm.orl(R1.valueReg(), scratch);
182 0 : masm.j(Assembler::Signed, &failure);
183 : }
184 :
185 : // Result is +0.
186 0 : masm.moveValue(Int32Value(0), R0);
187 0 : EmitReturnFromIC(masm);
188 : }
189 :
190 : // Revert the content of R0 in the fallible >>> case.
191 64 : if (op_ == JSOP_URSH && !allowDouble_) {
192 : // Scope continuation from JSOP_URSH case above.
193 0 : masm.bind(&revertRegister);
194 : // Restore tag and payload.
195 0 : masm.movq(*scratch, R0.valueReg());
196 : // Fall through to failure.
197 : }
198 : // Failure case - jump to next stub
199 64 : masm.bind(&failure);
200 64 : EmitStubGuardFailure(masm);
201 :
202 128 : return true;
203 : }
204 :
205 : bool
206 1 : ICUnaryArith_Int32::Compiler::generateStubCode(MacroAssembler& masm)
207 : {
208 2 : Label failure;
209 1 : masm.branchTestInt32(Assembler::NotEqual, R0, &failure);
210 :
211 1 : switch (op) {
212 : case JSOP_BITNOT:
213 1 : masm.notl(R0.valueReg());
214 1 : break;
215 : case JSOP_NEG:
216 : // Guard against 0 and MIN_INT, both result in a double.
217 0 : masm.branchTest32(Assembler::Zero, R0.valueReg(), Imm32(0x7fffffff), &failure);
218 0 : masm.negl(R0.valueReg());
219 0 : break;
220 : default:
221 0 : MOZ_CRASH("Unexpected op");
222 : }
223 :
224 1 : masm.tagValue(JSVAL_TYPE_INT32, R0.valueReg(), R0);
225 :
226 1 : EmitReturnFromIC(masm);
227 :
228 1 : masm.bind(&failure);
229 1 : EmitStubGuardFailure(masm);
230 2 : return true;
231 : }
232 :
233 : } // namespace jit
234 : } // namespace js
|