• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/ts_hcr_lowering.h"
17 #include "ecmascript/compiler/bytecodes.h"
18 #include "ecmascript/compiler/builtins_lowering.h"
19 #include "ecmascript/compiler/circuit.h"
20 #include "ecmascript/dfx/vmstat/opt_code_profiler.h"
21 #include "ecmascript/stackmap/llvm_stackmap_parser.h"
22 #include "ecmascript/ts_types/ts_type.h"
23 
24 namespace panda::ecmascript::kungfu {
RunTSHCRLowering()25 bool TSHCRLowering::RunTSHCRLowering()
26 {
27     std::vector<GateRef> gateList;
28     circuit_->GetAllGates(gateList);
29     for (const auto &gate : gateList) {
30         auto op = acc_.GetOpCode(gate);
31         if (op == OpCode::JS_BYTECODE) {
32             Lower(gate);
33             allJSBcCount_++;
34         }
35     }
36 
37     bool success = true;
38     double typeHitRate = 0.0;
39     auto allTypedOpCount = allJSBcCount_ - allNonTypedOpCount_;
40     if (allTypedOpCount != 0) {
41         typeHitRate = static_cast<double>(hitTypedOpCount_) / static_cast<double>(allTypedOpCount);
42         auto typeThreshold = tsManager_->GetTypeThreshold();
43         if (typeHitRate <= typeThreshold) {
44             success = false;
45         }
46     }
47     acc_.EliminateRedundantPhi();
48 
49     if (IsTypeLogEnabled()) {
50         pgoTypeLog_.PrintPGOTypeLog();
51     }
52 
53     if (IsLogEnabled()) {
54         LOG_COMPILER(INFO) << "";
55         LOG_COMPILER(INFO) << "\033[34m"
56                            << "===================="
57                            << " After TSHCRlowering "
58                            << "[" << GetMethodName() << "]"
59                            << "===================="
60                            << "\033[0m";
61         circuit_->PrintAllGatesWithBytecode();
62         LOG_COMPILER(INFO) << "\033[34m" << " =========================== End typeHitRate: "
63                            << std::to_string(typeHitRate)
64                            << " ===========================" << "\033[0m";
65         for (auto a : bytecodeMap_) {
66             if (bytecodeHitTimeMap_.find(a.first) != bytecodeHitTimeMap_.end()) {
67                 double rate = static_cast<double>(bytecodeHitTimeMap_[a.first]) / static_cast<double>(a.second);
68                 LOG_COMPILER(INFO) << "\033[34m" << " =========================== End opHitRate: "
69                                    << GetEcmaOpcodeStr(a.first) << " rate: " << std::to_string(rate)
70                                    << "(" << std::to_string(bytecodeHitTimeMap_[a.first])
71                                    << " / " << std::to_string(a.second) << ")"
72                                    << " ===========================" << "\033[0m";
73             } else {
74                 LOG_COMPILER(INFO) << "\033[34m" << " =========================== End opHitRate: "
75                                    << GetEcmaOpcodeStr(a.first) << " rate: " << std::to_string(0)
76                                    << "(" << std::to_string(0)
77                                    << " / " << std::to_string(a.second) << ")"
78                                    << " ===========================" << "\033[0m";
79             }
80         }
81     }
82 
83     return success;
84 }
85 
IsTrustedType(GateRef gate) const86 bool TSHCRLowering::IsTrustedType(GateRef gate) const
87 {
88     if (acc_.IsConstant(gate)) {
89         return true;
90     }
91     auto op = acc_.GetOpCode(gate);
92     if (acc_.IsTypedOperator(gate)) {
93         if (op == OpCode::TYPED_BINARY_OP) {
94             return !acc_.GetGateType(gate).IsIntType();
95         } else {
96             return true;
97         }
98     }
99     if (op == OpCode::JS_BYTECODE) {
100         EcmaOpcode ecmaOpcode = acc_.GetByteCodeOpcode(gate);
101         switch (ecmaOpcode) {
102             case EcmaOpcode::ADD2_IMM8_V8:
103             case EcmaOpcode::SUB2_IMM8_V8:
104             case EcmaOpcode::MUL2_IMM8_V8:
105                 return !acc_.GetGateType(gate).IsIntType();
106             case EcmaOpcode::INC_IMM8:
107             case EcmaOpcode::DEC_IMM8:
108             case EcmaOpcode::LESS_IMM8_V8:
109             case EcmaOpcode::LESSEQ_IMM8_V8:
110             case EcmaOpcode::GREATER_IMM8_V8:
111             case EcmaOpcode::GREATEREQ_IMM8_V8:
112             case EcmaOpcode::EQ_IMM8_V8:
113             case EcmaOpcode::NOTEQ_IMM8_V8:
114             case EcmaOpcode::STRICTEQ_IMM8_V8:
115             case EcmaOpcode::STRICTNOTEQ_IMM8_V8:
116             case EcmaOpcode::ISTRUE:
117             case EcmaOpcode::ISFALSE:
118                 return true;
119             default:
120                 break;
121         }
122     }
123     return false;
124 }
125 
Lower(GateRef gate)126 void TSHCRLowering::Lower(GateRef gate)
127 {
128     EcmaOpcode ecmaOpcode = acc_.GetByteCodeOpcode(gate);
129     // initialize label manager
130     Environment env(gate, circuit_, &builder_);
131     AddBytecodeCount(ecmaOpcode);
132     switch (ecmaOpcode) {
133         case EcmaOpcode::ADD2_IMM8_V8:
134             LowerTypedBinOp<TypedBinOp::TYPED_ADD>(gate);
135             break;
136         case EcmaOpcode::SUB2_IMM8_V8:
137             LowerTypedBinOp<TypedBinOp::TYPED_SUB>(gate);
138             break;
139         case EcmaOpcode::MUL2_IMM8_V8:
140             LowerTypedBinOp<TypedBinOp::TYPED_MUL>(gate);
141             break;
142         case EcmaOpcode::DIV2_IMM8_V8:
143             LowerTypedDiv(gate);
144             break;
145         case EcmaOpcode::MOD2_IMM8_V8:
146             LowerTypedMod(gate);
147             break;
148         case EcmaOpcode::LESS_IMM8_V8:
149             LowerTypedBinOp<TypedBinOp::TYPED_LESS>(gate);
150             break;
151         case EcmaOpcode::LESSEQ_IMM8_V8:
152             LowerTypedBinOp<TypedBinOp::TYPED_LESSEQ>(gate);
153             break;
154         case EcmaOpcode::GREATER_IMM8_V8:
155             LowerTypedBinOp<TypedBinOp::TYPED_GREATER>(gate);
156             break;
157         case EcmaOpcode::GREATEREQ_IMM8_V8:
158             LowerTypedBinOp<TypedBinOp::TYPED_GREATEREQ>(gate);
159             break;
160         case EcmaOpcode::EQ_IMM8_V8:
161             LowerTypedBinOp<TypedBinOp::TYPED_EQ>(gate);
162             break;
163         case EcmaOpcode::STRICTEQ_IMM8_V8:
164             LowerTypedStrictEq(gate);
165             break;
166         case EcmaOpcode::NOTEQ_IMM8_V8:
167             LowerTypedBinOp<TypedBinOp::TYPED_NOTEQ>(gate);
168             break;
169         case EcmaOpcode::SHL2_IMM8_V8:
170             LowerTypedShl(gate);
171             break;
172         case EcmaOpcode::SHR2_IMM8_V8:
173             LowerTypedShr(gate);
174             break;
175         case EcmaOpcode::ASHR2_IMM8_V8:
176             LowerTypedAshr(gate);
177             break;
178         case EcmaOpcode::AND2_IMM8_V8:
179             LowerTypedAnd(gate);
180             break;
181         case EcmaOpcode::OR2_IMM8_V8:
182             LowerTypedOr(gate);
183             break;
184         case EcmaOpcode::XOR2_IMM8_V8:
185             LowerTypedXor(gate);
186             break;
187         case EcmaOpcode::TONUMERIC_IMM8:
188             LowerTypeToNumeric(gate);
189             break;
190         case EcmaOpcode::NEG_IMM8:
191             LowerTypedNeg(gate);
192             break;
193         case EcmaOpcode::NOT_IMM8:
194             LowerTypedNot(gate);
195             break;
196         case EcmaOpcode::INC_IMM8:
197             LowerTypedInc(gate);
198             break;
199         case EcmaOpcode::DEC_IMM8:
200             LowerTypedDec(gate);
201             break;
202         case EcmaOpcode::ISTRUE:
203             LowerTypedIsTrueOrFalse(gate, true);
204             break;
205         case EcmaOpcode::ISFALSE:
206             LowerTypedIsTrueOrFalse(gate, false);
207             break;
208         case EcmaOpcode::JEQZ_IMM8:
209         case EcmaOpcode::JEQZ_IMM16:
210         case EcmaOpcode::JEQZ_IMM32:
211             LowerConditionJump(gate, false);
212             break;
213         case EcmaOpcode::JNEZ_IMM8:
214         case EcmaOpcode::JNEZ_IMM16:
215         case EcmaOpcode::JNEZ_IMM32:
216             LowerConditionJump(gate, true);
217             break;
218         case EcmaOpcode::LDOBJBYNAME_IMM8_ID16:
219         case EcmaOpcode::LDOBJBYNAME_IMM16_ID16:
220         case EcmaOpcode::LDTHISBYNAME_IMM8_ID16:
221         case EcmaOpcode::LDTHISBYNAME_IMM16_ID16:
222             LowerTypedLdObjByName(gate);
223             break;
224         case EcmaOpcode::STOBJBYNAME_IMM8_ID16_V8:
225         case EcmaOpcode::STOBJBYNAME_IMM16_ID16_V8:
226             LowerTypedStObjByName(gate, false);
227             break;
228         case EcmaOpcode::STTHISBYNAME_IMM8_ID16:
229         case EcmaOpcode::STTHISBYNAME_IMM16_ID16:
230             LowerTypedStObjByName(gate, true);
231             break;
232         case EcmaOpcode::LDOBJBYINDEX_IMM8_IMM16:
233         case EcmaOpcode::LDOBJBYINDEX_IMM16_IMM16:
234         case EcmaOpcode::WIDE_LDOBJBYINDEX_PREF_IMM32:
235             LowerTypedLdObjByIndex(gate);
236             break;
237         case EcmaOpcode::STOBJBYINDEX_IMM8_V8_IMM16:
238         case EcmaOpcode::STOBJBYINDEX_IMM16_V8_IMM16:
239         case EcmaOpcode::WIDE_STOBJBYINDEX_PREF_V8_IMM32:
240             LowerTypedStObjByIndex(gate);
241             break;
242         case EcmaOpcode::LDOBJBYVALUE_IMM8_V8:
243         case EcmaOpcode::LDOBJBYVALUE_IMM16_V8:
244             LowerTypedLdObjByValue(gate, false);
245             break;
246         case EcmaOpcode::LDTHISBYVALUE_IMM8:
247         case EcmaOpcode::LDTHISBYVALUE_IMM16:
248             LowerTypedLdObjByValue(gate, true);
249             break;
250         case EcmaOpcode::STOBJBYVALUE_IMM8_V8_V8:
251         case EcmaOpcode::STOBJBYVALUE_IMM16_V8_V8:
252             LowerTypedStObjByValue(gate);
253             break;
254         case EcmaOpcode::NEWOBJRANGE_IMM8_IMM8_V8:
255         case EcmaOpcode::NEWOBJRANGE_IMM16_IMM8_V8:
256         case EcmaOpcode::WIDE_NEWOBJRANGE_PREF_IMM16_V8:
257             LowerTypedNewObjRange(gate);
258             break;
259         case EcmaOpcode::SUPERCALLTHISRANGE_IMM8_IMM8_V8:
260         case EcmaOpcode::WIDE_SUPERCALLTHISRANGE_PREF_IMM16_V8:
261             LowerTypedSuperCall(gate);
262             break;
263         case EcmaOpcode::CALLARG0_IMM8:
264             LowerTypedCallArg0(gate);
265             break;
266         case EcmaOpcode::CALLARG1_IMM8_V8:
267             LowerTypedCallArg1(gate);
268             break;
269         case EcmaOpcode::CALLARGS2_IMM8_V8_V8:
270             LowerTypedCallArg2(gate);
271             break;
272         case EcmaOpcode::CALLARGS3_IMM8_V8_V8_V8:
273             LowerTypedCallArg3(gate);
274             break;
275         case EcmaOpcode::CALLRANGE_IMM8_IMM8_V8:
276             LowerTypedCallrange(gate);
277             break;
278         case EcmaOpcode::CALLTHIS0_IMM8_V8:
279             LowerTypedCallthis0(gate);
280             break;
281         case EcmaOpcode::CALLTHIS1_IMM8_V8_V8:
282             LowerTypedCallthis1(gate);
283             break;
284         case EcmaOpcode::CALLTHIS2_IMM8_V8_V8_V8:
285             LowerTypedCallthis2(gate);
286             break;
287         case EcmaOpcode::CALLTHIS3_IMM8_V8_V8_V8_V8:
288             LowerTypedCallthis3(gate);
289             break;
290         case EcmaOpcode::CALLTHISRANGE_IMM8_IMM8_V8:
291             LowerTypedCallthisrange(gate);
292             break;
293         default:
294             DeleteBytecodeCount(ecmaOpcode);
295             allNonTypedOpCount_++;
296             break;
297     }
298 }
299 
300 template<TypedBinOp Op>
LowerTypedBinOp(GateRef gate)301 void TSHCRLowering::LowerTypedBinOp(GateRef gate)
302 {
303     GateRef left = acc_.GetValueIn(gate, 0);
304     GateRef right = acc_.GetValueIn(gate, 1);
305     if (HasNumberType(gate, left, right)) {
306         SpeculateNumbers<Op>(gate);
307     }
308 }
309 
LowerTypedMod(GateRef gate)310 void TSHCRLowering::LowerTypedMod(GateRef gate)
311 {
312     GateRef left = acc_.GetValueIn(gate, 0);
313     GateRef right = acc_.GetValueIn(gate, 1);
314     if (HasNumberType(gate, left, right)) {
315         SpeculateNumbers<TypedBinOp::TYPED_MOD>(gate);
316     }
317 }
318 
LowerTypedDiv(GateRef gate)319 void TSHCRLowering::LowerTypedDiv(GateRef gate)
320 {
321     GateRef left = acc_.GetValueIn(gate, 0);
322     GateRef right = acc_.GetValueIn(gate, 1);
323     if (HasNumberType(gate, left, right)) {
324         SpeculateNumbers<TypedBinOp::TYPED_DIV>(gate);
325     }
326 }
327 
LowerTypedStrictEq(GateRef gate)328 void TSHCRLowering::LowerTypedStrictEq(GateRef gate)
329 {
330     GateRef left = acc_.GetValueIn(gate, 0);
331     GateRef right = acc_.GetValueIn(gate, 1);
332     GateType leftType = acc_.GetGateType(left);
333     GateType rightType = acc_.GetGateType(right);
334     GateType gateType = acc_.GetGateType(gate);
335     PGOSampleType sampleType = acc_.TryGetPGOType(gate);
336     if (acc_.IsConstantUndefined(left) || acc_.IsConstantUndefined(right) || HasNumberType(gate, left, right)) {
337         GateRef result = builder_.TypedBinaryOp<TypedBinOp::TYPED_STRICTEQ>(
338             left, right, leftType, rightType, gateType, sampleType);
339         acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), result);
340     }
341 }
342 
LowerTypedShl(GateRef gate)343 void TSHCRLowering::LowerTypedShl(GateRef gate)
344 {
345     GateRef left = acc_.GetValueIn(gate, 0);
346     GateRef right = acc_.GetValueIn(gate, 1);
347     if (HasNumberType(gate, left, right)) {
348         SpeculateNumbers<TypedBinOp::TYPED_SHL>(gate);
349     }
350 }
351 
LowerTypedShr(GateRef gate)352 void TSHCRLowering::LowerTypedShr(GateRef gate)
353 {
354     GateRef left = acc_.GetValueIn(gate, 0);
355     GateRef right = acc_.GetValueIn(gate, 1);
356     if (HasNumberType(gate, left, right)) {
357         SpeculateNumbers<TypedBinOp::TYPED_SHR>(gate);
358     }
359 }
360 
LowerTypedAshr(GateRef gate)361 void TSHCRLowering::LowerTypedAshr(GateRef gate)
362 {
363     GateRef left = acc_.GetValueIn(gate, 0);
364     GateRef right = acc_.GetValueIn(gate, 1);
365     if (HasNumberType(gate, left, right)) {
366         SpeculateNumbers<TypedBinOp::TYPED_ASHR>(gate);
367     }
368 }
369 
LowerTypedAnd(GateRef gate)370 void TSHCRLowering::LowerTypedAnd(GateRef gate)
371 {
372     GateRef left = acc_.GetValueIn(gate, 0);
373     GateRef right = acc_.GetValueIn(gate, 1);
374     if (HasNumberType(gate, left, right)) {
375         SpeculateNumbers<TypedBinOp::TYPED_AND>(gate);
376     }
377 }
378 
LowerTypedOr(GateRef gate)379 void TSHCRLowering::LowerTypedOr(GateRef gate)
380 {
381     GateRef left = acc_.GetValueIn(gate, 0);
382     GateRef right = acc_.GetValueIn(gate, 1);
383     if (HasNumberType(gate, left, right)) {
384         SpeculateNumbers<TypedBinOp::TYPED_OR>(gate);
385     }
386 }
387 
LowerTypedXor(GateRef gate)388 void TSHCRLowering::LowerTypedXor(GateRef gate)
389 {
390     GateRef left = acc_.GetValueIn(gate, 0);
391     GateRef right = acc_.GetValueIn(gate, 1);
392     if (HasNumberType(gate, left, right)) {
393         SpeculateNumbers<TypedBinOp::TYPED_XOR>(gate);
394     }
395 }
396 
LowerTypedInc(GateRef gate)397 void TSHCRLowering::LowerTypedInc(GateRef gate)
398 {
399     GateRef value = acc_.GetValueIn(gate, 0);
400     if (HasNumberType(gate, value)) {
401         SpeculateNumber<TypedUnOp::TYPED_INC>(gate);
402     }
403 }
404 
LowerTypedDec(GateRef gate)405 void TSHCRLowering::LowerTypedDec(GateRef gate)
406 {
407     GateRef value = acc_.GetValueIn(gate, 0);
408     if (HasNumberType(gate, value)) {
409         SpeculateNumber<TypedUnOp::TYPED_DEC>(gate);
410     }
411 }
412 
HasNumberType(GateRef gate,GateRef value) const413 bool TSHCRLowering::HasNumberType(GateRef gate, GateRef value) const
414 {
415     GateType valueType = acc_.GetGateType(value);
416     PGOSampleType sampleType = acc_.TryGetPGOType(gate);
417     if (sampleType.IsNumber() ||
418         (sampleType.IsNone() && valueType.IsNumberType())) {
419         return true;
420     }
421     return false;
422 }
423 
HasNumberType(GateRef gate,GateRef left,GateRef right) const424 bool TSHCRLowering::HasNumberType(GateRef gate, GateRef left, GateRef right) const
425 {
426     GateType leftType = acc_.GetGateType(left);
427     GateType rightType = acc_.GetGateType(right);
428 
429     PGOSampleType sampleType = acc_.TryGetPGOType(gate);
430     if (sampleType.IsNumber() ||
431         (sampleType.IsNone() && leftType.IsNumberType() && rightType.IsNumberType())) {
432         return true;
433     }
434     return false;
435 }
436 
437 template<TypedBinOp Op>
SpeculateNumbers(GateRef gate)438 void TSHCRLowering::SpeculateNumbers(GateRef gate)
439 {
440     AddProfiling(gate);
441     GateRef left = acc_.GetValueIn(gate, 0);
442     GateRef right = acc_.GetValueIn(gate, 1);
443     GateType leftType = acc_.GetGateType(left);
444     GateType rightType = acc_.GetGateType(right);
445     GateType gateType = acc_.GetGateType(gate);
446     PGOSampleType sampleType = acc_.TryGetPGOType(gate);
447     pgoTypeLog_.CollectGateTypeLogInfo(gate, true);
448 
449     GateRef result = builder_.TypedBinaryOp<Op>(left, right, leftType, rightType, gateType, sampleType);
450     acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), result);
451 }
452 
453 template<TypedUnOp Op>
SpeculateNumber(GateRef gate)454 void TSHCRLowering::SpeculateNumber(GateRef gate)
455 {
456     AddProfiling(gate);
457     GateRef value = acc_.GetValueIn(gate, 0);
458     GateType valueType = acc_.GetGateType(value);
459     GateType gateType = acc_.GetGateType(gate);
460     pgoTypeLog_.CollectGateTypeLogInfo(gate, false);
461 
462     PGOSampleType sampleType = acc_.TryGetPGOType(gate);
463     if (sampleType.IsNumber()) {
464         if (sampleType.IsInt()) {
465             gateType = GateType::IntType();
466         } else if (sampleType.IsDouble()) {
467             gateType = GateType::DoubleType();
468         } else {
469             gateType = GateType::NumberType();
470         }
471         valueType = gateType;
472     }
473 
474     GateRef result = builder_.TypedUnaryOp<Op>(value, valueType, gateType);
475 
476     acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), result);
477 }
478 
LowerTypeToNumeric(GateRef gate)479 void TSHCRLowering::LowerTypeToNumeric(GateRef gate)
480 {
481     GateRef src = acc_.GetValueIn(gate, 0);
482     if (HasNumberType(gate, src)) {
483         AddProfiling(gate);
484         LowerPrimitiveTypeToNumber(gate);
485     }
486 }
487 
LowerPrimitiveTypeToNumber(GateRef gate)488 void TSHCRLowering::LowerPrimitiveTypeToNumber(GateRef gate)
489 {
490     GateRef src = acc_.GetValueIn(gate, 0);
491     GateType srcType = acc_.GetGateType(src);
492 
493     GateRef result = builder_.PrimitiveToNumber(src, VariableType(MachineType::I64, srcType));
494 
495     acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), result);
496 }
497 
LowerConditionJump(GateRef gate,bool flag)498 void TSHCRLowering::LowerConditionJump(GateRef gate, bool flag)
499 {
500     GateRef condition = acc_.GetValueIn(gate, 0);
501     GateType conditionType = acc_.GetGateType(condition);
502     if (conditionType.IsBooleanType() && IsTrustedType(condition)) {
503         AddProfiling(gate);
504         SpeculateConditionJump(gate, flag);
505     }
506 }
507 
SpeculateConditionJump(GateRef gate,bool flag)508 void TSHCRLowering::SpeculateConditionJump(GateRef gate, bool flag)
509 {
510     GateRef value = acc_.GetValueIn(gate, 0);
511     GateType valueType = acc_.GetGateType(value);
512     GateRef jump = Circuit::NullGate();
513     if (flag) {
514         jump = builder_.TypedConditionJump<TypedJumpOp::TYPED_JNEZ>(value, valueType);
515     } else {
516         jump = builder_.TypedConditionJump<TypedJumpOp::TYPED_JEQZ>(value, valueType);
517     }
518     acc_.ReplaceGate(gate, jump, jump, Circuit::NullGate());
519 }
520 
LowerTypedNeg(GateRef gate)521 void TSHCRLowering::LowerTypedNeg(GateRef gate)
522 {
523     GateRef value = acc_.GetValueIn(gate, 0);
524     if (HasNumberType(gate, value)) {
525         SpeculateNumber<TypedUnOp::TYPED_NEG>(gate);
526     }
527 }
528 
LowerTypedNot(GateRef gate)529 void TSHCRLowering::LowerTypedNot(GateRef gate)
530 {
531     GateRef value = acc_.GetValueIn(gate, 0);
532     if (HasNumberType(gate, value)) {
533         SpeculateNumber<TypedUnOp::TYPED_NOT>(gate);
534     }
535 }
536 
DeleteConstDataIfNoUser(GateRef gate)537 void TSHCRLowering::DeleteConstDataIfNoUser(GateRef gate)
538 {
539     auto uses = acc_.Uses(gate);
540     if (uses.begin() == uses.end()) {
541         builder_.ClearConstantCache(gate);
542         acc_.DeleteGate(gate);
543     }
544 }
545 
LowerTypedLdObjByName(GateRef gate)546 void TSHCRLowering::LowerTypedLdObjByName(GateRef gate)
547 {
548     DISALLOW_GARBAGE_COLLECTION;
549     auto constData = acc_.GetValueIn(gate, 1); // 1: valueIn 1
550     uint16_t keyIndex = acc_.GetConstantValue(constData);
551     JSTaggedValue key = tsManager_->GetStringFromConstantPool(keyIndex);
552 
553     // 3: number of value inputs
554     ASSERT(acc_.GetNumValueIn(gate) == 3);
555     GateRef receiver = acc_.GetValueIn(gate, 2); // 2: acc or this object
556     LowerNamedAccess(gate, receiver, AccessMode::LOAD, key, Circuit::NullGate());
557     DeleteConstDataIfNoUser(constData);
558 }
559 
LowerTypedStObjByName(GateRef gate,bool isThis)560 void TSHCRLowering::LowerTypedStObjByName(GateRef gate, bool isThis)
561 {
562     DISALLOW_GARBAGE_COLLECTION;
563     auto constData = acc_.GetValueIn(gate, 1); // 1: valueIn 1
564     uint16_t keyIndex = acc_.GetConstantValue(constData);
565     JSTaggedValue key = tsManager_->GetStringFromConstantPool(keyIndex);
566 
567     GateRef receiver = Circuit::NullGate();
568     GateRef value = Circuit::NullGate();
569     if (isThis) {
570         // 3: number of value inputs
571         ASSERT(acc_.GetNumValueIn(gate) == 3);
572         receiver = argAcc_.GetFrameArgsIn(gate, FrameArgIdx::THIS_OBJECT);
573         value = acc_.GetValueIn(gate, 2); // 2: acc
574     } else {
575         // 4: number of value inputs
576         ASSERT(acc_.GetNumValueIn(gate) == 4);
577         receiver = acc_.GetValueIn(gate, 2); // 2: receiver
578         value = acc_.GetValueIn(gate, 3); // 3: acc
579     }
580     LowerNamedAccess(gate, receiver, AccessMode::STORE, key, value);
581     DeleteConstDataIfNoUser(constData);
582 }
583 
LowerNamedAccess(GateRef gate,GateRef receiver,AccessMode accessMode,JSTaggedValue key,GateRef value)584 void TSHCRLowering::LowerNamedAccess(GateRef gate, GateRef receiver, AccessMode accessMode, JSTaggedValue key,
585                                      GateRef value)
586 {
587     DISALLOW_GARBAGE_COLLECTION;
588     GateType receiverType = acc_.GetGateType(receiver);
589     receiverType = tsManager_->TryNarrowUnionType(receiverType);
590     if (accessMode == AccessMode::LOAD && TryLowerTypedLdObjByNameForArray(gate, receiverType, key)) {
591         return;
592     }
593 
594     ObjectAccessHelper accessHelper(tsManager_, accessMode, receiver, receiverType, key, value);
595     ChunkVector<ObjectAccessInfo> infos(circuit_->chunk());
596     bool continuation = accessHelper.Compute(infos);
597     if (!continuation) {
598         return;  // slowpath
599     }
600 
601     ASSERT(!infos.empty());
602     AddProfiling(gate);
603 
604     // If all elements of the array are objects, and receiver is one of the elements,
605     // no HeapObjectCheck is required.
606     bool isHeapObject = acc_.IsHeapObjectFromElementsKind(receiver);
607 
608     // monomorphic
609     if (infos.size() == 1) {
610         int hclassIndex = infos[0].HClassIndex();
611         PropertyLookupResult plr = infos[0].Plr();
612         if (!Uncheck()) {
613             GateRef hclassIndexGate = builder_.IntPtr(hclassIndex);
614             builder_.ObjectTypeCheck(infos[0].Type(), isHeapObject, receiver, hclassIndexGate);
615         }
616 
617         GateRef result = BuildNamedPropertyAccess(gate, accessHelper, plr);
618         acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), result);
619         return;
620     }
621 
622     // polymorphic
623     size_t size = infos.size();
624     GateRef fallthroughState = builder_.GetState();
625     GateRef fallthroughDepend = builder_.GetDepend();
626     std::vector<GateRef> values(size + 1, Circuit::NullGate());   // +1: state for value selector
627     std::vector<GateRef> depends(size + 1, Circuit::NullGate());  // +1: state for depend selector
628     std::vector<GateRef> states(size, Circuit::NullGate());
629     for (size_t i = 0; i < size; ++i) {
630         GateType type = infos[i].Type();
631         int hclassIndex = infos[i].HClassIndex();
632         PropertyLookupResult plr = infos[i].Plr();
633         GateRef hclassIndexGate = builder_.IntPtr(hclassIndex);
634 
635         builder_.SetState(fallthroughState);
636         builder_.SetDepend(fallthroughDepend);
637         if (i == size - 1) {
638             builder_.ObjectTypeCheck(type, isHeapObject, receiver, hclassIndexGate);
639             fallthroughState = Circuit::NullGate();
640             fallthroughDepend = Circuit::NullGate();
641         } else {
642             GateRef compare = builder_.ObjectTypeCompare(type, isHeapObject, receiver, hclassIndexGate);
643             GateRef branch = builder_.Branch(builder_.GetState(), compare);
644             GateRef ifTrue = builder_.IfTrue(branch);
645             GateRef ifFalse = builder_.IfFalse(branch);
646             GateRef tDepend = builder_.DependRelay(ifTrue, builder_.GetDepend());
647             fallthroughState = ifFalse;
648             fallthroughDepend = builder_.DependRelay(ifFalse, builder_.GetDepend());
649             builder_.SetState(ifTrue);
650             builder_.SetDepend(tDepend);
651         }
652 
653         values[i + 1] = BuildNamedPropertyAccess(gate, accessHelper, plr);
654         depends[i + 1] = builder_.GetDepend();
655         states[i] = builder_.GetState();
656     }
657     ASSERT(fallthroughState == Circuit::NullGate());
658     ASSERT(fallthroughDepend == Circuit::NullGate());
659     GateRef mergeState = circuit_->NewGate(circuit_->Merge(size), states);
660     depends[0] = mergeState;
661     values[0] = mergeState;
662     GateRef dependSelector = circuit_->NewGate(circuit_->DependSelector(size), depends);
663     GateRef result = accessHelper.IsLoading() ?
664         circuit_->NewGate(circuit_->ValueSelector(size), MachineType::I64, size + 1, values.data(), GateType::AnyType())
665         : Circuit::NullGate();
666     acc_.ReplaceHirAndDeleteIfException(gate, StateDepend(mergeState, dependSelector), result);
667 }
668 
BuildNamedPropertyAccess(GateRef hir,ObjectAccessHelper accessHelper,PropertyLookupResult plr)669 GateRef TSHCRLowering::BuildNamedPropertyAccess(GateRef hir, ObjectAccessHelper accessHelper, PropertyLookupResult plr)
670 {
671     GateRef receiver = accessHelper.GetReceiver();
672     GateRef plrGate = builder_.Int32(plr.GetData());
673     GateRef result = Circuit::NullGate();
674 
675     AccessMode mode = accessHelper.GetAccessMode();
676     switch (mode) {
677         case AccessMode::LOAD: {
678             if (LIKELY(!plr.IsAccessor())) {
679                 result = builder_.LoadProperty(receiver, plrGate, plr.IsFunction());
680                 if (UNLIKELY(IsVerifyVTbale())) {
681                     BuildNamedPropertyAccessVerifier(hir, receiver, mode, result);
682                 }
683             } else {
684                 result = builder_.CallGetter(hir, receiver, plrGate);
685             }
686         }
687             break;
688         case AccessMode::STORE: {
689             GateRef value = accessHelper.GetValue();
690             if (LIKELY(plr.IsLocal())) {
691                 builder_.StoreProperty(receiver, plrGate, value);
692                 if (UNLIKELY(IsVerifyVTbale())) {
693                     BuildNamedPropertyAccessVerifier(hir, receiver, mode, value);
694                 }
695             } else {
696                 builder_.CallSetter(hir, receiver, plrGate, value);
697             }
698         }
699             break;
700         default:
701             break;
702     }
703 
704     return result;
705 }
706 
BuildNamedPropertyAccessVerifier(GateRef gate,GateRef receiver,AccessMode mode,GateRef value)707 void TSHCRLowering::BuildNamedPropertyAccessVerifier(GateRef gate, GateRef receiver, AccessMode mode, GateRef value)
708 {
709     GateRef constData = acc_.GetValueIn(gate, 1);
710     uint16_t keyIndex = acc_.GetConstantValue(constData);
711     GateRef func = argAcc_.GetFrameArgsIn(gate, FrameArgIdx::FUNC);
712     GateRef constPool = builder_.GetConstPool(func);
713     GateRef key =  builder_.GetValueFromTaggedArray(constPool, builder_.Int32(keyIndex));
714     int stubId = mode == AccessMode::LOAD ? RTSTUB_ID(VerifyVTableLoading) : RTSTUB_ID(VerifyVTableStoring);
715     builder_.CallRuntime(glue_, stubId, builder_.GetDepend(), { receiver, key, value }, gate);
716 }
717 
TryLowerTypedLdObjByNameForArray(GateRef gate,GateType receiverType,JSTaggedValue key)718 bool TSHCRLowering::TryLowerTypedLdObjByNameForArray(GateRef gate, GateType receiverType, JSTaggedValue key)
719 {
720     EcmaString *propString = EcmaString::Cast(key.GetTaggedObject());
721     EcmaString *lengthString = EcmaString::Cast(thread_->GlobalConstants()->GetLengthString().GetTaggedObject());
722     if (propString == lengthString) {
723         if (tsManager_->IsArrayTypeKind(receiverType)) {
724             LowerTypedLdArrayLength(gate);
725             return true;
726         } else if (tsManager_->IsValidTypedArrayType(receiverType)) {
727             LowerTypedLdTypedArrayLength(gate);
728             return true;
729         }
730     }
731     return false;
732 }
733 
LowerTypedLdArrayLength(GateRef gate)734 void TSHCRLowering::LowerTypedLdArrayLength(GateRef gate)
735 {
736     AddProfiling(gate);
737     GateRef array = acc_.GetValueIn(gate, 2);
738     if (!Uncheck()) {
739         ElementsKind kind = acc_.TryGetElementsKind(gate);
740         builder_.StableArrayCheck(array, kind, ArrayMetaDataAccessor::Mode::LOAD_LENGTH);
741     }
742 
743     GateRef result = builder_.LoadArrayLength(array);
744     acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), result);
745 }
746 
LowerTypedLdTypedArrayLength(GateRef gate)747 void TSHCRLowering::LowerTypedLdTypedArrayLength(GateRef gate)
748 {
749     AddProfiling(gate);
750     GateRef array = acc_.GetValueIn(gate, 2);
751     GateType arrayType = acc_.GetGateType(array);
752     arrayType = tsManager_->TryNarrowUnionType(arrayType);
753     if (!Uncheck()) {
754         builder_.TypedArrayCheck(arrayType, array);
755     }
756     GateRef result = builder_.LoadTypedArrayLength(arrayType, array);
757     acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), result);
758 }
759 
LowerTypedLdObjByIndex(GateRef gate)760 void TSHCRLowering::LowerTypedLdObjByIndex(GateRef gate)
761 {
762     // 2: number of value inputs
763     ASSERT(acc_.GetNumValueIn(gate) == 2);
764     GateRef receiver = acc_.GetValueIn(gate, 1);
765     GateType receiverType = acc_.GetGateType(receiver);
766     receiverType = tsManager_->TryNarrowUnionType(receiverType);
767     GateRef result = Circuit::NullGate();
768     if (tsManager_->IsValidTypedArrayType(receiverType)) {
769         AddProfiling(gate);
770         GateRef index = acc_.GetValueIn(gate, 0);
771         uint32_t indexValue = static_cast<uint32_t>(acc_.GetConstantValue(index));
772         index = builder_.Int32(indexValue);
773         result = LoadTypedArrayByIndex(receiver, index);
774     } else {
775         return; // slowpath
776     }
777     acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), result);
778 }
779 
LowerTypedStObjByIndex(GateRef gate)780 void TSHCRLowering::LowerTypedStObjByIndex(GateRef gate)
781 {
782     // 3: number of value inputs
783     ASSERT(acc_.GetNumValueIn(gate) == 3);
784     GateRef receiver = acc_.GetValueIn(gate, 0);
785     GateRef value = acc_.GetValueIn(gate, 2);
786     GateType receiverType = acc_.GetGateType(receiver);
787     GateType valueType = acc_.GetGateType(value);
788     receiverType = tsManager_->TryNarrowUnionType(receiverType);
789     if ((!tsManager_->IsBuiltinInstanceType(BuiltinTypeId::FLOAT32_ARRAY, receiverType)) ||
790         (!valueType.IsNumberType())) { // slowpath
791         return;
792     }
793 
794     AddProfiling(gate);
795 
796     if (tsManager_->IsBuiltinInstanceType(BuiltinTypeId::FLOAT32_ARRAY, receiverType)) {
797         if (!Uncheck()) {
798             builder_.TypedArrayCheck(receiverType, receiver);
799         }
800     } else {
801         LOG_ECMA(FATAL) << "this branch is unreachable";
802         UNREACHABLE();
803     }
804     GateRef index = acc_.GetValueIn(gate, 1);
805     uint32_t indexValue = static_cast<uint32_t>(acc_.GetConstantValue(index));
806     index = builder_.Int32(indexValue);
807     auto length = builder_.LoadTypedArrayLength(receiverType, receiver);
808     if (!Uncheck()) {
809         builder_.IndexCheck(receiverType, length, index);
810     }
811 
812     if (tsManager_->IsBuiltinInstanceType(BuiltinTypeId::FLOAT32_ARRAY, receiverType)) {
813         builder_.StoreElement<TypedStoreOp::FLOAT32ARRAY_STORE_ELEMENT>(receiver, index, value);
814     } else {
815         LOG_ECMA(FATAL) << "this branch is unreachable";
816         UNREACHABLE();
817     }
818 
819     acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), Circuit::NullGate());
820 }
821 
LowerTypedLdObjByValue(GateRef gate,bool isThis)822 void TSHCRLowering::LowerTypedLdObjByValue(GateRef gate, bool isThis)
823 {
824     GateRef receiver = Circuit::NullGate();
825     GateRef propKey = Circuit::NullGate();
826     if (isThis) {
827         // 2: number of value inputs
828         ASSERT(acc_.GetNumValueIn(gate) == 2);
829         receiver = argAcc_.GetFrameArgsIn(gate, FrameArgIdx::THIS_OBJECT);
830         propKey = acc_.GetValueIn(gate, 1);
831     } else {
832         // 3: number of value inputs
833         ASSERT(acc_.GetNumValueIn(gate) == 3);
834         receiver = acc_.GetValueIn(gate, 1);
835         propKey = acc_.GetValueIn(gate, 2);  // 2: the third parameter
836     }
837     GateType receiverType = acc_.GetGateType(receiver);
838     GateType propKeyType = acc_.GetGateType(propKey);
839     receiverType = tsManager_->TryNarrowUnionType(receiverType);
840     if (!propKeyType.IsNumberType()) {
841         return; // slowpath
842     }
843 
844     GateRef result = Circuit::NullGate();
845     if (tsManager_->IsArrayTypeKind(receiverType)) {
846         AddProfiling(gate);
847         ElementsKind kind = acc_.TryGetElementsKind(gate);
848         result = LoadJSArrayByIndex(receiver, propKey, kind);
849     } else if (tsManager_->IsValidTypedArrayType(receiverType)) {
850         AddProfiling(gate);
851         result = LoadTypedArrayByIndex(receiver, propKey);
852     } else {
853         return; // slowpath
854     }
855     acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), result);
856 }
857 
LoadJSArrayByIndex(GateRef receiver,GateRef propKey,ElementsKind kind)858 GateRef TSHCRLowering::LoadJSArrayByIndex(GateRef receiver, GateRef propKey, ElementsKind kind)
859 {
860     if (!Uncheck()) {
861         GateType receiverType = acc_.GetGateType(receiver);
862         receiverType = tsManager_->TryNarrowUnionType(receiverType);
863         builder_.StableArrayCheck(receiver, kind, ArrayMetaDataAccessor::Mode::LOAD_ELEMENT);
864         GateRef length = builder_.LoadArrayLength(receiver);
865         propKey = builder_.IndexCheck(receiverType, length, propKey);
866     }
867 
868     GateRef result = Circuit::NullGate();
869     if (Elements::IsInt(kind)) {
870         result = builder_.LoadElement<TypedLoadOp::ARRAY_LOAD_INT_ELEMENT>(receiver, propKey);
871     } else if (Elements::IsDouble(kind)) {
872         result = builder_.LoadElement<TypedLoadOp::ARRAY_LOAD_DOUBLE_ELEMENT>(receiver, propKey);
873     } else if (Elements::IsObject(kind)) {
874         result = builder_.LoadElement<TypedLoadOp::ARRAY_LOAD_OBJECT_ELEMENT>(receiver, propKey);
875     } else if (!Elements::IsHole(kind)) {
876         result = builder_.LoadElement<TypedLoadOp::ARRAY_LOAD_TAGGED_ELEMENT>(receiver, propKey);
877     } else {
878         result = builder_.LoadElement<TypedLoadOp::ARRAY_LOAD_HOLE_TAGGED_ELEMENT>(receiver, propKey);
879     }
880     return result;
881 }
882 
LoadTypedArrayByIndex(GateRef receiver,GateRef propKey)883 GateRef TSHCRLowering::LoadTypedArrayByIndex(GateRef receiver, GateRef propKey)
884 {
885     GateType receiverType = acc_.GetGateType(receiver);
886     receiverType = tsManager_->TryNarrowUnionType(receiverType);
887     if (!Uncheck()) {
888         builder_.TypedArrayCheck(receiverType, receiver);
889         GateRef length = builder_.LoadTypedArrayLength(receiverType, receiver);
890         propKey = builder_.IndexCheck(receiverType, length, propKey);
891     }
892     auto builtinTypeId = tsManager_->GetTypedArrayBuiltinId(receiverType);
893     switch (builtinTypeId) {
894         case BuiltinTypeId::INT8_ARRAY:
895             return builder_.LoadElement<TypedLoadOp::INT8ARRAY_LOAD_ELEMENT>(receiver, propKey);
896         case BuiltinTypeId::UINT8_ARRAY:
897             return builder_.LoadElement<TypedLoadOp::UINT8ARRAY_LOAD_ELEMENT>(receiver, propKey);
898         case BuiltinTypeId::UINT8_CLAMPED_ARRAY:
899             return builder_.LoadElement<TypedLoadOp::UINT8CLAMPEDARRAY_LOAD_ELEMENT>(receiver, propKey);
900         case BuiltinTypeId::INT16_ARRAY:
901             return builder_.LoadElement<TypedLoadOp::INT16ARRAY_LOAD_ELEMENT>(receiver, propKey);
902         case BuiltinTypeId::UINT16_ARRAY:
903             return builder_.LoadElement<TypedLoadOp::UINT16ARRAY_LOAD_ELEMENT>(receiver, propKey);
904         case BuiltinTypeId::INT32_ARRAY:
905             return builder_.LoadElement<TypedLoadOp::INT32ARRAY_LOAD_ELEMENT>(receiver, propKey);
906         case BuiltinTypeId::UINT32_ARRAY:
907             return builder_.LoadElement<TypedLoadOp::UINT32ARRAY_LOAD_ELEMENT>(receiver, propKey);
908         case BuiltinTypeId::FLOAT32_ARRAY:
909             return builder_.LoadElement<TypedLoadOp::FLOAT32ARRAY_LOAD_ELEMENT>(receiver, propKey);
910         case BuiltinTypeId::FLOAT64_ARRAY:
911             return builder_.LoadElement<TypedLoadOp::FLOAT64ARRAY_LOAD_ELEMENT>(receiver, propKey);
912         default:
913             LOG_ECMA(FATAL) << "this branch is unreachable";
914             UNREACHABLE();
915     }
916 
917     return Circuit::NullGate();
918 }
919 
StoreJSArrayByIndex(GateRef receiver,GateRef propKey,GateRef value,ElementsKind kind)920 void TSHCRLowering::StoreJSArrayByIndex(GateRef receiver, GateRef propKey, GateRef value, ElementsKind kind)
921 {
922     if (!Uncheck()) {
923         GateType receiverType = acc_.GetGateType(receiver);
924         receiverType = tsManager_->TryNarrowUnionType(receiverType);
925         builder_.StableArrayCheck(receiver, kind, ArrayMetaDataAccessor::Mode::STORE_ELEMENT);
926         GateRef length = builder_.LoadArrayLength(receiver);
927         builder_.IndexCheck(receiverType, length, propKey);
928         builder_.COWArrayCheck(receiver);
929 
930         if (Elements::IsObject(kind)) {
931             GateRef frameState = acc_.FindNearestFrameState(builder_.GetDepend());
932             builder_.HeapObjectCheck(value, frameState);
933         }
934     }
935     builder_.StoreElement<TypedStoreOp::ARRAY_STORE_ELEMENT>(receiver, propKey, value);
936 }
937 
938 
StoreTypedArrayByIndex(GateRef receiver,GateRef propKey,GateRef value)939 void TSHCRLowering::StoreTypedArrayByIndex(GateRef receiver, GateRef propKey, GateRef value)
940 {
941     GateType receiverType = acc_.GetGateType(receiver);
942     receiverType = tsManager_->TryNarrowUnionType(receiverType);
943     if (!Uncheck()) {
944         builder_.TypedArrayCheck(receiverType, receiver);
945         GateRef length = builder_.LoadTypedArrayLength(receiverType, receiver);
946         propKey = builder_.IndexCheck(receiverType, length, propKey);
947     }
948 
949     auto builtinTypeId = tsManager_->GetTypedArrayBuiltinId(receiverType);
950     switch (builtinTypeId) {
951         case BuiltinTypeId::INT8_ARRAY:
952             builder_.StoreElement<TypedStoreOp::INT8ARRAY_STORE_ELEMENT>(receiver, propKey, value);
953             break;
954         case BuiltinTypeId::UINT8_ARRAY:
955             builder_.StoreElement<TypedStoreOp::UINT8ARRAY_STORE_ELEMENT>(receiver, propKey, value);
956             break;
957         case BuiltinTypeId::UINT8_CLAMPED_ARRAY:
958             builder_.StoreElement<TypedStoreOp::UINT8CLAMPEDARRAY_STORE_ELEMENT>(receiver, propKey, value);
959             break;
960         case BuiltinTypeId::INT16_ARRAY:
961             builder_.StoreElement<TypedStoreOp::INT16ARRAY_STORE_ELEMENT>(receiver, propKey, value);
962             break;
963         case BuiltinTypeId::UINT16_ARRAY:
964             builder_.StoreElement<TypedStoreOp::UINT16ARRAY_STORE_ELEMENT>(receiver, propKey, value);
965             break;
966         case BuiltinTypeId::INT32_ARRAY:
967             builder_.StoreElement<TypedStoreOp::INT32ARRAY_STORE_ELEMENT>(receiver, propKey, value);
968             break;
969         case BuiltinTypeId::UINT32_ARRAY:
970             builder_.StoreElement<TypedStoreOp::UINT32ARRAY_STORE_ELEMENT>(receiver, propKey, value);
971             break;
972         case BuiltinTypeId::FLOAT32_ARRAY:
973             builder_.StoreElement<TypedStoreOp::FLOAT32ARRAY_STORE_ELEMENT>(receiver, propKey, value);
974             break;
975         case BuiltinTypeId::FLOAT64_ARRAY:
976             builder_.StoreElement<TypedStoreOp::FLOAT64ARRAY_STORE_ELEMENT>(receiver, propKey, value);
977             break;
978         default:
979             LOG_ECMA(FATAL) << "this branch is unreachable";
980             UNREACHABLE();
981     }
982 }
983 
LowerTypedStObjByValue(GateRef gate)984 void TSHCRLowering::LowerTypedStObjByValue(GateRef gate)
985 {
986     ASSERT(acc_.GetNumValueIn(gate) == 4);        // 4: num of value ins
987     GateRef receiver = acc_.GetValueIn(gate, 1);  // 1: receiver
988     GateRef propKey = acc_.GetValueIn(gate, 2);   // 2: key
989     GateRef value = acc_.GetValueIn(gate, 3);     // 3: value
990     GateType receiverType = acc_.GetGateType(receiver);
991     GateType propKeyType = acc_.GetGateType(propKey);
992     receiverType = tsManager_->TryNarrowUnionType(receiverType);
993     if (!propKeyType.IsNumberType()) {
994         return; // slowpath
995     }
996 
997     if (tsManager_->IsArrayTypeKind(receiverType)) {
998         AddProfiling(gate);
999         ElementsKind kind = acc_.TryGetElementsKind(gate);
1000         StoreJSArrayByIndex(receiver, propKey, value, kind);
1001     } else if (tsManager_->IsValidTypedArrayType(receiverType)) {
1002         AddProfiling(gate);
1003         StoreTypedArrayByIndex(receiver, propKey, value);
1004     } else {
1005         return;
1006     }
1007 
1008     acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), Circuit::NullGate());
1009 }
1010 
LowerTypedIsTrueOrFalse(GateRef gate,bool flag)1011 void TSHCRLowering::LowerTypedIsTrueOrFalse(GateRef gate, bool flag)
1012 {
1013     ASSERT(acc_.GetNumValueIn(gate) == 1);
1014     auto value = acc_.GetValueIn(gate, 0);
1015     auto valueType = acc_.GetGateType(value);
1016     if ((!valueType.IsNumberType()) && (!valueType.IsBooleanType())) {
1017         return;
1018     }
1019 
1020     AddProfiling(gate);
1021     GateRef result;
1022     if (!flag) {
1023         result = builder_.TypedUnaryOp<TypedUnOp::TYPED_ISFALSE>(value, valueType, GateType::TaggedValue());
1024     } else {
1025         result = builder_.TypedUnaryOp<TypedUnOp::TYPED_ISTRUE>(value, valueType, GateType::TaggedValue());
1026     }
1027 
1028     acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), result);
1029 }
1030 
LowerTypedNewObjRange(GateRef gate)1031 void TSHCRLowering::LowerTypedNewObjRange(GateRef gate)
1032 {
1033     GateRef ctor = acc_.GetValueIn(gate, 0);
1034     GateType ctorType = acc_.GetGateType(ctor);
1035     if (!tsManager_->IsClassTypeKind(ctorType)) {
1036         return;
1037     }
1038 
1039     AddProfiling(gate);
1040 
1041     int hclassIndex = tsManager_->GetHClassIndexByClassGateType(ctorType);
1042     GateRef stateSplit = acc_.GetDep(gate);
1043 
1044     GateRef frameState = acc_.FindNearestFrameState(stateSplit);
1045     GateRef thisObj = builder_.TypedNewAllocateThis(ctor, builder_.IntPtr(hclassIndex), frameState);
1046 
1047     // call constructor
1048     size_t range = acc_.GetNumValueIn(gate);
1049     GateRef actualArgc = builder_.Int64(BytecodeCallArgc::ComputeCallArgc(range, EcmaOpcode::NEWOBJRANGE_IMM8_IMM8_V8));
1050     std::vector<GateRef> args { glue_, actualArgc, ctor, ctor, thisObj };
1051     for (size_t i = 1; i < range; ++i) {  // 1:skip ctor
1052         args.emplace_back(acc_.GetValueIn(gate, i));
1053     }
1054     GateRef constructGate = builder_.Construct(gate, args);
1055     acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), constructGate);
1056 }
1057 
LowerTypedSuperCall(GateRef gate)1058 void TSHCRLowering::LowerTypedSuperCall(GateRef gate)
1059 {
1060     GateRef ctor = argAcc_.GetFrameArgsIn(gate, FrameArgIdx::FUNC);
1061     GateType ctorType = acc_.GetGateType(ctor);  // ldfunction in derived constructor get function type
1062     if (!tsManager_->IsClassTypeKind(ctorType) && !tsManager_->IsFunctionTypeKind(ctorType)) {
1063         return;
1064     }
1065 
1066     AddProfiling(gate);
1067 
1068     // stateSplit maybe not a STATE_SPLIT
1069     GateRef stateSplit = acc_.GetDep(gate);
1070 
1071     GateRef frameState = acc_.FindNearestFrameState(stateSplit);
1072     GateRef superCtor = builder_.GetSuperConstructor(ctor);
1073     GateRef newTarget = argAcc_.GetFrameArgsIn(gate, FrameArgIdx::NEW_TARGET);
1074     GateRef thisObj = builder_.TypedSuperAllocateThis(superCtor, newTarget, frameState);
1075 
1076     // call constructor
1077     size_t range = acc_.GetNumValueIn(gate);
1078     GateRef actualArgc = builder_.Int64(range + 3);  // 3: ctor, newTaget, this
1079     std::vector<GateRef> args { glue_, actualArgc, superCtor, newTarget, thisObj };
1080     for (size_t i = 0; i < range; ++i) {
1081         args.emplace_back(acc_.GetValueIn(gate, i));
1082     }
1083 
1084     GateRef constructGate = builder_.Construct(gate, args);
1085     acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), constructGate);
1086 }
1087 
SpeculateCallBuiltin(GateRef gate,GateRef func,GateRef a0,BuiltinsStubCSigns::ID id)1088 void TSHCRLowering::SpeculateCallBuiltin(GateRef gate, GateRef func, GateRef a0, BuiltinsStubCSigns::ID id)
1089 {
1090     if (!Uncheck()) {
1091         builder_.CallTargetCheck(gate, func, builder_.IntPtr(static_cast<int64_t>(id)), a0);
1092     }
1093     GateRef result = builder_.TypedCallBuiltin(gate, a0, id);
1094 
1095     acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), result);
1096 }
1097 
SpeculateCallThis3Builtin(GateRef gate,BuiltinsStubCSigns::ID id)1098 void TSHCRLowering::SpeculateCallThis3Builtin(GateRef gate, BuiltinsStubCSigns::ID id)
1099 {
1100     GateRef thisObj = acc_.GetValueIn(gate, 0);
1101     GateRef a0 = acc_.GetValueIn(gate, 1);  // 1: the first-para
1102     GateRef a1 = acc_.GetValueIn(gate, 2);  // 2: the third-para
1103     GateRef a2 = acc_.GetValueIn(gate, 3);  // 3: the fourth-para
1104     GateRef result = builder_.TypedCallThis3Builtin(gate, thisObj, a0, a1, a2, id);
1105 
1106     acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), result);
1107 }
1108 
GetBuiltinId(BuiltinTypeId id,GateRef func)1109 BuiltinsStubCSigns::ID TSHCRLowering::GetBuiltinId(BuiltinTypeId id, GateRef func)
1110 {
1111     GateType funcType = acc_.GetGateType(func);
1112     if (!tsManager_->IsBuiltinObjectMethod(id, funcType)) {
1113         return BuiltinsStubCSigns::ID::NONE;
1114     }
1115     std::string name = tsManager_->GetFuncName(funcType);
1116     BuiltinsStubCSigns::ID stubId = BuiltinsStubCSigns::GetBuiltinId(name);
1117     return stubId;
1118 }
1119 
CheckCallTargetFromDefineFuncAndLowerCall(GateRef gate,GateRef func,GlobalTSTypeRef funcGt,GateType funcType,const std::vector<GateRef> & args,const std::vector<GateRef> & argsFastCall,bool isNoGC)1120 void TSHCRLowering::CheckCallTargetFromDefineFuncAndLowerCall(GateRef gate, GateRef func, GlobalTSTypeRef funcGt,
1121     GateType funcType, const std::vector<GateRef> &args, const std::vector<GateRef> &argsFastCall, bool isNoGC)
1122 {
1123     if (!Uncheck()) {
1124         builder_.JSCallTargetFromDefineFuncCheck(funcType, func, gate);
1125     }
1126     if (tsManager_->CanFastCall(funcGt)) {
1127         LowerFastCall(gate, func, argsFastCall, isNoGC);
1128     } else {
1129         LowerCall(gate, func, args, isNoGC);
1130     }
1131 }
1132 
LowerFastCall(GateRef gate,GateRef func,const std::vector<GateRef> & argsFastCall,bool isNoGC)1133 void TSHCRLowering::LowerFastCall(GateRef gate, GateRef func,
1134     const std::vector<GateRef> &argsFastCall, bool isNoGC)
1135 {
1136     builder_.StartCallTimer(glue_, gate, {glue_, func, builder_.True()}, true);
1137     GateRef result = builder_.TypedFastCall(gate, argsFastCall, isNoGC);
1138     builder_.EndCallTimer(glue_, gate, {glue_, func}, true);
1139     acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), result);
1140 }
1141 
LowerCall(GateRef gate,GateRef func,const std::vector<GateRef> & args,bool isNoGC)1142 void TSHCRLowering::LowerCall(GateRef gate, GateRef func,
1143     const std::vector<GateRef> &args, bool isNoGC)
1144 {
1145     builder_.StartCallTimer(glue_, gate, {glue_, func, builder_.True()}, true);
1146     GateRef result = builder_.TypedCall(gate, args, isNoGC);
1147     builder_.EndCallTimer(glue_, gate, {glue_, func}, true);
1148     acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), result);
1149 }
1150 
CheckCallTargetAndLowerCall(GateRef gate,GateRef func,GlobalTSTypeRef funcGt,GateType funcType,const std::vector<GateRef> & args,const std::vector<GateRef> & argsFastCall)1151 void TSHCRLowering::CheckCallTargetAndLowerCall(GateRef gate, GateRef func, GlobalTSTypeRef funcGt,
1152     GateType funcType, const std::vector<GateRef> &args, const std::vector<GateRef> &argsFastCall)
1153 {
1154     if (IsLoadVtable(func)) {
1155         CheckThisCallTargetAndLowerCall(gate, func, funcGt, funcType, args, argsFastCall); // func = a.foo, func()
1156     } else {
1157         bool isNoGC = tsManager_->IsNoGC(funcGt);
1158         auto op = acc_.GetOpCode(func);
1159         if (!tsManager_->FastCallFlagIsVaild(funcGt)) {
1160             return;
1161         }
1162         if (op == OpCode::JS_BYTECODE && (acc_.GetByteCodeOpcode(func) == EcmaOpcode::DEFINEFUNC_IMM8_ID16_IMM8 ||
1163                                           acc_.GetByteCodeOpcode(func) == EcmaOpcode::DEFINEFUNC_IMM16_ID16_IMM8)) {
1164             CheckCallTargetFromDefineFuncAndLowerCall(gate, func, funcGt, funcType, args, argsFastCall, isNoGC);
1165             return;
1166         }
1167         int methodIndex = tsManager_->GetMethodIndex(funcGt);
1168         if (!tsManager_->MethodOffsetIsVaild(funcGt) || methodIndex == -1) {
1169             return;
1170         }
1171         if (tsManager_->CanFastCall(funcGt)) {
1172             if (!Uncheck()) {
1173                 builder_.JSCallTargetTypeCheck<TypedCallTargetCheckOp::JSCALL_FAST>(funcType,
1174                     func, builder_.IntPtr(methodIndex), gate);
1175             }
1176             LowerFastCall(gate, func, argsFastCall, isNoGC);
1177         } else {
1178             if (!Uncheck()) {
1179                 builder_.JSCallTargetTypeCheck<TypedCallTargetCheckOp::JSCALL>(funcType,
1180                     func, builder_.IntPtr(methodIndex), gate);
1181             }
1182             LowerCall(gate, func, args, isNoGC);
1183         }
1184     }
1185 }
1186 
LowerTypedCallArg0(GateRef gate)1187 void TSHCRLowering::LowerTypedCallArg0(GateRef gate)
1188 {
1189     GateRef func = acc_.GetValueIn(gate, 0);
1190     GateType funcType = acc_.GetGateType(func);
1191     if (!tsManager_->IsFunctionTypeKind(funcType)) {
1192         return;
1193     }
1194     GateRef actualArgc = builder_.Int64(BytecodeCallArgc::ComputeCallArgc(acc_.GetNumValueIn(gate),
1195         EcmaOpcode::CALLARG0_IMM8));
1196     LowerTypedCall(gate, func, actualArgc, funcType, 0);
1197 }
1198 
LowerTypedCallArg1(GateRef gate)1199 void TSHCRLowering::LowerTypedCallArg1(GateRef gate)
1200 {
1201     GateRef func = acc_.GetValueIn(gate, 1);
1202     GateType funcType = acc_.GetGateType(func);
1203     if (!tsManager_->IsFunctionTypeKind(funcType)) {
1204         return;
1205     }
1206     GateRef a0Value = acc_.GetValueIn(gate, 0);
1207     GateType a0Type = acc_.GetGateType(a0Value);
1208     BuiltinsStubCSigns::ID id = GetBuiltinId(BuiltinTypeId::MATH, func);
1209     if (id != BuiltinsStubCSigns::ID::NONE && a0Type.IsNumberType()) {
1210         AddProfiling(gate);
1211         SpeculateCallBuiltin(gate, func, a0Value, id);
1212     } else {
1213         GateRef actualArgc = builder_.Int64(BytecodeCallArgc::ComputeCallArgc(acc_.GetNumValueIn(gate),
1214             EcmaOpcode::CALLARG1_IMM8_V8));
1215         LowerTypedCall(gate, func, actualArgc, funcType, 1);
1216     }
1217 }
1218 
LowerTypedCallArg2(GateRef gate)1219 void TSHCRLowering::LowerTypedCallArg2(GateRef gate)
1220 {
1221     GateRef func = acc_.GetValueIn(gate, 2); // 2:function
1222     GateType funcType = acc_.GetGateType(func);
1223     if (!tsManager_->IsFunctionTypeKind(funcType)) {
1224         return;
1225     }
1226     GateRef actualArgc = builder_.Int64(BytecodeCallArgc::ComputeCallArgc(acc_.GetNumValueIn(gate),
1227         EcmaOpcode::CALLARGS2_IMM8_V8_V8));
1228     LowerTypedCall(gate, func, actualArgc, funcType, 2); // 2: 2 params
1229 }
1230 
LowerTypedCallArg3(GateRef gate)1231 void TSHCRLowering::LowerTypedCallArg3(GateRef gate)
1232 {
1233     GateRef func = acc_.GetValueIn(gate, 3); // 3:function
1234     GateType funcType = acc_.GetGateType(func);
1235     if (!tsManager_->IsFunctionTypeKind(funcType)) {
1236         return;
1237     }
1238     GateRef actualArgc = builder_.Int64(BytecodeCallArgc::ComputeCallArgc(acc_.GetNumValueIn(gate),
1239         EcmaOpcode::CALLARGS3_IMM8_V8_V8_V8));
1240     LowerTypedCall(gate, func, actualArgc, funcType, 3); // 3: 3 params
1241 }
1242 
LowerTypedCallrange(GateRef gate)1243 void TSHCRLowering::LowerTypedCallrange(GateRef gate)
1244 {
1245     std::vector<GateRef> vec;
1246     std::vector<GateRef> vec1;
1247     size_t numArgs = acc_.GetNumValueIn(gate);
1248     GateRef actualArgc = builder_.Int64(BytecodeCallArgc::ComputeCallArgc(acc_.GetNumValueIn(gate),
1249         EcmaOpcode::CALLRANGE_IMM8_IMM8_V8));
1250     const size_t callTargetIndex = 1; // acc
1251     size_t argc = numArgs - callTargetIndex;
1252     GateRef func = acc_.GetValueIn(gate, argc);
1253     GateType funcType = acc_.GetGateType(func);
1254     if (!tsManager_->IsFunctionTypeKind(funcType)) {
1255         return;
1256     }
1257     LowerTypedCall(gate, func, actualArgc, funcType, argc);
1258 }
1259 
LowerTypedCall(GateRef gate,GateRef func,GateRef actualArgc,GateType funcType,uint32_t argc)1260 void TSHCRLowering::LowerTypedCall(GateRef gate, GateRef func, GateRef actualArgc, GateType funcType, uint32_t argc)
1261 {
1262     GlobalTSTypeRef funcGt = funcType.GetGTRef();
1263     uint32_t len = tsManager_->GetFunctionTypeLength(funcGt);
1264     GateRef newTarget = builder_.Undefined();
1265     GateRef thisObj = builder_.Undefined();
1266     std::vector<GateRef> argsFastCall { glue_, func, thisObj};
1267     std::vector<GateRef> args { glue_, actualArgc, func, newTarget, thisObj };
1268     for (uint32_t i = 0; i < argc; i++) {
1269         GateRef value = acc_.GetValueIn(gate, i);
1270         argsFastCall.emplace_back(value);
1271         args.emplace_back(value);
1272     }
1273     for (uint32_t i = argc; i < len; i++) {
1274         argsFastCall.emplace_back(builder_.Undefined());
1275         args.emplace_back(builder_.Undefined());
1276     }
1277     CheckCallTargetAndLowerCall(gate, func, funcGt, funcType, args, argsFastCall);
1278 }
1279 
IsLoadVtable(GateRef func)1280 bool TSHCRLowering::IsLoadVtable(GateRef func)
1281 {
1282     auto op = acc_.GetOpCode(func);
1283     if (op != OpCode::LOAD_PROPERTY || !acc_.IsVtable(func)) {
1284         return false;
1285     }
1286     return true;
1287 }
1288 
CanOptimizeAsFastCall(GateRef func)1289 bool TSHCRLowering::CanOptimizeAsFastCall(GateRef func)
1290 {
1291     GateType funcType = acc_.GetGateType(func);
1292     if (!tsManager_->IsFunctionTypeKind(funcType)) {
1293         return false;
1294     }
1295     auto op = acc_.GetOpCode(func);
1296     if (op != OpCode::LOAD_PROPERTY || !acc_.IsVtable(func)) {
1297         return false;
1298     }
1299     return true;
1300 }
1301 
CheckFastCallThisCallTarget(GateRef gate,GateRef func,GlobalTSTypeRef funcGt,GateType funcType,bool isNoGC)1302 void TSHCRLowering::CheckFastCallThisCallTarget(GateRef gate, GateRef func, GlobalTSTypeRef funcGt,
1303                                                 GateType funcType, bool isNoGC)
1304 {
1305     if (noCheck_) {
1306         return;
1307     }
1308     if (isNoGC) {
1309         auto methodOffset = tsManager_->GetFuncMethodOffset(funcGt);
1310         builder_.JSNoGCCallThisTargetTypeCheck<TypedCallTargetCheckOp::JSCALLTHIS_FAST_NOGC>(funcType,
1311             func, builder_.IntPtr(methodOffset), gate);
1312     } else {
1313         builder_.JSCallThisTargetTypeCheck<TypedCallTargetCheckOp::JSCALLTHIS_FAST>(funcType,
1314             func, gate);
1315     }
1316 }
1317 
CheckCallThisCallTarget(GateRef gate,GateRef func,GlobalTSTypeRef funcGt,GateType funcType,bool isNoGC)1318 void TSHCRLowering::CheckCallThisCallTarget(GateRef gate, GateRef func, GlobalTSTypeRef funcGt,
1319     GateType funcType, bool isNoGC)
1320 {
1321     if (noCheck_) {
1322         return;
1323     }
1324     if (isNoGC) {
1325         auto methodOffset = tsManager_->GetFuncMethodOffset(funcGt);
1326         builder_.JSNoGCCallThisTargetTypeCheck<TypedCallTargetCheckOp::JSCALLTHIS_NOGC>(funcType,
1327             func, builder_.IntPtr(methodOffset), gate);
1328     } else {
1329         builder_.JSCallThisTargetTypeCheck<TypedCallTargetCheckOp::JSCALLTHIS>(funcType,
1330             func, gate);
1331     }
1332 }
1333 
CheckThisCallTargetAndLowerCall(GateRef gate,GateRef func,GlobalTSTypeRef funcGt,GateType funcType,const std::vector<GateRef> & args,const std::vector<GateRef> & argsFastCall)1334 void TSHCRLowering::CheckThisCallTargetAndLowerCall(GateRef gate, GateRef func, GlobalTSTypeRef funcGt,
1335     GateType funcType, const std::vector<GateRef> &args, const std::vector<GateRef> &argsFastCall)
1336 {
1337     if (!tsManager_->FastCallFlagIsVaild(funcGt)) {
1338         return;
1339     }
1340     bool isNoGC = tsManager_->IsNoGC(funcGt);
1341     if (tsManager_->CanFastCall(funcGt)) {
1342         CheckFastCallThisCallTarget(gate, func, funcGt, funcType, isNoGC);
1343         LowerFastCall(gate, func, argsFastCall, isNoGC);
1344     } else {
1345         CheckCallThisCallTarget(gate, func, funcGt, funcType, isNoGC);
1346         LowerCall(gate, func, args, isNoGC);
1347     }
1348 }
1349 
LowerTypedCallthis0(GateRef gate)1350 void TSHCRLowering::LowerTypedCallthis0(GateRef gate)
1351 {
1352     // 2: number of value inputs
1353     ASSERT(acc_.GetNumValueIn(gate) == 2);
1354     GateRef func = acc_.GetValueIn(gate, 1);
1355     if (!CanOptimizeAsFastCall(func)) {
1356         return;
1357     }
1358     GateRef actualArgc = builder_.Int64(BytecodeCallArgc::ComputeCallArgc(acc_.GetNumValueIn(gate),
1359         EcmaOpcode::CALLTHIS0_IMM8_V8));
1360     LowerTypedThisCall(gate, func, actualArgc, 0);
1361 }
1362 
LowerTypedCallthis1(GateRef gate)1363 void TSHCRLowering::LowerTypedCallthis1(GateRef gate)
1364 {
1365     // 3: number of value inputs
1366     ASSERT(acc_.GetNumValueIn(gate) == 3);
1367     GateRef a0 = acc_.GetValueIn(gate, 1); // 1:parameter index
1368     GateType a0Type = acc_.GetGateType(a0);
1369     GateRef func = acc_.GetValueIn(gate, 2); // 2:function
1370     BuiltinsStubCSigns::ID id = GetBuiltinId(BuiltinTypeId::MATH, func);
1371     if (id != BuiltinsStubCSigns::ID::NONE && a0Type.IsNumberType()) {
1372         AddProfiling(gate);
1373         SpeculateCallBuiltin(gate, func, a0, id);
1374     } else {
1375         if (!CanOptimizeAsFastCall(func)) {
1376             return;
1377         }
1378         GateRef actualArgc = builder_.Int64(BytecodeCallArgc::ComputeCallArgc(acc_.GetNumValueIn(gate),
1379             EcmaOpcode::CALLTHIS1_IMM8_V8_V8));
1380         LowerTypedThisCall(gate, func, actualArgc, 1);
1381     }
1382 }
1383 
LowerTypedCallthis2(GateRef gate)1384 void TSHCRLowering::LowerTypedCallthis2(GateRef gate)
1385 {
1386     // 4: number of value inputs
1387     ASSERT(acc_.GetNumValueIn(gate) == 4);
1388     GateRef func = acc_.GetValueIn(gate, 3);  // 3: func
1389     if (!CanOptimizeAsFastCall(func)) {
1390         return;
1391     }
1392     GateRef actualArgc = builder_.Int64(BytecodeCallArgc::ComputeCallArgc(acc_.GetNumValueIn(gate),
1393         EcmaOpcode::CALLTHIS2_IMM8_V8_V8_V8));
1394     LowerTypedThisCall(gate, func, actualArgc, 2); // 2: 2 params
1395 }
1396 
LowerTypedCallthis3(GateRef gate)1397 void TSHCRLowering::LowerTypedCallthis3(GateRef gate)
1398 {
1399     // 5: number of value inputs
1400     ASSERT(acc_.GetNumValueIn(gate) == 5);
1401     GateRef func = acc_.GetValueIn(gate, 4); // 4: func
1402     BuiltinsStubCSigns::ID id = GetBuiltinId(BuiltinTypeId::STRING, func);
1403     if (id == BuiltinsStubCSigns::ID::LocaleCompare) {
1404         AddProfiling(gate);
1405         SpeculateCallThis3Builtin(gate, id);
1406         return;
1407     }
1408 
1409     if (!CanOptimizeAsFastCall(func)) {
1410         return;
1411     }
1412     GateRef actualArgc = builder_.Int64(BytecodeCallArgc::ComputeCallArgc(acc_.GetNumValueIn(gate),
1413         EcmaOpcode::CALLTHIS3_IMM8_V8_V8_V8_V8));
1414     LowerTypedThisCall(gate, func, actualArgc, 3); // 3: 3 params
1415 }
1416 
LowerTypedThisCall(GateRef gate,GateRef func,GateRef actualArgc,uint32_t argc)1417 void TSHCRLowering::LowerTypedThisCall(GateRef gate, GateRef func, GateRef actualArgc, uint32_t argc)
1418 {
1419     GateType funcType = acc_.GetGateType(func);
1420     GlobalTSTypeRef funcGt = funcType.GetGTRef();
1421     uint32_t len = tsManager_->GetFunctionTypeLength(funcGt);
1422     GateRef newTarget = builder_.Undefined();
1423     GateRef thisObj = acc_.GetValueIn(gate, 0);
1424     std::vector<GateRef> argsFastCall { glue_, func, thisObj};
1425     std::vector<GateRef> args { glue_, actualArgc, func, newTarget, thisObj };
1426     for (uint32_t i = 0; i < argc; i++) {
1427         GateRef value = acc_.GetValueIn(gate, i + 1);
1428         argsFastCall.emplace_back(value);
1429         args.emplace_back(value);
1430     }
1431     for (uint32_t i = argc; i < len; i++) {
1432         argsFastCall.emplace_back(builder_.Undefined());
1433         args.emplace_back(builder_.Undefined());
1434     }
1435     CheckThisCallTargetAndLowerCall(gate, func, funcGt, funcType, args, argsFastCall);
1436 }
1437 
1438 
LowerTypedCallthisrange(GateRef gate)1439 void TSHCRLowering::LowerTypedCallthisrange(GateRef gate)
1440 {
1441     // this
1442     size_t fixedInputsNum = 1;
1443     ASSERT(acc_.GetNumValueIn(gate) - fixedInputsNum >= 0);
1444     size_t numIns = acc_.GetNumValueIn(gate);
1445     GateRef actualArgc = builder_.Int64(BytecodeCallArgc::ComputeCallArgc(acc_.GetNumValueIn(gate),
1446         EcmaOpcode::CALLTHISRANGE_IMM8_IMM8_V8));
1447     const size_t callTargetIndex = 1;  // 1: acc
1448     GateRef func = acc_.GetValueIn(gate, numIns - callTargetIndex); // acc
1449     if (!CanOptimizeAsFastCall(func)) {
1450         return;
1451     }
1452     LowerTypedThisCall(gate, func, actualArgc, numIns - callTargetIndex - fixedInputsNum);
1453 }
1454 
AddProfiling(GateRef gate)1455 void TSHCRLowering::AddProfiling(GateRef gate)
1456 {
1457     hitTypedOpCount_++;
1458     AddHitBytecodeCount();
1459     if (IsTraceBC()) {
1460         // see stateSplit as a part of JSByteCode if exists
1461         GateRef maybeStateSplit = acc_.GetDep(gate);
1462         GateRef current = Circuit::NullGate();
1463         if (acc_.GetOpCode(maybeStateSplit) == OpCode::STATE_SPLIT) {
1464             current = maybeStateSplit;
1465         } else {
1466             current = gate;
1467         }
1468 
1469         EcmaOpcode ecmaOpcode = acc_.GetByteCodeOpcode(gate);
1470         auto ecmaOpcodeGate = builder_.Int32(static_cast<uint32_t>(ecmaOpcode));
1471         GateRef constOpcode = builder_.Int32ToTaggedInt(ecmaOpcodeGate);
1472         GateRef typedPath = builder_.Int32ToTaggedInt(builder_.Int32(1));
1473         GateRef traceGate = builder_.CallRuntime(glue_, RTSTUB_ID(DebugAOTPrint), acc_.GetDep(current),
1474                                                  { constOpcode, typedPath }, gate);
1475         acc_.SetDep(current, traceGate);
1476         builder_.SetDepend(acc_.GetDep(gate));  // set gate depend: trace or STATE_SPLIT
1477     }
1478 
1479     if (IsProfiling()) {
1480         // see stateSplit as a part of JSByteCode if exists
1481         GateRef maybeStateSplit = acc_.GetDep(gate);
1482         GateRef current = Circuit::NullGate();
1483         if (acc_.GetOpCode(maybeStateSplit) == OpCode::STATE_SPLIT) {
1484             current = maybeStateSplit;
1485         } else {
1486             current = gate;
1487         }
1488 
1489         EcmaOpcode ecmaOpcode = acc_.GetByteCodeOpcode(gate);
1490         auto ecmaOpcodeGate = builder_.Int32(static_cast<uint32_t>(ecmaOpcode));
1491         GateRef constOpcode = builder_.Int32ToTaggedInt(ecmaOpcodeGate);
1492         GateRef mode =
1493             builder_.Int32ToTaggedInt(builder_.Int32(static_cast<int32_t>(OptCodeProfiler::Mode::TYPED_PATH)));
1494         GateRef profiling = builder_.CallRuntime(glue_, RTSTUB_ID(ProfileOptimizedCode), acc_.GetDep(current),
1495                                                  { constOpcode, mode }, gate);
1496         acc_.SetDep(current, profiling);
1497         builder_.SetDepend(acc_.GetDep(gate));  // set gate depend: profiling or STATE_SPLIT
1498     }
1499 }
1500 
AddBytecodeCount(EcmaOpcode op)1501 void TSHCRLowering::AddBytecodeCount(EcmaOpcode op)
1502 {
1503     currentOp_ = op;
1504     if (bytecodeMap_.find(op) != bytecodeMap_.end()) {
1505         bytecodeMap_[op]++;
1506     } else {
1507         bytecodeMap_[op] = 1;
1508     }
1509 }
1510 
DeleteBytecodeCount(EcmaOpcode op)1511 void TSHCRLowering::DeleteBytecodeCount(EcmaOpcode op)
1512 {
1513     bytecodeMap_.erase(op);
1514 }
1515 
AddHitBytecodeCount()1516 void TSHCRLowering::AddHitBytecodeCount()
1517 {
1518     if (bytecodeHitTimeMap_.find(currentOp_) != bytecodeHitTimeMap_.end()) {
1519         bytecodeHitTimeMap_[currentOp_]++;
1520     } else {
1521         bytecodeHitTimeMap_[currentOp_] = 1;
1522     }
1523 }
1524 }  // namespace panda::ecmascript
1525