|
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 "jsiter.h" |
|
8 |
|
9 #include "jit/BaselineCompiler.h" |
|
10 #include "jit/BaselineHelpers.h" |
|
11 #include "jit/BaselineIC.h" |
|
12 #include "jit/BaselineJIT.h" |
|
13 #include "jit/IonLinker.h" |
|
14 |
|
15 #include "jsboolinlines.h" |
|
16 |
|
17 using namespace js; |
|
18 using namespace js::jit; |
|
19 |
|
20 namespace js { |
|
21 namespace jit { |
|
22 |
|
23 // ICCompare_Int32 |
|
24 |
|
25 bool |
|
26 ICCompare_Int32::Compiler::generateStubCode(MacroAssembler &masm) |
|
27 { |
|
28 // Guard that R0 is an integer and R1 is an integer. |
|
29 Label failure; |
|
30 Label conditionTrue; |
|
31 masm.branchTestInt32(Assembler::NotEqual, R0, &failure); |
|
32 masm.branchTestInt32(Assembler::NotEqual, R1, &failure); |
|
33 |
|
34 // Compare payload regs of R0 and R1. |
|
35 Assembler::Condition cond = JSOpToCondition(op, /* signed = */true); |
|
36 masm.ma_cmp_set(R0.payloadReg(), R0.payloadReg(), R1.payloadReg(), cond); |
|
37 |
|
38 masm.tagValue(JSVAL_TYPE_BOOLEAN, R0.payloadReg(), R0); |
|
39 EmitReturnFromIC(masm); |
|
40 |
|
41 // Failure case - jump to next stub |
|
42 masm.bind(&failure); |
|
43 EmitStubGuardFailure(masm); |
|
44 |
|
45 return true; |
|
46 } |
|
47 |
|
48 bool |
|
49 ICCompare_Double::Compiler::generateStubCode(MacroAssembler &masm) |
|
50 { |
|
51 Label failure, isNaN; |
|
52 masm.ensureDouble(R0, FloatReg0, &failure); |
|
53 masm.ensureDouble(R1, FloatReg1, &failure); |
|
54 |
|
55 Register dest = R0.scratchReg(); |
|
56 |
|
57 Assembler::DoubleCondition doubleCond = JSOpToDoubleCondition(op); |
|
58 |
|
59 masm.ma_cmp_set_double(dest, FloatReg0, FloatReg1, doubleCond); |
|
60 |
|
61 masm.tagValue(JSVAL_TYPE_BOOLEAN, dest, R0); |
|
62 EmitReturnFromIC(masm); |
|
63 |
|
64 // Failure case - jump to next stub |
|
65 masm.bind(&failure); |
|
66 EmitStubGuardFailure(masm); |
|
67 return true; |
|
68 } |
|
69 |
|
70 // ICBinaryArith_Int32 |
|
71 |
|
72 bool |
|
73 ICBinaryArith_Int32::Compiler::generateStubCode(MacroAssembler &masm) |
|
74 { |
|
75 // Guard that R0 is an integer and R1 is an integer. |
|
76 Label failure; |
|
77 masm.branchTestInt32(Assembler::NotEqual, R0, &failure); |
|
78 masm.branchTestInt32(Assembler::NotEqual, R1, &failure); |
|
79 |
|
80 // Add R0 and R1. Don't need to explicitly unbox, just use R2's payloadReg. |
|
81 Register scratchReg = R2.payloadReg(); |
|
82 |
|
83 // DIV and MOD need an extra non-volatile ValueOperand to hold R0. |
|
84 GeneralRegisterSet savedRegs = availableGeneralRegs(2); |
|
85 savedRegs = GeneralRegisterSet::Intersect(GeneralRegisterSet::NonVolatile(), savedRegs); |
|
86 ValueOperand savedValue = savedRegs.takeAnyValue(); |
|
87 |
|
88 Label goodMul, divTest1, divTest2; |
|
89 switch(op_) { |
|
90 case JSOP_ADD: |
|
91 // We know R0.typeReg() already contains the integer tag. No boxing |
|
92 // required. |
|
93 masm.ma_addTestOverflow(R0.payloadReg(), R0.payloadReg(), R1.payloadReg(), &failure); |
|
94 break; |
|
95 case JSOP_SUB: |
|
96 masm.ma_subTestOverflow(R0.payloadReg(), R0.payloadReg(), R1.payloadReg(), &failure); |
|
97 break; |
|
98 case JSOP_MUL: { |
|
99 masm.ma_mul_branch_overflow(scratchReg, R0.payloadReg(), R1.payloadReg(), &failure); |
|
100 |
|
101 masm.ma_b(scratchReg, Imm32(0), &goodMul, Assembler::NotEqual, ShortJump); |
|
102 |
|
103 // Result is -0 if operands have different signs. |
|
104 masm.as_xor(t8, R0.payloadReg(), R1.payloadReg()); |
|
105 masm.ma_b(t8, Imm32(0), &failure, Assembler::LessThan, ShortJump); |
|
106 |
|
107 masm.bind(&goodMul); |
|
108 masm.move32(scratchReg, R0.payloadReg()); |
|
109 break; |
|
110 } |
|
111 case JSOP_DIV: |
|
112 case JSOP_MOD: { |
|
113 // Check for INT_MIN / -1, it results in a double. |
|
114 masm.ma_b(R0.payloadReg(), Imm32(INT_MIN), &divTest1, Assembler::NotEqual, ShortJump); |
|
115 masm.ma_b(R1.payloadReg(), Imm32(-1), &failure, Assembler::Equal, ShortJump); |
|
116 masm.bind(&divTest1); |
|
117 |
|
118 // Check for division by zero |
|
119 masm.ma_b(R1.payloadReg(), Imm32(0), &failure, Assembler::Equal, ShortJump); |
|
120 |
|
121 // Check for 0 / X with X < 0 (results in -0). |
|
122 masm.ma_b(R0.payloadReg(), Imm32(0), &divTest2, Assembler::NotEqual, ShortJump); |
|
123 masm.ma_b(R1.payloadReg(), Imm32(0), &failure, Assembler::LessThan, ShortJump); |
|
124 masm.bind(&divTest2); |
|
125 |
|
126 masm.as_div(R0.payloadReg(), R1.payloadReg()); |
|
127 |
|
128 if (op_ == JSOP_DIV) { |
|
129 // Result is a double if the remainder != 0. |
|
130 masm.as_mfhi(scratchReg); |
|
131 masm.ma_b(scratchReg, Imm32(0), &failure, Assembler::NotEqual, ShortJump); |
|
132 masm.as_mflo(scratchReg); |
|
133 masm.tagValue(JSVAL_TYPE_INT32, scratchReg, R0); |
|
134 } else { |
|
135 Label done; |
|
136 // If X % Y == 0 and X < 0, the result is -0. |
|
137 masm.as_mfhi(scratchReg); |
|
138 masm.ma_b(scratchReg, Imm32(0), &done, Assembler::NotEqual, ShortJump); |
|
139 masm.ma_b(R0.payloadReg(), Imm32(0), &failure, Assembler::LessThan, ShortJump); |
|
140 masm.bind(&done); |
|
141 masm.tagValue(JSVAL_TYPE_INT32, scratchReg, R0); |
|
142 } |
|
143 break; |
|
144 } |
|
145 case JSOP_BITOR: |
|
146 masm.ma_or(R0.payloadReg() , R0.payloadReg(), R1.payloadReg()); |
|
147 break; |
|
148 case JSOP_BITXOR: |
|
149 masm.ma_xor(R0.payloadReg() , R0.payloadReg(), R1.payloadReg()); |
|
150 break; |
|
151 case JSOP_BITAND: |
|
152 masm.ma_and(R0.payloadReg() , R0.payloadReg(), R1.payloadReg()); |
|
153 break; |
|
154 case JSOP_LSH: |
|
155 // MIPS will only use 5 lowest bits in R1 as shift offset. |
|
156 masm.ma_sll(R0.payloadReg(), R0.payloadReg(), R1.payloadReg()); |
|
157 break; |
|
158 case JSOP_RSH: |
|
159 masm.ma_sra(R0.payloadReg(), R0.payloadReg(), R1.payloadReg()); |
|
160 break; |
|
161 case JSOP_URSH: |
|
162 masm.ma_srl(scratchReg, R0.payloadReg(), R1.payloadReg()); |
|
163 if (allowDouble_) { |
|
164 Label toUint; |
|
165 masm.ma_b(scratchReg, Imm32(0), &toUint, Assembler::LessThan, ShortJump); |
|
166 |
|
167 // Move result and box for return. |
|
168 masm.move32(scratchReg, R0.payloadReg()); |
|
169 EmitReturnFromIC(masm); |
|
170 |
|
171 masm.bind(&toUint); |
|
172 masm.convertUInt32ToDouble(scratchReg, FloatReg1); |
|
173 masm.boxDouble(FloatReg1, R0); |
|
174 } else { |
|
175 masm.ma_b(scratchReg, Imm32(0), &failure, Assembler::LessThan, ShortJump); |
|
176 // Move result for return. |
|
177 masm.move32(scratchReg, R0.payloadReg()); |
|
178 } |
|
179 break; |
|
180 default: |
|
181 MOZ_ASSUME_UNREACHABLE("Unhandled op for BinaryArith_Int32."); |
|
182 } |
|
183 |
|
184 EmitReturnFromIC(masm); |
|
185 |
|
186 // Failure case - jump to next stub |
|
187 masm.bind(&failure); |
|
188 EmitStubGuardFailure(masm); |
|
189 |
|
190 return true; |
|
191 } |
|
192 |
|
193 bool |
|
194 ICUnaryArith_Int32::Compiler::generateStubCode(MacroAssembler &masm) |
|
195 { |
|
196 Label failure; |
|
197 masm.branchTestInt32(Assembler::NotEqual, R0, &failure); |
|
198 |
|
199 switch (op) { |
|
200 case JSOP_BITNOT: |
|
201 masm.not32(R0.payloadReg()); |
|
202 break; |
|
203 case JSOP_NEG: |
|
204 // Guard against 0 and MIN_INT, both result in a double. |
|
205 masm.branchTest32(Assembler::Zero, R0.payloadReg(), Imm32(INT32_MAX), &failure); |
|
206 |
|
207 masm.neg32(R0.payloadReg()); |
|
208 break; |
|
209 default: |
|
210 MOZ_ASSUME_UNREACHABLE("Unexpected op"); |
|
211 return false; |
|
212 } |
|
213 |
|
214 EmitReturnFromIC(masm); |
|
215 |
|
216 masm.bind(&failure); |
|
217 EmitStubGuardFailure(masm); |
|
218 return true; |
|
219 } |
|
220 |
|
221 |
|
222 } // namespace jit |
|
223 } // namespace js |