1 /*
2 * Copyright (c) 2022 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 #include "ecmascript/compiler/share_gate_meta_data.h"
17 #include "ecmascript/compiler/number_gate_info.h"
18 #include "ecmascript/compiler/type.h"
19 #include "ecmascript/compiler/typed_hcr_lowering.h"
20 #include "ecmascript/compiler/builtins_lowering.h"
21 #include "ecmascript/compiler/new_object_stub_builder.h"
22 #include "ecmascript/compiler/number_speculative_lowering.h"
23 #include "ecmascript/deoptimizer/deoptimizer.h"
24 #include "ecmascript/js_arraybuffer.h"
25 #include "ecmascript/js_locale.h"
26 #include "ecmascript/js_native_pointer.h"
27 #include "ecmascript/js_object.h"
28
29 namespace panda::ecmascript::kungfu {
30
Run()31 void NumberSpeculativeLowering::Run()
32 {
33 std::vector<GateRef> gateList;
34 acc_.GetAllGates(gateList);
35 for (auto gate : gateList) {
36 auto op = acc_.GetOpCode(gate);
37 switch (op) {
38 case OpCode::RANGE_GUARD: {
39 rangeGuardGates_.push_back(gate);
40 break;
41 }
42 default: {
43 VisitGate(gate);
44 }
45 }
46 }
47 for (auto rangeGuard : rangeGuardGates_) {
48 VisitRangeGuard(rangeGuard);
49 }
50 }
51
VisitGate(GateRef gate)52 void NumberSpeculativeLowering::VisitGate(GateRef gate)
53 {
54 OpCode op = acc_.GetOpCode(gate);
55 switch (op) {
56 case OpCode::TYPED_BINARY_OP: {
57 VisitTypedBinaryOp(gate);
58 break;
59 }
60 case OpCode::TYPED_UNARY_OP: {
61 VisitTypedUnaryOp(gate);
62 break;
63 }
64 case OpCode::TYPED_CONDITION_JUMP: {
65 VisitTypedConditionJump(gate);
66 break;
67 }
68 case OpCode::VALUE_SELECTOR: {
69 VisitPhi(gate);
70 break;
71 }
72 case OpCode::CONSTANT: {
73 VisitConstant(gate);
74 break;
75 }
76 case OpCode::LOAD_ELEMENT: {
77 VisitLoadElement(gate);
78 break;
79 }
80 case OpCode::INDEX_CHECK: {
81 VisitIndexCheck(gate);
82 break;
83 }
84 case OpCode::RANGE_CHECK_PREDICATE: {
85 VisitRangeCheckPredicate(gate);
86 break;
87 }
88 case OpCode::LOAD_ARRAY_LENGTH:
89 case OpCode::LOAD_TYPED_ARRAY_LENGTH: {
90 VisitLoadArrayLength(gate);
91 break;
92 }
93 case OpCode::LOAD_STRING_LENGTH: {
94 VisitLoadStringLength(gate);
95 break;
96 }
97 case OpCode::LOAD_MAP_SIZE: {
98 VisitLoadMapSize(gate);
99 break;
100 }
101 case OpCode::LOAD_PROPERTY: {
102 VisitLoadProperty(gate);
103 break;
104 }
105 case OpCode::MONO_LOAD_PROPERTY_ON_PROTO: {
106 VisitLoadPropertyOnProto(gate);
107 break;
108 }
109 case OpCode::MATH_ROUND: {
110 VisitRound(gate);
111 break;
112 }
113 default:
114 break;
115 }
116 }
117
VisitTypedBinaryOp(GateRef gate)118 void NumberSpeculativeLowering::VisitTypedBinaryOp(GateRef gate)
119 {
120 Environment env(gate, circuit_, &builder_);
121 if (acc_.HasStringType(gate)) {
122 VisitStringBinaryOp(gate);
123 return;
124 }
125 auto op = acc_.GetTypedBinaryOp(gate);
126 switch (op) {
127 case TypedBinOp::TYPED_STRICTEQ:
128 case TypedBinOp::TYPED_STRICTNOTEQ: {
129 VisitStrictEqualOrStrictNotEqual(gate);
130 break;
131 }
132 case TypedBinOp::TYPED_EQ:
133 case TypedBinOp::TYPED_NOTEQ: {
134 VisitEqualOrNotEqual(gate);
135 break;
136 }
137 default: {
138 if (acc_.HasNumberType(gate)) {
139 VisitNumberBinaryOp(gate);
140 }
141 break;
142 }
143 }
144 }
145
VisitEqualOrNotEqual(GateRef gate)146 void NumberSpeculativeLowering::VisitEqualOrNotEqual(GateRef gate)
147 {
148 if (acc_.HasNumberType(gate)) {
149 VisitNumberBinaryOp(gate);
150 } else {
151 VisitUndefinedEqOrUndefinedNotEq(gate);
152 }
153 }
154
VisitStrictEqualOrStrictNotEqual(GateRef gate)155 void NumberSpeculativeLowering::VisitStrictEqualOrStrictNotEqual(GateRef gate)
156 {
157 if (acc_.HasNumberType(gate)) {
158 VisitNumberBinaryOp(gate);
159 } else {
160 VisitUndefinedStrictEqOrUndefinedStrictNotEq(gate);
161 }
162 }
163
VisitNumberBinaryOp(GateRef gate)164 void NumberSpeculativeLowering::VisitNumberBinaryOp(GateRef gate)
165 {
166 TypedBinOp Op = acc_.GetTypedBinaryOp(gate);
167 switch (Op) {
168 case TypedBinOp::TYPED_ADD: {
169 VisitNumberCalculate<TypedBinOp::TYPED_ADD>(gate);
170 break;
171 }
172 case TypedBinOp::TYPED_SUB: {
173 VisitNumberCalculate<TypedBinOp::TYPED_SUB>(gate);
174 break;
175 }
176 case TypedBinOp::TYPED_MUL: {
177 VisitNumberCalculate<TypedBinOp::TYPED_MUL>(gate);
178 break;
179 }
180 case TypedBinOp::TYPED_LESS: {
181 VisitNumberCompare<TypedBinOp::TYPED_LESS>(gate);
182 break;
183 }
184 case TypedBinOp::TYPED_LESSEQ: {
185 VisitNumberCompare<TypedBinOp::TYPED_LESSEQ>(gate);
186 break;
187 }
188 case TypedBinOp::TYPED_GREATER: {
189 VisitNumberCompare<TypedBinOp::TYPED_GREATER>(gate);
190 break;
191 }
192 case TypedBinOp::TYPED_GREATEREQ: {
193 VisitNumberCompare<TypedBinOp::TYPED_GREATEREQ>(gate);
194 break;
195 }
196 case TypedBinOp::TYPED_EQ: {
197 VisitNumberCompare<TypedBinOp::TYPED_EQ>(gate);
198 break;
199 }
200 case TypedBinOp::TYPED_NOTEQ: {
201 VisitNumberCompare<TypedBinOp::TYPED_NOTEQ>(gate);
202 break;
203 }
204 case TypedBinOp::TYPED_STRICTEQ: {
205 VisitNumberCompare<TypedBinOp::TYPED_STRICTEQ>(gate);
206 break;
207 }
208 case TypedBinOp::TYPED_STRICTNOTEQ: {
209 VisitNumberCompare<TypedBinOp::TYPED_STRICTNOTEQ>(gate);
210 break;
211 }
212 case TypedBinOp::TYPED_SHL: {
213 VisitNumberShift<TypedBinOp::TYPED_SHL>(gate);
214 break;
215 }
216 case TypedBinOp::TYPED_SHR: {
217 VisitNumberShift<TypedBinOp::TYPED_SHR>(gate);
218 break;
219 }
220 case TypedBinOp::TYPED_ASHR: {
221 VisitNumberShift<TypedBinOp::TYPED_ASHR>(gate);
222 break;
223 }
224 case TypedBinOp::TYPED_AND: {
225 VisitNumberLogical<TypedBinOp::TYPED_AND>(gate);
226 break;
227 }
228 case TypedBinOp::TYPED_OR: {
229 VisitNumberLogical<TypedBinOp::TYPED_OR>(gate);
230 break;
231 }
232 case TypedBinOp::TYPED_XOR: {
233 VisitNumberLogical<TypedBinOp::TYPED_XOR>(gate);
234 break;
235 }
236 case TypedBinOp::TYPED_DIV: {
237 VisitNumberDiv(gate);
238 break;
239 }
240 case TypedBinOp::TYPED_MOD: {
241 VisitNumberMod<TypedBinOp::TYPED_MOD>(gate);
242 break;
243 }
244 default:
245 break;
246 }
247 }
248
VisitTypedUnaryOp(GateRef gate)249 void NumberSpeculativeLowering::VisitTypedUnaryOp(GateRef gate)
250 {
251 Environment env(gate, circuit_, &builder_);
252 TypedUnOp Op = acc_.GetTypedUnAccessor(gate).GetTypedUnOp();
253 switch (Op) {
254 case TypedUnOp::TYPED_INC: {
255 VisitNumberMonocular<TypedUnOp::TYPED_INC>(gate);
256 return;
257 }
258 case TypedUnOp::TYPED_DEC: {
259 VisitNumberMonocular<TypedUnOp::TYPED_DEC>(gate);
260 return;
261 }
262 case TypedUnOp::TYPED_NEG: {
263 VisitNumberMonocular<TypedUnOp::TYPED_NEG>(gate);
264 return;
265 }
266 case TypedUnOp::TYPED_ISFALSE: {
267 VisitIsTrueOrFalse(gate, false);
268 return;
269 }
270 case TypedUnOp::TYPED_ISTRUE: {
271 VisitIsTrueOrFalse(gate, true);
272 return;
273 }
274 case TypedUnOp::TYPED_NOT: {
275 VisitNumberNot(gate);
276 return;
277 }
278 default:
279 break;
280 }
281 }
282
VisitTypedConditionJump(GateRef gate)283 void NumberSpeculativeLowering::VisitTypedConditionJump(GateRef gate)
284 {
285 Environment env(gate, circuit_, &builder_);
286 ParamType type = acc_.GetTypedJumpAccessor(gate).GetParamType();
287 if (type.IsBooleanType()) {
288 VisitBooleanJump(gate);
289 } else {
290 UNREACHABLE();
291 }
292 }
293
294 template<TypedBinOp Op>
VisitNumberCalculate(GateRef gate)295 void NumberSpeculativeLowering::VisitNumberCalculate(GateRef gate)
296 {
297 GateRef left = acc_.GetValueIn(gate, 0);
298 GateRef right = acc_.GetValueIn(gate, 1);
299 TypedBinaryAccessor accessor(acc_.TryGetValue(gate));
300 const ParamType paramType = accessor.GetParamType();
301 ASSERT(paramType.HasNumberType());
302 GateRef result = Circuit::NullGate();
303 if (paramType.IsIntType()) {
304 result = CalculateInts<Op>(left, right); // int op int
305 UpdateRange(result, GetRange(gate));
306 acc_.SetMachineType(gate, MachineType::I32);
307 } else {
308 result = CalculateDoubles<Op>(left, right); // float op float
309 acc_.SetMachineType(gate, MachineType::F64);
310 }
311 acc_.SetGateType(gate, GateType::NJSValue());
312 acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), result);
313 }
314
315 template<TypedBinOp Op>
VisitNumberCompare(GateRef gate)316 void NumberSpeculativeLowering::VisitNumberCompare(GateRef gate)
317 {
318 GateRef left = acc_.GetValueIn(gate, 0);
319 GateRef right = acc_.GetValueIn(gate, 1);
320 TypedBinaryAccessor accessor(acc_.TryGetValue(gate));
321 const ParamType paramType = accessor.GetParamType();
322 ASSERT(paramType.HasNumberType());
323 GateRef result = Circuit::NullGate();
324 if (paramType.IsIntType()) {
325 result = CompareInts<Op>(left, right); // int op int
326 } else {
327 result = CompareDoubles<Op>(left, right); // float op float
328 }
329 acc_.SetMachineType(gate, MachineType::I1);
330 acc_.SetGateType(gate, GateType::NJSValue());
331 acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), result);
332 }
333
334 template<TypedBinOp Op>
VisitNumberShift(GateRef gate)335 void NumberSpeculativeLowering::VisitNumberShift(GateRef gate)
336 {
337 GateRef left = acc_.GetValueIn(gate, 0);
338 GateRef right = acc_.GetValueIn(gate, 1);
339 GateRef result = ShiftInts<Op>(left, right); // int op int
340 UpdateRange(result, GetRange(gate));
341 acc_.SetMachineType(gate, MachineType::I32);
342 acc_.SetGateType(gate, GateType::NJSValue());
343 acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), result);
344 }
345
346 template<TypedBinOp Op>
VisitNumberLogical(GateRef gate)347 void NumberSpeculativeLowering::VisitNumberLogical(GateRef gate)
348 {
349 GateRef left = acc_.GetValueIn(gate, 0);
350 GateRef right = acc_.GetValueIn(gate, 1);
351 GateRef result = LogicalInts<Op>(left, right); // int op int
352 UpdateRange(result, GetRange(gate));
353 acc_.SetMachineType(gate, MachineType::I32);
354 acc_.SetGateType(gate, GateType::NJSValue());
355 acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), result);
356 }
357
VisitNumberDiv(GateRef gate)358 void NumberSpeculativeLowering::VisitNumberDiv(GateRef gate)
359 {
360 GateRef left = acc_.GetValueIn(gate, 0);
361 GateRef right = acc_.GetValueIn(gate, 1);
362 TypedBinaryAccessor accessor(acc_.TryGetValue(gate));
363 const ParamType paramType = accessor.GetParamType();
364 ASSERT(paramType.HasNumberType());
365 GateRef result = Circuit::NullGate();
366 if (paramType.IsIntType()) {
367 result = builder_.Int32DivWithCheck(left, right);
368 acc_.SetMachineType(gate, MachineType::I32);
369 } else {
370 result = builder_.BinaryArithmetic(circuit_->Fdiv(),
371 MachineType::F64, left, right, GateType::NJSValue());
372 acc_.SetMachineType(gate, MachineType::F64);
373 }
374 acc_.SetGateType(gate, GateType::NJSValue());
375 acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), result);
376 }
377
378 template<TypedBinOp Op>
VisitNumberMod(GateRef gate)379 void NumberSpeculativeLowering::VisitNumberMod(GateRef gate)
380 {
381 GateRef left = acc_.GetValueIn(gate, 0);
382 GateRef right = acc_.GetValueIn(gate, 1);
383 TypedBinaryAccessor accessor(acc_.TryGetValue(gate));
384 const ParamType paramType = accessor.GetParamType();
385 ASSERT(paramType.HasNumberType());
386 GateRef result = Circuit::NullGate();
387 if (paramType.IsIntType()) {
388 if (GetRange(right).MaybeZero()) {
389 builder_.Int32CheckRightIsZero(right);
390 }
391 bool isNegativeZero = (GetRange(left) % GetRange(right)).MaybeZero() && GetRange(left).MaybeNegative();
392 if (isNegativeZero) {
393 builder_.RemainderIsNegativeZero(left, right);
394 }
395 result = CalculateInts<Op>(left, right);
396 UpdateRange(result, GetRange(gate));
397 acc_.SetMachineType(gate, MachineType::I32);
398 } else {
399 GateRef glue = acc_.GetGlueFromArgList();
400 result = builder_.CallNGCRuntime(glue, RTSTUB_ID(FloatMod),
401 Gate::InvalidGateRef, {left, right}, Circuit::NullGate());
402 acc_.SetMachineType(gate, MachineType::F64);
403 }
404 acc_.SetGateType(gate, GateType::NJSValue());
405 acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), result);
406 }
407
408 template<TypedUnOp Op>
VisitNumberMonocular(GateRef gate)409 void NumberSpeculativeLowering::VisitNumberMonocular(GateRef gate)
410 {
411 TypedUnaryAccessor accessor(acc_.TryGetValue(gate));
412 ParamType type = accessor.GetParamType();
413 ASSERT(type.HasNumberType());
414 GateRef value = acc_.GetValueIn(gate, 0);
415 GateRef result = Circuit::NullGate();
416 if (type.IsIntType()) {
417 if (Op == TypedUnOp::TYPED_NEG) {
418 builder_.ValueCheckNegOverflow(value);
419 }
420 result = MonocularInt<Op>(value);
421 UpdateRange(result, GetRange(gate));
422 acc_.SetMachineType(gate, MachineType::I32);
423 } else {
424 result = MonocularDouble<Op>(value);
425 acc_.SetMachineType(gate, MachineType::F64);
426 }
427 acc_.SetGateType(gate, GateType::NJSValue());
428 acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), result);
429 }
430
VisitNumberNot(GateRef gate)431 void NumberSpeculativeLowering::VisitNumberNot(GateRef gate)
432 {
433 ASSERT(TypedUnaryAccessor(acc_.TryGetValue(gate)).GetParamType().HasNumberType());
434 GateRef value = acc_.GetValueIn(gate, 0);
435 GateRef result = builder_.Int32Not(value);
436 UpdateRange(result, GetRange(gate));
437 acc_.SetMachineType(gate, MachineType::I32);
438 acc_.SetGateType(gate, GateType::NJSValue());
439 acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), result);
440 }
441
VisitIsTrueOrFalse(GateRef gate,bool flag)442 void NumberSpeculativeLowering::VisitIsTrueOrFalse(GateRef gate, bool flag)
443 {
444 GateRef value = acc_.GetValueIn(gate, 0);
445 GateRef result = Circuit::NullGate();
446 if (!flag) {
447 result = builder_.BoolNot(value);
448 } else {
449 result = value;
450 }
451 acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), result);
452 }
453
VisitBooleanJump(GateRef gate)454 void NumberSpeculativeLowering::VisitBooleanJump(GateRef gate)
455 {
456 TypedJumpAccessor jumpAcc = acc_.GetTypedJumpAccessor(gate);
457 TypedJumpOp jumpOp = jumpAcc.GetTypedJumpOp();
458 ASSERT((jumpOp == TypedJumpOp::TYPED_JEQZ) || (jumpOp == TypedJumpOp::TYPED_JNEZ));
459 GateRef condition = acc_.GetValueIn(gate, 0);
460 uint32_t trueWeight = jumpAcc.GetTrueWeight();
461 uint32_t falseWeight = jumpAcc.GetFalseWeight();
462 if (jumpOp == TypedJumpOp::TYPED_JEQZ) {
463 std::swap(trueWeight, falseWeight);
464 condition = builder_.BoolNot(condition);
465 }
466 GateRef ifBranch = builder_.Branch(acc_.GetState(gate), condition, trueWeight, falseWeight, "booleanJump");
467 acc_.ReplaceGate(gate, ifBranch, acc_.GetDep(gate), Circuit::NullGate());
468 }
469
VisitUndefinedStrictEqOrUndefinedStrictNotEq(GateRef gate)470 void NumberSpeculativeLowering::VisitUndefinedStrictEqOrUndefinedStrictNotEq(GateRef gate)
471 {
472 ASSERT(acc_.GetTypedBinaryOp(gate) == TypedBinOp::TYPED_STRICTEQ ||
473 acc_.GetTypedBinaryOp(gate) == TypedBinOp::TYPED_STRICTNOTEQ);
474 GateRef left = acc_.GetValueIn(gate, 0);
475 GateRef right = acc_.GetValueIn(gate, 1);
476 ASSERT(acc_.IsUndefinedOrNullOrHole(left) || acc_.IsUndefinedOrNullOrHole(right));
477 GateRef result = Circuit::NullGate();
478 if (acc_.GetTypedBinaryOp(gate) == TypedBinOp::TYPED_STRICTEQ) {
479 result = builder_.Equal(left, right);
480 } else {
481 result = builder_.NotEqual(left, right);
482 }
483 ASSERT(result != Circuit::NullGate());
484 acc_.SetMachineType(gate, MachineType::I1);
485 acc_.SetGateType(gate, GateType::NJSValue());
486 acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), result);
487 }
488
VisitUndefinedEqOrUndefinedNotEq(GateRef gate)489 void NumberSpeculativeLowering::VisitUndefinedEqOrUndefinedNotEq(GateRef gate)
490 {
491 ASSERT(acc_.GetTypedBinaryOp(gate) == TypedBinOp::TYPED_EQ ||
492 acc_.GetTypedBinaryOp(gate) == TypedBinOp::TYPED_NOTEQ);
493 GateRef left = acc_.GetValueIn(gate, 0);
494 GateRef right = acc_.GetValueIn(gate, 1);
495 ASSERT(acc_.IsUndefinedOrNullOrHole(left) || acc_.IsUndefinedOrNullOrHole(right));
496 GateRef valueGate = acc_.IsUndefinedOrNullOrHole(left) ? right : left;
497 GateRef result = Circuit::NullGate();
498 if (acc_.GetTypedBinaryOp(gate) == TypedBinOp::TYPED_EQ) {
499 result = builder_.TaggedIsUndefinedOrNullOrHole(valueGate);
500 } else {
501 result = builder_.TaggedIsNotUndefinedAndNullAndHole(valueGate);
502 }
503 acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), result);
504 }
505
VisitConstant(GateRef gate)506 void NumberSpeculativeLowering::VisitConstant(GateRef gate)
507 {
508 TypeInfo output = GetOutputType(gate);
509 switch (output) {
510 case TypeInfo::INT32: {
511 int value = acc_.GetInt32FromConstant(gate);
512 GateRef constGate = GetConstInt32(value);
513 acc_.UpdateAllUses(gate, constGate);
514 break;
515 }
516 case TypeInfo::FLOAT64: {
517 double value = acc_.GetFloat64FromConstant(gate);
518 acc_.UpdateAllUses(gate, builder_.Double(value));
519 break;
520 }
521 default:
522 break;
523 }
524 }
525
VisitPhi(GateRef gate)526 void NumberSpeculativeLowering::VisitPhi(GateRef gate)
527 {
528 TypeInfo output = GetOutputType(gate);
529 switch (output) {
530 case TypeInfo::INT1: {
531 acc_.SetGateType(gate, GateType::NJSValue());
532 acc_.SetMachineType(gate, MachineType::I1);
533 break;
534 }
535 case TypeInfo::INT32:
536 case TypeInfo::UINT32: {
537 acc_.SetGateType(gate, GateType::NJSValue());
538 acc_.SetMachineType(gate, MachineType::I32);
539 break;
540 }
541 case TypeInfo::FLOAT64: {
542 acc_.SetGateType(gate, GateType::NJSValue());
543 acc_.SetMachineType(gate, MachineType::F64);
544 break;
545 }
546 case TypeInfo::CHAR: {
547 acc_.SetGateType(gate, GateType::NJSValue());
548 acc_.SetMachineType(gate, MachineType::I32);
549 break;
550 }
551 default:
552 break;
553 }
554 }
555
VisitRangeCheckPredicate(GateRef gate)556 void NumberSpeculativeLowering::VisitRangeCheckPredicate(GateRef gate)
557 {
558 acc_.SetGateType(gate, GateType::NJSValue());
559 acc_.SetMachineType(gate, MachineType::I32);
560 }
561
VisitIndexCheck(GateRef gate)562 void NumberSpeculativeLowering::VisitIndexCheck(GateRef gate)
563 {
564 acc_.SetGateType(gate, GateType::NJSValue());
565 acc_.SetMachineType(gate, MachineType::I32);
566 }
567
VisitLoadArrayLength(GateRef gate)568 void NumberSpeculativeLowering::VisitLoadArrayLength(GateRef gate)
569 {
570 acc_.SetGateType(gate, GateType::NJSValue());
571 acc_.SetMachineType(gate, MachineType::I32);
572 }
573
VisitLoadStringLength(GateRef gate)574 void NumberSpeculativeLowering::VisitLoadStringLength(GateRef gate)
575 {
576 acc_.SetGateType(gate, GateType::NJSValue());
577 acc_.SetMachineType(gate, MachineType::I32);
578 }
579
VisitLoadMapSize(GateRef gate)580 void NumberSpeculativeLowering::VisitLoadMapSize(GateRef gate)
581 {
582 acc_.SetGateType(gate, GateType::NJSValue());
583 acc_.SetMachineType(gate, MachineType::I32);
584 }
585
VisitLoadElement(GateRef gate)586 void NumberSpeculativeLowering::VisitLoadElement(GateRef gate)
587 {
588 auto op = acc_.GetTypedLoadOp(gate);
589 switch (op) {
590 case TypedLoadOp::INT8ARRAY_LOAD_ELEMENT:
591 case TypedLoadOp::UINT8ARRAY_LOAD_ELEMENT:
592 case TypedLoadOp::UINT8CLAMPEDARRAY_LOAD_ELEMENT:
593 case TypedLoadOp::INT16ARRAY_LOAD_ELEMENT:
594 case TypedLoadOp::UINT16ARRAY_LOAD_ELEMENT:
595 case TypedLoadOp::INT32ARRAY_LOAD_ELEMENT:
596 case TypedLoadOp::UINT32ARRAY_LOAD_ELEMENT:
597 acc_.SetMachineType(gate, MachineType::I32);
598 acc_.SetGateType(gate, GateType::NJSValue());
599 break;
600 case TypedLoadOp::ARRAY_LOAD_HOLE_INT_ELEMENT:
601 case TypedLoadOp::ARRAY_LOAD_HOLE_DOUBLE_ELEMENT:
602 acc_.SetMachineType(gate, MachineType::I64);
603 acc_.SetGateType(gate, GateType::NJSValue());
604 break;
605 case TypedLoadOp::FLOAT32ARRAY_LOAD_ELEMENT:
606 case TypedLoadOp::FLOAT64ARRAY_LOAD_ELEMENT:
607 acc_.SetMachineType(gate, MachineType::F64);
608 acc_.SetGateType(gate, GateType::NJSValue());
609 break;
610 default:
611 break;
612 }
613 }
614
VisitLoadProperty(GateRef gate)615 void NumberSpeculativeLowering::VisitLoadProperty(GateRef gate)
616 {
617 TypeInfo output = GetOutputType(gate);
618 if (output == TypeInfo::INT32 || output == TypeInfo::FLOAT64) {
619 Environment env(gate, circuit_, &builder_);
620 ASSERT(acc_.GetNumValueIn(gate) == 2); // 2: receiver, plr
621 GateRef receiver = acc_.GetValueIn(gate, 0);
622 GateRef propertyLookupResult = acc_.GetValueIn(gate, 1);
623 PropertyLookupResult plr(acc_.TryGetValue(propertyLookupResult));
624 ASSERT(plr.IsLocal() || plr.IsFunction());
625
626 // Hole check?
627 GateRef result = Circuit::NullGate();
628 if (output == TypeInfo::FLOAT64) {
629 if (plr.IsInlinedProps()) {
630 result = builder_.LoadConstOffset(VariableType::FLOAT64(), receiver, plr.GetOffset());
631 } else {
632 auto properties =
633 builder_.LoadConstOffset(VariableType::JS_ANY(), receiver, JSObject::PROPERTIES_OFFSET);
634 result = builder_.GetValueFromTaggedArray(
635 VariableType::FLOAT64(), properties, builder_.Int32(plr.GetOffset()));
636 }
637 acc_.SetMachineType(gate, MachineType::F64);
638 } else {
639 if (plr.IsInlinedProps()) {
640 result = builder_.LoadConstOffset(VariableType::INT32(), receiver, plr.GetOffset());
641 } else {
642 auto properties =
643 builder_.LoadConstOffset(VariableType::JS_ANY(), receiver, JSObject::PROPERTIES_OFFSET);
644 result = builder_.GetValueFromTaggedArray(
645 VariableType::INT32(), properties, builder_.Int32(plr.GetOffset()));
646 }
647 acc_.SetMachineType(gate, MachineType::I32);
648 }
649 acc_.SetGateType(gate, GateType::NJSValue());
650 acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), result);
651 }
652 }
653
VisitRangeGuard(GateRef gate)654 void NumberSpeculativeLowering::VisitRangeGuard(GateRef gate)
655 {
656 Environment env(gate, circuit_, &builder_);
657 GateRef inputLength = acc_.GetValueIn(gate, 0);
658 acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), inputLength);
659 }
660
661 template<TypedBinOp Op>
CalculateInts(GateRef left,GateRef right)662 GateRef NumberSpeculativeLowering::CalculateInts(GateRef left, GateRef right)
663 {
664 GateRef res = Circuit::NullGate();
665 RangeInfo leftRange = GetRange(left);
666 RangeInfo rightRange = GetRange(right);
667 switch (Op) {
668 case TypedBinOp::TYPED_ADD: {
669 if (!leftRange.MaybeAddOverflowOrUnderflow(rightRange)) {
670 return builder_.Int32Add(left, right, GateType::NJSValue());
671 }
672 res = builder_.AddWithOverflow(left, right);
673 break;
674 }
675 case TypedBinOp::TYPED_SUB: {
676 if (!leftRange.MaybeSubOverflowOrUnderflow(rightRange)) {
677 return builder_.Int32Sub(left, right, GateType::NJSValue());
678 }
679 res = builder_.SubWithOverflow(left, right);
680 break;
681 }
682 case TypedBinOp::TYPED_MUL:
683 if (!leftRange.MaybeMulOverflowOrUnderflow(rightRange)) {
684 return builder_.Int32Mul(left, right);
685 }
686 res = builder_.MulWithOverflow(left, right);
687 break;
688 case TypedBinOp::TYPED_MOD: {
689 return builder_.BinaryArithmetic(circuit_->Smod(),
690 MachineType::I32, left, right, GateType::NJSValue());
691 break;
692 }
693 default:
694 break;
695 }
696 // DeoptCheckForOverFlow
697 builder_.OverflowCheck(res);
698 return builder_.ExtractValue(MachineType::I32, res, GetConstInt32(0));
699 }
700
701 template<TypedBinOp Op>
CalculateDoubles(GateRef left,GateRef right)702 GateRef NumberSpeculativeLowering::CalculateDoubles(GateRef left, GateRef right)
703 {
704 GateRef res = Circuit::NullGate();
705 switch (Op) {
706 case TypedBinOp::TYPED_ADD:
707 res = builder_.DoubleAdd(left, right, GateType::NJSValue());
708 break;
709 case TypedBinOp::TYPED_SUB:
710 res = builder_.DoubleSub(left, right, GateType::NJSValue());
711 break;
712 case TypedBinOp::TYPED_MUL:
713 res = builder_.DoubleMul(left, right, GateType::NJSValue());
714 break;
715 default:
716 break;
717 }
718 return res;
719 }
720
721 template<TypedBinOp Op>
CompareInts(GateRef left,GateRef right)722 GateRef NumberSpeculativeLowering::CompareInts(GateRef left, GateRef right)
723 {
724 GateRef condition = Circuit::NullGate();
725 switch (Op) {
726 case TypedBinOp::TYPED_LESS:
727 condition = builder_.Int32LessThan(left, right);
728 break;
729 case TypedBinOp::TYPED_LESSEQ:
730 condition = builder_.Int32LessThanOrEqual(left, right);
731 break;
732 case TypedBinOp::TYPED_GREATER:
733 condition = builder_.Int32GreaterThan(left, right);
734 break;
735 case TypedBinOp::TYPED_GREATEREQ:
736 condition = builder_.Int32GreaterThanOrEqual(left, right);
737 break;
738 case TypedBinOp::TYPED_EQ:
739 case TypedBinOp::TYPED_STRICTEQ:
740 condition = builder_.Int32Equal(left, right);
741 break;
742 case TypedBinOp::TYPED_NOTEQ:
743 case TypedBinOp::TYPED_STRICTNOTEQ:
744 condition = builder_.Int32NotEqual(left, right);
745 break;
746 default:
747 break;
748 }
749 return condition;
750 }
751
752 template<TypedBinOp Op>
CompareDoubles(GateRef left,GateRef right)753 GateRef NumberSpeculativeLowering::CompareDoubles(GateRef left, GateRef right)
754 {
755 GateRef condition = Circuit::NullGate();
756 switch (Op) {
757 case TypedBinOp::TYPED_LESS:
758 condition = builder_.DoubleLessThan(left, right);
759 break;
760 case TypedBinOp::TYPED_LESSEQ:
761 condition = builder_.DoubleLessThanOrEqual(left, right);
762 break;
763 case TypedBinOp::TYPED_GREATER:
764 condition = builder_.DoubleGreaterThan(left, right);
765 break;
766 case TypedBinOp::TYPED_GREATEREQ:
767 condition = builder_.DoubleGreaterThanOrEqual(left, right);
768 break;
769 case TypedBinOp::TYPED_EQ:
770 case TypedBinOp::TYPED_STRICTEQ: {
771 condition = LogicAndBuilder(builder_.GetCurrentEnvironment())
772 .And(builder_.BoolNot(builder_.DoubleIsNAN(left)))
773 .And(builder_.BoolNot(builder_.DoubleIsNAN(right)))
774 .And(builder_.DoubleEqual(left, right))
775 .Done();
776 break;
777 }
778 case TypedBinOp::TYPED_NOTEQ:
779 case TypedBinOp::TYPED_STRICTNOTEQ: {
780 condition = LogicOrBuilder(builder_.GetCurrentEnvironment())
781 .Or(builder_.DoubleIsNAN(left))
782 .Or(builder_.DoubleIsNAN(right))
783 .Or(builder_.DoubleNotEqual(left, right))
784 .Done();
785 break;
786 }
787 default:
788 break;
789 }
790 return condition;
791 }
792
793 template<TypedBinOp Op>
ShiftInts(GateRef left,GateRef right)794 GateRef NumberSpeculativeLowering::ShiftInts(GateRef left, GateRef right)
795 {
796 GateRef value = Circuit::NullGate();
797 GateRef bitmask = GetConstInt32(0x1f); // 0x1f: bit mask of shift value
798 GateRef shift = builder_.Int32And(right, bitmask, GateType::NJSValue());
799 switch (Op) {
800 case TypedBinOp::TYPED_SHL: {
801 value = builder_.Int32LSL(left, shift, GateType::NJSValue());
802 break;
803 }
804 case TypedBinOp::TYPED_SHR: {
805 value = builder_.Int32LSR(left, shift, GateType::NJSValue());
806 RangeInfo leftRange = GetRange(left);
807 RangeInfo rightRange = GetRange(right);
808 if (!leftRange.MaybeShrOverflow(rightRange)) {
809 return value;
810 }
811 builder_.Int32UnsignedUpperBoundCheck(value, builder_.Int32(INT32_MAX));
812 break;
813 }
814 case TypedBinOp::TYPED_ASHR: {
815 value = builder_.Int32ASR(left, shift, GateType::NJSValue());
816 break;
817 }
818 default:
819 LOG_ECMA(FATAL) << "this branch is unreachable";
820 UNREACHABLE();
821 break;
822 }
823 return value;
824 }
825
826 template<TypedBinOp Op>
LogicalInts(GateRef left,GateRef right)827 GateRef NumberSpeculativeLowering::LogicalInts(GateRef left, GateRef right)
828 {
829 GateRef value = Circuit::NullGate();
830 switch (Op) {
831 case TypedBinOp::TYPED_AND: {
832 value = builder_.Int32And(left, right, GateType::NJSValue());
833 break;
834 }
835 case TypedBinOp::TYPED_OR: {
836 value = builder_.Int32Or(left, right, GateType::NJSValue());
837 break;
838 }
839 case TypedBinOp::TYPED_XOR: {
840 value = builder_.Int32Xor(left, right, GateType::NJSValue());
841 break;
842 }
843 default:
844 LOG_ECMA(FATAL) << "this branch is unreachable";
845 UNREACHABLE();
846 break;
847 }
848 return value;
849 }
850
851 template<TypedUnOp Op>
MonocularInt(GateRef value)852 GateRef NumberSpeculativeLowering::MonocularInt(GateRef value)
853 {
854 GateRef res = Circuit::NullGate();
855 switch (Op) {
856 case TypedUnOp::TYPED_INC:
857 res = CalculateInts<TypedBinOp::TYPED_ADD>(value, GetConstInt32(1));
858 break;
859 case TypedUnOp::TYPED_DEC:
860 res = CalculateInts<TypedBinOp::TYPED_SUB>(value, GetConstInt32(1));
861 break;
862 case TypedUnOp::TYPED_NEG:
863 res = builder_.Int32Sub(GetConstInt32(0), value, GateType::NJSValue());
864 break;
865 default:
866 break;
867 }
868 return res;
869 }
870
871 template<TypedUnOp Op>
MonocularDouble(GateRef value)872 GateRef NumberSpeculativeLowering::MonocularDouble(GateRef value)
873 {
874 GateRef res = Circuit::NullGate();
875 switch (Op) {
876 case TypedUnOp::TYPED_INC:
877 res = CalculateDoubles<TypedBinOp::TYPED_ADD>(value, GetConstDouble(1));
878 break;
879 case TypedUnOp::TYPED_DEC:
880 res = CalculateDoubles<TypedBinOp::TYPED_SUB>(value, GetConstDouble(1));
881 break;
882 case TypedUnOp::TYPED_NEG:
883 res = CalculateDoubles<TypedBinOp::TYPED_MUL>(value, GetConstDouble(-1));
884 break;
885 default:
886 break;
887 }
888 return res;
889 }
890
UpdateRange(GateRef gate,const RangeInfo & range)891 void NumberSpeculativeLowering::UpdateRange(GateRef gate, const RangeInfo& range)
892 {
893 auto id = acc_.GetId(gate);
894 if (id >= rangeInfos_.size()) {
895 rangeInfos_.resize(id + 1, RangeInfo::ANY());
896 }
897 rangeInfos_[id] = range;
898 }
899
GetRange(GateRef gate) const900 RangeInfo NumberSpeculativeLowering::GetRange(GateRef gate) const
901 {
902 auto id = acc_.GetId(gate);
903 if (id >= rangeInfos_.size()) {
904 rangeInfos_.resize(id + 1, RangeInfo::ANY());
905 }
906 ASSERT(!rangeInfos_[id].IsNone());
907 return rangeInfos_[id];
908 }
909
GetConstInt32(int32_t v)910 GateRef NumberSpeculativeLowering::GetConstInt32(int32_t v)
911 {
912 auto val = builder_.Int32(v);
913 UpdateRange(val, RangeInfo(v, v));
914 return val;
915 }
916
GetConstDouble(double v)917 GateRef NumberSpeculativeLowering::GetConstDouble(double v)
918 {
919 auto val = builder_.Double(v);
920 UpdateRange(val, RangeInfo(v, v));
921 return val;
922 }
923
VisitStringBinaryOp(GateRef gate)924 void NumberSpeculativeLowering::VisitStringBinaryOp(GateRef gate)
925 {
926 TypedBinOp Op = acc_.GetTypedBinaryOp(gate);
927 switch (Op) {
928 case TypedBinOp::TYPED_EQ: {
929 VisitStringCompare<TypedBinOp::TYPED_EQ>(gate);
930 break;
931 }
932 case TypedBinOp::TYPED_ADD: {
933 VisitStringAdd<TypedBinOp::TYPED_ADD>(gate);
934 break;
935 }
936 default:
937 LOG_COMPILER(FATAL) << "this branch is unreachable";
938 UNREACHABLE();
939 }
940 }
941
942 template<TypedBinOp Op>
VisitStringCompare(GateRef gate)943 void NumberSpeculativeLowering::VisitStringCompare(GateRef gate)
944 {
945 GateRef left = acc_.GetValueIn(gate, 0);
946 GateRef right = acc_.GetValueIn(gate, 1);
947
948 GateRef result;
949 ASSERT(Op == TypedBinOp::TYPED_EQ);
950 result = builder_.StringEqual(left, right);
951
952 acc_.SetMachineType(gate, MachineType::I1);
953 acc_.SetGateType(gate, GateType::NJSValue());
954 acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), result);
955 }
956
957 template<TypedBinOp Op>
VisitStringAdd(GateRef gate)958 void NumberSpeculativeLowering::VisitStringAdd(GateRef gate)
959 {
960 GateRef left = acc_.GetValueIn(gate, 0);
961 GateRef right = acc_.GetValueIn(gate, 1);
962
963 GateRef result;
964 ASSERT(Op == TypedBinOp::TYPED_ADD);
965 result = builder_.StringAdd(left, right);
966
967 acc_.SetMachineType(gate, MachineType::I64);
968 acc_.SetGateType(gate, GateType::NJSValue());
969 acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), result);
970 }
971
VisitLoadPropertyOnProto(GateRef gate)972 void NumberSpeculativeLowering::VisitLoadPropertyOnProto(GateRef gate)
973 {
974 TypeInfo output = GetOutputType(gate);
975 if (output == TypeInfo::INT32 || output == TypeInfo::FLOAT64) {
976 Environment env(gate, circuit_, &builder_);
977 GateRef frameState = acc_.GetFrameState(gate);
978 GateRef receiver = acc_.GetValueIn(gate, 0);
979 GateRef propertyLookupResult = acc_.GetValueIn(gate, 1); // 1: propertyLookupResult
980 GateRef hclassIndex = acc_.GetValueIn(gate, 2); // 2: hclassIndex
981 GateRef unsharedConstPool = acc_.GetValueIn(gate, 3); // 3: constpool
982 PropertyLookupResult plr(acc_.TryGetValue(propertyLookupResult));
983 GateRef result = Circuit::NullGate();
984 ASSERT(plr.IsLocal() || plr.IsFunction());
985
986 auto receiverHC = builder_.LoadConstOffset(VariableType::JS_POINTER(), receiver, TaggedObject::HCLASS_OFFSET);
987 auto prototype = builder_.LoadConstOffset(VariableType::JS_ANY(), receiverHC, JSHClass::PROTOTYPE_OFFSET);
988
989 auto holderHC = builder_.LoadHClassFromConstpool(unsharedConstPool, acc_.GetConstantValue(hclassIndex));
990 DEFVALUE(current, (&builder_), VariableType::JS_ANY(), prototype);
991 Label exit(&builder_);
992 Label loopHead(&builder_);
993 Label loadHolder(&builder_);
994 Label lookUpProto(&builder_);
995 builder_.Jump(&loopHead);
996
997 builder_.LoopBegin(&loopHead);
998 builder_.DeoptCheck(builder_.TaggedIsNotNull(*current), frameState, DeoptType::INCONSISTENTHCLASS7);
999 auto curHC = builder_.LoadConstOffset(VariableType::JS_POINTER(), *current, TaggedObject::HCLASS_OFFSET);
1000 BRANCH_CIR(builder_.Equal(curHC, holderHC), &loadHolder, &lookUpProto);
1001
1002 builder_.Bind(&lookUpProto);
1003 current = builder_.LoadConstOffset(VariableType::JS_ANY(), curHC, JSHClass::PROTOTYPE_OFFSET);
1004 builder_.LoopEnd(&loopHead);
1005
1006 builder_.Bind(&loadHolder);
1007 if (output == TypeInfo::FLOAT64) {
1008 if (plr.IsInlinedProps()) {
1009 result = builder_.LoadConstOffset(VariableType::FLOAT64(), *current, plr.GetOffset());
1010 } else {
1011 auto properties =
1012 builder_.LoadConstOffset(VariableType::JS_ANY(), *current, JSObject::PROPERTIES_OFFSET);
1013 result = builder_.GetValueFromTaggedArray(
1014 VariableType::FLOAT64(), properties, builder_.Int32(plr.GetOffset()));
1015 }
1016 acc_.SetMachineType(gate, MachineType::F64);
1017 } else {
1018 if (plr.IsInlinedProps()) {
1019 result = builder_.LoadConstOffset(VariableType::INT32(), *current, plr.GetOffset());
1020 } else {
1021 auto properties =
1022 builder_.LoadConstOffset(VariableType::JS_ANY(), *current, JSObject::PROPERTIES_OFFSET);
1023 result = builder_.GetValueFromTaggedArray(
1024 VariableType::INT32(), properties, builder_.Int32(plr.GetOffset()));
1025 }
1026 acc_.SetMachineType(gate, MachineType::I32);
1027 }
1028 builder_.Jump(&exit);
1029 builder_.Bind(&exit);
1030 acc_.SetGateType(gate, GateType::NJSValue());
1031 acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), result);
1032 }
1033 }
1034
VisitRound(GateRef gate)1035 void NumberSpeculativeLowering::VisitRound(GateRef gate)
1036 {
1037 TypeInfo output = GetOutputType(gate);
1038 GateRef in = acc_.GetValueIn(gate, 0);
1039 if (output == TypeInfo::INT32) {
1040 acc_.ReplaceGate(gate, in);
1041 }
1042 }
1043
1044 } // namespace panda::ecmascript
1045