• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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