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/BaselineIC.h"
11 #include "jit/BaselineJIT.h"
12 #include "jit/Linker.h"
13 #include "jit/SharedICHelpers.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 // ICBinaryArith_Int32
24 
25 bool
generateStubCode(MacroAssembler & masm)26 ICBinaryArith_Int32::Compiler::generateStubCode(MacroAssembler& masm)
27 {
28     // Guard that R0 is an integer and R1 is an integer.
29     Label failure;
30     masm.branchTestInt32(Assembler::NotEqual, R0, &failure);
31     masm.branchTestInt32(Assembler::NotEqual, R1, &failure);
32 
33     // Add R0 and R1. Don't need to explicitly unbox, just use R2's payloadReg.
34     Register scratchReg = R2.payloadReg();
35 
36     // DIV and MOD need an extra non-volatile ValueOperand to hold R0.
37     AllocatableGeneralRegisterSet savedRegs(availableGeneralRegs(2));
38     savedRegs.set() = GeneralRegisterSet::Intersect(GeneralRegisterSet::NonVolatile(), savedRegs.set());
39 
40     Label goodMul, divTest1, divTest2;
41     switch(op_) {
42       case JSOP_ADD:
43         // We know R0.typeReg() already contains the integer tag. No boxing
44         // required.
45         masm.ma_addTestOverflow(scratchReg, R0.payloadReg(), R1.payloadReg(), &failure);
46         masm.move32(scratchReg, R0.payloadReg());
47         break;
48       case JSOP_SUB:
49         masm.ma_subTestOverflow(scratchReg, R0.payloadReg(), R1.payloadReg(), &failure);
50         masm.move32(scratchReg, R0.payloadReg());
51         break;
52       case JSOP_MUL: {
53         masm.ma_mul_branch_overflow(scratchReg, R0.payloadReg(), R1.payloadReg(), &failure);
54 
55         masm.ma_b(scratchReg, Imm32(0), &goodMul, Assembler::NotEqual, ShortJump);
56 
57         // Result is -0 if operands have different signs.
58         masm.as_xor(t8, R0.payloadReg(), R1.payloadReg());
59         masm.ma_b(t8, Imm32(0), &failure, Assembler::LessThan, ShortJump);
60 
61         masm.bind(&goodMul);
62         masm.move32(scratchReg, R0.payloadReg());
63         break;
64       }
65       case JSOP_DIV:
66       case JSOP_MOD: {
67         // Check for INT_MIN / -1, it results in a double.
68         masm.ma_b(R0.payloadReg(), Imm32(INT_MIN), &divTest1, Assembler::NotEqual, ShortJump);
69         masm.ma_b(R1.payloadReg(), Imm32(-1), &failure, Assembler::Equal, ShortJump);
70         masm.bind(&divTest1);
71 
72         // Check for division by zero
73         masm.ma_b(R1.payloadReg(), Imm32(0), &failure, Assembler::Equal, ShortJump);
74 
75         // Check for 0 / X with X < 0 (results in -0).
76         masm.ma_b(R0.payloadReg(), Imm32(0), &divTest2, Assembler::NotEqual, ShortJump);
77         masm.ma_b(R1.payloadReg(), Imm32(0), &failure, Assembler::LessThan, ShortJump);
78         masm.bind(&divTest2);
79 
80         masm.as_div(R0.payloadReg(), R1.payloadReg());
81 
82         if (op_ == JSOP_DIV) {
83             // Result is a double if the remainder != 0.
84             masm.as_mfhi(scratchReg);
85             masm.ma_b(scratchReg, Imm32(0), &failure, Assembler::NotEqual, ShortJump);
86             masm.as_mflo(scratchReg);
87             masm.tagValue(JSVAL_TYPE_INT32, scratchReg, R0);
88         } else {
89             Label done;
90             // If X % Y == 0 and X < 0, the result is -0.
91             masm.as_mfhi(scratchReg);
92             masm.ma_b(scratchReg, Imm32(0), &done, Assembler::NotEqual, ShortJump);
93             masm.ma_b(R0.payloadReg(), Imm32(0), &failure, Assembler::LessThan, ShortJump);
94             masm.bind(&done);
95             masm.tagValue(JSVAL_TYPE_INT32, scratchReg, R0);
96         }
97         break;
98       }
99       case JSOP_BITOR:
100         masm.as_or(R0.payloadReg() , R0.payloadReg(), R1.payloadReg());
101         break;
102       case JSOP_BITXOR:
103         masm.as_xor(R0.payloadReg() , R0.payloadReg(), R1.payloadReg());
104         break;
105       case JSOP_BITAND:
106         masm.as_and(R0.payloadReg() , R0.payloadReg(), R1.payloadReg());
107         break;
108       case JSOP_LSH:
109         // MIPS will only use 5 lowest bits in R1 as shift offset.
110         masm.ma_sll(R0.payloadReg(), R0.payloadReg(), R1.payloadReg());
111         break;
112       case JSOP_RSH:
113         masm.ma_sra(R0.payloadReg(), R0.payloadReg(), R1.payloadReg());
114         break;
115       case JSOP_URSH:
116         masm.ma_srl(scratchReg, R0.payloadReg(), R1.payloadReg());
117         if (allowDouble_) {
118             Label toUint;
119             masm.ma_b(scratchReg, Imm32(0), &toUint, Assembler::LessThan, ShortJump);
120 
121             // Move result and box for return.
122             masm.move32(scratchReg, R0.payloadReg());
123             EmitReturnFromIC(masm);
124 
125             masm.bind(&toUint);
126             masm.convertUInt32ToDouble(scratchReg, FloatReg1);
127             masm.boxDouble(FloatReg1, R0);
128         } else {
129             masm.ma_b(scratchReg, Imm32(0), &failure, Assembler::LessThan, ShortJump);
130             // Move result for return.
131             masm.move32(scratchReg, R0.payloadReg());
132         }
133         break;
134       default:
135         MOZ_CRASH("Unhandled op for BinaryArith_Int32.");
136     }
137 
138     EmitReturnFromIC(masm);
139 
140     // Failure case - jump to next stub
141     masm.bind(&failure);
142     EmitStubGuardFailure(masm);
143 
144     return true;
145 }
146 
147 bool
generateStubCode(MacroAssembler & masm)148 ICUnaryArith_Int32::Compiler::generateStubCode(MacroAssembler& masm)
149 {
150     Label failure;
151     masm.branchTestInt32(Assembler::NotEqual, R0, &failure);
152 
153     switch (op) {
154       case JSOP_BITNOT:
155         masm.not32(R0.payloadReg());
156         break;
157       case JSOP_NEG:
158         // Guard against 0 and MIN_INT, both result in a double.
159         masm.branchTest32(Assembler::Zero, R0.payloadReg(), Imm32(INT32_MAX), &failure);
160 
161         masm.neg32(R0.payloadReg());
162         break;
163       default:
164         MOZ_CRASH("Unexpected op");
165         return false;
166     }
167 
168     EmitReturnFromIC(masm);
169 
170     masm.bind(&failure);
171     EmitStubGuardFailure(masm);
172     return true;
173 }
174 
175 
176 } // namespace jit
177 } // namespace js
178