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