1 /*
2 * Copyright (c) 2021 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #ifndef ECMASCRIPT_IC_IC_BINARY_OP_INL_H_
17 #define ECMASCRIPT_IC_IC_BINARY_OP_INL_H_
18
19 #include "ic_binary_op.h"
20 #include "ecmascript/ic/proto_change_details.h"
21 #include "ecmascript/interpreter/interpreter-inl.h"
22 #include "ecmascript/interpreter/slow_runtime_stub.h"
23 #include "ecmascript/js_array.h"
24 #include "ecmascript/js_handle.h"
25 #include "ecmascript/js_tagged_value-inl.h"
26 #include "ecmascript/napi/include/jsnapi.h"
27
28 namespace panda::ecmascript {
AddWithTSType(JSThread * thread,EcmaVM * ecma_vm,JSTaggedValue left,JSTaggedValue right,JSTaggedValue argType)29 JSTaggedValue ICBinaryOP::AddWithTSType(JSThread *thread, EcmaVM *ecma_vm, JSTaggedValue left,
30 JSTaggedValue right, JSTaggedValue argType)
31 {
32 INTERPRETER_TRACE(thread, AddWithTSType);
33 BinaryType addType = static_cast<BinaryType>(argType.GetInt());
34 switch (addType) {
35 // Support cases, such as: int + double, int + int, double + double
36 case BinaryType::NUMBER: {
37 double a0Double = left.IsInt() ? left.GetInt() : left.GetDouble();
38 double a1Double = right.IsInt() ? right.GetInt() : right.GetDouble();
39 double ret = a0Double + a1Double;
40 return JSTaggedValue(ret);
41 }
42 // Support cases, such as: number + null, undefined + null, boolean + number, etc.
43 case BinaryType::NUMBER_GEN: {
44 JSHandle<JSTaggedValue> leftValue(thread, left);
45 JSHandle<JSTaggedValue> rightValue(thread, right);
46 JSHandle<JSTaggedValue> primitiveA0(thread, JSTaggedValue::ToPrimitive(thread, leftValue));
47 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
48 JSHandle<JSTaggedValue> primitiveA1(thread, JSTaggedValue::ToPrimitive(thread, rightValue));
49 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
50
51 JSTaggedNumber taggedValueA0 = JSTaggedValue::ToNumber(thread, primitiveA0);
52 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
53 JSTaggedNumber taggedValueA1 = JSTaggedValue::ToNumber(thread, primitiveA1);
54 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
55 double a0Double = taggedValueA0.GetNumber();
56 double a1Double = taggedValueA1.GetNumber();
57 return JSTaggedValue(a0Double + a1Double);
58 }
59 // Support case: string + string.
60 case BinaryType::STRING: {
61 JSHandle<EcmaString> stringA0 = JSHandle<EcmaString>(JSHandle<JSTaggedValue>(thread, left));
62 JSHandle<EcmaString> stringA1 = JSHandle<EcmaString>(JSHandle<JSTaggedValue>(thread, right));
63 EcmaString *ret = EcmaString::Concat(stringA0, stringA1, ecma_vm);
64 return JSTaggedValue(ret);
65 }
66 // Support cases, such as: string + null, string + object, string + boolean, string + number, etc.
67 case BinaryType::STRING_GEN: {
68 JSHandle<JSTaggedValue> leftValue(thread, left);
69 JSHandle<JSTaggedValue> rightValue(thread, right);
70 if (left.IsString()) {
71 JSHandle<EcmaString> stringA0 = JSHandle<EcmaString>(leftValue);
72 JSHandle<EcmaString> stringA1 = JSTaggedValue::ToString(thread, rightValue);
73 EcmaString *ret = EcmaString::Concat(stringA0, stringA1, ecma_vm);
74 return JSTaggedValue(ret);
75 } else {
76 JSHandle<EcmaString> stringA0 = JSTaggedValue::ToString(thread, leftValue);
77 JSHandle<EcmaString> stringA1 = JSHandle<EcmaString>(rightValue);
78 EcmaString *ret = EcmaString::Concat(stringA0, stringA1, ecma_vm);
79 return JSTaggedValue(ret);
80 }
81 }
82 // Some special cases, such as: object + undefined, object + boolean, etc.
83 case BinaryType::GENERIC: {
84 JSTaggedValue res = SlowRuntimeStub::Add2Dyn(thread, ecma_vm, left, right);
85 return res;
86 }
87 default: {
88 UNREACHABLE();
89 }
90 }
91 }
92
SubWithTSType(JSThread * thread,EcmaVM * ecma_vm,JSTaggedValue left,JSTaggedValue right,JSTaggedValue argType)93 JSTaggedValue ICBinaryOP::SubWithTSType(JSThread *thread, EcmaVM *ecma_vm, JSTaggedValue left,
94 JSTaggedValue right, JSTaggedValue argType)
95 {
96 INTERPRETER_TRACE(thread, SubWithTSType);
97 BinaryType subType = static_cast<BinaryType>(argType.GetInt());
98 switch (subType) {
99 // Support int or number
100 case BinaryType::NUMBER: {
101 double a0Double = left.IsInt() ? left.GetInt() : left.GetDouble();
102 double a1Double = right.IsInt() ? right.GetInt() : right.GetDouble();
103 double ret = a0Double - a1Double;
104 return JSTaggedValue(ret);
105 }
106 // Support cases, such as: string like '2333', boolean, null
107 case BinaryType::GENERIC: {
108 JSHandle<JSTaggedValue> leftValue(thread, left);
109 JSHandle<JSTaggedValue> rightValue(thread, right);
110 JSTaggedNumber number0 = JSTaggedValue::ToNumber(thread, leftValue);
111 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
112 JSTaggedNumber number1 = JSTaggedValue::ToNumber(thread, rightValue);
113 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
114 auto ret = number0 - number1;
115 return JSTaggedValue(ret);
116 }
117 case BinaryType::NUMBER_GEN:
118 case BinaryType::STRING:
119 case BinaryType::STRING_GEN:
120 default: {
121 UNREACHABLE();
122 }
123 }
124 }
125
MulWithTSType(JSThread * thread,EcmaVM * ecma_vm,JSTaggedValue left,JSTaggedValue right,JSTaggedValue argType)126 JSTaggedValue ICBinaryOP::MulWithTSType(JSThread *thread, EcmaVM *ecma_vm, JSTaggedValue left,
127 JSTaggedValue right, JSTaggedValue argType)
128 {
129 INTERPRETER_TRACE(thread, MulWithTSType);
130 BinaryType mulType = static_cast<BinaryType>(argType.GetInt());
131 switch (mulType) {
132 // Support int or number
133 case BinaryType::NUMBER: {
134 return JSTaggedValue(left.GetNumber() * right.GetNumber());
135 }
136 // Support cases, such as: string like '2333', boolean, null
137 case BinaryType::GENERIC: {
138 JSHandle<JSTaggedValue> leftValue(thread, left);
139 JSHandle<JSTaggedValue> rightValue(thread, right);
140 // 6. Let lnum be ToNumber(leftValue).
141 JSTaggedNumber primitiveA = JSTaggedValue::ToNumber(thread, leftValue);
142 // 7. ReturnIfAbrupt(lnum).
143 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
144 // 8. Let rnum be ToNumber(rightValue).
145 JSTaggedNumber primitiveB = JSTaggedValue::ToNumber(thread, rightValue);
146 // 9. ReturnIfAbrupt(rnum).
147 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
148 // 12.6.3.1 Applying the * Operator
149 return primitiveA * primitiveB;
150 }
151 case BinaryType::NUMBER_GEN:
152 case BinaryType::STRING:
153 case BinaryType::STRING_GEN:
154 default: {
155 UNREACHABLE();
156 }
157 }
158 }
159
DivWithTSType(JSThread * thread,EcmaVM * ecma_vm,JSTaggedValue left,JSTaggedValue right,JSTaggedValue argType)160 JSTaggedValue ICBinaryOP::DivWithTSType(JSThread *thread, EcmaVM *ecma_vm, JSTaggedValue left,
161 JSTaggedValue right, JSTaggedValue argType)
162 {
163 INTERPRETER_TRACE(thread, DivWithTSType);
164 BinaryType divType = static_cast<BinaryType>(argType.GetInt());
165 switch (divType) {
166 // Support int or number
167 case BinaryType::NUMBER: {
168 double dLeft = left.IsInt() ? left.GetInt() : left.GetDouble();
169 double dRight = right.IsInt() ? right.GetInt() : right.GetDouble();
170 if (UNLIKELY(dRight == 0.0)) {
171 if (dLeft == 0.0 || std::isnan(dLeft)) {
172 return JSTaggedValue(base::NAN_VALUE);
173 }
174 uint64_t flagBit = ((bit_cast<uint64_t>(dLeft)) ^ (bit_cast<uint64_t>(dRight))) &
175 base::DOUBLE_SIGN_MASK;
176 return JSTaggedValue(bit_cast<double>(flagBit ^ (bit_cast<uint64_t>(base::POSITIVE_INFINITY))));
177 }
178 return JSTaggedValue(dLeft / dRight);
179 }
180 // Support special cases, such as: string like '2333', boolean, null
181 case BinaryType::GENERIC: {
182 auto res = SlowRuntimeStub::Div2Dyn(thread, left, right);
183 return res;
184 }
185 case BinaryType::NUMBER_GEN:
186 case BinaryType::STRING:
187 case BinaryType::STRING_GEN:
188 default: {
189 UNREACHABLE();
190 }
191 }
192 }
193
ModWithTSType(JSThread * thread,EcmaVM * ecma_vm,JSTaggedValue left,JSTaggedValue right,JSTaggedValue argType)194 JSTaggedValue ICBinaryOP::ModWithTSType(JSThread *thread, EcmaVM *ecma_vm, JSTaggedValue left,
195 JSTaggedValue right, JSTaggedValue argType)
196 {
197 INTERPRETER_TRACE(thread, ModWithTSType);
198 BinaryType modType = static_cast<BinaryType>(argType.GetInt());
199 switch (modType) {
200 // Support int or number
201 case BinaryType::NUMBER: {
202 double dLeft = left.IsInt() ? left.GetInt() : left.GetDouble();
203 double dRight = right.IsInt() ? right.GetInt() : right.GetDouble();
204 if (dRight == 0.0 || std::isnan(dRight) || std::isnan(dLeft) || std::isinf(dLeft)) {
205 return JSTaggedValue(base::NAN_VALUE);
206 }
207 if (dLeft == 0.0 || std::isinf(dRight)) {
208 return JSTaggedValue(dLeft);
209 }
210 return JSTaggedValue(std::fmod(dLeft, dRight));
211 }
212 // Support special cases, such as: string like '2333', boolean, null
213 case BinaryType::GENERIC: {
214 JSHandle<JSTaggedValue> leftValue(thread, left);
215 JSHandle<JSTaggedValue> rightValue(thread, right);
216 JSTaggedNumber leftNumber = JSTaggedValue::ToNumber(thread, leftValue);
217 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
218 double dLeft = leftNumber.GetNumber();
219 JSTaggedNumber rightNumber = JSTaggedValue::ToNumber(thread, rightValue);
220 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
221 double dRight = rightNumber.GetNumber();
222 // 12.6.3.3 Applying the % Operator
223 if ((dRight == 0.0) || std::isnan(dRight) || std::isnan(dLeft) || std::isinf(dLeft)) {
224 return JSTaggedValue(base::NAN_VALUE);
225 }
226 if ((dLeft == 0.0) || std::isinf(dRight)) {
227 return JSTaggedValue(dLeft);
228 }
229 return JSTaggedValue(std::fmod(dLeft, dRight));
230 }
231 case BinaryType::NUMBER_GEN:
232 case BinaryType::STRING:
233 case BinaryType::STRING_GEN:
234 default: {
235 UNREACHABLE();
236 }
237 }
238 }
239
GetBitOPDate(JSThread * thread,JSTaggedValue left,JSTaggedValue right,int32_t & opNumber0,int32_t & opNumber1,BinaryType opType)240 void ICBinaryOP::GetBitOPDate(JSThread *thread, JSTaggedValue left, JSTaggedValue right,
241 int32_t &opNumber0, int32_t &opNumber1, BinaryType opType)
242 {
243 INTERPRETER_TRACE(thread, GetBitOPDate);
244 switch (opType) {
245 case BinaryType::NUMBER: {
246 opNumber0 =
247 left.IsInt() ? left.GetInt() : base::NumberHelper::DoubleToInt(left.GetDouble(), base::INT32_BITS);
248 opNumber1 =
249 right.IsInt() ? right.GetInt() : base::NumberHelper::DoubleToInt(right.GetDouble(), base::INT32_BITS);
250 break;
251 }
252 // Support special cases, such as: string like '2333', boolean, null
253 case BinaryType::GENERIC: {
254 JSHandle<JSTaggedValue> leftValue(thread, left);
255 JSHandle<JSTaggedValue> rightValue(thread, right);
256 JSTaggedValue taggedNumber0 = SlowRuntimeStub::ToJSTaggedValueWithInt32(thread,
257 leftValue.GetTaggedValue());
258 JSTaggedValue taggedNumber1 = SlowRuntimeStub::ToJSTaggedValueWithUint32(thread,
259 rightValue.GetTaggedValue());
260 opNumber0 = taggedNumber0.GetInt();
261 opNumber1 = taggedNumber1.GetInt();
262 break;
263 }
264 case BinaryType::NUMBER_GEN:
265 case BinaryType::STRING:
266 case BinaryType::STRING_GEN:
267 default: {
268 UNREACHABLE();
269 }
270 }
271 return;
272 }
273
ShlWithTSType(JSThread * thread,EcmaVM * ecma_vm,JSTaggedValue left,JSTaggedValue right,JSTaggedValue argType)274 JSTaggedValue ICBinaryOP::ShlWithTSType(JSThread *thread, EcmaVM *ecma_vm, JSTaggedValue left,
275 JSTaggedValue right, JSTaggedValue argType)
276 {
277 INTERPRETER_TRACE(thread, ShlWithTSType);
278 BinaryType shlType = static_cast<BinaryType>(argType.GetInt());
279 int32_t opNumber0;
280 int32_t opNumber1;
281 GetBitOPDate(thread, left, right, opNumber0, opNumber1, shlType);
282 uint32_t shift =
283 static_cast<uint32_t>(opNumber1) & 0x1f; // NOLINT(hicpp-signed-bitwise, readability-magic-numbers)
284 using unsigned_type = std::make_unsigned_t<int32_t>;
285 auto ret =
286 static_cast<int32_t>(static_cast<unsigned_type>(opNumber0) << shift); // NOLINT(hicpp-signed-bitwise)
287 return JSTaggedValue(ret);
288 }
289
ShrWithTSType(JSThread * thread,EcmaVM * ecma_vm,JSTaggedValue left,JSTaggedValue right,JSTaggedValue argType)290 JSTaggedValue ICBinaryOP::ShrWithTSType(JSThread *thread, EcmaVM *ecma_vm, JSTaggedValue left,
291 JSTaggedValue right, JSTaggedValue argType)
292 {
293 INTERPRETER_TRACE(thread, ShrWithTSType);
294 BinaryType shrType = static_cast<BinaryType>(argType.GetInt());
295 int32_t opNumber0;
296 int32_t opNumber1;
297 GetBitOPDate(thread, left, right, opNumber0, opNumber1, shrType);
298 uint32_t shift =
299 static_cast<uint32_t>(opNumber1) & 0x1f; // NOLINT(hicpp-signed-bitwise, readability-magic-numbers)
300 auto ret = static_cast<int32_t>(opNumber0 >> shift); // NOLINT(hicpp-signed-bitwise)
301 return JSTaggedValue(ret);
302 }
303
AshrWithTSType(JSThread * thread,EcmaVM * ecma_vm,JSTaggedValue left,JSTaggedValue right,JSTaggedValue argType)304 JSTaggedValue ICBinaryOP::AshrWithTSType(JSThread *thread, EcmaVM *ecma_vm, JSTaggedValue left,
305 JSTaggedValue right, JSTaggedValue argType)
306 {
307 INTERPRETER_TRACE(thread, AshrWithTSType);
308 BinaryType ashrType = static_cast<BinaryType>(argType.GetInt());
309 int32_t opNumber0;
310 int32_t opNumber1;
311 GetBitOPDate(thread, left, right, opNumber0, opNumber1, ashrType);
312 uint32_t shift =
313 static_cast<uint32_t>(opNumber1) & 0x1f; // NOLINT(hicpp-signed-bitwise, readability-magic-numbers)
314 using unsigned_type = std::make_unsigned_t<uint32_t>;
315 auto ret =
316 static_cast<uint32_t>(static_cast<unsigned_type>(opNumber0) >> shift); // NOLINT(hicpp-signed-bitwise)
317 return JSTaggedValue(ret);
318 }
319
AndWithTSType(JSThread * thread,EcmaVM * ecma_vm,JSTaggedValue left,JSTaggedValue right,JSTaggedValue argType)320 JSTaggedValue ICBinaryOP::AndWithTSType(JSThread *thread, EcmaVM *ecma_vm, JSTaggedValue left,
321 JSTaggedValue right, JSTaggedValue argType)
322 {
323 INTERPRETER_TRACE(thread, AndWithTSType);
324 BinaryType andType = static_cast<BinaryType>(argType.GetInt());
325 int32_t opNumber0;
326 int32_t opNumber1;
327 GetBitOPDate(thread, left, right, opNumber0, opNumber1, andType);
328 // NOLINT(hicpp-signed-bitwise)
329 auto ret = static_cast<uint32_t>(opNumber0) & static_cast<uint32_t>(opNumber1);
330 return JSTaggedValue(ret);
331 }
332
OrWithTSType(JSThread * thread,EcmaVM * ecma_vm,JSTaggedValue left,JSTaggedValue right,JSTaggedValue argType)333 JSTaggedValue ICBinaryOP::OrWithTSType(JSThread *thread, EcmaVM *ecma_vm, JSTaggedValue left,
334 JSTaggedValue right, JSTaggedValue argType)
335 {
336 INTERPRETER_TRACE(thread, OrWithTSType);
337 BinaryType orType = static_cast<BinaryType>(argType.GetInt());
338 int32_t opNumber0;
339 int32_t opNumber1;
340 GetBitOPDate(thread, left, right, opNumber0, opNumber1, orType);
341 // NOLINT(hicpp-signed-bitwise)
342 auto ret = static_cast<uint32_t>(opNumber0) | static_cast<uint32_t>(opNumber1);
343 return JSTaggedValue(ret);
344 }
345
XorWithTSType(JSThread * thread,EcmaVM * ecma_vm,JSTaggedValue left,JSTaggedValue right,JSTaggedValue argType)346 JSTaggedValue ICBinaryOP::XorWithTSType(JSThread *thread, EcmaVM *ecma_vm, JSTaggedValue left,
347 JSTaggedValue right, JSTaggedValue argType)
348 {
349 INTERPRETER_TRACE(thread, XorWithTSType);
350 BinaryType xorType = static_cast<BinaryType>(argType.GetInt());
351 int32_t opNumber0;
352 int32_t opNumber1;
353 GetBitOPDate(thread, left, right, opNumber0, opNumber1, xorType);
354 // NOLINT(hicpp-signed-bitwise)
355 auto ret = static_cast<uint32_t>(opNumber0) ^ static_cast<uint32_t>(opNumber1);
356 return JSTaggedValue(ret);
357 }
358 } // namespace panda::ecmascript
359 #endif // ECMASCRIPT_IC_IC_BINARY_OP_INL_H_
360