• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022-2024 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 
17 #include "ecmascript/compiler/typed_bytecode_lowering.h"
18 
19 #include "ecmascript/compiler/circuit_builder_helper.h"
20 #include "ecmascript/compiler/variable_type.h"
21 #include "ecmascript/dfx/vmstat/opt_code_profiler.h"
22 #include "ecmascript/jit/jit.h"
23 #include "ecmascript/js_object-inl.h"
24 #include "ecmascript/js_tagged_value.h"
25 #include "ecmascript/js_tagged_value_internals.h"
26 
27 namespace panda::ecmascript::kungfu {
RunTypedBytecodeLowering()28 void TypedBytecodeLowering::RunTypedBytecodeLowering()
29 {
30     std::vector<GateRef> gateList;
31     circuit_->GetAllGates(gateList);
32     ParseOptBytecodeRange();
33     for (const auto &gate : gateList) {
34         auto op = acc_.GetOpCode(gate);
35         if (op == OpCode::JS_BYTECODE) {
36             Lower(gate);
37         }
38     }
39 
40     if (IsTypeLogEnabled()) {
41         pgoTypeLog_.PrintPGOTypeLog();
42     }
43 
44     if (IsLogEnabled()) {
45         LOG_COMPILER(INFO) << "";
46         LOG_COMPILER(INFO) << "\033[34m"
47                            << "===================="
48                            << " After TypedBytecodeLowering "
49                            << "[" << GetMethodName() << "]"
50                            << "===================="
51                            << "\033[0m";
52         for (auto a : bytecodeMap_) {
53             if (bytecodeHitTimeMap_.find(a.first) != bytecodeHitTimeMap_.end()) {
54                 double rate = static_cast<double>(bytecodeHitTimeMap_[a.first]) / static_cast<double>(a.second);
55                 LOG_COMPILER(INFO) << "\033[34m" << " =========================== End opHitRate: "
56                                    << GetEcmaOpcodeStr(a.first) << " rate: " << std::to_string(rate)
57                                    << "(" << std::to_string(bytecodeHitTimeMap_[a.first])
58                                    << " / " << std::to_string(a.second) << ")"
59                                    << " ===========================" << "\033[0m";
60             } else {
61                 LOG_COMPILER(INFO) << "\033[34m" << " =========================== End opHitRate: "
62                                    << GetEcmaOpcodeStr(a.first) << " rate: " << std::to_string(0)
63                                    << "(" << std::to_string(0)
64                                    << " / " << std::to_string(a.second) << ")"
65                                    << " ===========================" << "\033[0m";
66             }
67         }
68     }
69 }
70 
ParseOptBytecodeRange()71 void TypedBytecodeLowering::ParseOptBytecodeRange()
72 {
73     std::vector<std::string> splitStrs = base::StringHelper::SplitString(optBCRange_, ",");
74     for (const auto &optBCRange : splitStrs) {
75         std::vector<std::string> splitRange = base::StringHelper::SplitString(optBCRange, ":");
76         // 2:Used to determine whether the size of the split string array splitRange is as expected.
77         if (splitRange.size() == 2) {
78             std::vector<int32_t> range;
79             std::string start = splitRange[0];
80             std::string end = splitRange[1];
81             uint32_t startNumber = std::strtoull(start.c_str(), nullptr, 10);
82             uint32_t endNumber = std::strtoull(end.c_str(), nullptr, 10);
83             range.push_back(static_cast<int32_t>(startNumber));
84             range.push_back(static_cast<int32_t>(endNumber));
85             optBCRangeList_.push_back(range);
86         }
87     }
88 }
89 
CheckIsInOptBCIgnoreRange(int32_t index,EcmaOpcode ecmaOpcode)90 bool TypedBytecodeLowering::CheckIsInOptBCIgnoreRange(int32_t index, EcmaOpcode ecmaOpcode)
91 {
92     for (std::vector<int32_t> range : optBCRangeList_) {
93         if (index >= range[0] && index <= range[1]) {
94             LOG_COMPILER(INFO) << "TypedBytecodeLowering ignore opcode:" << GetEcmaOpcodeStr(ecmaOpcode);
95             return true;
96         }
97     }
98     return false;
99 }
100 
Lower(GateRef gate)101 void TypedBytecodeLowering::Lower(GateRef gate)
102 {
103     [[maybe_unused]] auto scopedGate = circuit_->VisitGateBegin(gate);
104     // not all opcode will visit heap, but now jit lock all opcode
105     Jit::JitLockHolder lock(compilationEnv_, "TypedBytecodeLowering::Lower");
106 
107     EcmaOpcode ecmaOpcode = acc_.GetByteCodeOpcode(gate);
108     // initialize label manager
109     Environment env(gate, circuit_, &builder_);
110     AddBytecodeCount(ecmaOpcode);
111     // The order in the switch is referred to in ecmascript/compiler/ecma_opcode_des.h
112     int32_t index = GetEcmaOpCodeListIndex(ecmaOpcode);
113     if (optBCRangeList_.size() > 0 && CheckIsInOptBCIgnoreRange(index, ecmaOpcode)) {
114         DeleteBytecodeCount(ecmaOpcode);
115         allNonTypedOpCount_++;
116         return;
117     }
118     switch (ecmaOpcode) {
119         case EcmaOpcode::GETITERATOR_IMM8:
120         case EcmaOpcode::GETITERATOR_IMM16:
121             LowerGetIterator(gate);
122             break;
123         case EcmaOpcode::CREATEEMPTYOBJECT:
124             LowerCreateEmptyObject(gate);
125             break;
126         case EcmaOpcode::CREATEOBJECTWITHBUFFER_IMM8_ID16:
127         case EcmaOpcode::CREATEOBJECTWITHBUFFER_IMM16_ID16:
128             LowerCreateObjectWithBuffer(gate);
129             break;
130         case EcmaOpcode::ADD2_IMM8_V8:
131             LowerTypedBinOp<TypedBinOp::TYPED_ADD>(gate);
132             break;
133         case EcmaOpcode::SUB2_IMM8_V8:
134             LowerTypedBinOp<TypedBinOp::TYPED_SUB>(gate);
135             break;
136         case EcmaOpcode::MUL2_IMM8_V8:
137             LowerTypedBinOp<TypedBinOp::TYPED_MUL>(gate);
138             break;
139         case EcmaOpcode::DIV2_IMM8_V8:
140             LowerTypedBinOp<TypedBinOp::TYPED_DIV>(gate);
141             break;
142         case EcmaOpcode::MOD2_IMM8_V8:
143             LowerTypedBinOp<TypedBinOp::TYPED_MOD>(gate);
144             break;
145         case EcmaOpcode::EQ_IMM8_V8:
146             LowerTypedEqOrNotEq<TypedBinOp::TYPED_EQ>(gate);
147             break;
148         case EcmaOpcode::NOTEQ_IMM8_V8:
149             LowerTypedEqOrNotEq<TypedBinOp::TYPED_NOTEQ>(gate);
150             break;
151         case EcmaOpcode::LESS_IMM8_V8:
152             LowerTypedBinOp<TypedBinOp::TYPED_LESS>(gate);
153             break;
154         case EcmaOpcode::LESSEQ_IMM8_V8:
155             LowerTypedBinOp<TypedBinOp::TYPED_LESSEQ>(gate);
156             break;
157         case EcmaOpcode::GREATER_IMM8_V8:
158             LowerTypedBinOp<TypedBinOp::TYPED_GREATER>(gate);
159             break;
160         case EcmaOpcode::GREATEREQ_IMM8_V8:
161             LowerTypedBinOp<TypedBinOp::TYPED_GREATEREQ>(gate);
162             break;
163         case EcmaOpcode::SHL2_IMM8_V8:
164             LowerTypedBinOp<TypedBinOp::TYPED_SHL>(gate);
165             break;
166         case EcmaOpcode::SHR2_IMM8_V8:
167             LowerTypedBinOp<TypedBinOp::TYPED_SHR>(gate);
168             break;
169         case EcmaOpcode::ASHR2_IMM8_V8:
170             LowerTypedBinOp<TypedBinOp::TYPED_ASHR>(gate);
171             break;
172         case EcmaOpcode::AND2_IMM8_V8:
173             LowerTypedBinOp<TypedBinOp::TYPED_AND>(gate);
174             break;
175         case EcmaOpcode::OR2_IMM8_V8:
176             LowerTypedBinOp<TypedBinOp::TYPED_OR>(gate);
177             break;
178         case EcmaOpcode::XOR2_IMM8_V8:
179             LowerTypedBinOp<TypedBinOp::TYPED_XOR>(gate);
180             break;
181         case EcmaOpcode::TYPEOF_IMM8:
182         case EcmaOpcode::TYPEOF_IMM16:
183             LowerTypedTypeOf(gate);
184             break;
185         case EcmaOpcode::TONUMERIC_IMM8:
186             LowerTypeToNumeric(gate);
187             break;
188         case EcmaOpcode::NEG_IMM8:
189             LowerTypedUnOp<TypedUnOp::TYPED_NEG>(gate);
190             break;
191         case EcmaOpcode::NOT_IMM8:
192             LowerTypedUnOp<TypedUnOp::TYPED_NOT>(gate);
193             break;
194         case EcmaOpcode::INC_IMM8:
195             LowerTypedUnOp<TypedUnOp::TYPED_INC>(gate);
196             break;
197         case EcmaOpcode::DEC_IMM8:
198             LowerTypedUnOp<TypedUnOp::TYPED_DEC>(gate);
199             break;
200         case EcmaOpcode::INSTANCEOF_IMM8_V8:
201             LowerInstanceOf(gate);
202             break;
203         case EcmaOpcode::STRICTNOTEQ_IMM8_V8:
204             LowerTypedEqOrNotEq<TypedBinOp::TYPED_STRICTNOTEQ>(gate);
205             break;
206         case EcmaOpcode::STRICTEQ_IMM8_V8:
207             LowerTypedEqOrNotEq<TypedBinOp::TYPED_STRICTEQ>(gate);
208             break;
209         case EcmaOpcode::ISTRUE:
210         case EcmaOpcode::CALLRUNTIME_ISTRUE_PREF_IMM8:
211             LowerTypedIsTrueOrFalse(gate, true);
212             break;
213         case EcmaOpcode::ISFALSE:
214         case EcmaOpcode::CALLRUNTIME_ISFALSE_PREF_IMM8:
215             LowerTypedIsTrueOrFalse(gate, false);
216             break;
217         case EcmaOpcode::CALLARG0_IMM8:
218             LowerTypedCallArg0(gate);
219             break;
220         case EcmaOpcode::CALLARG1_IMM8_V8:
221             LowerTypedCallArg1(gate);
222             break;
223         case EcmaOpcode::CALLARGS2_IMM8_V8_V8:
224             LowerTypedCallArg2(gate);
225             break;
226         case EcmaOpcode::CALLARGS3_IMM8_V8_V8_V8:
227             LowerTypedCallArg3(gate);
228             break;
229         case EcmaOpcode::CALLRANGE_IMM8_IMM8_V8:
230             LowerTypedCallrange(gate);
231             break;
232         case EcmaOpcode::CALLTHIS0_IMM8_V8:
233             LowerTypedCallthis0(gate);
234             break;
235         case EcmaOpcode::CALLTHIS1_IMM8_V8_V8:
236             LowerTypedCallthis1(gate);
237             break;
238         case EcmaOpcode::CALLTHIS2_IMM8_V8_V8_V8:
239             LowerTypedCallthis2(gate);
240             break;
241         case EcmaOpcode::CALLTHIS3_IMM8_V8_V8_V8_V8:
242             LowerTypedCallthis3(gate);
243             break;
244         case EcmaOpcode::CALLTHISRANGE_IMM8_IMM8_V8:
245             LowerTypedCallthisrange(gate);
246             break;
247         case EcmaOpcode::CALLRUNTIME_CALLINIT_PREF_IMM8_V8:
248             LowerTypedCallInit(gate);
249             break;
250         case EcmaOpcode::SUPERCALLTHISRANGE_IMM8_IMM8_V8:
251         case EcmaOpcode::WIDE_SUPERCALLTHISRANGE_PREF_IMM16_V8:
252             LowerTypedSuperCall(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::STPRIVATEPROPERTY_IMM8_IMM16_IMM16_V8:
260             LowerTypedStPrivateProperty(gate);
261             break;
262         case EcmaOpcode::LDPRIVATEPROPERTY_IMM8_IMM16_IMM16:
263             LowerTypedLdPrivateProperty(gate);
264             break;
265         case EcmaOpcode::LDOBJBYNAME_IMM8_ID16:
266         case EcmaOpcode::LDOBJBYNAME_IMM16_ID16:
267         case EcmaOpcode::LDTHISBYNAME_IMM8_ID16:
268         case EcmaOpcode::LDTHISBYNAME_IMM16_ID16:
269             LowerTypedLdObjByName(gate);
270             break;
271         case EcmaOpcode::STOBJBYNAME_IMM8_ID16_V8:
272         case EcmaOpcode::STOBJBYNAME_IMM16_ID16_V8:
273         case EcmaOpcode::STTHISBYNAME_IMM8_ID16:
274         case EcmaOpcode::STTHISBYNAME_IMM16_ID16:
275         case EcmaOpcode::DEFINEFIELDBYNAME_IMM8_ID16_V8:
276         case EcmaOpcode::DEFINEPROPERTYBYNAME_IMM8_ID16_V8:
277             LowerTypedStObjByName(gate);
278             break;
279         case EcmaOpcode::LDOBJBYVALUE_IMM8_V8:
280         case EcmaOpcode::LDOBJBYVALUE_IMM16_V8:
281         case EcmaOpcode::LDTHISBYVALUE_IMM8:
282         case EcmaOpcode::LDTHISBYVALUE_IMM16:
283             LowerTypedLdObjByValue(gate);
284             break;
285         case EcmaOpcode::STOBJBYVALUE_IMM8_V8_V8:
286         case EcmaOpcode::STOBJBYVALUE_IMM16_V8_V8:
287             LowerTypedStObjByValue(gate);
288             break;
289         case EcmaOpcode::STOWNBYVALUE_IMM8_V8_V8:
290         case EcmaOpcode::STOWNBYVALUE_IMM16_V8_V8:
291             LowerTypedStOwnByValue(gate);
292             break;
293         case EcmaOpcode::LDOBJBYINDEX_IMM8_IMM16:
294         case EcmaOpcode::LDOBJBYINDEX_IMM16_IMM16:
295         case EcmaOpcode::WIDE_LDOBJBYINDEX_PREF_IMM32:
296             LowerTypedLdObjByIndex(gate);
297             break;
298         case EcmaOpcode::STOBJBYINDEX_IMM8_V8_IMM16:
299         case EcmaOpcode::STOBJBYINDEX_IMM16_V8_IMM16:
300         case EcmaOpcode::WIDE_STOBJBYINDEX_PREF_V8_IMM32:
301             LowerTypedStObjByIndex(gate);
302             break;
303         case EcmaOpcode::TRYLDGLOBALBYNAME_IMM8_ID16:
304         case EcmaOpcode::TRYLDGLOBALBYNAME_IMM16_ID16:
305             LowerTypedTryLdGlobalByName(gate);
306             break;
307         case EcmaOpcode::STOWNBYNAME_IMM8_ID16_V8:
308         case EcmaOpcode::STOWNBYNAME_IMM16_ID16_V8:
309             LowerTypedStOwnByName(gate);
310             break;
311         case EcmaOpcode::JEQZ_IMM8:
312         case EcmaOpcode::JEQZ_IMM16:
313         case EcmaOpcode::JEQZ_IMM32:
314             LowerConditionJump(gate, false);
315             break;
316         case EcmaOpcode::JNEZ_IMM8:
317         case EcmaOpcode::JNEZ_IMM16:
318         case EcmaOpcode::JNEZ_IMM32:
319             LowerConditionJump(gate, true);
320             break;
321         default:
322             DeleteBytecodeCount(ecmaOpcode);
323             allNonTypedOpCount_++;
324             break;
325     }
326 }
327 
GetEcmaOpCodeListIndex(EcmaOpcode ecmaOpCode)328 int32_t TypedBytecodeLowering::GetEcmaOpCodeListIndex(EcmaOpcode ecmaOpCode)
329 {
330     std::vector<EcmaOpcode> opcodeList = GetEcmaCodeListForRange();
331     int32_t index =  static_cast<int32_t>(opcodeList.size());
332     int32_t size = static_cast<int32_t>(opcodeList.size());
333     for (int32_t i = 0; i < size; i++) {
334         if (opcodeList[i] == ecmaOpCode) {
335             index = i;
336             break;
337         }
338     }
339     if (index != size) {
340         return index;
341     } else {
342         return -1;
343     }
344 }
345 
346 template<TypedBinOp Op>
LowerTypedBinOp(GateRef gate)347 void TypedBytecodeLowering::LowerTypedBinOp(GateRef gate)
348 {
349     BinOpTypeInfoAccessor tacc(compilationEnv_, circuit_, gate);
350     if (Op == TypedBinOp::TYPED_SHR && tacc.GetParamType().IsIntOverflowType()) {
351         return;
352     }
353     if (tacc.HasNumberType()) {
354         SpeculateNumbers<Op>(tacc);
355     } else if (tacc.IsInternStringType()) {
356         SpeculateInternStrings<Op>(tacc);
357     } else if (tacc.IsStringType()) {
358         SpeculateStrings<Op>(tacc);
359     }
360 }
361 
362 template<TypedUnOp Op>
LowerTypedUnOp(GateRef gate)363 void TypedBytecodeLowering::LowerTypedUnOp(GateRef gate)
364 {
365     UnOpTypeInfoAccessor tacc(compilationEnv_, circuit_, gate);
366     // NOTICE-PGO: wx add support for PrimitiveNumberType
367     if (Op == TypedUnOp::TYPED_NEG && tacc.GetParamType().IsIntOverflowType()) {
368         return;
369     }
370     if (tacc.HasNumberType()) {
371         SpeculateNumber<Op>(tacc);
372     }
373 }
374 
375 template<TypedBinOp Op>
LowerTypedEqOrNotEq(GateRef gate)376 void TypedBytecodeLowering::LowerTypedEqOrNotEq(GateRef gate)
377 {
378     BinOpTypeInfoAccessor tacc(compilationEnv_, circuit_, gate);
379     if (tacc.LeftOrRightIsUndefinedOrNull()) {
380         AddProfiling(gate);
381         GateRef left = tacc.GetLeftGate();
382         GateRef right = tacc.GetReightGate();
383         GateRef result = builder_.TypedBinaryOp<Op>(left, right, tacc.GetParamType());
384         acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), result);
385     } else {
386         LowerTypedBinOp<Op>(gate);
387     }
388 }
389 
InternStringCheck(GateRef value)390 GateRef TypedBytecodeLowering::InternStringCheck(GateRef value)
391 {
392     // Marking a string as an Intern String is a runtime behavior.
393     // The tag of Intern String in JIT process will not become invalid and can be used during compilation.
394     if (compilationEnv_->IsJitCompiler()) {
395         // We believe that the Intern String tag of a constant string will not change during interpreted execution,
396         // JIT compilation, and JIT code execution. Therefore, the check for the constant Intern String can be removed
397         // during JIT compilation.
398         JSTaggedValue stringObject = JSTaggedValue::Undefined();
399         if (acc_.GetOpCode(value) == OpCode::JS_BYTECODE && acc_.GetByteCodeOpcode(value) == EcmaOpcode::LDA_STR_ID16) {
400             uint16_t stringIndex = acc_.GetConstantValue(acc_.GetValueIn(value, 0));
401             auto methodOffset = acc_.TryGetMethodOffset(value);
402             stringObject = compilationEnv_->GetStringFromConstantPool(methodOffset, stringIndex);
403         }
404         if (stringObject.IsHeapObject()) {
405             EcmaString* ecmaString = EcmaString::Cast(stringObject.GetTaggedObject());
406             EcmaStringAccessor ecmaStringAccessor(ecmaString);
407             if (ecmaStringAccessor.IsInternString()) {
408                 return builder_.True();
409             }
410         }
411     }
412     return builder_.InternStringCheck(value);
413 }
414 
415 template<TypedBinOp Op>
SpeculateInternStrings(const BinOpTypeInfoAccessor & tacc)416 void TypedBytecodeLowering::SpeculateInternStrings(const BinOpTypeInfoAccessor &tacc)
417 {
418     if (Op != TypedBinOp::TYPED_STRICTEQ && Op != TypedBinOp::TYPED_STRICTNOTEQ) {
419         SpeculateStrings<Op>(tacc);
420         return;
421     }
422     AddProfiling(tacc.GetGate());
423     GateRef left = tacc.GetLeftGate();
424     GateRef right = tacc.GetReightGate();
425     InternStringCheck(left);
426     InternStringCheck(right);
427     GateRef result = builder_.TypedBinaryOp<Op>(left, right, tacc.GetParamType());
428     acc_.ReplaceHirAndDeleteIfException(tacc.GetGate(), builder_.GetStateDepend(), result);
429 }
430 
431 template<TypedBinOp Op>
SpeculateStrings(const BinOpTypeInfoAccessor & tacc)432 void TypedBytecodeLowering::SpeculateStrings(const BinOpTypeInfoAccessor &tacc)
433 {
434     if (Op == TypedBinOp::TYPED_EQ || Op == TypedBinOp::TYPED_ADD) {
435         AddProfiling(tacc.GetGate());
436         GateRef left = tacc.GetLeftGate();
437         GateRef right = tacc.GetReightGate();
438         if (!TypeInfoAccessor::IsTrustedStringType(compilationEnv_, circuit_, chunk_, acc_, left)) {
439             if (!Uncheck()) {
440                 builder_.EcmaStringCheck(left);
441             }
442         }
443         if (!TypeInfoAccessor::IsTrustedStringType(compilationEnv_, circuit_, chunk_, acc_, right)) {
444             if (!Uncheck()) {
445                 builder_.EcmaStringCheck(right);
446             }
447         }
448         GateRef result = builder_.TypedBinaryOp<Op>(left, right, tacc.GetParamType());
449         acc_.ReplaceHirAndDeleteIfException(tacc.GetGate(), builder_.GetStateDepend(), result);
450     }
451 }
452 
453 template<TypedBinOp Op>
SpeculateNumbers(const BinOpTypeInfoAccessor & tacc)454 void TypedBytecodeLowering::SpeculateNumbers(const BinOpTypeInfoAccessor &tacc)
455 {
456     AddProfiling(tacc.GetGate());
457     pgoTypeLog_.CollectGateTypeLogInfo(tacc.GetGate(), true);
458     GateRef left = tacc.GetLeftGate();
459     GateRef right = tacc.GetReightGate();
460     GateRef result = builder_.TypedBinaryOp<Op>(left, right, tacc.GetParamType());
461     acc_.ReplaceHirAndDeleteIfException(tacc.GetGate(), builder_.GetStateDepend(), result);
462 }
463 
464 template<TypedUnOp Op>
SpeculateNumber(const UnOpTypeInfoAccessor & tacc)465 void TypedBytecodeLowering::SpeculateNumber(const UnOpTypeInfoAccessor &tacc)
466 {
467     AddProfiling(tacc.GetGate());
468     pgoTypeLog_.CollectGateTypeLogInfo(tacc.GetGate(), false);
469     GateRef result = builder_.TypedUnaryOp<Op>(tacc.GetValue(), tacc.GetParamType());
470     acc_.ReplaceHirAndDeleteIfException(tacc.GetGate(), builder_.GetStateDepend(), result);
471 }
472 
CheckedNumberToString(CircuitBuilder * builder,GateRef numOrStr,Label * exit)473 GateRef CheckedNumberToString(CircuitBuilder *builder, GateRef numOrStr, Label *exit)
474 {
475     auto isNum = builder->TaggedIsNumber(numOrStr);
476     Label numberBranch(builder);
477     Label notNumberBranch(builder);
478 
479     DEFVALUE(res, builder, VariableType::JS_ANY(), numOrStr);
480     builder->Branch(isNum, &numberBranch, &notNumberBranch, BranchWeight::ONE_WEIGHT, BranchWeight::ONE_WEIGHT,
481                     "IsNumber");
482     builder->Bind(&numberBranch);
483     {
484         res = builder->NumberToString(numOrStr);
485         builder->Jump(exit);
486     }
487     builder->Bind(&notNumberBranch);
488     {
489         builder->EcmaStringCheck(numOrStr);
490         res = numOrStr;
491         builder->Jump(exit);
492     }
493     builder->Bind(exit);
494 
495     return *res;
496 }
497 
498 template<TypedBinOp Op>
SpeculateNumbersOrString(const BinOpTypeInfoAccessor & tacc)499 void TypedBytecodeLowering::SpeculateNumbersOrString(const BinOpTypeInfoAccessor &tacc)
500 {
501     if (Op == TypedBinOp::TYPED_ADD) {
502         AddProfiling(tacc.GetGate());
503         GateRef left = tacc.GetLeftGate();
504         GateRef right = tacc.GetReightGate();
505 
506         Label exit(&builder_);
507         if (TypeInfoAccessor::IsTrustedStringType(compilationEnv_, circuit_, chunk_, acc_, left)) {
508             right = CheckedNumberToString(&builder_, right, &exit);
509             ASSERT(tacc.GetParamType() == ParamType::StringType());
510             GateRef result = builder_.TypedBinaryOp<Op>(left, right, ParamType::StringType());
511             acc_.ReplaceHirAndDeleteIfException(tacc.GetGate(), builder_.GetStateDepend(), result);
512         } else if (TypeInfoAccessor::IsTrustedStringType(compilationEnv_, circuit_, chunk_, acc_, right)) {
513             left = CheckedNumberToString(&builder_, left, &exit);
514             ASSERT(tacc.GetParamType() == ParamType::StringType());
515             GateRef result = builder_.TypedBinaryOp<Op>(left, right, ParamType::StringType());
516             acc_.ReplaceHirAndDeleteIfException(tacc.GetGate(), builder_.GetStateDepend(), result);
517         }
518     }
519 }
520 
LowerTypeToNumeric(GateRef gate)521 void TypedBytecodeLowering::LowerTypeToNumeric(GateRef gate)
522 {
523     UnOpTypeInfoAccessor tacc(compilationEnv_, circuit_, gate);
524     if (tacc.HasNumberType()) {
525         AddProfiling(gate);
526         LowerPrimitiveTypeToNumber(tacc);
527     }
528 }
529 
LowerPrimitiveTypeToNumber(const UnOpTypeInfoAccessor & tacc)530 void TypedBytecodeLowering::LowerPrimitiveTypeToNumber(const UnOpTypeInfoAccessor &tacc)
531 {
532     GateRef result = builder_.PrimitiveToNumber(tacc.GetValue(), tacc.GetParamType());
533     acc_.ReplaceHirAndDeleteIfException(tacc.GetGate(), builder_.GetStateDepend(), result);
534 }
535 
LowerConditionJump(GateRef gate,bool flag)536 void TypedBytecodeLowering::LowerConditionJump(GateRef gate, bool flag)
537 {
538     ConditionJumpTypeInfoAccessor tacc(compilationEnv_, circuit_, gate);
539     if (TypeInfoAccessor::IsTrustedBooleanType(acc_, tacc.GetValue())) {
540         AddProfiling(gate);
541         SpeculateConditionJump(tacc, flag);
542     }
543 }
544 
SpeculateConditionJump(const ConditionJumpTypeInfoAccessor & tacc,bool flag)545 void TypedBytecodeLowering::SpeculateConditionJump(const ConditionJumpTypeInfoAccessor &tacc, bool flag)
546 {
547     GateRef value = tacc.GetValue();
548     ParamType paramType = ParamType::BooleanType();
549     uint32_t weight = tacc.GetBranchWeight();
550     GateRef jump = Circuit::NullGate();
551     if (flag) {
552         jump = builder_.TypedConditionJump<TypedJumpOp::TYPED_JNEZ>(value, paramType, weight);
553     } else {
554         jump = builder_.TypedConditionJump<TypedJumpOp::TYPED_JEQZ>(value, paramType, weight);
555     }
556     acc_.ReplaceGate(tacc.GetGate(), jump, jump, Circuit::NullGate());
557 }
558 
DeleteConstDataIfNoUser(GateRef gate)559 void TypedBytecodeLowering::DeleteConstDataIfNoUser(GateRef gate)
560 {
561     auto uses = acc_.Uses(gate);
562     if (uses.begin() == uses.end()) {
563         builder_.ClearConstantCache(gate);
564         acc_.DeleteGate(gate);
565     }
566 }
567 
LowerTypedLdObjByName(GateRef gate)568 void TypedBytecodeLowering::LowerTypedLdObjByName(GateRef gate)
569 {
570     LoadObjByNameTypeInfoAccessor tacc(compilationEnv_, circuit_, gate, chunk_);
571 
572     if (TryLowerTypedLdobjBynameFromGloablBuiltin(gate)) {
573         return;
574     }
575     if (TryLowerTypedLdObjByNameForBuiltin(gate)) {
576         return;
577     }
578     if (tacc.TypesIsEmpty() || tacc.HasIllegalType()) {
579         return;
580     }
581 
582     DEFVALUE(result, (&builder_), VariableType::JS_ANY(), builder_.Hole());
583     size_t typeCount = tacc.GetTypeCount();
584     std::vector<Label> loaders;
585     std::vector<Label> fails;
586     ASSERT(typeCount > 0);
587     for (size_t i = 0; i < typeCount - 1; ++i) {
588         loaders.emplace_back(Label(&builder_));
589         fails.emplace_back(Label(&builder_));
590     }
591     Label exit(&builder_);
592     AddProfiling(gate);
593     GateRef frameState = acc_.GetFrameState(gate);
594     if (tacc.IsMono()) {
595         GateRef receiver = tacc.GetReceiver();
596         builder_.ObjectTypeCheck(false, receiver,
597                                  builder_.Int32(tacc.GetExpectedHClassIndex(0)), frameState);
598         if (tacc.IsReceiverEqHolder(0)) {
599             result = BuildNamedPropertyAccess(gate, receiver, receiver, tacc.GetAccessInfo(0).Plr());
600         } else {
601             builder_.ProtoChangeMarkerCheck(receiver, frameState);
602             PropertyLookupResult plr = tacc.GetAccessInfo(0).Plr();
603             GateRef plrGate = builder_.Int32(plr.GetData());
604             GateRef unsharedConstPoool = argAcc_.GetFrameArgsIn(gate, FrameArgIdx::UNSHARED_CONST_POOL);
605             size_t holderHClassIndex = static_cast<size_t>(tacc.GetAccessInfo(0).HClassIndex());
606             if (LIKELY(!plr.IsAccessor())) {
607                 result = builder_.MonoLoadPropertyOnProto(receiver, plrGate, unsharedConstPoool, holderHClassIndex);
608             } else {
609                 result = builder_.MonoCallGetterOnProto(gate, receiver, plrGate, unsharedConstPoool, holderHClassIndex);
610             }
611         }
612         acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), *result);
613         DeleteConstDataIfNoUser(tacc.GetKey());
614         return;
615     }
616     builder_.HeapObjectCheck(tacc.GetReceiver(), frameState);
617     auto receiverHC = builder_.LoadConstOffset(VariableType::JS_POINTER(), tacc.GetReceiver(),
618                                                TaggedObject::HCLASS_OFFSET);
619     for (size_t i = 0; i < typeCount; ++i) {
620         auto expected = builder_.GetHClassGateFromIndex(gate, tacc.GetExpectedHClassIndex(i));
621         if (i != typeCount - 1) {
622             BRANCH_CIR(builder_.Equal(receiverHC, expected), &loaders[i], &fails[i]);
623             builder_.Bind(&loaders[i]);
624         } else {
625             // Deopt if fails at last hclass compare
626             builder_.DeoptCheck(builder_.Equal(receiverHC, expected), frameState, DeoptType::INCONSISTENTHCLASS1);
627         }
628 
629         if (tacc.IsReceiverEqHolder(i)) {
630             result = BuildNamedPropertyAccess(gate, tacc.GetReceiver(), tacc.GetReceiver(),
631                                               tacc.GetAccessInfo(i).Plr());
632             builder_.Jump(&exit);
633         } else {
634             // prototype change marker check
635             builder_.ProtoChangeMarkerCheck(tacc.GetReceiver(), frameState);
636             // lookup from receiver for holder
637             auto prototype = builder_.LoadConstOffset(VariableType::JS_ANY(), receiverHC, JSHClass::PROTOTYPE_OFFSET);
638             // lookup from receiver for holder
639             ObjectAccessTypeInfoAccessor::ObjectAccessInfo info = tacc.GetAccessInfo(i);
640             auto holderHC = builder_.GetHClassGateFromIndex(gate, info.HClassIndex());
641             DEFVALUE(current, (&builder_), VariableType::JS_ANY(), prototype);
642             Label loopHead(&builder_);
643             Label loadHolder(&builder_);
644             Label lookUpProto(&builder_);
645             builder_.Jump(&loopHead);
646 
647             builder_.LoopBegin(&loopHead);
648             builder_.DeoptCheck(builder_.TaggedIsNotNull(*current), frameState, DeoptType::INCONSISTENTHCLASS2);
649             auto curHC = builder_.LoadConstOffset(VariableType::JS_POINTER(), *current, TaggedObject::HCLASS_OFFSET);
650             BRANCH_CIR(builder_.Equal(curHC, holderHC), &loadHolder, &lookUpProto);
651 
652             builder_.Bind(&lookUpProto);
653             current = builder_.LoadConstOffset(VariableType::JS_ANY(), curHC, JSHClass::PROTOTYPE_OFFSET);
654             builder_.LoopEnd(&loopHead);
655 
656             builder_.Bind(&loadHolder);
657             result = BuildNamedPropertyAccess(gate, tacc.GetReceiver(), *current, tacc.GetAccessInfo(i).Plr());
658             builder_.Jump(&exit);
659         }
660         if (i != typeCount - 1) {
661             builder_.Bind(&fails[i]);
662         }
663     }
664     builder_.Bind(&exit);
665     acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), *result);
666     DeleteConstDataIfNoUser(tacc.GetKey());
667 }
668 
LowerTypedLdPrivateProperty(GateRef gate)669 void TypedBytecodeLowering::LowerTypedLdPrivateProperty(GateRef gate)
670 {
671     LoadPrivatePropertyTypeInfoAccessor tacc(compilationEnv_, circuit_, gate, chunk_);
672 
673     if (tacc.HasIllegalType()) {
674         return;
675     }
676 
677     AddProfiling(gate);
678     Label exit(&builder_);
679 
680     GateRef receiver = tacc.GetReceiver();
681     GateRef levelIndex = tacc.GetLevelIndex();
682     GateRef slotIndex = tacc.GetSlotIndex();
683 
684     DEFVALUE(result, (&builder_), VariableType::JS_ANY(), builder_.Undefined());
685     GateRef frameState = acc_.FindNearestFrameState(builder_.GetDepend());
686     GateRef key = builder_.GetKeyFromLexivalEnv(
687         tacc.GetLexicalEnv(), builder_.TaggedGetInt(levelIndex), builder_.TaggedGetInt(slotIndex));
688 
689     builder_.HeapObjectCheck(key, frameState);
690     if (tacc.IsAccessor()) {
691         builder_.DeoptCheck(builder_.IsJSFunction(key), frameState, DeoptType::NOTJSFUNCTION);
692         result = builder_.CallPrivateGetter(gate, receiver, key);
693         builder_.Jump(&exit);
694     } else {
695         builder_.DeoptCheck(builder_.TaggedIsSymbol(key), frameState, DeoptType::NOTSYMBOL);
696         builder_.ObjectTypeCheck(false, receiver, builder_.Int32(tacc.GetExpectedHClassIndex(0)), frameState);
697         result = BuildNamedPropertyAccess(gate, receiver, receiver, tacc.GetAccessInfo(0).Plr());
698         builder_.Jump(&exit);
699     }
700 
701     builder_.Bind(&exit);
702     acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), *result);
703     DeleteConstDataIfNoUser(key);
704 }
705 
LowerTypedStPrivateProperty(GateRef gate)706 void TypedBytecodeLowering::LowerTypedStPrivateProperty(GateRef gate)
707 {
708     StorePrivatePropertyTypeInfoAccessor tacc(compilationEnv_, circuit_, gate, chunk_);
709 
710     if (tacc.HasIllegalType()) {
711         return;
712     }
713 
714     AddProfiling(gate);
715     Label exit(&builder_);
716 
717     GateRef receiver = tacc.GetReceiver();
718     GateRef levelIndex = tacc.GetLevelIndex();
719     GateRef slotIndex = tacc.GetSlotIndex();
720     GateRef value = tacc.GetValue();
721 
722     GateRef frameState = acc_.FindNearestFrameState(builder_.GetDepend());
723     GateRef key = builder_.GetKeyFromLexivalEnv(
724         tacc.GetLexicalEnv(), builder_.TaggedGetInt(levelIndex), builder_.TaggedGetInt(slotIndex));
725 
726     builder_.HeapObjectCheck(key, frameState);
727     if (tacc.IsAccessor()) {
728         builder_.DeoptCheck(builder_.IsJSFunction(key), frameState, DeoptType::NOTJSFUNCTION);
729         builder_.CallPrivateSetter(gate, receiver, key, value);
730         builder_.Jump(&exit);
731     } else {
732         builder_.DeoptCheck(builder_.TaggedIsSymbol(key), frameState, DeoptType::NOTSYMBOL);
733         builder_.ObjectTypeCheck(false, receiver, builder_.Int32(tacc.GetExpectedHClassIndex(0)), frameState);
734         BuildNamedPropertyAccess(
735             gate, receiver, receiver, value, tacc.GetAccessInfo(0).Plr(), tacc.GetExpectedHClassIndex(0));
736         builder_.Jump(&exit);
737     }
738 
739     builder_.Bind(&exit);
740     acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), Circuit::NullGate());
741     DeleteConstDataIfNoUser(key);
742 }
743 
LowerTypedStObjByName(GateRef gate)744 void TypedBytecodeLowering::LowerTypedStObjByName(GateRef gate)
745 {
746     StoreObjByNameTypeInfoAccessor tacc(compilationEnv_, circuit_, gate, chunk_);
747     if (tacc.TypesIsEmpty() || tacc.HasIllegalType()) {
748         return;
749     }
750     size_t typeCount = tacc.GetTypeCount();
751     std::vector<Label> loaders;
752     std::vector<Label> fails;
753     ASSERT(typeCount > 0);
754     for (size_t i = 0; i < typeCount - 1; ++i) {
755         loaders.emplace_back(Label(&builder_));
756         fails.emplace_back(Label(&builder_));
757     }
758     Label exit(&builder_);
759     AddProfiling(gate);
760     GateRef frameState = Circuit::NullGate();
761     auto opcode = acc_.GetByteCodeOpcode(gate);
762     // The framestate of Call and Accessor related instructions directives is placed on IR. Using the depend edge to
763     // climb up and find the nearest framestate for other instructions
764     if (opcode == EcmaOpcode::STOWNBYNAME_IMM8_ID16_V8 ||
765         opcode == EcmaOpcode::STOWNBYNAME_IMM16_ID16_V8) {
766         frameState = acc_.FindNearestFrameState(builder_.GetDepend());
767     } else if (opcode == EcmaOpcode::STOBJBYNAME_IMM8_ID16_V8 ||
768                opcode == EcmaOpcode::STOBJBYNAME_IMM16_ID16_V8 ||
769                opcode == EcmaOpcode::STTHISBYNAME_IMM8_ID16 ||
770                opcode == EcmaOpcode::STTHISBYNAME_IMM16_ID16 ||
771                opcode == EcmaOpcode::DEFINEFIELDBYNAME_IMM8_ID16_V8 ||
772                opcode == EcmaOpcode::DEFINEPROPERTYBYNAME_IMM8_ID16_V8) {
773         frameState = acc_.GetFrameState(gate);
774     } else {
775         UNREACHABLE();
776     }
777     if (tacc.IsMono()) {
778         GateRef receiver = tacc.GetReceiver();
779         builder_.ObjectTypeCheck(false, receiver,
780                                  builder_.Int32(tacc.GetExpectedHClassIndex(0)), frameState);
781         if (tacc.IsReceiverNoEqNewHolder(0)) {
782             builder_.ProtoChangeMarkerCheck(tacc.GetReceiver(), frameState);
783             PropertyLookupResult plr = tacc.GetAccessInfo(0).Plr();
784             GateRef plrGate = builder_.Int32(plr.GetData());
785             GateRef unsharedConstPool = argAcc_.GetFrameArgsIn(gate, FrameArgIdx::UNSHARED_CONST_POOL);
786             size_t holderHClassIndex = static_cast<size_t>(tacc.GetAccessInfo(0).HClassIndex());
787             GateRef value = tacc.GetValue();
788             if (tacc.IsHolderEqNewHolder(0)) {
789                 builder_.MonoStorePropertyLookUpProto(tacc.GetReceiver(), plrGate, unsharedConstPool, holderHClassIndex,
790                                                       value);
791             } else {
792                 builder_.MonoStoreProperty(tacc.GetReceiver(), plrGate, unsharedConstPool, holderHClassIndex, value,
793                                            builder_.TruncInt64ToInt32(tacc.GetKey()),
794                                            builder_.Boolean(tacc.IsPrototypeHclass(0)), frameState);
795             }
796         } else if (tacc.IsReceiverEqHolder(0)) {
797             BuildNamedPropertyAccess(gate, tacc.GetReceiver(), tacc.GetReceiver(),
798                                      tacc.GetValue(), tacc.GetAccessInfo(0).Plr(), tacc.GetExpectedHClassIndex(0));
799         }
800         acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), Circuit::NullGate());
801         DeleteConstDataIfNoUser(tacc.GetKey());
802         return;
803     }
804     builder_.HeapObjectCheck(tacc.GetReceiver(), frameState);
805     auto receiverHC = builder_.LoadConstOffset(VariableType::JS_POINTER(), tacc.GetReceiver(),
806                                                TaggedObject::HCLASS_OFFSET);
807     for (size_t i = 0; i < typeCount; ++i) {
808         auto expected = builder_.GetHClassGateFromIndex(gate, tacc.GetExpectedHClassIndex(i));
809         if (i != typeCount - 1) {
810             BRANCH_CIR(builder_.Equal(receiverHC, expected),
811                 &loaders[i], &fails[i]);
812             builder_.Bind(&loaders[i]);
813         } else {
814             builder_.DeoptCheck(builder_.Equal(receiverHC, expected), frameState, DeoptType::INCONSISTENTHCLASS3);
815         }
816         if (tacc.IsReceiverNoEqNewHolder(i)) {
817             builder_.ProtoChangeMarkerCheck(tacc.GetReceiver(), frameState);
818             if (tacc.IsHolderEqNewHolder(i)) {
819                 // lookup from receiver for holder
820                 auto prototype = builder_.LoadConstOffset(VariableType::JS_ANY(), receiverHC,
821                                                           JSHClass::PROTOTYPE_OFFSET);
822                 auto holderHC = builder_.GetHClassGateFromIndex(gate, tacc.GetAccessInfo(i).HClassIndex());
823                 DEFVALUE(current, (&builder_), VariableType::JS_ANY(), prototype);
824                 Label loopHead(&builder_);
825                 Label loadHolder(&builder_);
826                 Label lookUpProto(&builder_);
827                 builder_.Jump(&loopHead);
828 
829                 builder_.LoopBegin(&loopHead);
830                 builder_.DeoptCheck(builder_.TaggedIsNotNull(*current), frameState, DeoptType::INCONSISTENTHCLASS4);
831                 auto curHC = builder_.LoadConstOffset(VariableType::JS_POINTER(), *current,
832                                                       TaggedObject::HCLASS_OFFSET);
833                 BRANCH_CIR(builder_.Equal(curHC, holderHC), &loadHolder, &lookUpProto);
834 
835                 builder_.Bind(&lookUpProto);
836                 current = builder_.LoadConstOffset(VariableType::JS_ANY(), curHC, JSHClass::PROTOTYPE_OFFSET);
837                 builder_.LoopEnd(&loopHead);
838 
839                 builder_.Bind(&loadHolder);
840                 BuildNamedPropertyAccess(gate, tacc.GetReceiver(), *current, tacc.GetValue(),
841                                          tacc.GetAccessInfo(i).Plr());
842                 builder_.Jump(&exit);
843             } else {
844                 TypedStObjByNameTransition(gate, receiverHC, frameState, exit, tacc, i);
845             }
846         } else if (tacc.IsReceiverEqHolder(i)) {
847             // Local
848             BuildNamedPropertyAccess(gate, tacc.GetReceiver(), tacc.GetReceiver(),
849                                      tacc.GetValue(), tacc.GetAccessInfo(i).Plr());
850             builder_.Jump(&exit);
851         } else {
852             // find in prototype, same as transition
853             UNREACHABLE();
854             return;
855         }
856         if (i != typeCount - 1) {
857             // process fastpath for next type
858             builder_.Bind(&fails[i]);
859         }
860     }
861     builder_.Bind(&exit);
862     acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), Circuit::NullGate());
863     DeleteConstDataIfNoUser(tacc.GetKey());
864 }
865 
TypedStObjByNameTransition(GateRef gate,GateRef receiverHC,GateRef frameState,Label & exit,StoreObjByNameTypeInfoAccessor & tacc,size_t i)866 void TypedBytecodeLowering::TypedStObjByNameTransition(GateRef gate, GateRef receiverHC, GateRef frameState,
867                                                        Label &exit, StoreObjByNameTypeInfoAccessor &tacc, size_t i)
868 {
869     Label notProto(&builder_);
870     Label isProto(&builder_);
871     auto newHolderHC = builder_.GetHClassGateFromIndex(gate, tacc.GetAccessInfo(i).HClassIndex());
872     if (compilationEnv_->IsAotCompiler()) {
873         auto prototype = builder_.LoadConstOffset(VariableType::JS_ANY(), receiverHC, JSHClass::PROTOTYPE_OFFSET);
874         builder_.StoreConstOffset(VariableType::JS_ANY(), newHolderHC, JSHClass::PROTOTYPE_OFFSET, prototype);
875     }
876     if (!tacc.IsPrototypeHclass(i)) {
877         builder_.DeoptCheck(builder_.BoolNot(builder_.IsPrototypeHClass(receiverHC)), frameState,
878                             DeoptType::PROTOTYPECHANGED2);
879     } else {
880         builder_.Branch(builder_.IsPrototypeHClass(receiverHC), &isProto, &notProto,
881                         BranchWeight::ONE_WEIGHT, BranchWeight::DEOPT_WEIGHT, "isPrototypeHClass");
882         builder_.Bind(&isProto);
883         GateRef propKey =
884             builder_.GetObjectByIndexFromConstPool(glue_, gate, frameState,
885                                                    builder_.TruncInt64ToInt32(tacc.GetKey()), ConstPoolType::STRING);
886         builder_.CallRuntime(glue_, RTSTUB_ID(UpdateAOTHClass), Gate::InvalidGateRef,
887                              { receiverHC, newHolderHC, propKey }, gate);
888         builder_.Jump(&notProto);
889         builder_.Bind(&notProto);
890     }
891     MemoryAttribute mAttr = MemoryAttribute::NeedBarrierAndAtomic();
892     builder_.StoreConstOffset(VariableType::JS_ANY(), tacc.GetReceiver(), TaggedObject::HCLASS_OFFSET,
893                               newHolderHC, mAttr);
894     if (!tacc.GetAccessInfo(i).Plr().IsInlinedProps()) {
895         auto properties = builder_.LoadConstOffset(VariableType::JS_ANY(), tacc.GetReceiver(),
896                                                    JSObject::PROPERTIES_OFFSET);
897         auto capacity = builder_.LoadConstOffset(VariableType::INT32(), properties, TaggedArray::LENGTH_OFFSET);
898         auto index = builder_.Int32(tacc.GetAccessInfo(i).Plr().GetOffset());
899         Label needExtend(&builder_);
900         Label notExtend(&builder_);
901         BRANCH_CIR(builder_.Int32UnsignedLessThan(index, capacity), &notExtend, &needExtend);
902         builder_.Bind(&notExtend);
903         BuildNamedPropertyAccess(gate, tacc.GetReceiver(), tacc.GetReceiver(), tacc.GetValue(),
904                                  tacc.GetAccessInfo(i).Plr());
905         builder_.Jump(&exit);
906         builder_.Bind(&needExtend);
907         builder_.CallRuntime(glue_, RTSTUB_ID(PropertiesSetValue), Gate::InvalidGateRef,
908                              { tacc.GetReceiver(), tacc.GetValue(), properties, builder_.Int32ToTaggedInt(capacity),
909                                builder_.Int32ToTaggedInt(index) }, gate);
910         builder_.Jump(&exit);
911     } else {
912         BuildNamedPropertyAccess(gate, tacc.GetReceiver(), tacc.GetReceiver(), tacc.GetValue(),
913                                  tacc.GetAccessInfo(i).Plr());
914         builder_.Jump(&exit);
915     }
916 }
917 
LowerTypedStOwnByName(GateRef gate)918 void TypedBytecodeLowering::LowerTypedStOwnByName(GateRef gate)
919 {
920     LowerTypedStObjByName(gate);
921 }
922 
BuildNamedPropertyAccess(GateRef hir,GateRef receiver,GateRef holder,PropertyLookupResult plr)923 GateRef TypedBytecodeLowering::BuildNamedPropertyAccess(
924     GateRef hir, GateRef receiver, GateRef holder, PropertyLookupResult plr)
925 {
926     GateRef plrGate = builder_.Int32(plr.GetData());
927     GateRef result = Circuit::NullGate();
928     if (LIKELY(!plr.IsAccessor())) {
929         result = builder_.LoadProperty(holder, plrGate, plr.IsFunction());
930     } else {
931         result = builder_.CallGetter(hir, receiver, holder, plrGate);
932     }
933     return result;
934 }
935 
BuildNamedPropertyAccess(GateRef hir,GateRef receiver,GateRef holder,GateRef value,PropertyLookupResult plr,uint32_t receiverHClassIndex)936 GateRef TypedBytecodeLowering::BuildNamedPropertyAccess(
937     GateRef hir, GateRef receiver, GateRef holder, GateRef value, PropertyLookupResult plr,
938     uint32_t receiverHClassIndex)
939 {
940     GateRef plrGate = builder_.Int32(plr.GetData());
941     GateRef result = Circuit::NullGate();
942     if (LIKELY(!plr.IsAccessor())) {
943         builder_.StoreProperty(receiver, plrGate, value, receiverHClassIndex);
944     } else {
945         builder_.CallSetter(hir, receiver, holder, plrGate, value);
946     }
947     return result;
948 }
949 
TryLowerTypedLdObjByNameForBuiltin(GateRef gate)950 bool TypedBytecodeLowering::TryLowerTypedLdObjByNameForBuiltin(GateRef gate)
951 {
952     LoadBulitinObjTypeInfoAccessor tacc(compilationEnv_, circuit_, gate, chunk_);
953     // Just supported mono.
954     if (tacc.IsMono()) {
955         if (tacc.IsBuiltinsType()) {
956             auto builtinsId = tacc.GetBuiltinsTypeId();
957             if (builtinsId.has_value()) {
958                 if (TryLowerTypedLdObjByNameForBuiltin(tacc)) {
959                     return true;
960                 }
961                 return TryLowerTypedLdObjByNameForBuiltinMethod(tacc, builtinsId.value());
962             }
963         } else if (tacc.IsGlobalsType()) {
964             auto globalsId = tacc.GetGlobalsId();
965             if (globalsId.has_value()) {
966                 return TryLowerTypedLdObjByNameForGlobalsId(tacc, globalsId.value());
967             }
968         }
969     } else if (tacc.GetTypeCount() > 0) {
970         auto builtinsId = tacc.GetBuiltinsTypeId();
971         if (builtinsId.has_value()) {
972             return TryLowerTypedLdObjByNameForBuiltin(tacc);
973         }
974     }
975     return false; // No lowering performed
976 }
977 
TryLowerTypedLdObjByNameForBuiltin(const LoadBulitinObjTypeInfoAccessor & tacc)978 bool TypedBytecodeLowering::TryLowerTypedLdObjByNameForBuiltin(const LoadBulitinObjTypeInfoAccessor &tacc)
979 {
980     JSTaggedValue key = tacc.GetKeyTaggedValue();
981     if (key.IsUndefined()) {
982         return false;
983     }
984     EcmaString *propString = EcmaString::Cast(key.GetTaggedObject());
985     // (1) get length
986     EcmaString *lengthString =
987         EcmaString::Cast(compilationEnv_->GlobalConstants()->GetLengthString().GetTaggedObject());
988     if (propString == lengthString) {
989         if (tacc.IsBuiltinsArray()) {
990             LowerTypedLdArrayLength(tacc);
991             return true;
992         }
993         if (tacc.IsBuiltinsString()) {
994             LowerTypedLdStringLength(tacc);
995             return true;
996         }
997         if (tacc.IsBuiltinsTypeArray()) {
998             LowerTypedLdTypedArrayLength(tacc);
999             return true;
1000         }
1001     }
1002 
1003     EcmaString *sizeString = EcmaString::Cast(compilationEnv_->GlobalConstants()->GetSizeString().GetTaggedObject());
1004     if (propString == sizeString) {
1005         if (tacc.IsBuiltinsMap()) {
1006             LowerTypedLdMapSize(tacc);
1007             return true;
1008         }
1009     }
1010 
1011     // (2) other functions
1012     return false;
1013 }
1014 
TryLowerTypedLdObjByNameForGlobalsId(const LoadBulitinObjTypeInfoAccessor & tacc,GlobalIndex globalsId)1015 bool TypedBytecodeLowering::TryLowerTypedLdObjByNameForGlobalsId(const LoadBulitinObjTypeInfoAccessor &tacc,
1016                                                                  GlobalIndex globalsId)
1017 {
1018     GateRef receiver = tacc.GetReceiver();
1019     GateRef gate = tacc.GetGate();
1020     JSTaggedValue key = tacc.GetKeyTaggedValue();
1021     if (key.IsUndefined()) {
1022         return false;
1023     }
1024     GateRef frameState = acc_.FindNearestFrameState(gate);
1025     if (globalsId.IsGlobalConstId()) {
1026         ConstantIndex index = static_cast<ConstantIndex>(globalsId.GetGlobalConstId());
1027         JSHClass *hclass = JSHClass::Cast(compilationEnv_->GlobalConstants()->GetGlobalConstantObject(
1028             static_cast<size_t>(index)).GetTaggedObject());
1029         PropertyLookupResult plr = JSHClass::LookupPropertyInBuiltinHClass(compilationEnv_->GetJSThread(), hclass, key);
1030         if (!plr.IsFound() || plr.IsAccessor()) {
1031             return false;
1032         }
1033         AddProfiling(gate);
1034         // 1. check hclass
1035         builder_.HeapObjectCheck(receiver, frameState);
1036         GateRef receiverHClass = builder_.LoadHClassByConstOffset(receiver);
1037         GateRef expectedHClass = builder_.GetGlobalConstantValue(index);
1038         builder_.DeoptCheck(builder_.Equal(receiverHClass, expectedHClass), frameState,
1039                             DeoptType::INCONSISTENTHCLASS11);
1040         // 2. load property
1041         GateRef plrGate = builder_.Int32(plr.GetData());
1042         GateRef result = builder_.LoadProperty(receiver, plrGate, plr.IsFunction());
1043         acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), result);
1044         DeleteConstDataIfNoUser(tacc.GetKey());
1045         return true;
1046     } else if (globalsId.IsGlobalEnvId()) { // ctor Hclass
1047         GlobalEnvField index = static_cast<GlobalEnvField>(globalsId.GetGlobalEnvId());
1048         JSHClass *hclass = JSHClass::Cast(compilationEnv_->GetGlobalEnv()->GetGlobalEnvObjectByIndex(
1049             static_cast<size_t>(index))->GetTaggedObject()->GetClass());
1050         PropertyLookupResult plr = JSHClass::LookupPropertyInBuiltinHClass(compilationEnv_->GetJSThread(), hclass, key);
1051         if (!plr.IsFound() || plr.IsAccessor()) {
1052             return false;
1053         }
1054         AddProfiling(gate);
1055         // 1. check hclass
1056         builder_.HeapObjectCheck(receiver, frameState);
1057         GateRef globalEnvObj = builder_.GetGlobalEnvObj(builder_.GetGlobalEnv(), static_cast<size_t>(index));
1058         builder_.DeoptCheck(builder_.Equal(receiver, globalEnvObj), frameState,
1059                             DeoptType::INCONSISTENTHCLASS12);
1060         // 2. load property
1061         GateRef plrGate = builder_.Int32(plr.GetData());
1062         GateRef result = builder_.LoadProperty(receiver, plrGate, plr.IsFunction());
1063         acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), result);
1064         DeleteConstDataIfNoUser(tacc.GetKey());
1065         return true;
1066     }
1067     return false;
1068 }
1069 
TryLowerTypedLdobjBynameFromGloablBuiltin(GateRef gate)1070 bool TypedBytecodeLowering::TryLowerTypedLdobjBynameFromGloablBuiltin(GateRef gate)
1071 {
1072     LoadBulitinObjTypeInfoAccessor tacc(compilationEnv_, circuit_, gate, chunk_);
1073     GateRef receiver = tacc.GetReceiver();
1074     if (acc_.GetOpCode(receiver) != OpCode::LOAD_BUILTIN_OBJECT) {
1075         return false;
1076     }
1077     JSHandle<GlobalEnv> globalEnv = compilationEnv_->GetGlobalEnv();
1078     uint64_t index = acc_.TryGetValue(receiver);
1079     BuiltinType type = static_cast<BuiltinType>(index);
1080     if (type == BuiltinType::BT_MATH) {
1081         auto math = globalEnv->GetMathFunction();
1082         JSHClass *hclass = math.GetTaggedValue().GetTaggedObject()->GetClass();
1083         JSTaggedValue key = tacc.GetKeyTaggedValue();
1084         if (key.IsUndefined()) {
1085             return false;
1086         }
1087         PropertyLookupResult plr = JSHClass::LookupPropertyInBuiltinHClass(compilationEnv_->GetJSThread(), hclass, key);
1088         if (!plr.IsFound() || plr.IsAccessor()) {
1089             return false;
1090         }
1091         AddProfiling(gate);
1092         builder_.MathHClassConsistencyCheck(receiver);
1093         GateRef plrGate = builder_.Int32(plr.GetData());
1094         GateRef result = builder_.LoadProperty(receiver, plrGate, plr.IsFunction());
1095         acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), result);
1096         DeleteConstDataIfNoUser(tacc.GetKey());
1097         return true;
1098     }
1099     return false;
1100 }
1101 
LowerTypedLdArrayLength(const LoadBulitinObjTypeInfoAccessor & tacc)1102 void TypedBytecodeLowering::LowerTypedLdArrayLength(const LoadBulitinObjTypeInfoAccessor &tacc)
1103 {
1104     GateRef gate = tacc.GetGate();
1105     GateRef array = tacc.GetReceiver();
1106     ElementsKind kind = acc_.TryGetElementsKind(gate);
1107     AddProfiling(gate);
1108     if (!Uncheck()) {
1109         if (!acc_.IsCreateArray(array)) {
1110             builder_.StableArrayCheck(array, kind, ArrayMetaDataAccessor::Mode::LOAD_LENGTH);
1111         }
1112     }
1113 
1114     GateRef result = builder_.LoadArrayLength(array, kind, ArrayMetaDataAccessor::Mode::LOAD_LENGTH);
1115     acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), result);
1116 }
1117 
LowerTypedLdTypedArrayLength(const LoadBulitinObjTypeInfoAccessor & tacc)1118 void TypedBytecodeLowering::LowerTypedLdTypedArrayLength(const LoadBulitinObjTypeInfoAccessor &tacc)
1119 {
1120     GateRef gate = tacc.GetGate();
1121     GateRef array = tacc.GetReceiver();
1122     AddProfiling(gate);
1123     ParamType arrayType = tacc.GetParamType();
1124     OnHeapMode onHeap = acc_.TryGetOnHeapMode(gate);
1125     if (!Uncheck()) {
1126         builder_.TypedArrayCheck(array, arrayType, TypedArrayMetaDataAccessor::Mode::LOAD_LENGTH, onHeap);
1127     }
1128     GateRef result = builder_.LoadTypedArrayLength(array, arrayType, onHeap);
1129     acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), result);
1130 }
1131 
LowerTypedLdStringLength(const LoadBulitinObjTypeInfoAccessor & tacc)1132 void TypedBytecodeLowering::LowerTypedLdStringLength(const LoadBulitinObjTypeInfoAccessor &tacc)
1133 {
1134     GateRef gate = tacc.GetGate();
1135     GateRef str = tacc.GetReceiver();
1136     AddProfiling(gate);
1137     if (!TypeInfoAccessor::IsTrustedStringType(compilationEnv_, circuit_, chunk_, acc_, str)) {
1138         if (!Uncheck()) {
1139             builder_.EcmaStringCheck(str);
1140         }
1141     }
1142     GateRef result = builder_.LoadStringLength(str);
1143     acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), result);
1144 }
1145 
LowerTypedLdMapSize(const LoadBulitinObjTypeInfoAccessor & tacc)1146 void TypedBytecodeLowering::LowerTypedLdMapSize(const LoadBulitinObjTypeInfoAccessor &tacc)
1147 {
1148     GateRef gate = tacc.GetGate();
1149     GateRef jsMap = tacc.GetReceiver();
1150     AddProfiling(gate);
1151     if (!Uncheck()) {
1152         builder_.EcmaMapCheck(jsMap);
1153     }
1154     GateRef result = builder_.LoadMapSize(jsMap);
1155     acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), result);
1156 }
1157 
TryLowerTypedLdObjByNameForBuiltinMethod(const LoadBulitinObjTypeInfoAccessor & tacc,BuiltinTypeId type)1158 bool TypedBytecodeLowering::TryLowerTypedLdObjByNameForBuiltinMethod(const LoadBulitinObjTypeInfoAccessor &tacc,
1159                                                                      BuiltinTypeId type)
1160 {
1161     GateRef gate = tacc.GetGate();
1162     JSTaggedValue key = tacc.GetKeyTaggedValue();
1163     std::optional<GlobalEnvField> protoField = ToGlobelEnvPrototypeField(type);
1164     if (key.IsUndefined() || !protoField.has_value()) {
1165         return false;
1166     }
1167     size_t protoFieldIndex = static_cast<size_t>(*protoField);
1168     JSHandle<GlobalEnv> globalEnv = compilationEnv_->GetGlobalEnv();
1169     JSHClass *prototypeHClass = globalEnv->GetGlobalEnvObjectByIndex(protoFieldIndex)->GetTaggedObject()->GetClass();
1170     PropertyLookupResult plr = JSHClass::LookupPropertyInBuiltinPrototypeHClass(compilationEnv_->GetJSThread(),
1171         prototypeHClass, key);
1172     bool isPrototypeOfPrototype = false;
1173     // Unable to handle accessor at the moment
1174     if (!plr.IsFound() || plr.IsAccessor()) {
1175         if (type == BuiltinTypeId::ARRAY_ITERATOR) {
1176             protoField = ToGlobelEnvPrototypeField(BuiltinTypeId::ITERATOR);
1177             if (!protoField.has_value()) {
1178                 return false;
1179             }
1180             protoFieldIndex = static_cast<size_t>(*protoField);
1181             prototypeHClass = globalEnv->GetGlobalEnvObjectByIndex(protoFieldIndex)->GetTaggedObject()->GetClass();
1182             plr = JSHClass::LookupPropertyInBuiltinPrototypeHClass(compilationEnv_->GetJSThread(),
1183                 prototypeHClass, key);
1184             if (!plr.IsFound() || plr.IsAccessor()) {
1185                 return false;
1186             } else {
1187                 isPrototypeOfPrototype = true;
1188             }
1189         } else {
1190             return false;
1191         }
1192     }
1193     AddProfiling(gate);
1194     GateRef receiver = acc_.GetValueIn(gate, 2);
1195     if (!Uncheck()) {
1196         // For Array type only: array stability shall be ensured.
1197         ElementsKind kind = ElementsKind::NONE;
1198         if (type == BuiltinTypeId::ARRAY) {
1199             builder_.StableArrayCheck(receiver, ElementsKind::GENERIC, ArrayMetaDataAccessor::CALL_BUILTIN_METHOD);
1200             kind = tacc.TryGetArrayElementsKind();
1201         }
1202 
1203         builder_.BuiltinPrototypeHClassCheck(receiver, type, kind, isPrototypeOfPrototype);
1204     }
1205     // Successfully goes to typed path
1206     GateRef plrGate = builder_.Int32(plr.GetData());
1207     GateRef prototype = builder_.GetGlobalEnvObj(builder_.GetGlobalEnv(), static_cast<size_t>(*protoField));
1208     GateRef result = builder_.LoadProperty(prototype, plrGate, plr.IsFunction());
1209     acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), result);
1210     return true;
1211 }
1212 
TryLowerTypedLdObjByIndexForBuiltin(GateRef gate)1213 bool TypedBytecodeLowering::TryLowerTypedLdObjByIndexForBuiltin(GateRef gate)
1214 {
1215     LoadBulitinObjTypeInfoAccessor tacc(compilationEnv_, circuit_, gate, chunk_);
1216     GateRef result = Circuit::NullGate();
1217     // Just supported mono.
1218     if (tacc.IsMono()) {
1219         if (tacc.IsBuiltinsTypeArray()) {  // pgo need dump profile type
1220             AddProfiling(gate);
1221             result = LoadTypedArrayByIndex(tacc);
1222             acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), result);
1223             return true;
1224         }
1225     }
1226     return false;
1227 }
1228 
LowerTypedLdObjByIndex(GateRef gate)1229 void TypedBytecodeLowering::LowerTypedLdObjByIndex(GateRef gate)
1230 {
1231     if (TryLowerTypedLdObjByIndexForBuiltin(gate)) {
1232         return;
1233     }
1234 }
1235 
TryLowerTypedStObjByIndexForBuiltin(GateRef gate)1236 bool TypedBytecodeLowering::TryLowerTypedStObjByIndexForBuiltin(GateRef gate)
1237 {
1238     StoreBulitinObjTypeInfoAccessor tacc(compilationEnv_, circuit_, gate, chunk_);
1239     if (tacc.HasNoType()) {
1240         return false;
1241     }
1242     if (tacc.GetBuiltinsJSType() != JSType::JS_FLOAT32_ARRAY) {
1243         return false;
1244     }
1245     AddProfiling(gate);
1246     GateRef receiver = tacc.GetReceiver();
1247     ParamType receiverType = tacc.GetParamType();
1248     if (!Uncheck()) {
1249         OnHeapMode onHeap = tacc.TryGetHeapMode();
1250         builder_.TypedArrayCheck(receiver, receiverType, TypedArrayMetaDataAccessor::Mode::ACCESS_ELEMENT, onHeap);
1251     }
1252     GateRef index = builder_.Int32(tacc.TryConvertKeyToInt());
1253     GateRef value = tacc.GetValue();
1254     OnHeapMode onHeap = tacc.TryGetHeapMode();
1255     auto length = builder_.LoadTypedArrayLength(receiver, receiverType, onHeap);
1256     if (!Uncheck()) {
1257         builder_.IndexCheck(length, index);
1258     }
1259     builder_.StoreElement<TypedStoreOp::FLOAT32ARRAY_STORE_ELEMENT>(receiver, index, value, onHeap);
1260     acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), Circuit::NullGate());
1261     return true;
1262 }
1263 
LowerTypedStObjByIndex(GateRef gate)1264 void TypedBytecodeLowering::LowerTypedStObjByIndex(GateRef gate)
1265 {
1266     if (TryLowerTypedStObjByIndexForBuiltin(gate)) {
1267         return;
1268     }
1269 }
1270 
TryLowerTypedLdObjByValueForBuiltin(GateRef gate)1271 bool TypedBytecodeLowering::TryLowerTypedLdObjByValueForBuiltin(GateRef gate)
1272 {
1273     LoadBulitinObjTypeInfoAccessor tacc(compilationEnv_, circuit_, gate, chunk_);
1274     GateRef result = Circuit::NullGate();
1275     // Just supported mono.
1276     if (tacc.IsMono()) {
1277         if (tacc.IsBuiltinsString()) {
1278             AddProfiling(gate);
1279             result = LoadStringByIndex(tacc);
1280             acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), result);
1281             return true;
1282         } else if (tacc.IsBuiltinsArray()) {
1283             AddProfiling(gate);
1284             result = LoadJSArrayByIndex(tacc);
1285             acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), result);
1286             return true;
1287         } else if (tacc.IsBuiltinsTypeArray()) {
1288             AddProfiling(gate);
1289             result = LoadTypedArrayByIndex(tacc);
1290             acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), result);
1291             return true;
1292         }
1293     }
1294     return false;
1295 }
1296 
LowerTypedLdObjByValue(GateRef gate)1297 void TypedBytecodeLowering::LowerTypedLdObjByValue(GateRef gate)
1298 {
1299     if (TryLowerTypedLdObjByValueForBuiltin(gate)) {
1300         return;
1301     }
1302 }
1303 
LoadStringByIndex(const LoadBulitinObjTypeInfoAccessor & tacc)1304 GateRef TypedBytecodeLowering::LoadStringByIndex(const LoadBulitinObjTypeInfoAccessor &tacc)
1305 {
1306     GateRef receiver = tacc.GetReceiver();
1307     GateRef propKey = tacc.GetKey();
1308     acc_.SetGateType(propKey, GateType::NumberType());
1309     if (!Uncheck()) {
1310         if (!TypeInfoAccessor::IsTrustedStringType(compilationEnv_, circuit_, chunk_, acc_, receiver)) {
1311             builder_.EcmaStringCheck(receiver);
1312         }
1313         GateRef length = builder_.LoadStringLength(receiver);
1314         propKey = builder_.IndexCheck(length, propKey);
1315         receiver = builder_.FlattenTreeStringCheck(receiver);
1316     }
1317     return builder_.LoadElement<TypedLoadOp::STRING_LOAD_ELEMENT>(receiver, propKey);
1318 }
1319 
LoadJSArrayByIndex(const LoadBulitinObjTypeInfoAccessor & tacc)1320 GateRef TypedBytecodeLowering::LoadJSArrayByIndex(const LoadBulitinObjTypeInfoAccessor &tacc)
1321 {
1322     GateRef receiver = tacc.GetReceiver();
1323     GateRef propKey = tacc.GetKey();
1324     acc_.SetGateType(propKey, GateType::NumberType());
1325     ElementsKind kind = tacc.TryGetArrayElementsKind();
1326     if (!Uncheck()) {
1327         if (!acc_.IsCreateArray(receiver)) {
1328             builder_.StableArrayCheck(receiver, kind, ArrayMetaDataAccessor::Mode::LOAD_ELEMENT);
1329             builder_.ElementsKindCheck(receiver, kind, ArrayMetaDataAccessor::Mode::LOAD_ELEMENT);
1330         }
1331         GateRef length = builder_.LoadArrayLength(receiver, kind, ArrayMetaDataAccessor::Mode::LOAD_LENGTH);
1332         propKey = builder_.IndexCheck(length, propKey);
1333     }
1334 
1335     GateRef result = Circuit::NullGate();
1336     if (Elements::IsInt(kind)) {
1337         // When elementskind switch on, need to add retype for loadInt
1338         result = builder_.LoadElement<TypedLoadOp::ARRAY_LOAD_INT_ELEMENT>(receiver, propKey);
1339     } else if (Elements::IsNumber(kind)) {
1340         // When elementskind switch on, need to add retype for loadNumber
1341         result = builder_.LoadElement<TypedLoadOp::ARRAY_LOAD_DOUBLE_ELEMENT>(receiver, propKey);
1342     } else if (Elements::IsObject(kind)) {
1343         result = builder_.LoadElement<TypedLoadOp::ARRAY_LOAD_OBJECT_ELEMENT>(receiver, propKey);
1344     } else if (!Elements::IsHole(kind)) {
1345         result = builder_.LoadElement<TypedLoadOp::ARRAY_LOAD_TAGGED_ELEMENT>(receiver, propKey);
1346     } else {
1347         result = builder_.LoadElement<TypedLoadOp::ARRAY_LOAD_HOLE_TAGGED_ELEMENT>(receiver, propKey);
1348     }
1349     return result;
1350 }
1351 
LoadElmentFromFloat64Array(const LoadBulitinObjTypeInfoAccessor & tacc)1352 GateRef TypedBytecodeLowering::LoadElmentFromFloat64Array(const LoadBulitinObjTypeInfoAccessor &tacc)
1353 {
1354     GateRef receiver = tacc.GetReceiver();
1355     GateRef propKey = tacc.GetKey();
1356     OnHeapMode onHeap = tacc.TryGetHeapMode();
1357     auto resTemp = builder_.LoadElement<TypedLoadOp::FLOAT64ARRAY_LOAD_ELEMENT>(receiver, propKey, onHeap);
1358     Label entry(&builder_);
1359     builder_.SubCfgEntry(&entry);
1360     Label ifTrue(&builder_);
1361     Label ifFalse(&builder_);
1362     Label exit(&builder_);
1363     Variable result(builder_.GetCurrentEnvironment(),
1364         VariableType::JS_ANY(), builder_.NextVariableId(), builder_.Undefined());
1365 
1366     builder_.Branch(builder_.DoubleIsImpureNaN(resTemp), &ifTrue, &ifFalse);
1367     builder_.Bind(&ifTrue);
1368     {
1369         result = builder_.Double(base::NAN_VALUE);
1370         builder_.Jump(&exit);
1371     }
1372     builder_.Bind(&ifFalse);
1373     {
1374         result = resTemp;
1375         builder_.Jump(&exit);
1376     }
1377     builder_.Bind(&exit);
1378     auto res = *result;
1379     builder_.SubCfgExit();
1380     return res;
1381 }
1382 
LoadTypedArrayByIndex(const LoadBulitinObjTypeInfoAccessor & tacc)1383 GateRef TypedBytecodeLowering::LoadTypedArrayByIndex(const LoadBulitinObjTypeInfoAccessor &tacc)
1384 {
1385     GateRef receiver = tacc.GetReceiver();
1386     ParamType receiverType = tacc.GetParamType();
1387     GateRef propKey = tacc.GetKey();
1388     OnHeapMode onHeap = tacc.TryGetHeapMode();
1389     JSType builtinsType = tacc.GetBuiltinsJSType();
1390     if (!Uncheck()) {
1391         builder_.TypedArrayCheck(receiver, receiverType, TypedArrayMetaDataAccessor::Mode::ACCESS_ELEMENT, onHeap);
1392         GateRef length = builder_.LoadTypedArrayLength(receiver, receiverType, onHeap);
1393         propKey = builder_.IndexCheck(length, propKey);
1394     }
1395     switch (builtinsType) {
1396         case JSType::JS_INT8_ARRAY:
1397             return builder_.LoadElement<TypedLoadOp::INT8ARRAY_LOAD_ELEMENT>(receiver, propKey, onHeap);
1398         case JSType::JS_UINT8_ARRAY:
1399             return builder_.LoadElement<TypedLoadOp::UINT8ARRAY_LOAD_ELEMENT>(receiver, propKey, onHeap);
1400         case JSType::JS_UINT8_CLAMPED_ARRAY:
1401             return builder_.LoadElement<TypedLoadOp::UINT8CLAMPEDARRAY_LOAD_ELEMENT>(receiver, propKey, onHeap);
1402         case JSType::JS_INT16_ARRAY:
1403             return builder_.LoadElement<TypedLoadOp::INT16ARRAY_LOAD_ELEMENT>(receiver, propKey, onHeap);
1404         case JSType::JS_UINT16_ARRAY:
1405             return builder_.LoadElement<TypedLoadOp::UINT16ARRAY_LOAD_ELEMENT>(receiver, propKey, onHeap);
1406         case JSType::JS_INT32_ARRAY:
1407             return builder_.LoadElement<TypedLoadOp::INT32ARRAY_LOAD_ELEMENT>(receiver, propKey, onHeap);
1408         case JSType::JS_UINT32_ARRAY:
1409             return builder_.LoadElement<TypedLoadOp::UINT32ARRAY_LOAD_ELEMENT>(receiver, propKey, onHeap);
1410         case JSType::JS_FLOAT32_ARRAY:
1411             return builder_.LoadElement<TypedLoadOp::FLOAT32ARRAY_LOAD_ELEMENT>(receiver, propKey, onHeap);
1412         case JSType::JS_FLOAT64_ARRAY: {
1413             return LoadElmentFromFloat64Array(tacc);
1414         }
1415         default:
1416             LOG_ECMA(FATAL) << "this branch is unreachable";
1417             UNREACHABLE();
1418     }
1419 
1420     return Circuit::NullGate();
1421 }
1422 
StoreJSArrayByIndex(const StoreBulitinObjTypeInfoAccessor & tacc)1423 void TypedBytecodeLowering::StoreJSArrayByIndex(const StoreBulitinObjTypeInfoAccessor &tacc)
1424 {
1425     GateRef receiver = tacc.GetReceiver();
1426     GateRef propKey = tacc.GetKey();
1427     GateRef value = tacc.GetValue();
1428     ElementsKind kind = tacc.TryGetArrayElementsKind();
1429     if (!Uncheck()) {
1430         if (!acc_.IsCreateArray(receiver)) {
1431             builder_.StableArrayCheck(receiver, kind, ArrayMetaDataAccessor::Mode::STORE_ELEMENT);
1432         }
1433         GateRef length = builder_.LoadArrayLength(receiver, kind, ArrayMetaDataAccessor::Mode::LOAD_LENGTH);
1434         builder_.IndexCheck(length, propKey);
1435         builder_.COWArrayCheck(receiver);
1436 
1437         if (Elements::IsObject(kind)) {
1438             GateRef frameState = acc_.FindNearestFrameState(builder_.GetDepend());
1439             builder_.HeapObjectCheck(value, frameState);
1440         }
1441     }
1442     builder_.StoreElement<TypedStoreOp::ARRAY_STORE_ELEMENT>(receiver, propKey, value);
1443 }
1444 
StoreTypedArrayByIndex(const StoreBulitinObjTypeInfoAccessor & tacc)1445 void TypedBytecodeLowering::StoreTypedArrayByIndex(const StoreBulitinObjTypeInfoAccessor &tacc)
1446 {
1447     GateRef receiver = tacc.GetReceiver();
1448     ParamType receiverType = tacc.GetParamType();
1449     GateRef propKey = tacc.GetKey();
1450     GateRef value = tacc.GetValue();
1451     OnHeapMode onHeap = tacc.TryGetHeapMode();
1452     if (!Uncheck()) {
1453         builder_.TypedArrayCheck(receiver, receiverType, TypedArrayMetaDataAccessor::Mode::ACCESS_ELEMENT, onHeap);
1454         GateRef length = builder_.LoadTypedArrayLength(receiver, receiverType, onHeap);
1455         propKey = builder_.IndexCheck(length, propKey);
1456     }
1457 
1458     JSType builtinsType = tacc.GetBuiltinsJSType();
1459     switch (builtinsType) {
1460         case JSType::JS_INT8_ARRAY:
1461             builder_.StoreElement<TypedStoreOp::INT8ARRAY_STORE_ELEMENT>(receiver, propKey, value, onHeap);
1462             break;
1463         case JSType::JS_UINT8_ARRAY:
1464             builder_.StoreElement<TypedStoreOp::UINT8ARRAY_STORE_ELEMENT>(receiver, propKey, value, onHeap);
1465             break;
1466         case JSType::JS_UINT8_CLAMPED_ARRAY:
1467             builder_.StoreElement<TypedStoreOp::UINT8CLAMPEDARRAY_STORE_ELEMENT>(receiver, propKey, value, onHeap);
1468             break;
1469         case JSType::JS_INT16_ARRAY:
1470             builder_.StoreElement<TypedStoreOp::INT16ARRAY_STORE_ELEMENT>(receiver, propKey, value, onHeap);
1471             break;
1472         case JSType::JS_UINT16_ARRAY:
1473             builder_.StoreElement<TypedStoreOp::UINT16ARRAY_STORE_ELEMENT>(receiver, propKey, value, onHeap);
1474             break;
1475         case JSType::JS_INT32_ARRAY:
1476             builder_.StoreElement<TypedStoreOp::INT32ARRAY_STORE_ELEMENT>(receiver, propKey, value, onHeap);
1477             break;
1478         case JSType::JS_UINT32_ARRAY:
1479             builder_.StoreElement<TypedStoreOp::UINT32ARRAY_STORE_ELEMENT>(receiver, propKey, value, onHeap);
1480             break;
1481         case JSType::JS_FLOAT32_ARRAY:
1482             builder_.StoreElement<TypedStoreOp::FLOAT32ARRAY_STORE_ELEMENT>(receiver, propKey, value, onHeap);
1483             break;
1484         case JSType::JS_FLOAT64_ARRAY:
1485             builder_.StoreElement<TypedStoreOp::FLOAT64ARRAY_STORE_ELEMENT>(receiver, propKey, value, onHeap);
1486             break;
1487         default:
1488             LOG_ECMA(FATAL) << "this branch is unreachable";
1489             UNREACHABLE();
1490     }
1491 }
1492 
TryLowerTypedStObjByValueForBuiltin(GateRef gate)1493 bool TypedBytecodeLowering::TryLowerTypedStObjByValueForBuiltin(GateRef gate)
1494 {
1495     StoreBulitinObjTypeInfoAccessor tacc(compilationEnv_, circuit_, gate, chunk_);
1496     // Just supported mono.
1497     if (tacc.IsMono() && !tacc.IsStoreOutOfBounds()) {
1498         if (tacc.IsBuiltinsArray()) {
1499             AddProfiling(gate);
1500             StoreJSArrayByIndex(tacc);
1501             acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), Circuit::NullGate());
1502             return true;
1503         } else if (tacc.IsBuiltinsTypeArray()) {
1504             AddProfiling(gate);
1505             StoreTypedArrayByIndex(tacc);
1506             acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), Circuit::NullGate());
1507             return true;
1508         }
1509     }
1510 
1511     return false;
1512 }
1513 
LowerTypedStObjByValue(GateRef gate)1514 void TypedBytecodeLowering::LowerTypedStObjByValue(GateRef gate)
1515 {
1516     if (TryLowerTypedStObjByValueForBuiltin(gate)) {
1517         return;
1518     }
1519 }
1520 
IsTrueOrFalseHasProfileType(GateRef gate) const1521 bool TypedBytecodeLowering::IsTrueOrFalseHasProfileType(GateRef gate) const
1522 {
1523     ASSERT(acc_.GetOpCode(gate) == OpCode::JS_BYTECODE);
1524     return acc_.GetByteCodeOpcode(gate) == EcmaOpcode::CALLRUNTIME_ISTRUE_PREF_IMM8 ||
1525            acc_.GetByteCodeOpcode(gate) == EcmaOpcode::CALLRUNTIME_ISFALSE_PREF_IMM8;
1526 }
1527 
LowerTypedIsTrueOrFalse(GateRef gate,bool flag)1528 void TypedBytecodeLowering::LowerTypedIsTrueOrFalse(GateRef gate, bool flag)
1529 {
1530     UnOpTypeInfoAccessor tacc(compilationEnv_, circuit_, gate);
1531     ParamType paramType;
1532     if (TypeInfoAccessor::IsTrustedBooleanType(acc_, tacc.GetValue()) ||
1533     (IsTrueOrFalseHasProfileType(gate) && tacc.IsBooleanType())) {
1534         paramType = ParamType::BooleanType();
1535     } else if (TypeInfoAccessor::IsTrustedNumberType(acc_, tacc.GetValue()) ||
1536     (IsTrueOrFalseHasProfileType(gate) && tacc.HasNumberType())) {
1537         paramType = ParamType::NumberType();
1538     } else {
1539         return;
1540     }
1541     AddProfiling(gate);
1542     GateRef result;
1543     if (!flag) {
1544         result = builder_.TypedUnaryOp<TypedUnOp::TYPED_ISFALSE>(tacc.GetValue(), paramType);
1545     } else {
1546         result = builder_.TypedUnaryOp<TypedUnOp::TYPED_ISTRUE>(tacc.GetValue(), paramType);
1547     }
1548 
1549     acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), result);
1550 }
1551 
TryLowerNewNumber(CircuitBuilder * builder,GateAccessor acc,GateRef gate)1552 bool TryLowerNewNumber(CircuitBuilder *builder, GateAccessor acc, GateRef gate)
1553 {
1554     auto loadBuiltin = acc.GetValueIn(gate, 0);
1555     if ((acc.GetOpCode(loadBuiltin) == OpCode::LOAD_BUILTIN_OBJECT) &&
1556             (acc.GetIndex(loadBuiltin) == static_cast<size_t>(BuiltinType::BT_NUMBER))) {
1557         auto arg = builder->ToTaggedIntPtr(builder->Int32(0));
1558         if (acc.GetNumValueIn(gate) > 1) {
1559             arg = acc.GetValueIn(gate, 1);
1560         }
1561 
1562         auto currentLabel = builder->GetCurrentEnvironment()->GetCurrentLabel();
1563         auto currentControl = currentLabel->GetControl();
1564         auto currentDepend = currentLabel->GetDepend();
1565         GateRef frameState = acc.FindNearestFrameState(gate);
1566         GateRef newNumber = acc.GetCircuit()->NewGate(acc.GetCircuit()->NewNumber(),
1567             MachineType::I64,
1568             {currentControl, currentDepend, loadBuiltin, arg, frameState},
1569             GateType::TaggedPointer());
1570 
1571         currentLabel->SetControl(newNumber);
1572         currentLabel->SetDepend(newNumber);
1573 
1574         acc.ReplaceHirAndDeleteIfException(gate, builder->GetStateDepend(), newNumber);
1575         return true;
1576     }
1577     return false;
1578 }
1579 
LowerTypedNewObjRange(GateRef gate)1580 void TypedBytecodeLowering::LowerTypedNewObjRange(GateRef gate)
1581 {
1582     if (TryLowerNewBuiltinConstructor(gate)) {
1583         return;
1584     }
1585     if (TryLowerNewNumber(&builder_, acc_, gate)) {
1586         return;
1587     }
1588     NewObjRangeTypeInfoAccessor tacc(compilationEnv_, circuit_, gate, chunk_);
1589     if (!tacc.FindHClass() || !tacc.IsValidCallMethodId()) {
1590         return;
1591     }
1592     size_t methodId = tacc.GetCallMethodId();
1593     MethodLiteral* method = ctx_->GetJSPandaFile()->FindMethodLiteral(methodId);
1594     JSTaggedValue value = tacc.GetHClass();
1595     JSHClass *hclass = JSHClass::Cast(value.GetTaggedObject());
1596     if (method == nullptr || !value.IsJSHClass() || hclass->GetObjectType() != JSType::JS_OBJECT) {
1597         return ;
1598     }
1599     AddProfiling(gate);
1600     GateRef ctor = tacc.GetValue();
1601     GateRef hclassIndex = tacc.GetHClassIndex();
1602     GateRef stateSplit = acc_.GetDep(gate);
1603     GateRef frameState = acc_.FindNearestFrameState(stateSplit);
1604     GateRef ihclass = builder_.GetHClassGateFromIndex(frameState, hclassIndex);
1605     GateRef size = builder_.IntPtr(hclass->GetObjectSize());
1606     // call target check
1607     builder_.JSCallTargetTypeCheck<TypedCallTargetCheckOp::JS_NEWOBJRANGE>(ctor, builder_.IntPtr(INVALID_INDEX), gate);
1608     // check IHC
1609     GateRef protoOrHclass = builder_.LoadConstOffset(VariableType::JS_ANY(), ctor,
1610         JSFunction::PROTO_OR_DYNCLASS_OFFSET);
1611     GateRef checkProto = builder_.Equal(ihclass, protoOrHclass);
1612     builder_.DeoptCheck(checkProto, frameState, DeoptType::NOTNEWOBJ2);
1613     // construct
1614     GateRef thisObj = builder_.TypedNewAllocateThis(ctor, ihclass, size, frameState);
1615     size_t range = acc_.GetNumValueIn(gate);
1616     size_t expectedArgc = method->GetNumArgs();
1617     size_t actualArgc = static_cast<size_t>(BytecodeCallArgc::ComputeCallArgc(acc_.GetNumValueIn(gate),
1618         EcmaOpcode::NEWOBJRANGE_IMM8_IMM8_V8));
1619     GateRef argc = builder_.Int64(actualArgc);
1620     GateRef argv = builder_.IntPtr(0);
1621     std::vector<GateRef> args { glue_, argc, argv, ctor, ctor, thisObj }; // func thisobj numofargs
1622     for (size_t i = 1; i < range; ++i) {  // 1:skip ctor
1623         args.emplace_back(acc_.GetValueIn(gate, i));
1624     }
1625     bool needPushArgv = (expectedArgc != actualArgc);
1626     GateRef result = builder_.CallNew(gate, args, needPushArgv);
1627     ReplaceGateWithPendingException(acc_.GetGlueFromArgList(), gate, builder_.GetState(),
1628         builder_.GetDepend(), result);
1629 }
1630 
TryLowerNewBuiltinConstructor(GateRef gate)1631 bool TypedBytecodeLowering::TryLowerNewBuiltinConstructor(GateRef gate)
1632 {
1633     NewBuiltinCtorTypeInfoAccessor tacc(compilationEnv_, circuit_, gate);
1634 
1635     GateRef ctor = tacc.GetValue();
1636     GateRef constructGate = Circuit::NullGate();
1637     if (tacc.IsBuiltinId(BuiltinsStubCSigns::ID::ArrayConstructor)) {
1638         return false;
1639     } else if (tacc.IsBuiltinId(BuiltinsStubCSigns::ID::ObjectConstructor)) {
1640         AddProfiling(gate);
1641         if (!Uncheck()) {
1642             builder_.ObjectConstructorCheck(ctor);
1643         }
1644         constructGate = builder_.BuiltinConstructor(BuiltinsStubCSigns::ID::ObjectConstructor, gate);
1645     } else if (tacc.IsBuiltinId(BuiltinsStubCSigns::ID::BooleanConstructor)) {
1646         if (acc_.GetNumValueIn(gate) <= 2) { // 2: ctor and first arg
1647             AddProfiling(gate);
1648             if (!Uncheck()) {
1649                 builder_.BooleanConstructorCheck(ctor);
1650             }
1651             constructGate = builder_.BuiltinConstructor(BuiltinsStubCSigns::ID::BooleanConstructor, gate);
1652         }
1653     } else if (tacc.IsBuiltinId(BuiltinsStubCSigns::ID::Float32ArrayConstructor)) {
1654         if (acc_.GetNumValueIn(gate) <= 2) { // 2: ctor and first arg
1655             AddProfiling(gate);
1656             if (!Uncheck()) {
1657                 builder_.Float32ArrayConstructorCheck(ctor);
1658             }
1659             constructGate = builder_.BuiltinConstructor(BuiltinsStubCSigns::ID::Float32ArrayConstructor, gate);
1660         }
1661     }
1662     if (constructGate == Circuit::NullGate()) {
1663         return false;
1664     }
1665     ReplaceGateWithPendingException(acc_.GetGlueFromArgList(), gate, builder_.GetState(),
1666         builder_.GetDepend(), constructGate);
1667     return true;
1668 }
1669 
LowerTypedSuperCall(GateRef gate)1670 void TypedBytecodeLowering::LowerTypedSuperCall(GateRef gate)
1671 {
1672     SuperCallTypeInfoAccessor tacc(compilationEnv_, circuit_, gate, GetCalleePandaFile(gate), callMethodFlagMap_);
1673 
1674     auto methodId = tacc.GetMethodId();
1675     if (methodId == 0) {
1676         return;
1677     }
1678     auto *methodLiteral = ctx_->GetJSPandaFile()->FindMethodLiteral(methodId);
1679     if (methodLiteral == nullptr || !methodLiteral->IsTypedCall()) {
1680         return;
1681     }
1682     if (!tacc.IsValidCallMethodId()) {
1683         return;
1684     }
1685     AddProfiling(gate);
1686 
1687     GateRef ctor = tacc.GetCtor();
1688     // stateSplit maybe not a STATE_SPLIT
1689     GateRef stateSplit = acc_.GetDep(gate);
1690 
1691     GateRef frameState = acc_.FindNearestFrameState(stateSplit);
1692     GateRef superCtor = builder_.GetSuperConstructor(ctor);
1693     GateRef newTarget = argAcc_.GetFrameArgsIn(gate, FrameArgIdx::NEW_TARGET);
1694     GateRef thisObj = builder_.TypedSuperAllocateThis(superCtor, newTarget, frameState);
1695 
1696     // call constructor
1697     size_t range = acc_.GetNumValueIn(gate);
1698     GateRef actualArgc = builder_.Int64(range + 3);  // 3: ctor, newTaget, this
1699     GateRef actualArgv = builder_.IntPtr(0);
1700     std::vector<GateRef> args { glue_, actualArgc, actualArgv, superCtor, newTarget, thisObj };
1701     for (size_t i = 0; i < range; ++i) {
1702         args.emplace_back(acc_.GetValueIn(gate, i));
1703     }
1704 
1705     GateRef constructGate = builder_.Construct(gate, args);
1706     ReplaceGateWithPendingException(acc_.GetGlueFromArgList(), gate, builder_.GetState(),
1707         builder_.GetDepend(), constructGate);
1708 }
1709 
SpeculateCallBuiltin(GateRef gate,GateRef func,const std::vector<GateRef> & args,BuiltinsStubCSigns::ID id,bool isThrow)1710 void TypedBytecodeLowering::SpeculateCallBuiltin(GateRef gate, GateRef func, const std::vector<GateRef> &args,
1711                                                  BuiltinsStubCSigns::ID id, bool isThrow)
1712 {
1713     if (!Uncheck()) {
1714         builder_.CallTargetCheck(gate, func, builder_.IntPtr(static_cast<int64_t>(id)), {args[0]});
1715     }
1716 
1717     GateRef result = builder_.TypedCallBuiltin(gate, args, id, IS_SIDE_EFFECT_BUILTINS_ID(id));
1718 
1719     if (isThrow) {
1720         ReplaceGateWithPendingException(acc_.GetGlueFromArgList(), gate, builder_.GetState(),
1721             builder_.GetDepend(), result);
1722     } else {
1723         acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), result);
1724     }
1725 }
1726 
SpeculateCallBuiltinFromGlobal(GateRef gate,const std::vector<GateRef> & args,BuiltinsStubCSigns::ID id,bool isThrow,bool isSideEffect)1727 void TypedBytecodeLowering::SpeculateCallBuiltinFromGlobal(GateRef gate, const std::vector<GateRef> &args,
1728                                                            BuiltinsStubCSigns::ID id, bool isThrow, bool isSideEffect)
1729 {
1730     GateRef result = builder_.TypedCallBuiltin(gate, args, id, isSideEffect);
1731 
1732     if (isThrow) {
1733         ReplaceGateWithPendingException(acc_.GetGlueFromArgList(), gate, builder_.GetState(),
1734             builder_.GetDepend(), result);
1735     } else {
1736         acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), result);
1737     }
1738 }
1739 
LowerFastCall(GateRef gate,GateRef func,const std::vector<GateRef> & argsFastCall,bool isNoGC)1740 void TypedBytecodeLowering::LowerFastCall(GateRef gate, GateRef func,
1741     const std::vector<GateRef> &argsFastCall, bool isNoGC)
1742 {
1743     builder_.StartCallTimer(glue_, gate, {glue_, func, builder_.True()}, true);
1744     GateRef result = builder_.TypedFastCall(gate, argsFastCall, isNoGC);
1745     builder_.EndCallTimer(glue_, gate, {glue_, func}, true);
1746     ReplaceGateWithPendingException(acc_.GetGlueFromArgList(), gate, builder_.GetState(),
1747         builder_.GetDepend(), result);
1748 }
1749 
LowerCall(GateRef gate,GateRef func,const std::vector<GateRef> & args,bool isNoGC)1750 void TypedBytecodeLowering::LowerCall(GateRef gate, GateRef func,
1751     const std::vector<GateRef> &args, bool isNoGC)
1752 {
1753     builder_.StartCallTimer(glue_, gate, {glue_, func, builder_.True()}, true);
1754     GateRef result = builder_.TypedCall(gate, args, isNoGC);
1755     builder_.EndCallTimer(glue_, gate, {glue_, func}, true);
1756     ReplaceGateWithPendingException(acc_.GetGlueFromArgList(), gate, builder_.GetState(),
1757         builder_.GetDepend(), result);
1758 }
1759 
1760 template<class TypeAccessor>
CheckFastCallThisCallTarget(const TypeAccessor & tacc)1761 void TypedBytecodeLowering::CheckFastCallThisCallTarget(const TypeAccessor &tacc)
1762 {
1763     if (noCheck_) {
1764         return;
1765     }
1766     GateRef func = tacc.GetFunc();
1767     GateRef gate = tacc.GetGate();
1768     GateRef methodIndex = builder_.IntPtr(tacc.GetFuncMethodOffset());
1769     if (tacc.IsNoGC()) {
1770         builder_.JSNoGCCallThisTargetTypeCheck<TypedCallTargetCheckOp::JSCALLTHIS_FAST_NOGC>(func, methodIndex, gate);
1771     } else {
1772         builder_.JSCallTargetTypeCheck<TypedCallTargetCheckOp::JSCALLTHIS_FAST>(func, methodIndex, gate);
1773     }
1774 }
1775 
1776 template<class TypeAccessor>
CheckCallThisCallTarget(const TypeAccessor & tacc)1777 void TypedBytecodeLowering::CheckCallThisCallTarget(const TypeAccessor &tacc)
1778 {
1779     if (noCheck_) {
1780         return;
1781     }
1782     GateRef func = tacc.GetFunc();
1783     GateRef gate = tacc.GetGate();
1784     GateRef methodIndex = builder_.IntPtr(tacc.GetFuncMethodOffset());
1785     if (tacc.IsNoGC()) {
1786         builder_.JSNoGCCallThisTargetTypeCheck<TypedCallTargetCheckOp::JSCALLTHIS_NOGC>(func, methodIndex, gate);
1787     } else {
1788         builder_.JSCallTargetTypeCheck<TypedCallTargetCheckOp::JSCALLTHIS>(func, methodIndex, gate);
1789     }
1790 }
1791 
1792 template<class TypeAccessor>
CheckThisCallTargetAndLowerCall(const TypeAccessor & tacc,const std::vector<GateRef> & args,const std::vector<GateRef> & argsFastCall)1793 void TypedBytecodeLowering::CheckThisCallTargetAndLowerCall(const TypeAccessor &tacc,
1794     const std::vector<GateRef> &args, const std::vector<GateRef> &argsFastCall)
1795 {
1796     GateRef func = tacc.GetFunc();
1797     GateRef gate = tacc.GetGate();
1798     bool isNoGC = tacc.IsNoGC();
1799     if (tacc.CanFastCall()) {
1800         CheckFastCallThisCallTarget(tacc);
1801         LowerFastCall(gate, func, argsFastCall, isNoGC);
1802     } else {
1803         CheckCallThisCallTarget(tacc);
1804         LowerCall(gate, func, args, isNoGC);
1805     }
1806 }
1807 
1808 template<class TypeAccessor>
CheckCallTargetFromDefineFuncAndLowerCall(const TypeAccessor & tacc,const std::vector<GateRef> & args,const std::vector<GateRef> & argsFastCall,bool isNoGC)1809 void TypedBytecodeLowering::CheckCallTargetFromDefineFuncAndLowerCall(const TypeAccessor &tacc,
1810     const std::vector<GateRef> &args, const std::vector<GateRef> &argsFastCall, bool isNoGC)
1811 {
1812     GateRef func = tacc.GetFunc();
1813     GateRef gate = tacc.GetGate();
1814     // NO CHECK
1815     if (!Uncheck()) {
1816         builder_.CallTargetIsCompiledCheck(func, gate);
1817     }
1818     if (tacc.CanFastCall()) {
1819         LowerFastCall(gate, func, argsFastCall, isNoGC);
1820     } else {
1821         LowerCall(gate, func, args, isNoGC);
1822     }
1823 }
1824 
1825 template<class TypeAccessor>
InSameConstPool(const TypeAccessor & tacc) const1826 bool TypedBytecodeLowering::InSameConstPool(const TypeAccessor &tacc) const
1827 {
1828     auto pandaFile = ctx_->GetJSPandaFile();
1829     auto targetPandaFile = tacc.GetPandaFile();
1830     if (pandaFile != targetPandaFile) {
1831         return false;
1832     }
1833     auto targetMethodId = tacc.GetMethodId();
1834     panda_file::IndexAccessor indexAccessor(*(targetPandaFile->GetPandaFile()),
1835                                             panda_file::File::EntityId(targetMethodId));
1836     auto targetCpId = static_cast<uint32_t>(indexAccessor.GetHeaderIndex());
1837     if (constPoolId_ != targetCpId) {
1838         return false;
1839     }
1840     return true;
1841 }
1842 
1843 template<class TypeAccessor>
CheckCallTargetAndLowerCall(const TypeAccessor & tacc,const std::vector<GateRef> & args,const std::vector<GateRef> & argsFastCall)1844 void TypedBytecodeLowering::CheckCallTargetAndLowerCall(const TypeAccessor &tacc,
1845     const std::vector<GateRef> &args, const std::vector<GateRef> &argsFastCall)
1846 {
1847     GateRef func = tacc.GetFunc();
1848     if (IsLoadVtable(func)) {
1849         CheckThisCallTargetAndLowerCall(tacc, args, argsFastCall); // func = a.foo, func()
1850     } else {
1851         bool isNoGC = tacc.IsNoGC();
1852         auto op = acc_.GetOpCode(func);
1853         if (op == OpCode::JS_BYTECODE && (acc_.GetByteCodeOpcode(func) == EcmaOpcode::DEFINEFUNC_IMM8_ID16_IMM8 ||
1854                                           acc_.GetByteCodeOpcode(func) == EcmaOpcode::DEFINEFUNC_IMM16_ID16_IMM8)) {
1855             CheckCallTargetFromDefineFuncAndLowerCall(tacc, args, argsFastCall, isNoGC);
1856             return;
1857         }
1858         int methodIndex = tacc.GetMethodIndex();
1859         if (!tacc.MethodOffsetIsVaild() || methodIndex == -1) {
1860             return;
1861         }
1862         if (!InSameConstPool(tacc)) {
1863             return;
1864         }
1865 
1866         GateRef gate = tacc.GetGate();
1867         if (tacc.CanFastCall()) {
1868             if (!Uncheck()) {
1869                 builder_.JSCallTargetTypeCheck<TypedCallTargetCheckOp::JSCALL_FAST>(func,
1870                     builder_.IntPtr(methodIndex), gate);
1871             }
1872             LowerFastCall(gate, func, argsFastCall, isNoGC);
1873         } else {
1874             if (!Uncheck()) {
1875                 builder_.JSCallTargetTypeCheck<TypedCallTargetCheckOp::JSCALL>(func,
1876                     builder_.IntPtr(methodIndex), gate);
1877             }
1878             LowerCall(gate, func, args, isNoGC);
1879         }
1880     }
1881 }
1882 
1883 template<EcmaOpcode Op, class TypeAccessor>
LowerTypedCall(const TypeAccessor & tacc)1884 void TypedBytecodeLowering::LowerTypedCall(const TypeAccessor &tacc)
1885 {
1886     if (!tacc.IsHotnessFunc()) {
1887         return;
1888     }
1889     auto methodId = tacc.GetMethodId();
1890     if (methodId == 0) {
1891         return;
1892     }
1893     auto *methodLiteral = ctx_->GetJSPandaFile()->FindMethodLiteral(methodId);
1894     if (methodLiteral == nullptr || !methodLiteral->IsTypedCall()) {
1895         return;
1896     }
1897     uint32_t argc = tacc.GetArgc();
1898     GateRef gate = tacc.GetGate();
1899     GateRef actualArgc = Circuit::NullGate();
1900     GateRef actualArgv = builder_.IntPtr(0);
1901     switch (Op) {
1902         case EcmaOpcode::CALLARG0_IMM8: {
1903             actualArgc = builder_.Int64(BytecodeCallArgc::ComputeCallArgc(acc_.GetNumValueIn(gate),
1904                 EcmaOpcode::CALLARG0_IMM8));
1905             break;
1906         }
1907         case EcmaOpcode::CALLARG1_IMM8_V8: {
1908             actualArgc = builder_.Int64(BytecodeCallArgc::ComputeCallArgc(acc_.GetNumValueIn(gate),
1909                 EcmaOpcode::CALLARG1_IMM8_V8));
1910             break;
1911         }
1912         case EcmaOpcode::CALLARGS2_IMM8_V8_V8: {
1913             actualArgc = builder_.Int64(BytecodeCallArgc::ComputeCallArgc(acc_.GetNumValueIn(gate),
1914                 EcmaOpcode::CALLARGS2_IMM8_V8_V8));
1915             break;
1916         }
1917         case EcmaOpcode::CALLARGS3_IMM8_V8_V8_V8: {
1918             actualArgc = builder_.Int64(BytecodeCallArgc::ComputeCallArgc(acc_.GetNumValueIn(gate),
1919                 EcmaOpcode::CALLARGS3_IMM8_V8_V8_V8));
1920             break;
1921         }
1922         case EcmaOpcode::CALLRANGE_IMM8_IMM8_V8: {
1923             actualArgc = builder_.Int64(BytecodeCallArgc::ComputeCallArgc(acc_.GetNumValueIn(gate),
1924                 EcmaOpcode::CALLRANGE_IMM8_IMM8_V8));
1925             break;
1926         }
1927         default:
1928             UNREACHABLE();
1929     }
1930     uint32_t len = tacc.GetFunctionTypeLength();
1931     if (len == tacc.INVALID_LEN) {
1932         return;
1933     }
1934     GateRef func = tacc.GetFunc();
1935     GateRef newTarget = builder_.Undefined();
1936     GateRef thisObj = builder_.Undefined();
1937     std::vector<GateRef> argsFastCall { glue_, func, thisObj};
1938     std::vector<GateRef> args { glue_, actualArgc, actualArgv, func, newTarget, thisObj };
1939     for (uint32_t i = 0; i < argc; i++) {
1940         GateRef value = acc_.GetValueIn(gate, i);
1941         argsFastCall.emplace_back(value);
1942         args.emplace_back(value);
1943     }
1944     for (uint32_t i = argc; i < len; i++) {
1945         argsFastCall.emplace_back(builder_.Undefined());
1946         args.emplace_back(builder_.Undefined());
1947     }
1948     if (argc != len) {
1949         return ;
1950     }
1951     AddProfiling(gate);
1952     CheckCallTargetAndLowerCall(tacc, args, argsFastCall);
1953 }
1954 
GetCalleePandaFile(GateRef gate)1955 const JSPandaFile* TypedBytecodeLowering::GetCalleePandaFile(GateRef gate)
1956 {
1957     auto profileType = acc_.TryGetPGOType(gate).GetPGOSampleType();
1958     bool haveProfileType = profileType->IsProfileType() && !profileType->IsProfileTypeNone();
1959     if (haveProfileType) {
1960         if (compilationEnv_->IsJitCompiler()) {
1961             return compilationEnv_->GetJSPandaFile();
1962         }
1963         auto abcId = profileType->GetProfileType().GetAbcId();
1964         CString fileDesc;
1965         if (!decoder_->GetAbcNameById(abcId, fileDesc)) {
1966             UNREACHABLE();
1967         }
1968         fileDesc = JSPandaFile::GetNormalizedFileDesc(fileDesc);
1969         return JSPandaFileManager::GetInstance()->FindJSPandaFileByNormalizedName(fileDesc).get();
1970     }
1971     // nullptr if no pgo info
1972     return nullptr;
1973 }
1974 
LowerTypedCallArg0(GateRef gate)1975 void TypedBytecodeLowering::LowerTypedCallArg0(GateRef gate)
1976 {
1977     if (GetCalleePandaFile(gate) == nullptr) {
1978         return;
1979     }
1980     CallArg0TypeInfoAccessor tacc(compilationEnv_, circuit_, gate, GetCalleePandaFile(gate), callMethodFlagMap_);
1981     if (!tacc.IsValidCallMethodId()) {
1982         return;
1983     }
1984     LowerTypedCall<EcmaOpcode::CALLARG0_IMM8>(tacc);
1985 }
1986 
LowerTypedCallArg1(GateRef gate)1987 void TypedBytecodeLowering::LowerTypedCallArg1(GateRef gate)
1988 {
1989     if (GetCalleePandaFile(gate) == nullptr) {
1990         return;
1991     }
1992     CallArg1TypeInfoAccessor tacc(compilationEnv_, circuit_, gate, GetCalleePandaFile(gate), callMethodFlagMap_);
1993     GateRef func = tacc.GetFunc();
1994     GateRef a0Value = tacc.GetValue();
1995     BuiltinsStubCSigns::ID id = tacc.TryGetPGOBuiltinMethodId();
1996     if (!IS_INVALID_ID(id) && (IS_TYPED_BUILTINS_NUMBER_ID(id) || IS_TYPED_BUILTINS_GLOBAL_ID(id))) {
1997         if (IS_TYPED_INLINE_BUILTINS_ID(id)) {
1998             return;
1999         }
2000         AddProfiling(gate);
2001         if (IsFuncFromGlobal(func)) {
2002             // No need to do CallTargetCheck if func is from LOAD_BUILTIN_OBJECT.
2003             SpeculateCallBuiltinFromGlobal(gate, { a0Value }, id, true);
2004         } else {
2005             SpeculateCallBuiltin(gate, func, { a0Value }, id, true);
2006         }
2007     } else {
2008         if (!tacc.IsValidCallMethodId()) {
2009             return;
2010         }
2011         LowerTypedCall<EcmaOpcode::CALLARG1_IMM8_V8>(tacc);
2012     }
2013 }
2014 
LowerTypedCallArg2(GateRef gate)2015 void TypedBytecodeLowering::LowerTypedCallArg2(GateRef gate)
2016 {
2017     if (GetCalleePandaFile(gate) == nullptr) {
2018         return;
2019     }
2020     CallArg2TypeInfoAccessor tacc(compilationEnv_, circuit_, gate, GetCalleePandaFile(gate), callMethodFlagMap_);
2021     if (!tacc.IsValidCallMethodId()) {
2022         return;
2023     }
2024     LowerTypedCall<EcmaOpcode::CALLARGS2_IMM8_V8_V8>(tacc);
2025 }
2026 
LowerTypedCallArg3(GateRef gate)2027 void TypedBytecodeLowering::LowerTypedCallArg3(GateRef gate)
2028 {
2029     if (GetCalleePandaFile(gate) == nullptr) {
2030         return;
2031     }
2032     CallArg3TypeInfoAccessor tacc(compilationEnv_, circuit_, gate, GetCalleePandaFile(gate), callMethodFlagMap_);
2033     if (!tacc.IsValidCallMethodId()) {
2034         return;
2035     }
2036     LowerTypedCall<EcmaOpcode::CALLARGS3_IMM8_V8_V8_V8>(tacc);
2037 }
2038 
LowerTypedCallrange(GateRef gate)2039 void TypedBytecodeLowering::LowerTypedCallrange(GateRef gate)
2040 {
2041     if (GetCalleePandaFile(gate) == nullptr) {
2042         return;
2043     }
2044     CallRangeTypeInfoAccessor tacc(compilationEnv_, circuit_, gate, GetCalleePandaFile(gate), callMethodFlagMap_);
2045     if (!tacc.IsValidCallMethodId()) {
2046         return;
2047     }
2048     LowerTypedCall<EcmaOpcode::CALLRANGE_IMM8_IMM8_V8>(tacc);
2049 }
2050 
IsLoadVtable(GateRef func)2051 bool TypedBytecodeLowering::IsLoadVtable(GateRef func)
2052 {
2053     auto op = acc_.GetOpCode(func);
2054     if (op != OpCode::LOAD_PROPERTY) {
2055         return false;
2056     }
2057     return true;
2058 }
2059 
2060 template<EcmaOpcode Op, class TypeAccessor>
LowerTypedThisCall(const TypeAccessor & tacc)2061 void TypedBytecodeLowering::LowerTypedThisCall(const TypeAccessor &tacc)
2062 {
2063     auto methodId = tacc.GetMethodId();
2064     if (methodId == 0) {
2065         return;
2066     }
2067     auto *methodLiteral = ctx_->GetJSPandaFile()->FindMethodLiteral(methodId);
2068     if (methodLiteral == nullptr || !methodLiteral->IsTypedCall()) {
2069         return;
2070     }
2071     if (!tacc.IsHotnessFunc()) {
2072         return;
2073     }
2074     uint32_t argc = tacc.GetArgc();
2075     GateRef gate = tacc.GetGate();
2076     GateRef actualArgc = Circuit::NullGate();
2077     GateRef actualArgv = builder_.IntPtr(0);
2078     switch (Op) {
2079         case EcmaOpcode::CALLTHIS0_IMM8_V8: {
2080             actualArgc = builder_.Int64(BytecodeCallArgc::ComputeCallArgc(acc_.GetNumValueIn(gate),
2081                 EcmaOpcode::CALLTHIS0_IMM8_V8));
2082             break;
2083         }
2084         case EcmaOpcode::CALLTHIS1_IMM8_V8_V8: {
2085             actualArgc = builder_.Int64(BytecodeCallArgc::ComputeCallArgc(acc_.GetNumValueIn(gate),
2086                 EcmaOpcode::CALLTHIS1_IMM8_V8_V8));
2087             break;
2088         }
2089         case EcmaOpcode::CALLTHIS2_IMM8_V8_V8_V8: {
2090             actualArgc = builder_.Int64(BytecodeCallArgc::ComputeCallArgc(acc_.GetNumValueIn(gate),
2091                 EcmaOpcode::CALLTHIS2_IMM8_V8_V8_V8));
2092             break;
2093         }
2094         case EcmaOpcode::CALLTHIS3_IMM8_V8_V8_V8_V8: {
2095             actualArgc = builder_.Int64(BytecodeCallArgc::ComputeCallArgc(acc_.GetNumValueIn(gate),
2096                 EcmaOpcode::CALLTHIS3_IMM8_V8_V8_V8_V8));
2097             break;
2098         }
2099         case EcmaOpcode::CALLTHISRANGE_IMM8_IMM8_V8: {
2100             actualArgc = builder_.Int64(BytecodeCallArgc::ComputeCallArgc(acc_.GetNumValueIn(gate),
2101                 EcmaOpcode::CALLTHISRANGE_IMM8_IMM8_V8));
2102             break;
2103         }
2104         default:
2105             UNREACHABLE();
2106     }
2107 
2108     uint32_t len = tacc.GetFunctionTypeLength();
2109     if (len == tacc.INVALID_LEN) {
2110         return;
2111     }
2112     GateRef func = tacc.GetFunc();
2113     GateRef newTarget = builder_.Undefined();
2114     GateRef thisObj = tacc.GetThisObj();
2115     std::vector<GateRef> argsFastCall { glue_, func, thisObj};
2116     std::vector<GateRef> args { glue_, actualArgc, actualArgv, func, newTarget, thisObj };
2117     for (uint32_t i = 0; i < argc; i++) {
2118         GateRef value = acc_.GetValueIn(gate, i + 1);
2119         argsFastCall.emplace_back(value);
2120         args.emplace_back(value);
2121     }
2122     for (uint32_t i = argc; i < len; i++) {
2123         argsFastCall.emplace_back(builder_.Undefined());
2124         args.emplace_back(builder_.Undefined());
2125     }
2126     AddProfiling(gate);
2127     CheckThisCallTargetAndLowerCall(tacc, args, argsFastCall);
2128 }
2129 
LowerTypedCallthis0(GateRef gate)2130 void TypedBytecodeLowering::LowerTypedCallthis0(GateRef gate)
2131 {
2132     if (GetCalleePandaFile(gate) == nullptr) {
2133         return;
2134     }
2135     CallThis0TypeInfoAccessor tacc(compilationEnv_, circuit_, gate, GetCalleePandaFile(gate), callMethodFlagMap_);
2136     BuiltinsStubCSigns::ID pgoFuncId = tacc.TryGetPGOBuiltinMethodId();
2137     if (!IS_INVALID_ID(pgoFuncId) && IS_TYPED_BUILTINS_ID_CALL_THIS0(pgoFuncId)) {
2138         AddProfiling(gate);
2139         SpeculateCallBuiltin(gate, tacc.GetFunc(), {tacc.GetThisObj()}, pgoFuncId, true);
2140         return;
2141     }
2142     if (!tacc.CanOptimizeAsFastCall()) {
2143         return;
2144     }
2145     LowerTypedThisCall<EcmaOpcode::CALLTHIS0_IMM8_V8>(tacc);
2146 }
2147 
LowerTypedCallthis1(GateRef gate)2148 void TypedBytecodeLowering::LowerTypedCallthis1(GateRef gate)
2149 {
2150     if (GetCalleePandaFile(gate) == nullptr) {
2151         return;
2152     }
2153     CallThis1TypeInfoAccessor tacc(compilationEnv_, circuit_, gate, GetCalleePandaFile(gate), callMethodFlagMap_);
2154     BuiltinsStubCSigns::ID pgoFuncId = tacc.TryGetPGOBuiltinMethodId();
2155     if (!IS_INVALID_ID(pgoFuncId) && IS_TYPED_BUILTINS_ID_CALL_THIS1(pgoFuncId)) {
2156         AddProfiling(gate);
2157         SpeculateCallBuiltin(gate, tacc.GetFunc(), {tacc.GetArgs()}, pgoFuncId, true);
2158         return;
2159     }
2160     if (!tacc.CanOptimizeAsFastCall()) {
2161         return;
2162     }
2163     LowerTypedThisCall<EcmaOpcode::CALLTHIS1_IMM8_V8_V8>(tacc);
2164 }
2165 
LowerTypedCallthis2(GateRef gate)2166 void TypedBytecodeLowering::LowerTypedCallthis2(GateRef gate)
2167 {
2168     if (GetCalleePandaFile(gate) == nullptr) {
2169         return;
2170     }
2171     CallThis2TypeInfoAccessor tacc(compilationEnv_, circuit_, gate, GetCalleePandaFile(gate), callMethodFlagMap_);
2172     BuiltinsStubCSigns::ID pgoFuncId = tacc.TryGetPGOBuiltinMethodId();
2173     if (!IS_INVALID_ID(pgoFuncId) && IS_TYPED_BUILTINS_ID_CALL_THIS2(pgoFuncId)) {
2174         AddProfiling(gate);
2175         SpeculateCallBuiltin(gate, tacc.GetFunc(), { tacc.GetArgs() }, pgoFuncId, true);
2176         return;
2177     }
2178     if (!tacc.CanOptimizeAsFastCall()) {
2179         return;
2180     }
2181     LowerTypedThisCall<EcmaOpcode::CALLTHIS2_IMM8_V8_V8_V8>(tacc);
2182 }
2183 
LowerTypedCallthis3(GateRef gate)2184 void TypedBytecodeLowering::LowerTypedCallthis3(GateRef gate)
2185 {
2186     if (GetCalleePandaFile(gate) == nullptr) {
2187         return;
2188     }
2189     CallThis3TypeInfoAccessor tacc(compilationEnv_, circuit_, gate, GetCalleePandaFile(gate), callMethodFlagMap_);
2190     BuiltinsStubCSigns::ID pgoFuncId = tacc.TryGetPGOBuiltinMethodId();
2191     if (!IS_INVALID_ID(pgoFuncId) && IS_TYPED_BUILTINS_ID_CALL_THIS3(pgoFuncId)) {
2192         AddProfiling(gate);
2193         SpeculateCallBuiltin(gate, tacc.GetFunc(), { tacc.GetArgs() }, pgoFuncId, true);
2194         return;
2195     }
2196     if (!tacc.CanOptimizeAsFastCall()) {
2197         return;
2198     }
2199     LowerTypedThisCall<EcmaOpcode::CALLTHIS3_IMM8_V8_V8_V8_V8>(tacc);
2200 }
2201 
LowerTypedCallthisrange(GateRef gate)2202 void TypedBytecodeLowering::LowerTypedCallthisrange(GateRef gate)
2203 {
2204     if (GetCalleePandaFile(gate) == nullptr) {
2205         return;
2206     }
2207     CallThisRangeTypeInfoAccessor tacc(compilationEnv_, circuit_, gate, GetCalleePandaFile(gate), callMethodFlagMap_);
2208     if (!tacc.CanOptimizeAsFastCall()) {
2209         return;
2210     }
2211     LowerTypedThisCall<EcmaOpcode::CALLTHISRANGE_IMM8_IMM8_V8>(tacc);
2212 }
2213 
LowerTypedCallInit(GateRef gate)2214 void TypedBytecodeLowering::LowerTypedCallInit(GateRef gate)
2215 {
2216     // same as callthis0
2217     LowerTypedCallthis0(gate);
2218 }
2219 
AddProfiling(GateRef gate)2220 void TypedBytecodeLowering::AddProfiling(GateRef gate)
2221 {
2222     hitTypedOpCount_++;
2223     AddHitBytecodeCount();
2224     if (IsTraceBC()) {
2225         // see stateSplit as a part of JSByteCode if exists
2226         GateRef maybeStateSplit = acc_.GetDep(gate);
2227         GateRef current = Circuit::NullGate();
2228         if (acc_.GetOpCode(maybeStateSplit) == OpCode::STATE_SPLIT) {
2229             current = maybeStateSplit;
2230         } else {
2231             current = gate;
2232         }
2233 
2234         EcmaOpcode ecmaOpcode = acc_.GetByteCodeOpcode(gate);
2235         auto ecmaOpcodeGate = builder_.Int32(static_cast<uint32_t>(ecmaOpcode));
2236         GateRef constOpcode = builder_.Int32ToTaggedInt(ecmaOpcodeGate);
2237         GateRef typedPath = builder_.Int32ToTaggedInt(builder_.Int32(1));
2238         GateRef traceGate = builder_.CallRuntime(glue_, RTSTUB_ID(DebugAOTPrint), acc_.GetDep(current),
2239                                                  { constOpcode, typedPath }, gate);
2240         acc_.SetDep(current, traceGate);
2241         builder_.SetDepend(acc_.GetDep(gate));  // set gate depend: trace or STATE_SPLIT
2242     }
2243 
2244     if (IsProfiling()) {
2245         // see stateSplit as a part of JSByteCode if exists
2246         GateRef maybeStateSplit = acc_.GetDep(gate);
2247         GateRef current = Circuit::NullGate();
2248         if (acc_.GetOpCode(maybeStateSplit) == OpCode::STATE_SPLIT) {
2249             current = maybeStateSplit;
2250         } else {
2251             current = gate;
2252         }
2253 
2254         GateRef func = builder_.Undefined();
2255         if (acc_.HasFrameState(gate)) {
2256             func = argAcc_.GetFrameArgsIn(gate, FrameArgIdx::FUNC);
2257         }
2258 
2259         GateRef bcIndex = builder_.Int32ToTaggedInt(builder_.Int32(acc_.TryGetBcIndex(gate)));
2260         EcmaOpcode ecmaOpcode = acc_.GetByteCodeOpcode(gate);
2261         auto ecmaOpcodeGate = builder_.Int32(static_cast<uint32_t>(ecmaOpcode));
2262         GateRef constOpcode = builder_.Int32ToTaggedInt(ecmaOpcodeGate);
2263         GateRef mode =
2264             builder_.Int32ToTaggedInt(builder_.Int32(static_cast<int32_t>(OptCodeProfiler::Mode::TYPED_PATH)));
2265         GateRef profiling = builder_.CallRuntime(glue_, RTSTUB_ID(ProfileOptimizedCode), acc_.GetDep(current),
2266             { func, bcIndex, constOpcode, mode }, gate);
2267         acc_.SetDep(current, profiling);
2268         builder_.SetDepend(acc_.GetDep(gate));  // set gate depend: profiling or STATE_SPLIT
2269     }
2270 }
2271 
AddBytecodeCount(EcmaOpcode op)2272 void TypedBytecodeLowering::AddBytecodeCount(EcmaOpcode op)
2273 {
2274     currentOp_ = op;
2275     if (bytecodeMap_.find(op) != bytecodeMap_.end()) {
2276         bytecodeMap_[op]++;
2277     } else {
2278         bytecodeMap_[op] = 1;
2279     }
2280 }
2281 
DeleteBytecodeCount(EcmaOpcode op)2282 void TypedBytecodeLowering::DeleteBytecodeCount(EcmaOpcode op)
2283 {
2284     bytecodeMap_.erase(op);
2285 }
2286 
AddHitBytecodeCount()2287 void TypedBytecodeLowering::AddHitBytecodeCount()
2288 {
2289     if (bytecodeHitTimeMap_.find(currentOp_) != bytecodeHitTimeMap_.end()) {
2290         bytecodeHitTimeMap_[currentOp_]++;
2291     } else {
2292         bytecodeHitTimeMap_[currentOp_] = 1;
2293     }
2294 }
2295 
LowerTypedTypeOf(GateRef gate)2296 void TypedBytecodeLowering::LowerTypedTypeOf(GateRef gate)
2297 {
2298     TypeOfTypeInfoAccessor tacc(compilationEnv_, circuit_, gate);
2299     if (tacc.IsIllegalType()) {
2300         return;
2301     }
2302     AddProfiling(gate);
2303     if (!Uncheck()) {
2304         builder_.TypeOfCheck(tacc.GetValue(), tacc.GetParamType());
2305     }
2306     GateRef result = builder_.TypedTypeOf(tacc.GetParamType());
2307     acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), result);
2308 }
2309 
LowerGetIterator(GateRef gate)2310 void TypedBytecodeLowering::LowerGetIterator(GateRef gate)
2311 {
2312     if (GetCalleePandaFile(gate) == nullptr) {
2313         return;
2314     }
2315     GetIteratorTypeInfoAccessor tacc(compilationEnv_, circuit_, gate, GetCalleePandaFile(gate), callMethodFlagMap_);
2316     BuiltinsStubCSigns::ID id = tacc.TryGetPGOBuiltinMethodId();
2317     if (IS_INVALID_ID(id) || id == BuiltinsStubCSigns::ID::NONE) {
2318         return;
2319     }
2320     AddProfiling(gate);
2321     GateRef obj = tacc.GetCallee();
2322     SpeculateCallBuiltin(gate, obj, { obj }, id, true);
2323 }
2324 
LowerTypedTryLdGlobalByName(GateRef gate)2325 void TypedBytecodeLowering::LowerTypedTryLdGlobalByName(GateRef gate)
2326 {
2327     if (!enableLoweringBuiltin_) {
2328         return;
2329     }
2330     LoadGlobalObjByNameTypeInfoAccessor tacc(compilationEnv_, circuit_, gate);
2331     JSTaggedValue key = tacc.GetKeyTaggedValue();
2332     if (key.IsUndefined()) {
2333         return;
2334     }
2335 
2336     BuiltinIndex& builtin = BuiltinIndex::GetInstance();
2337     auto index = builtin.GetBuiltinIndex(key);
2338     if (index == builtin.NOT_FOUND) {
2339         return;
2340     }
2341     AddProfiling(gate);
2342     GateRef result = builder_.LoadBuiltinObject(index);
2343     acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), result);
2344     DeleteConstDataIfNoUser(tacc.GetKey());
2345 }
2346 
LowerInstanceOf(GateRef gate)2347 void TypedBytecodeLowering::LowerInstanceOf(GateRef gate)
2348 {
2349     InstanceOfTypeInfoAccessor tacc(compilationEnv_, circuit_, gate, chunk_);
2350     if (tacc.TypesIsEmpty() || tacc.HasIllegalType()) {
2351         return;
2352     }
2353     AddProfiling(gate);
2354     size_t typeCount = tacc.GetTypeCount();
2355     std::vector<GateRef> expectedHCIndexes;
2356     for (size_t i = 0; i < typeCount; ++i) {
2357         GateRef temp = builder_.Int32(tacc.GetExpectedHClassIndex(i));
2358         expectedHCIndexes.emplace_back(temp);
2359     }
2360     DEFVALUE(result, (&builder_), VariableType::JS_ANY(), builder_.Hole());
2361     // RuntimeCheck -
2362     // 1. pgo.hclass == ctor.hclass
2363     // 2. ctor.hclass has a prototype chain up to Function.prototype
2364     GateRef obj = tacc.GetReceiver();
2365     GateRef target = tacc.GetTarget();
2366 
2367     builder_.ObjectTypeCheck(false, target, expectedHCIndexes[0]);
2368     builder_.ProtoChangeMarkerCheck(target);
2369 
2370     result = builder_.OrdinaryHasInstance(obj, target);
2371     acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), *result);
2372 }
2373 
LowerCreateEmptyObject(GateRef gate)2374 void TypedBytecodeLowering::LowerCreateEmptyObject(GateRef gate)
2375 {
2376     AddProfiling(gate);
2377     GateRef globalEnv = builder_.GetGlobalEnv();
2378     GateRef hclass = builder_.GetGlobalEnvObjHClass(globalEnv, GlobalEnv::OBJECT_FUNCTION_INDEX);
2379 
2380     JSHandle<JSFunction> objectFunc(compilationEnv_->GetGlobalEnv()->GetObjectFunction());
2381     JSTaggedValue protoOrHClass = objectFunc->GetProtoOrHClass();
2382     JSHClass *objectHC = JSHClass::Cast(protoOrHClass.GetTaggedObject());
2383     size_t objectSize = objectHC->GetObjectSize();
2384 
2385     GateRef emptyArray = builder_.GetGlobalConstantValue(ConstantIndex::EMPTY_ARRAY_OBJECT_INDEX);
2386     GateRef size = builder_.IntPtr(objectHC->GetObjectSize());
2387 
2388     builder_.StartAllocate();
2389     GateRef object = builder_.HeapAlloc(glue_, size, GateType::TaggedValue(), RegionSpaceFlag::IN_YOUNG_SPACE);
2390 
2391     // initialization
2392     for (size_t offset = JSObject::SIZE; offset < objectSize; offset += JSTaggedValue::TaggedTypeSize()) {
2393         builder_.StoreConstOffset(VariableType::INT64(), object, offset, builder_.Undefined());
2394     }
2395     builder_.StoreConstOffset(VariableType::JS_POINTER(), object, JSObject::HCLASS_OFFSET, hclass,
2396                               MemoryAttribute::NeedBarrierAndAtomic());
2397     builder_.StoreConstOffset(VariableType::INT64(), object, JSObject::HASH_OFFSET,
2398                               builder_.Int64(JSTaggedValue(0).GetRawData()));
2399     builder_.StoreConstOffset(VariableType::JS_POINTER(), object, JSObject::PROPERTIES_OFFSET, emptyArray,
2400                               MemoryAttribute::NoBarrier());
2401     builder_.StoreConstOffset(VariableType::JS_POINTER(), object, JSObject::ELEMENTS_OFFSET, emptyArray,
2402                               MemoryAttribute::NoBarrier());
2403     GateRef result = builder_.FinishAllocate(object);
2404 
2405     acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), result);
2406 }
2407 
LowerTypedStOwnByValue(GateRef gate)2408 void TypedBytecodeLowering::LowerTypedStOwnByValue(GateRef gate)
2409 {
2410     // StOwnByValue is rarely used, so the callruntime solution is used
2411     AddProfiling(gate);
2412     return;
2413 }
2414 
LowerCreateObjectWithBuffer(GateRef gate)2415 void TypedBytecodeLowering::LowerCreateObjectWithBuffer(GateRef gate)
2416 {
2417     CreateObjWithBufferTypeInfoAccessor tacc(compilationEnv_, circuit_, gate, recordName_, chunk_);
2418     if (!tacc.CanOptimize()) {
2419         return;
2420     }
2421     JSTaggedValue hclassVal = tacc.GetHClass();
2422     if (hclassVal.IsUndefined()) {
2423         return;
2424     }
2425     JSHClass *newClass = JSHClass::Cast(hclassVal.GetTaggedObject());
2426     GateRef index = tacc.GetIndex();
2427     JSTaggedValue obj = tacc.GetObject();
2428     if (obj.IsUndefined()) {
2429         return;
2430     }
2431     JSObject *objhandle = JSObject::Cast(obj);
2432     std::vector<uint64_t> inlinedProps;
2433     auto layout = LayoutInfo::Cast(newClass->GetLayout().GetTaggedObject());
2434     uint32_t numOfProps = newClass->NumberOfProps();
2435     uint32_t numInlinedProps = newClass->GetInlinedProperties();
2436     for (uint32_t i = 0; i < numOfProps; i++) {
2437         auto attr = layout->GetAttr(i);
2438         JSTaggedValue value = objhandle->GetPropertyInlinedProps(i);
2439         if ((!attr.IsTaggedRep()) || value.IsUndefinedOrNull() ||
2440             value.IsNumber() || value.IsBoolean() || value.IsException()) {
2441             auto converted = JSObject::ConvertValueWithRep(attr, value);
2442             if (!converted.first) {
2443                 return;
2444             }
2445             // CanOptimize.GetObject had convert value, just used directly
2446             inlinedProps.emplace_back(value.GetRawData());
2447         } else {
2448             return;
2449         }
2450     }
2451 
2452     AddProfiling(gate);
2453     auto size = newClass->GetObjectSize();
2454     std::vector<GateRef> valueIn;
2455     valueIn.emplace_back(builder_.IntPtr(size));
2456     valueIn.emplace_back(index);
2457     valueIn.emplace_back(builder_.Int64(JSTaggedValue(newClass).GetRawData()));
2458     valueIn.emplace_back(acc_.GetValueIn(gate, 1));
2459     for (uint32_t i = 0; i < numOfProps; i++) {
2460         auto attr = layout->GetAttr(i);
2461         GateRef prop;
2462         if (attr.IsIntRep()) {
2463             prop = builder_.Int32(inlinedProps.at(i));
2464         } else if (attr.IsTaggedRep()) {
2465             prop = circuit_->NewGate(circuit_->GetMetaBuilder()->Constant(inlinedProps.at(i)),
2466                                      MachineType::I64, GateType::AnyType());
2467         } else if (attr.IsDoubleRep()) {
2468             prop = circuit_->NewGate(circuit_->GetMetaBuilder()->Constant(inlinedProps.at(i)),
2469                                      MachineType::F64, GateType::NJSValue());
2470         } else {
2471             prop = builder_.Int64(inlinedProps.at(i));
2472         }
2473         valueIn.emplace_back(prop);
2474         valueIn.emplace_back(builder_.Int32(newClass->GetInlinedPropertiesOffset(i)));
2475     }
2476     GateRef prop = newClass->IsAOT() ? builder_.Hole() : builder_.Undefined();
2477     for (uint32_t i = numOfProps; i < numInlinedProps; i++) {
2478         valueIn.emplace_back(prop);
2479         valueIn.emplace_back(builder_.Int32(newClass->GetInlinedPropertiesOffset(i)));
2480     }
2481     GateRef ret = builder_.TypedCreateObjWithBuffer(valueIn);
2482     acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), ret);
2483 }
2484 
ReplaceGateWithPendingException(GateRef glue,GateRef gate,GateRef state,GateRef depend,GateRef value)2485 void TypedBytecodeLowering::ReplaceGateWithPendingException(GateRef glue, GateRef gate, GateRef state, GateRef depend,
2486                                                             GateRef value)
2487 {
2488     auto condition = builder_.HasPendingException(glue);
2489     GateRef ifBranch = builder_.Branch(state, condition, 1, BranchWeight::DEOPT_WEIGHT, "checkException");
2490     GateRef ifTrue = builder_.IfTrue(ifBranch);
2491     GateRef ifFalse = builder_.IfFalse(ifBranch);
2492     GateRef eDepend = builder_.DependRelay(ifTrue, depend);
2493     GateRef sDepend = builder_.DependRelay(ifFalse, depend);
2494 
2495     StateDepend success(ifFalse, sDepend);
2496     StateDepend exception(ifTrue, eDepend);
2497     acc_.ReplaceHirWithIfBranch(gate, success, exception, value);
2498 }
2499 }  // namespace panda::ecmascript
2500