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