• 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_.ReplaceHirAndReplaceDeadIfException(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_.ReplaceHirAndReplaceDeadIfException(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         if (Op == TypedBinOp::TYPED_ADD) {
450             ReplaceGateWithPendingException(glue_, tacc.GetGate(), builder_.GetState(), builder_.GetDepend(), result);
451         } else {
452             acc_.ReplaceHirAndReplaceDeadIfException(tacc.GetGate(), builder_.GetStateDepend(), result);
453         }
454     }
455 }
456 
457 template<TypedBinOp Op>
SpeculateNumbers(const BinOpTypeInfoAccessor & tacc)458 void TypedBytecodeLowering::SpeculateNumbers(const BinOpTypeInfoAccessor &tacc)
459 {
460     AddProfiling(tacc.GetGate());
461     pgoTypeLog_.CollectGateTypeLogInfo(tacc.GetGate(), true);
462     GateRef left = tacc.GetLeftGate();
463     GateRef right = tacc.GetReightGate();
464     GateRef result = builder_.TypedBinaryOp<Op>(left, right, tacc.GetParamType());
465     acc_.ReplaceHirAndReplaceDeadIfException(tacc.GetGate(), builder_.GetStateDepend(), result);
466 }
467 
468 template<TypedUnOp Op>
SpeculateNumber(const UnOpTypeInfoAccessor & tacc)469 void TypedBytecodeLowering::SpeculateNumber(const UnOpTypeInfoAccessor &tacc)
470 {
471     AddProfiling(tacc.GetGate());
472     pgoTypeLog_.CollectGateTypeLogInfo(tacc.GetGate(), false);
473     GateRef result = builder_.TypedUnaryOp<Op>(tacc.GetValue(), tacc.GetParamType());
474     acc_.ReplaceHirAndReplaceDeadIfException(tacc.GetGate(), builder_.GetStateDepend(), result);
475 }
476 
CheckedNumberToString(CircuitBuilder * builder,GateRef numOrStr,Label * exit)477 GateRef CheckedNumberToString(CircuitBuilder *builder, GateRef numOrStr, Label *exit)
478 {
479     auto isNum = builder->TaggedIsNumber(numOrStr);
480     Label numberBranch(builder);
481     Label notNumberBranch(builder);
482 
483     DEFVALUE(res, builder, VariableType::JS_ANY(), numOrStr);
484     builder->Branch(isNum, &numberBranch, &notNumberBranch, BranchWeight::ONE_WEIGHT, BranchWeight::ONE_WEIGHT,
485                     "IsNumber");
486     builder->Bind(&numberBranch);
487     {
488         res = builder->NumberToString(numOrStr);
489         builder->Jump(exit);
490     }
491     builder->Bind(&notNumberBranch);
492     {
493         builder->EcmaStringCheck(numOrStr);
494         res = numOrStr;
495         builder->Jump(exit);
496     }
497     builder->Bind(exit);
498 
499     return *res;
500 }
501 
502 template<TypedBinOp Op>
SpeculateNumbersOrString(const BinOpTypeInfoAccessor & tacc)503 void TypedBytecodeLowering::SpeculateNumbersOrString(const BinOpTypeInfoAccessor &tacc)
504 {
505     if (Op == TypedBinOp::TYPED_ADD) {
506         AddProfiling(tacc.GetGate());
507         GateRef left = tacc.GetLeftGate();
508         GateRef right = tacc.GetReightGate();
509 
510         Label exit(&builder_);
511         if (TypeInfoAccessor::IsTrustedStringType(compilationEnv_, circuit_, chunk_, acc_, left)) {
512             right = CheckedNumberToString(&builder_, right, &exit);
513             ASSERT(tacc.GetParamType() == ParamType::StringType());
514             GateRef result = builder_.TypedBinaryOp<Op>(left, right, ParamType::StringType());
515             acc_.ReplaceHirAndReplaceDeadIfException(tacc.GetGate(), builder_.GetStateDepend(), result);
516         } else if (TypeInfoAccessor::IsTrustedStringType(compilationEnv_, circuit_, chunk_, acc_, right)) {
517             left = CheckedNumberToString(&builder_, left, &exit);
518             ASSERT(tacc.GetParamType() == ParamType::StringType());
519             GateRef result = builder_.TypedBinaryOp<Op>(left, right, ParamType::StringType());
520             acc_.ReplaceHirAndReplaceDeadIfException(tacc.GetGate(), builder_.GetStateDepend(), result);
521         }
522     }
523 }
524 
LowerTypeToNumeric(GateRef gate)525 void TypedBytecodeLowering::LowerTypeToNumeric(GateRef gate)
526 {
527     UnOpTypeInfoAccessor tacc(compilationEnv_, circuit_, gate);
528     if (tacc.HasNumberType()) {
529         AddProfiling(gate);
530         LowerPrimitiveTypeToNumber(tacc);
531     }
532 }
533 
LowerPrimitiveTypeToNumber(const UnOpTypeInfoAccessor & tacc)534 void TypedBytecodeLowering::LowerPrimitiveTypeToNumber(const UnOpTypeInfoAccessor &tacc)
535 {
536     GateRef result = builder_.PrimitiveToNumber(tacc.GetValue(), tacc.GetParamType());
537     acc_.ReplaceHirAndReplaceDeadIfException(tacc.GetGate(), builder_.GetStateDepend(), result);
538 }
539 
LowerConditionJump(GateRef gate,bool flag)540 void TypedBytecodeLowering::LowerConditionJump(GateRef gate, bool flag)
541 {
542     ConditionJumpTypeInfoAccessor tacc(compilationEnv_, circuit_, gate);
543     if (TypeInfoAccessor::IsTrustedBooleanType(acc_, tacc.GetValue())) {
544         AddProfiling(gate);
545         SpeculateConditionJump(tacc, flag);
546     }
547 }
548 
SpeculateConditionJump(const ConditionJumpTypeInfoAccessor & tacc,bool flag)549 void TypedBytecodeLowering::SpeculateConditionJump(const ConditionJumpTypeInfoAccessor &tacc, bool flag)
550 {
551     GateRef value = tacc.GetValue();
552     ParamType paramType = ParamType::BooleanType();
553     uint32_t weight = tacc.GetBranchWeight();
554     GateRef jump = Circuit::NullGate();
555     if (flag) {
556         jump = builder_.TypedConditionJump<TypedJumpOp::TYPED_JNEZ>(value, paramType, weight);
557     } else {
558         jump = builder_.TypedConditionJump<TypedJumpOp::TYPED_JEQZ>(value, paramType, weight);
559     }
560     acc_.ReplaceGate(tacc.GetGate(), jump, jump, Circuit::NullGate());
561 }
562 
DeleteConstDataIfNoUser(GateRef gate)563 void TypedBytecodeLowering::DeleteConstDataIfNoUser(GateRef gate)
564 {
565     auto uses = acc_.Uses(gate);
566     if (uses.begin() == uses.end()) {
567         builder_.ClearConstantCache(gate);
568         acc_.DeleteGate(gate);
569     }
570 }
571 
GeneratePrimitiveTypeCheck(CircuitBuilder & builder,GateRef receiver,PrimitiveType primitiveType)572 static void GeneratePrimitiveTypeCheck(CircuitBuilder &builder, GateRef receiver, PrimitiveType primitiveType)
573 {
574     switch (primitiveType) {
575         case PrimitiveType::PRIMITIVE_BOOLEAN:
576             builder.TryPrimitiveTypeCheck(GateType::BooleanType(), receiver);
577             break;
578         case PrimitiveType::PRIMITIVE_NUMBER:
579             builder.TryPrimitiveTypeCheck(GateType::NumberType(), receiver);
580             break;
581         default:
582             LOG_ECMA(FATAL) << "Implementation Error: Unreachable branch.";
583             UNREACHABLE();
584             break;
585     }
586 }
587 
GetPrimitiveTypeProto(PrimitiveType primitiveType)588 GateRef TypedBytecodeLowering::GetPrimitiveTypeProto(PrimitiveType primitiveType)
589 {
590     size_t index = -1;
591     if (primitiveType == PrimitiveType::PRIMITIVE_BOOLEAN) {
592         index = GlobalEnv::BOOLEAN_PROTOTYPE_INDEX;
593     } else if (primitiveType == PrimitiveType::PRIMITIVE_NUMBER) {
594         index = GlobalEnv::NUMBER_PROTOTYPE_INDEX;
595     } else {
596         LOG_ECMA(FATAL) << "Implementation Error: Unreachable branch, not supported primitiveType currently";
597         UNREACHABLE();
598     }
599     ASSERT(index != static_cast<size_t>(-1));
600     return builder_.GetGlobalEnvValue(VariableType::JS_ANY(), glue_, circuit_->GetGlobalEnvCache(), index);
601 }
602 
PolyPrimitiveTypeCheckAndLoad(LoadObjByNameDataInfo & info,std::map<size_t,uint32_t> & typeIndex2HeapConstantIndex)603 void TypedBytecodeLowering::PolyPrimitiveTypeCheckAndLoad(LoadObjByNameDataInfo &info,
604     std::map<size_t, uint32_t> &typeIndex2HeapConstantIndex)
605 {
606     GateRef receiver = info.tacc.GetReceiver();
607     auto itr = typeIndex2HeapConstantIndex.begin();
608     size_t typeCount = info.tacc.GetTypeCount();
609     GateRef gate = info.tacc.GetGate();
610     GateRef frameState = acc_.GetFrameState(gate);
611     for (size_t i = 0; i < typeIndex2HeapConstantIndex.size(); ++i) {
612         auto primitiveType = info.tacc.GetPrimitiveType(itr->first);
613         // only boolean and number are supported currently
614         ASSERT(primitiveType == PrimitiveType::PRIMITIVE_BOOLEAN || primitiveType == PrimitiveType::PRIMITIVE_NUMBER);
615         Label isDesignatePrimitiveType(&builder_);
616         if (i != typeCount - 1) {
617             if (primitiveType == PrimitiveType::PRIMITIVE_NUMBER) {
618                 BRANCH_CIR(builder_.TaggedIsNumber(receiver), &isDesignatePrimitiveType, &info.fails[i]);
619             } else {
620                 BRANCH_CIR(builder_.TaggedIsBoolean(receiver), &isDesignatePrimitiveType, &info.fails[i]);
621             }
622         } else {
623             GeneratePrimitiveTypeCheck(builder_, receiver, primitiveType);
624             builder_.Jump(&isDesignatePrimitiveType);
625         }
626         builder_.Bind(&isDesignatePrimitiveType);
627         GateRef protoType = GetPrimitiveTypeProto(primitiveType);
628         builder_.PrimitiveTypeProtoChangeMarkerCheck(protoType, frameState);
629         GateRef protoConstant = builder_.HeapConstant(itr->second);
630         info.result = BuildNamedPropertyAccess(gate, receiver, protoConstant, info.tacc.GetAccessInfo(i).Plr());
631         builder_.Jump(&info.exit);
632 
633         if (i != typeCount - 1) {
634             builder_.Bind(&info.fails[i]);
635         }
636         itr++;
637     }
638 }
639 
LoadOnPrototypeForHeapObjectReceiver(const LoadObjPropertyTypeInfoAccessor & tacc,Variable & result,LoadObjByNameOnProtoTypeInfo ldProtoInfo)640 void TypedBytecodeLowering::LoadOnPrototypeForHeapObjectReceiver(const LoadObjPropertyTypeInfoAccessor &tacc,
641     Variable &result, LoadObjByNameOnProtoTypeInfo ldProtoInfo)
642 {
643     auto gate = tacc.GetGate();
644     // prototype change marker check
645     if (!TryLazyDeoptStableProtoChain(tacc, ldProtoInfo.typeIndex, gate)) {
646         builder_.ProtoChangeMarkerCheck(tacc.GetReceiver(), ldProtoInfo.frameState);
647     }
648     // lookup from receiver for holder
649     auto prototype = builder_.LoadPrototype(glue_, ldProtoInfo.receiverHC);
650     // lookup from receiver for holder
651     ObjectAccessTypeInfoAccessor::ObjectAccessInfo info = tacc.GetAccessInfo(ldProtoInfo.typeIndex);
652     bool protoConstantFound = false;
653     if (compilationEnv_->SupportHeapConstant()) {
654         auto *jitCompilationEnv = static_cast<JitCompilationEnv*>(compilationEnv_);
655         const auto &holderHClassIndex2HeapConstantIndex =
656             jitCompilationEnv->GetHolderHClassIndex2HeapConstantIndex();
657         auto holderHClassIndex = info.HClassIndex();
658         auto itr = holderHClassIndex2HeapConstantIndex.find(holderHClassIndex);
659         if (itr != holderHClassIndex2HeapConstantIndex.end()) {
660             // holder is HeapConstant, which is recorded at jit profiler. so don't need to visit protochain
661             GateRef protoConstant = builder_.HeapConstant(itr->second);
662             result = BuildNamedPropertyAccess(
663                 gate, tacc.GetReceiver(), protoConstant, tacc.GetAccessInfo(ldProtoInfo.typeIndex).Plr());
664             builder_.Jump(ldProtoInfo.exit);
665             protoConstantFound = true;
666         }
667     }
668     if (!protoConstantFound) {
669         auto holderHC = builder_.GetHClassGateFromIndex(gate, info.HClassIndex());
670         DEFVALUE(current, (&builder_), VariableType::JS_ANY(), prototype);
671         Label loopHead(&builder_);
672         Label loadHolder(&builder_);
673         Label lookUpProto(&builder_);
674         builder_.Jump(&loopHead);
675 
676         builder_.LoopBegin(&loopHead);
677         builder_.DeoptCheck(builder_.TaggedIsNotNull(*current),
678                             ldProtoInfo.frameState, DeoptType::INCONSISTENTHCLASS2);
679         auto curHC = builder_.LoadHClassByConstOffset(glue_, *current);
680         BRANCH_CIR(builder_.Equal(curHC, holderHC), &loadHolder, &lookUpProto);
681 
682         builder_.Bind(&lookUpProto);
683         current =  builder_.LoadPrototype(glue_, curHC);
684         builder_.LoopEnd(&loopHead);
685 
686         builder_.Bind(&loadHolder);
687         result = BuildNamedPropertyAccess(gate, tacc.GetReceiver(),
688                                           *current, tacc.GetAccessInfo(ldProtoInfo.typeIndex).Plr());
689         builder_.Jump(ldProtoInfo.exit);
690     }
691 }
692 
LowerTypedMonoLdObjByNameOnProto(const LoadObjPropertyTypeInfoAccessor & tacc,Variable & result)693 void TypedBytecodeLowering::LowerTypedMonoLdObjByNameOnProto(const LoadObjPropertyTypeInfoAccessor &tacc,
694                                                              Variable &result)
695 {
696     GateRef receiver = tacc.GetReceiver();
697     GateRef gate = tacc.GetGate();
698     PropertyLookupResult plr = tacc.GetAccessInfo(0).Plr();
699     GateRef plrGate = builder_.Int32(plr.GetData());
700     GateRef unsharedConstPool = argAcc_->GetFrameArgsIn(gate, FrameArgIdx::UNSHARED_CONST_POOL);
701     size_t holderHClassIndex = static_cast<size_t>(tacc.GetAccessInfo(0).HClassIndex());
702     if (LIKELY(!plr.IsAccessor())) {
703         result = builder_.MonoLoadPropertyOnProto(receiver, plrGate, unsharedConstPool, holderHClassIndex);
704     } else {
705         result = builder_.MonoCallGetterOnProto(gate, receiver, plrGate, unsharedConstPool, holderHClassIndex);
706     }
707 }
708 
LowerTypedMonoLdObjByName(const LoadObjPropertyTypeInfoAccessor & tacc)709 void TypedBytecodeLowering::LowerTypedMonoLdObjByName(const LoadObjPropertyTypeInfoAccessor &tacc)
710 {
711     GateRef receiver = tacc.GetReceiver();
712     GateRef gate = tacc.GetGate();
713     PrimitiveType primitiveType = tacc.GetPrimitiveType(0);
714     DEFVALUE(result, (&builder_), VariableType::JS_ANY(), builder_.Hole());
715     GateRef frameState = acc_.GetFrameState(gate);
716     if ((primitiveType != PrimitiveType::PRIMITIVE_TYPE_INVALID) && compilationEnv_->SupportHeapConstant()) {
717         Label notPrimitive(&builder_);
718         Label isPrimitive(&builder_);
719         if (primitiveType == PrimitiveType::PRIMITIVE_NUMBER) {
720             Label isNumber(&builder_);
721             BRANCH_CIR(builder_.TaggedIsNumber(receiver), &isNumber, &notPrimitive);
722             builder_.Bind(&isNumber);
723             GateRef protoType = GetPrimitiveTypeProto(PrimitiveType::PRIMITIVE_NUMBER);
724             builder_.PrimitiveTypeProtoChangeMarkerCheck(protoType, frameState);
725             builder_.Jump(&isPrimitive);
726         } else {
727             ASSERT(primitiveType == PrimitiveType::PRIMITIVE_BOOLEAN);
728             Label isBoolean(&builder_);
729             BRANCH_CIR(builder_.TaggedIsBoolean(receiver), &isBoolean, &notPrimitive);
730             builder_.Bind(&isBoolean);
731             GateRef prototype = GetPrimitiveTypeProto(PrimitiveType::PRIMITIVE_BOOLEAN);
732             builder_.PrimitiveTypeProtoChangeMarkerCheck(prototype, frameState);
733             builder_.Jump(&isPrimitive);
734         }
735         builder_.Bind(&notPrimitive);
736         {
737             builder_.ObjectTypeCheck(false, receiver, tacc.GetExpectedHClassIndexList(0), frameState);
738             builder_.ProtoChangeMarkerCheck(receiver, frameState);
739             builder_.Jump(&isPrimitive);
740         }
741         builder_.Bind(&isPrimitive);
742         LowerTypedMonoLdObjByNameOnProto(tacc, result);
743     } else {
744         builder_.ObjectTypeCheck(false, receiver, tacc.GetExpectedHClassIndexList(0), frameState);
745         if (IsNonExist(tacc, 0)) {
746             if (TryLazyDeoptStableProtoChain(tacc, 0, gate)) {
747                 result = builder_.Undefined();
748             } else {
749                 builder_.DeoptCheck(builder_.Boolean(false), frameState, DeoptType::PROTOTYPECHANGED4);
750             }
751         } else {
752             if (tacc.IsReceiverEqHolder(0)) {
753                 result = BuildNamedPropertyAccess(gate, receiver, receiver, tacc.GetAccessInfo(0).Plr());
754             } else {
755                 if (!TryLazyDeoptStableProtoChain(tacc, 0, gate)) {
756                     builder_.ProtoChangeMarkerCheck(receiver, frameState);
757                 }
758                 LowerTypedMonoLdObjByNameOnProto(tacc, result);
759             }
760         }
761     }
762     ReplaceHirWithCheckingAccessor(glue_, gate, builder_.GetStateDepend(), *result,
763         tacc.GetAccessInfo(0).Plr().IsAccessor());
764     DeleteConstDataIfNoUser(tacc.GetKey());
765 }
766 
GenerateMergedHClassListCheck(LoadObjByNameDataInfo & info,Label & hclassCheckExit,Variable & checkResult,size_t index,GateRef receiverHC)767 void TypedBytecodeLowering::GenerateMergedHClassListCheck(LoadObjByNameDataInfo &info, Label &hclassCheckExit,
768     Variable &checkResult, size_t index, GateRef receiverHC)
769 {
770     std::vector<Label> ifFalse;
771     Label resultIsTrue(&builder_);
772     Label resultIsFalse(&builder_);
773     const auto& hclassList = info.tacc.GetExpectedHClassIndexList(index);
774     size_t hclassCount = hclassList.size();
775 
776     for (size_t j = 0; j < hclassCount - 1; j++) {
777         ifFalse.emplace_back(Label(&builder_));
778     }
779     for (size_t j = 0; j < hclassCount; j++) {
780         auto expected = builder_.GetHClassGateFromIndex(info.tacc.GetGate(), hclassList[j]);
781         if (j != hclassCount - 1) {
782             BRANCH_CIR(builder_.Equal(receiverHC, expected), &resultIsTrue, &ifFalse[j]);
783             builder_.Bind(&ifFalse[j]);
784         } else {
785             BRANCH_CIR(builder_.Equal(receiverHC, expected), &resultIsTrue, &resultIsFalse);
786         }
787     }
788     builder_.Bind(&resultIsFalse);
789     {
790         checkResult = builder_.Boolean(false);
791         builder_.Jump(&hclassCheckExit);
792     }
793     builder_.Bind(&resultIsTrue);
794     {
795         checkResult = builder_.Boolean(true);
796         builder_.Jump(&hclassCheckExit);
797     }
798 }
799 
PolyHeapObjectCheckAndLoad(LoadObjByNameDataInfo & info,const std::map<size_t,uint32_t> & typeIndex2HeapConstantIndex)800 void TypedBytecodeLowering::PolyHeapObjectCheckAndLoad(LoadObjByNameDataInfo &info,
801     const std::map<size_t, uint32_t> &typeIndex2HeapConstantIndex)
802 {
803     GateRef gate = info.tacc.GetGate();
804     GateRef frameState = acc_.GetFrameState(gate);
805     builder_.HeapObjectCheck(info.tacc.GetReceiver(), frameState);
806     auto receiverHC = builder_.LoadHClassByConstOffset(glue_, info.tacc.GetReceiver());
807     size_t labelIndex = typeIndex2HeapConstantIndex.size();
808     size_t typeCount = info.tacc.GetTypeCount();
809     for (size_t i = 0; i < typeCount; ++i) {
810         if (typeIndex2HeapConstantIndex.find(i) != typeIndex2HeapConstantIndex.end()) {
811             continue;
812         }
813         Label hclassCheckExit(&builder_);
814         DEFVALUE(checkResult, (&builder_), VariableType::BOOL(), builder_.Boolean(false));
815         GenerateMergedHClassListCheck(info, hclassCheckExit, checkResult, i, receiverHC);
816         builder_.Bind(&hclassCheckExit);
817         if (labelIndex != typeCount - 1) {
818             BRANCH_CIR(*checkResult, &info.loaders[labelIndex], &info.fails[labelIndex]);
819             builder_.Bind(&info.loaders[labelIndex]);
820         } else {
821             // Deopt if fails at last hclass compare
822             builder_.DeoptCheck(*checkResult, frameState, DeoptType::INCONSISTENTHCLASS1);
823         }
824 
825         if (IsNonExist(info.tacc, i)) {
826             if (TryLazyDeoptStableProtoChain(info.tacc, i, gate)) {
827                 info.result = builder_.Undefined();
828                 builder_.Jump(&info.exit);
829             } else {
830                 builder_.DeoptCheck(builder_.Boolean(false), frameState, DeoptType::PROTOTYPECHANGED4);
831                 builder_.Jump(&info.exit);
832             }
833         } else {
834             if (info.tacc.IsReceiverEqHolder(i)) {
835                 info.result = BuildNamedPropertyAccess(gate, info.tacc.GetReceiver(), info.tacc.GetReceiver(),
836                                                        info.tacc.GetAccessInfo(i).Plr());
837                 builder_.Jump(&info.exit);
838             } else {
839                 LoadOnPrototypeForHeapObjectReceiver(info.tacc, info.result,
840                     { gate, frameState, receiverHC, &info.exit, i });
841             }
842         }
843         if (labelIndex != typeCount - 1) {
844             builder_.Bind(&info.fails[labelIndex]);
845         }
846         labelIndex++;
847     }
848 }
849 
LowerTypedPolyLdObjByName(const LoadObjPropertyTypeInfoAccessor & tacc)850 void TypedBytecodeLowering::LowerTypedPolyLdObjByName(const LoadObjPropertyTypeInfoAccessor &tacc)
851 {
852     DEFVALUE(result, (&builder_), VariableType::JS_ANY(), builder_.Hole());
853     size_t typeCount = tacc.GetTypeCount();
854     std::vector<Label> loaders;
855     std::vector<Label> fails;
856     ASSERT(typeCount > 0);
857     bool hasGetter = false;
858     for (size_t i = 0; i < typeCount; ++i) {
859         hasGetter |= tacc.GetAccessInfo(i).Plr().IsAccessor();
860     }
861     for (size_t i = 0; i < typeCount - 1; ++i) {
862         loaders.emplace_back(Label(&builder_));
863         fails.emplace_back(Label(&builder_));
864     }
865     Label exit(&builder_);
866     GateRef gate = tacc.GetGate();
867     std::map<size_t, uint32_t> typeIndex2HeapConstantIndex = tacc.CollectPrimitiveTypeInfo(compilationEnv_);
868     LoadObjByNameDataInfo info(loaders, fails, tacc, result, exit);
869     if (!typeIndex2HeapConstantIndex.empty()) {
870         PolyPrimitiveTypeCheckAndLoad(info, typeIndex2HeapConstantIndex);
871     }
872 
873     if (typeIndex2HeapConstantIndex.size() < typeCount) {
874         PolyHeapObjectCheckAndLoad(info, typeIndex2HeapConstantIndex);
875     }
876     builder_.Bind(&exit);
877     ReplaceHirWithCheckingAccessor(glue_, gate, builder_.GetStateDepend(), *result,
878         hasGetter);
879     DeleteConstDataIfNoUser(tacc.GetKey());
880 }
881 
LowerTypedLdObjByName(GateRef gate)882 void TypedBytecodeLowering::LowerTypedLdObjByName(GateRef gate)
883 {
884     LoadObjPropertyTypeInfoAccessor tacc(compilationEnv_, circuit_, gate, chunk_);
885 
886     if (TryLowerTypedLdobjBynameFromGloablBuiltin(gate)) {
887         return;
888     }
889     if (TryLowerTypedLdObjByNameForBuiltin(gate)) {
890         return;
891     }
892     if (tacc.TypesIsEmpty() || tacc.HasIllegalType()) {
893         return;
894     }
895     if (enableMergePoly_) {
896         tacc.TryMergeExpectedHClass();
897     }
898     AddProfiling(gate);
899     if (tacc.IsMono()) {
900         LowerTypedMonoLdObjByName(tacc);
901         return;
902     }
903     LowerTypedPolyLdObjByName(tacc);
904 }
905 
LowerTypedLdPrivateProperty(GateRef gate)906 void TypedBytecodeLowering::LowerTypedLdPrivateProperty(GateRef gate)
907 {
908     LoadPrivatePropertyTypeInfoAccessor tacc(compilationEnv_, circuit_, gate, chunk_);
909 
910     if (tacc.HasIllegalType()) {
911         return;
912     }
913 
914     AddProfiling(gate);
915     Label exit(&builder_);
916 
917     GateRef receiver = tacc.GetReceiver();
918     GateRef levelIndex = tacc.GetLevelIndex();
919     GateRef slotIndex = tacc.GetSlotIndex();
920 
921     DEFVALUE(result, (&builder_), VariableType::JS_ANY(), builder_.Undefined());
922     GateRef frameState = acc_.FindNearestFrameState(builder_.GetDepend());
923     GateRef key = builder_.GetKeyFromLexivalEnv(glue_,
924         tacc.GetLexicalEnv(), builder_.TaggedGetInt(levelIndex), builder_.TaggedGetInt(slotIndex));
925 
926     builder_.HeapObjectCheck(key, frameState);
927     if (tacc.IsAccessor()) {
928         builder_.DeoptCheck(builder_.IsJSFunction(glue_, key), frameState, DeoptType::NOTJSFUNCTION);
929         result = builder_.CallPrivateGetter(gate, receiver, key);
930         builder_.Jump(&exit);
931     } else {
932         builder_.DeoptCheck(builder_.TaggedIsSymbol(glue_, key), frameState, DeoptType::NOTSYMBOL);
933         builder_.ObjectTypeCheck(false, receiver, builder_.Int32(tacc.GetExpectedHClassIndex(0)), frameState);
934         result = BuildNamedPropertyAccess(gate, receiver, receiver, tacc.GetAccessInfo(0).Plr());
935         builder_.Jump(&exit);
936     }
937 
938     builder_.Bind(&exit);
939     ReplaceHirWithCheckingAccessor(glue_, gate, builder_.GetStateDepend(), *result, tacc.IsAccessor());
940     DeleteConstDataIfNoUser(key);
941 }
942 
LowerTypedStPrivateProperty(GateRef gate)943 void TypedBytecodeLowering::LowerTypedStPrivateProperty(GateRef gate)
944 {
945     StorePrivatePropertyTypeInfoAccessor tacc(compilationEnv_, circuit_, gate, chunk_);
946 
947     if (tacc.HasIllegalType()) {
948         return;
949     }
950 
951     AddProfiling(gate);
952     Label exit(&builder_);
953 
954     GateRef receiver = tacc.GetReceiver();
955     GateRef levelIndex = tacc.GetLevelIndex();
956     GateRef slotIndex = tacc.GetSlotIndex();
957     GateRef value = tacc.GetValue();
958 
959     GateRef frameState = acc_.FindNearestFrameState(builder_.GetDepend());
960     GateRef key = builder_.GetKeyFromLexivalEnv(glue_,
961         tacc.GetLexicalEnv(), builder_.TaggedGetInt(levelIndex), builder_.TaggedGetInt(slotIndex));
962 
963     builder_.HeapObjectCheck(key, frameState);
964     if (tacc.IsAccessor()) {
965         builder_.DeoptCheck(builder_.IsJSFunction(glue_, key), frameState, DeoptType::NOTJSFUNCTION);
966         builder_.CallPrivateSetter(gate, receiver, key, value);
967         builder_.Jump(&exit);
968     } else {
969         builder_.DeoptCheck(builder_.TaggedIsSymbol(glue_, key), frameState, DeoptType::NOTSYMBOL);
970         builder_.ObjectTypeCheck(false, receiver, builder_.Int32(tacc.GetExpectedHClassIndex(0)), frameState);
971         BuildNamedPropertyAccess(
972             gate, receiver, receiver, value, tacc.GetAccessInfo(0).Plr(), tacc.GetExpectedHClassIndex(0));
973         builder_.Jump(&exit);
974     }
975 
976     builder_.Bind(&exit);
977     ReplaceHirWithCheckingAccessor(glue_, gate, builder_.GetStateDepend(), Circuit::NullGate(), tacc.IsAccessor());
978     DeleteConstDataIfNoUser(key);
979 }
980 
RecordGate2HeapConstantIndex(CompilationEnv * compilationEnv,uint32_t methodOffset,uint32_t keyIndex,GateRef resultGate)981 static void RecordGate2HeapConstantIndex(CompilationEnv *compilationEnv, uint32_t methodOffset,
982                                          uint32_t keyIndex, GateRef resultGate)
983 {
984     if (!compilationEnv->SupportHeapConstant()) {
985         return;
986     }
987     auto *jitCompilationEnv = static_cast<JitCompilationEnv*>(compilationEnv);
988     JSTaggedValue strObj = jitCompilationEnv->GetStringFromConstantPool(methodOffset, keyIndex, false);
989     if (strObj.IsUndefined()) {
990         return;
991     }
992     JSHandle<JSTaggedValue> strObjHandle = jitCompilationEnv->NewJSHandle(strObj);
993     auto constpool = jitCompilationEnv->GetConstantPoolByMethodOffset(methodOffset);
994     ASSERT(!constpool.IsUndefined());
995     auto constpoolId = static_cast<uint32_t>(
996         ConstantPool::Cast(constpool.GetTaggedObject())->GetSharedConstpoolId().GetInt());
997     uint32_t indexInConstantTable = jitCompilationEnv->RecordHeapConstant(
998         { constpoolId, keyIndex, JitCompilationEnv::IN_SHARED_CONSTANTPOOL }, strObjHandle);
999     jitCompilationEnv->RecordGate2HeapConstantIndex(resultGate, indexInConstantTable);
1000 }
1001 
LowerTypedStObjByName(GateRef gate)1002 void TypedBytecodeLowering::LowerTypedStObjByName(GateRef gate)
1003 {
1004     StoreObjByNameTypeInfoAccessor tacc(compilationEnv_, circuit_, gate, chunk_);
1005     if (tacc.TypesIsEmpty() || tacc.HasIllegalType()) {
1006         return;
1007     }
1008     size_t typeCount = tacc.GetTypeCount();
1009     std::vector<Label> loaders;
1010     std::vector<Label> fails;
1011     ASSERT(typeCount > 0);
1012     for (size_t i = 0; i < typeCount - 1; ++i) {
1013         loaders.emplace_back(Label(&builder_));
1014         fails.emplace_back(Label(&builder_));
1015     }
1016     Label exit(&builder_);
1017     AddProfiling(gate);
1018     GateRef frameState = Circuit::NullGate();
1019     auto opcode = acc_.GetByteCodeOpcode(gate);
1020     // The framestate of Call and Accessor related instructions directives is placed on IR. Using the depend edge to
1021     // climb up and find the nearest framestate for other instructions
1022     if (opcode == EcmaOpcode::STOWNBYNAME_IMM8_ID16_V8 ||
1023         opcode == EcmaOpcode::STOWNBYNAME_IMM16_ID16_V8) {
1024         frameState = acc_.FindNearestFrameState(builder_.GetDepend());
1025     } else if (opcode == EcmaOpcode::STOBJBYNAME_IMM8_ID16_V8 ||
1026                opcode == EcmaOpcode::STOBJBYNAME_IMM16_ID16_V8 ||
1027                opcode == EcmaOpcode::STTHISBYNAME_IMM8_ID16 ||
1028                opcode == EcmaOpcode::STTHISBYNAME_IMM16_ID16 ||
1029                opcode == EcmaOpcode::DEFINEFIELDBYNAME_IMM8_ID16_V8 ||
1030                opcode == EcmaOpcode::DEFINEPROPERTYBYNAME_IMM8_ID16_V8) {
1031         frameState = acc_.GetFrameState(gate);
1032     } else {
1033         UNREACHABLE();
1034     }
1035     if (tacc.IsMono()) {
1036         GateRef receiver = tacc.GetReceiver();
1037         builder_.ObjectTypeCheck(false, receiver,
1038                                  builder_.Int32(tacc.GetExpectedHClassIndex(0)), frameState);
1039         if (tacc.IsReceiverNoEqNewHolder(0)) {
1040             if (!TryLazyDeoptStableProtoChain(tacc, 0, gate)) {
1041                 builder_.ProtoChangeMarkerCheck(receiver, frameState);
1042             }
1043             PropertyLookupResult plr = tacc.GetAccessInfo(0).Plr();
1044             GateRef plrGate = builder_.Int32(plr.GetData());
1045             GateRef unsharedConstPool = argAcc_->GetFrameArgsIn(gate, FrameArgIdx::UNSHARED_CONST_POOL);
1046             size_t holderHClassIndex = static_cast<size_t>(tacc.GetAccessInfo(0).HClassIndex());
1047             GateRef value = tacc.GetValue();
1048             if (tacc.IsHolderEqNewHolder(0)) {
1049                 builder_.MonoStorePropertyLookUpProto(tacc.GetReceiver(), plrGate, unsharedConstPool, holderHClassIndex,
1050                                                       value);
1051             } else {
1052                 if (!tacc.IsPrototypeHclass(0)) {
1053                     if (!TryLazyDeoptNotPrototype(tacc, 0, gate)) {
1054                         builder_.DeoptCheck(builder_.BoolNot(builder_.IsPrototypeHClass(tacc.GetReceiver())),
1055                             frameState, DeoptType::PROTOTYPECHANGED3);
1056                     }
1057                 }
1058                 GateRef ret = builder_.MonoStoreProperty(tacc.GetReceiver(), plrGate, unsharedConstPool,
1059                     holderHClassIndex, value, builder_.TruncInt64ToInt32(tacc.GetKey()),
1060                     builder_.Boolean(tacc.IsPrototypeHclass(0)), frameState);
1061                 auto methodOffset = acc_.TryGetMethodOffset(gate);
1062                 uint32_t keyIndex = static_cast<uint32_t>(acc_.GetConstantValue(tacc.GetKey()));
1063                 RecordGate2HeapConstantIndex(compilationEnv_, methodOffset, keyIndex, ret);
1064             }
1065         } else if (tacc.IsReceiverEqHolder(0)) {
1066             BuildNamedPropertyAccess(gate, tacc.GetReceiver(), tacc.GetReceiver(),
1067                                      tacc.GetValue(), tacc.GetAccessInfo(0).Plr(), tacc.GetExpectedHClassIndex(0));
1068         }
1069         ReplaceHirWithCheckingAccessor(glue_, gate, builder_.GetStateDepend(), Circuit::NullGate(),
1070             tacc.GetAccessInfo(0).Plr().IsAccessor());
1071         DeleteConstDataIfNoUser(tacc.GetKey());
1072         return;
1073     }
1074     builder_.HeapObjectCheck(tacc.GetReceiver(), frameState);
1075     auto receiverHC = builder_.LoadHClassByConstOffset(glue_, tacc.GetReceiver());
1076     bool hasSetter = false;
1077     for (size_t i = 0; i < typeCount; ++i) {
1078         hasSetter |= tacc.GetAccessInfo(i).Plr().IsAccessor();
1079         auto expected = builder_.GetHClassGateFromIndex(gate, tacc.GetExpectedHClassIndex(i));
1080         if (i != typeCount - 1) {
1081             BRANCH_CIR(builder_.Equal(receiverHC, expected),
1082                 &loaders[i], &fails[i]);
1083             builder_.Bind(&loaders[i]);
1084         } else {
1085             builder_.DeoptCheck(builder_.Equal(receiverHC, expected), frameState, DeoptType::INCONSISTENTHCLASS3);
1086         }
1087         if (tacc.IsReceiverNoEqNewHolder(i)) {
1088             if (!TryLazyDeoptStableProtoChain(tacc, i, gate)) {
1089                 builder_.ProtoChangeMarkerCheck(tacc.GetReceiver(), frameState);
1090             }
1091             if (tacc.IsHolderEqNewHolder(i)) {
1092                 // lookup from receiver for holder
1093                 auto prototype = builder_.LoadPrototype(glue_, receiverHC);
1094                 auto holderHC = builder_.GetHClassGateFromIndex(gate, tacc.GetAccessInfo(i).HClassIndex());
1095                 DEFVALUE(current, (&builder_), VariableType::JS_ANY(), prototype);
1096                 Label loopHead(&builder_);
1097                 Label loadHolder(&builder_);
1098                 Label lookUpProto(&builder_);
1099                 builder_.Jump(&loopHead);
1100 
1101                 builder_.LoopBegin(&loopHead);
1102                 builder_.DeoptCheck(builder_.TaggedIsNotNull(*current), frameState, DeoptType::INCONSISTENTHCLASS4);
1103                 auto curHC = builder_.LoadHClassByConstOffset(glue_, *current);
1104                 BRANCH_CIR(builder_.Equal(curHC, holderHC), &loadHolder, &lookUpProto);
1105 
1106                 builder_.Bind(&lookUpProto);
1107                 current = builder_.LoadPrototype(glue_, curHC);
1108                 builder_.LoopEnd(&loopHead);
1109 
1110                 builder_.Bind(&loadHolder);
1111                 BuildNamedPropertyAccess(gate, tacc.GetReceiver(), *current, tacc.GetValue(),
1112                                          tacc.GetAccessInfo(i).Plr());
1113                 builder_.Jump(&exit);
1114             } else {
1115                 TypedStObjByNameTransition(gate, receiverHC, frameState, exit, tacc, i);
1116             }
1117         } else if (tacc.IsReceiverEqHolder(i)) {
1118             // Local
1119             BuildNamedPropertyAccess(gate, tacc.GetReceiver(), tacc.GetReceiver(),
1120                                      tacc.GetValue(), tacc.GetAccessInfo(i).Plr());
1121             builder_.Jump(&exit);
1122         } else {
1123             // find in prototype, same as transition
1124             UNREACHABLE();
1125             return;
1126         }
1127         if (i != typeCount - 1) {
1128             // process fastpath for next type
1129             builder_.Bind(&fails[i]);
1130         }
1131     }
1132     builder_.Bind(&exit);
1133     ReplaceHirWithCheckingAccessor(glue_, gate, builder_.GetStateDepend(), Circuit::NullGate(), hasSetter);
1134     DeleteConstDataIfNoUser(tacc.GetKey());
1135 }
1136 
TypedStObjByNameTransition(GateRef gate,GateRef receiverHC,GateRef frameState,Label & exit,StoreObjByNameTypeInfoAccessor & tacc,size_t i)1137 void TypedBytecodeLowering::TypedStObjByNameTransition(GateRef gate, GateRef receiverHC, GateRef frameState,
1138                                                        Label &exit, StoreObjByNameTypeInfoAccessor &tacc, size_t i)
1139 {
1140     Label notProto(&builder_);
1141     Label isProto(&builder_);
1142     auto newHolderHC = builder_.GetHClassGateFromIndex(gate, tacc.GetAccessInfo(i).HClassIndex());
1143     if (compilationEnv_->IsAotCompiler()) {
1144         auto prototype = builder_.LoadPrototype(glue_, receiverHC);
1145         builder_.StoreConstOffset(VariableType::JS_ANY(), newHolderHC, JSHClass::PROTOTYPE_OFFSET, prototype);
1146     }
1147     if (!tacc.IsPrototypeHclass(i)) {
1148         if (!TryLazyDeoptNotPrototype(tacc, i, gate)) {
1149             builder_.DeoptCheck(builder_.BoolNot(builder_.IsPrototypeHClass(tacc.GetReceiver())),
1150                 frameState, DeoptType::PROTOTYPECHANGED3);
1151         }
1152     } else {
1153         builder_.Branch(builder_.IsPrototypeHClass(receiverHC), &isProto, &notProto,
1154                         BranchWeight::ONE_WEIGHT, BranchWeight::DEOPT_WEIGHT, "isPrototypeHClass");
1155         builder_.Bind(&isProto);
1156         GateRef propKey =
1157             builder_.GetObjectByIndexFromConstPool(glue_, gate, frameState,
1158                                                    builder_.TruncInt64ToInt32(tacc.GetKey()), ConstPoolType::STRING);
1159         builder_.CallRuntime(glue_, RTSTUB_ID(UpdateAOTHClass), Gate::InvalidGateRef,
1160                              { receiverHC, newHolderHC, propKey }, gate);
1161         builder_.Jump(&notProto);
1162         builder_.Bind(&notProto);
1163     }
1164     MemoryAttribute mAttr = MemoryAttribute::NeedBarrierAndAtomic();
1165     builder_.TransitionHClassByConstOffset(glue_, tacc.GetReceiver(), newHolderHC, mAttr);
1166     if (!tacc.GetAccessInfo(i).Plr().IsInlinedProps()) {
1167         auto properties = builder_.LoadConstOffset(VariableType::JS_ANY(), tacc.GetReceiver(),
1168                                                    JSObject::PROPERTIES_OFFSET);
1169         auto capacity = builder_.LoadConstOffset(VariableType::INT32(), properties, TaggedArray::LENGTH_OFFSET);
1170         auto index = builder_.Int32(tacc.GetAccessInfo(i).Plr().GetOffset());
1171         Label needExtend(&builder_);
1172         Label notExtend(&builder_);
1173         BRANCH_CIR(builder_.Int32UnsignedLessThan(index, capacity), &notExtend, &needExtend);
1174         builder_.Bind(&notExtend);
1175         BuildNamedPropertyAccess(gate, tacc.GetReceiver(), tacc.GetReceiver(), tacc.GetValue(),
1176                                  tacc.GetAccessInfo(i).Plr());
1177         builder_.Jump(&exit);
1178         builder_.Bind(&needExtend);
1179         builder_.CallRuntime(glue_, RTSTUB_ID(PropertiesSetValue), Gate::InvalidGateRef,
1180                              { tacc.GetReceiver(), tacc.GetValue(), properties, builder_.Int32ToTaggedInt(capacity),
1181                                builder_.Int32ToTaggedInt(index) }, gate);
1182         builder_.Jump(&exit);
1183     } else {
1184         BuildNamedPropertyAccess(gate, tacc.GetReceiver(), tacc.GetReceiver(), tacc.GetValue(),
1185                                  tacc.GetAccessInfo(i).Plr());
1186         builder_.Jump(&exit);
1187     }
1188 }
1189 
LowerTypedStOwnByName(GateRef gate)1190 void TypedBytecodeLowering::LowerTypedStOwnByName(GateRef gate)
1191 {
1192     LowerTypedStObjByName(gate);
1193 }
1194 
BuildNamedPropertyAccess(GateRef hir,GateRef receiver,GateRef holder,PropertyLookupResult plr)1195 GateRef TypedBytecodeLowering::BuildNamedPropertyAccess(
1196     GateRef hir, GateRef receiver, GateRef holder, PropertyLookupResult plr)
1197 {
1198     GateRef plrGate = builder_.Int32(plr.GetData());
1199     GateRef result = Circuit::NullGate();
1200     if (LIKELY(!plr.IsAccessor())) {
1201         result = builder_.LoadProperty(holder, plrGate, plr.IsFunction());
1202     } else {
1203         result = builder_.CallGetter(hir, receiver, holder, plrGate);
1204     }
1205     return result;
1206 }
1207 
BuildNamedPropertyAccess(GateRef hir,GateRef receiver,GateRef holder,GateRef value,PropertyLookupResult plr,uint32_t receiverHClassIndex)1208 GateRef TypedBytecodeLowering::BuildNamedPropertyAccess(
1209     GateRef hir, GateRef receiver, GateRef holder, GateRef value, PropertyLookupResult plr,
1210     uint32_t receiverHClassIndex)
1211 {
1212     GateRef plrGate = builder_.Int32(plr.GetData());
1213     GateRef result = Circuit::NullGate();
1214     if (LIKELY(!plr.IsAccessor())) {
1215         builder_.StoreProperty(receiver, plrGate, value, receiverHClassIndex);
1216     } else {
1217         builder_.CallSetter(hir, receiver, holder, plrGate, value);
1218     }
1219     return result;
1220 }
1221 
TryLowerTypedLdObjByNameForBuiltin(GateRef gate)1222 bool TypedBytecodeLowering::TryLowerTypedLdObjByNameForBuiltin(GateRef gate)
1223 {
1224     LoadBuiltinObjTypeInfoAccessor tacc(compilationEnv_, circuit_, gate, chunk_);
1225     // Just supported mono.
1226     if (tacc.IsMono()) {
1227         if (tacc.IsBuiltinsType()) {
1228             auto builtinsId = tacc.GetBuiltinsTypeId();
1229             if (builtinsId.has_value()) {
1230                 if (TryLowerTypedLdObjByNameForBuiltin(tacc)) {
1231                     return true;
1232                 }
1233                 return TryLowerTypedLdObjByNameForBuiltinMethod(tacc, builtinsId.value());
1234             }
1235         } else if (tacc.IsGlobalsType()) {
1236             auto globalsId = tacc.GetGlobalsId();
1237             if (globalsId.has_value()) {
1238                 return TryLowerTypedLdObjByNameForGlobalsId(tacc, globalsId.value());
1239             }
1240         }
1241     } else if (tacc.GetTypeCount() > 0) {
1242         auto builtinsId = tacc.GetBuiltinsTypeId();
1243         if (builtinsId.has_value()) {
1244             return TryLowerTypedLdObjByNameForBuiltin(tacc);
1245         }
1246     }
1247     return false; // No lowering performed
1248 }
1249 
TryLowerTypedLdObjByNameForBuiltin(const LoadBuiltinObjTypeInfoAccessor & tacc)1250 bool TypedBytecodeLowering::TryLowerTypedLdObjByNameForBuiltin(const LoadBuiltinObjTypeInfoAccessor &tacc)
1251 {
1252     JSTaggedValue key = tacc.GetKeyTaggedValue();
1253     if (key.IsUndefined()) {
1254         return false;
1255     }
1256     EcmaString *propString = EcmaString::Cast(key.GetTaggedObject());
1257     // (1) get length
1258     EcmaString *lengthString =
1259         EcmaString::Cast(compilationEnv_->GlobalConstants()->GetLengthString().GetTaggedObject());
1260     if (propString == lengthString) {
1261         if (tacc.IsBuiltinsArray()) {
1262             LowerTypedLdArrayLength(tacc);
1263             return true;
1264         }
1265         if (tacc.IsBuiltinsString()) {
1266             LowerTypedLdStringLength(tacc);
1267             return true;
1268         }
1269         if (tacc.IsBuiltinsTypeArray()) {
1270             LowerTypedLdTypedArrayLength(tacc);
1271             return true;
1272         }
1273     }
1274 
1275     EcmaString *sizeString = EcmaString::Cast(compilationEnv_->GlobalConstants()->GetSizeString().GetTaggedObject());
1276     if (propString == sizeString) {
1277         if (tacc.IsBuiltinsMap()) {
1278             LowerTypedLdMapSize(tacc);
1279             return true;
1280         }
1281     }
1282 
1283     // (2) other functions
1284     return false;
1285 }
1286 
SetPlrLdFromIterResult(GlobalEnvField index,PropertyLookupResult & plr)1287 static void SetPlrLdFromIterResult(GlobalEnvField index, PropertyLookupResult &plr)
1288 {
1289     if (index == GlobalEnvField::ITERATOR_RESULT_CLASS_INDEX) {
1290         plr.SetIsLoadFromIterResult(true);
1291     }
1292 }
1293 
TryLowerTypedLdObjByNameForGlobalsId(const LoadBuiltinObjTypeInfoAccessor & tacc,GlobalIndex globalsId)1294 bool TypedBytecodeLowering::TryLowerTypedLdObjByNameForGlobalsId(const LoadBuiltinObjTypeInfoAccessor &tacc,
1295                                                                  GlobalIndex globalsId)
1296 {
1297     GateRef receiver = tacc.GetReceiver();
1298     GateRef gate = tacc.GetGate();
1299     JSTaggedValue key = tacc.GetKeyTaggedValue();
1300     if (key.IsUndefined()) {
1301         return false;
1302     }
1303     GateRef frameState = acc_.FindNearestFrameState(gate);
1304     if (globalsId.IsGlobalConstId()) {
1305         ConstantIndex index = static_cast<ConstantIndex>(globalsId.GetGlobalConstId());
1306         JSHClass *hclass = JSHClass::Cast(compilationEnv_->GlobalConstants()->GetGlobalConstantObject(
1307             static_cast<size_t>(index)).GetTaggedObject());
1308         PropertyLookupResult plr = JSHClass::LookupPropertyInBuiltinHClass(compilationEnv_->GetJSThread(), hclass, key);
1309         if (!plr.IsFound() || plr.IsAccessor()) {
1310             return false;
1311         }
1312         AddProfiling(gate);
1313         // 1. check hclass
1314         builder_.HeapObjectCheck(receiver, frameState);
1315         GateRef receiverHClass = builder_.LoadHClassByConstOffset(glue_, receiver);
1316         GateRef expectedHClass = builder_.GetGlobalConstantValue(index);
1317         builder_.DeoptCheck(builder_.Equal(receiverHClass, expectedHClass), frameState,
1318                             DeoptType::INCONSISTENTHCLASS11);
1319         // 2. load property
1320         GateRef plrGate = builder_.Int32(plr.GetData());
1321         GateRef result = builder_.LoadProperty(receiver, plrGate, plr.IsFunction());
1322         acc_.ReplaceHirAndReplaceDeadIfException(gate, builder_.GetStateDepend(), result);
1323         DeleteConstDataIfNoUser(tacc.GetKey());
1324         return true;
1325     } else if (globalsId.IsGlobalEnvId()) { // ctor Hclass
1326         GlobalEnvField index = static_cast<GlobalEnvField>(globalsId.GetGlobalEnvId());
1327         JSHClass *hclass = JSHClass::Cast(compilationEnv_->GetGlobalEnv()->GetGlobalEnvObjectByIndex(
1328             static_cast<size_t>(index))->GetTaggedObject());
1329         PropertyLookupResult plr = JSHClass::LookupPropertyInBuiltinHClass(compilationEnv_->GetJSThread(), hclass, key);
1330         if (!plr.IsFound() || plr.IsAccessor()) {
1331             return false;
1332         }
1333         SetPlrLdFromIterResult(index, plr);
1334         AddProfiling(gate);
1335         // 1. check hclass
1336         builder_.HeapObjectCheck(receiver, frameState);
1337         GateRef receiverHClass = builder_.LoadHClassByConstOffset(glue_, receiver);
1338         GateRef globalEnvObj = builder_.GetGlobalEnvObj(circuit_->GetGlobalEnvCache(), static_cast<size_t>(index));
1339         builder_.DeoptCheck(builder_.Equal(receiverHClass, globalEnvObj), frameState,
1340                             DeoptType::INCONSISTENTHCLASS12);
1341         // 2. load property
1342         GateRef plrGate = builder_.Int32(plr.GetData());
1343         GateRef result = builder_.LoadProperty(receiver, plrGate, plr.IsFunction());
1344         acc_.ReplaceHirAndReplaceDeadIfException(gate, builder_.GetStateDepend(), result);
1345         DeleteConstDataIfNoUser(tacc.GetKey());
1346         return true;
1347     }
1348     return false;
1349 }
1350 
TryLowerTypedLdobjBynameFromGloablBuiltin(GateRef gate)1351 bool TypedBytecodeLowering::TryLowerTypedLdobjBynameFromGloablBuiltin(GateRef gate)
1352 {
1353     LoadBuiltinObjTypeInfoAccessor tacc(compilationEnv_, circuit_, gate, chunk_);
1354     GateRef receiver = tacc.GetReceiver();
1355     if (acc_.GetOpCode(receiver) != OpCode::LOAD_BUILTIN_OBJECT) {
1356         return false;
1357     }
1358     JSHandle<GlobalEnv> globalEnv = compilationEnv_->GetGlobalEnv();
1359     uint64_t index = acc_.TryGetValue(receiver);
1360     BuiltinType type = static_cast<BuiltinType>(index);
1361     if (type == BuiltinType::BT_MATH) {
1362         auto math = globalEnv->GetMathFunction();
1363         JSHClass *hclass = math.GetTaggedValue().GetTaggedObject()->GetClass();
1364         JSTaggedValue key = tacc.GetKeyTaggedValue();
1365         if (key.IsUndefined()) {
1366             return false;
1367         }
1368         PropertyLookupResult plr = JSHClass::LookupPropertyInBuiltinHClass(compilationEnv_->GetJSThread(), hclass, key);
1369         if (!plr.IsFound() || plr.IsAccessor()) {
1370             return false;
1371         }
1372         AddProfiling(gate);
1373         builder_.MathHClassConsistencyCheck(receiver);
1374         GateRef plrGate = builder_.Int32(plr.GetData());
1375         GateRef result = builder_.LoadProperty(receiver, plrGate, plr.IsFunction());
1376         acc_.ReplaceHirAndReplaceDeadIfException(gate, builder_.GetStateDepend(), result);
1377         DeleteConstDataIfNoUser(tacc.GetKey());
1378         return true;
1379     }
1380     return false;
1381 }
1382 
LowerTypedLdArrayLength(const LoadBuiltinObjTypeInfoAccessor & tacc)1383 void TypedBytecodeLowering::LowerTypedLdArrayLength(const LoadBuiltinObjTypeInfoAccessor &tacc)
1384 {
1385     GateRef gate = tacc.GetGate();
1386     GateRef array = tacc.GetReceiver();
1387     ElementsKind kind = acc_.TryGetElementsKind(gate);
1388     AddProfiling(gate);
1389     if (!Uncheck()) {
1390         if (!acc_.IsCreateArray(array)) {
1391             builder_.StableArrayCheck(array, kind, ArrayMetaDataAccessor::Mode::LOAD_LENGTH);
1392         }
1393     }
1394 
1395     GateRef result = builder_.LoadArrayLength(array, kind, ArrayMetaDataAccessor::Mode::LOAD_LENGTH);
1396     acc_.ReplaceHirAndReplaceDeadIfException(gate, builder_.GetStateDepend(), result);
1397 }
1398 
LowerTypedLdTypedArrayLength(const LoadBuiltinObjTypeInfoAccessor & tacc)1399 void TypedBytecodeLowering::LowerTypedLdTypedArrayLength(const LoadBuiltinObjTypeInfoAccessor &tacc)
1400 {
1401     GateRef gate = tacc.GetGate();
1402     GateRef array = tacc.GetReceiver();
1403     AddProfiling(gate);
1404     ParamType arrayType = tacc.GetParamType();
1405     OnHeapMode onHeap = acc_.TryGetOnHeapMode(gate);
1406     if (!Uncheck()) {
1407         builder_.TypedArrayCheck(array, arrayType, TypedArrayMetaDataAccessor::Mode::LOAD_LENGTH, onHeap);
1408     }
1409     GateRef result = builder_.LoadTypedArrayLength(array, arrayType, onHeap);
1410     acc_.ReplaceHirAndReplaceDeadIfException(gate, builder_.GetStateDepend(), result);
1411 }
1412 
LowerTypedLdStringLength(const LoadBuiltinObjTypeInfoAccessor & tacc)1413 void TypedBytecodeLowering::LowerTypedLdStringLength(const LoadBuiltinObjTypeInfoAccessor &tacc)
1414 {
1415     GateRef gate = tacc.GetGate();
1416     GateRef str = tacc.GetReceiver();
1417     AddProfiling(gate);
1418     if (!TypeInfoAccessor::IsTrustedStringType(compilationEnv_, circuit_, chunk_, acc_, str)) {
1419         if (!Uncheck()) {
1420             builder_.EcmaStringCheck(str);
1421         }
1422     }
1423     GateRef result = builder_.LoadStringLength(str);
1424     acc_.ReplaceHirAndReplaceDeadIfException(gate, builder_.GetStateDepend(), result);
1425 }
1426 
LowerTypedLdMapSize(const LoadBuiltinObjTypeInfoAccessor & tacc)1427 void TypedBytecodeLowering::LowerTypedLdMapSize(const LoadBuiltinObjTypeInfoAccessor &tacc)
1428 {
1429     GateRef gate = tacc.GetGate();
1430     GateRef jsMap = tacc.GetReceiver();
1431     AddProfiling(gate);
1432     if (!Uncheck()) {
1433         builder_.EcmaMapCheck(jsMap);
1434     }
1435     GateRef result = builder_.LoadMapSize(jsMap);
1436     acc_.ReplaceHirAndReplaceDeadIfException(gate, builder_.GetStateDepend(), result);
1437 }
1438 
TryLowerTypedLdObjByNameForBuiltinMethod(const LoadBuiltinObjTypeInfoAccessor & tacc,BuiltinTypeId type)1439 bool TypedBytecodeLowering::TryLowerTypedLdObjByNameForBuiltinMethod(const LoadBuiltinObjTypeInfoAccessor &tacc,
1440                                                                      BuiltinTypeId type)
1441 {
1442     GateRef gate = tacc.GetGate();
1443     JSTaggedValue key = tacc.GetKeyTaggedValue();
1444     std::optional<GlobalEnvField> protoField = ToGlobalEnvPrototypeField(type);
1445     if (key.IsUndefined() || !protoField.has_value()) {
1446         return false;
1447     }
1448     size_t protoFieldIndex = static_cast<size_t>(*protoField);
1449     JSHandle<GlobalEnv> globalEnv = compilationEnv_->GetGlobalEnv();
1450     JSHClass *prototypeHClass = globalEnv->GetGlobalEnvObjectByIndex(protoFieldIndex)->GetTaggedObject()->GetClass();
1451     PropertyLookupResult plr = JSHClass::LookupPropertyInBuiltinPrototypeHClass(compilationEnv_->GetJSThread(),
1452         prototypeHClass, key);
1453     bool isPrototypeOfPrototype = false;
1454     // Unable to handle accessor at the moment
1455     if (!plr.IsFound() || plr.IsAccessor()) {
1456         if (type == BuiltinTypeId::ARRAY_ITERATOR) {
1457             protoField = ToGlobalEnvPrototypeField(BuiltinTypeId::ITERATOR);
1458             if (!protoField.has_value()) {
1459                 return false;
1460             }
1461             protoFieldIndex = static_cast<size_t>(*protoField);
1462             prototypeHClass = globalEnv->GetGlobalEnvObjectByIndex(protoFieldIndex)->GetTaggedObject()->GetClass();
1463             plr = JSHClass::LookupPropertyInBuiltinPrototypeHClass(compilationEnv_->GetJSThread(),
1464                 prototypeHClass, key);
1465             if (!plr.IsFound() || plr.IsAccessor()) {
1466                 return false;
1467             } else {
1468                 isPrototypeOfPrototype = true;
1469             }
1470         } else {
1471             return false;
1472         }
1473     }
1474     AddProfiling(gate);
1475     GateRef receiver = acc_.GetValueIn(gate, 2);
1476     if (!Uncheck()) {
1477         /**
1478          * Fixme: Cannot detect changes to Number.prototype.
1479          */
1480         ElementsKind kind = ElementsKind::NONE;
1481         if (type == BuiltinTypeId::ARRAY) {
1482             kind = tacc.TryGetArrayElementsKind();
1483         }
1484         if (enableLazyDeopt_) {
1485             builder_.BuiltinInstanceHClassCheck(receiver, type, kind, isPrototypeOfPrototype);
1486             if (!TryLazyDeoptBuiltinStableProtoChain(const_cast<LoadBuiltinObjTypeInfoAccessor&>(tacc), 0,
1487                 gate, compilationEnv_->GetGlobalEnv())) {
1488                 return false;
1489             }
1490             if (type == BuiltinTypeId::ARRAY) {
1491                 if (!TryLazyDeoptArrayGuardianCheck(gate)) {
1492                     return false;
1493                 }
1494             }
1495         } else {
1496             // For Array type only: array stability shall be ensured.
1497             if (type == BuiltinTypeId::ARRAY) {
1498                 builder_.StableArrayCheck(receiver, ElementsKind::GENERIC, ArrayMetaDataAccessor::CALL_BUILTIN_METHOD);
1499             }
1500             builder_.BuiltinPrototypeHClassCheck(receiver, type, kind, isPrototypeOfPrototype);
1501         }
1502     }
1503     // Successfully goes to typed path
1504     GateRef plrGate = builder_.Int32(plr.GetData());
1505     GateRef prototype = builder_.GetGlobalEnvObj(circuit_->GetGlobalEnvCache(), static_cast<size_t>(*protoField));
1506     GateRef result = builder_.LoadProperty(prototype, plrGate, plr.IsFunction());
1507     acc_.ReplaceHirAndReplaceDeadIfException(gate, builder_.GetStateDepend(), result);
1508     return true;
1509 }
1510 
TryLowerTypedLdObjByIndexForBuiltin(GateRef gate)1511 bool TypedBytecodeLowering::TryLowerTypedLdObjByIndexForBuiltin(GateRef gate)
1512 {
1513     LoadBuiltinObjTypeInfoAccessor tacc(compilationEnv_, circuit_, gate, chunk_);
1514     GateRef result = Circuit::NullGate();
1515     // Just supported mono.
1516     if (tacc.IsMono()) {
1517         if (tacc.IsBuiltinsTypeArray()) {  // pgo need dump profile type
1518             AddProfiling(gate);
1519             result = LoadTypedArrayByIndex(tacc);
1520             acc_.ReplaceHirAndReplaceDeadIfException(gate, builder_.GetStateDepend(), result);
1521             return true;
1522         }
1523     }
1524     return false;
1525 }
1526 
LowerTypedLdObjByIndex(GateRef gate)1527 void TypedBytecodeLowering::LowerTypedLdObjByIndex(GateRef gate)
1528 {
1529     if (TryLowerTypedLdObjByIndexForBuiltin(gate)) {
1530         return;
1531     }
1532 }
1533 
TryLowerTypedStObjByIndexForBuiltin(GateRef gate)1534 bool TypedBytecodeLowering::TryLowerTypedStObjByIndexForBuiltin(GateRef gate)
1535 {
1536     StoreBuiltinObjTypeInfoAccessor tacc(compilationEnv_, circuit_, gate, chunk_);
1537     if (tacc.HasNoType()) {
1538         return false;
1539     }
1540     if (tacc.GetBuiltinsJSType() != JSType::JS_FLOAT32_ARRAY) {
1541         return false;
1542     }
1543     AddProfiling(gate);
1544     GateRef receiver = tacc.GetReceiver();
1545     ParamType receiverType = tacc.GetParamType();
1546     if (!Uncheck()) {
1547         OnHeapMode onHeap = tacc.TryGetHeapMode();
1548         builder_.TypedArrayCheck(receiver, receiverType, TypedArrayMetaDataAccessor::Mode::ACCESS_ELEMENT, onHeap);
1549     }
1550     GateRef index = builder_.Int32(tacc.TryConvertKeyToInt());
1551     GateRef value = tacc.GetValue();
1552     OnHeapMode onHeap = tacc.TryGetHeapMode();
1553     auto length = builder_.LoadTypedArrayLength(receiver, receiverType, onHeap);
1554     if (!Uncheck()) {
1555         builder_.IndexCheck(length, index);
1556     }
1557     builder_.StoreElement<TypedStoreOp::FLOAT32ARRAY_STORE_ELEMENT>(receiver, index, value, onHeap);
1558     acc_.ReplaceHirAndReplaceDeadIfException(gate, builder_.GetStateDepend(), Circuit::NullGate());
1559     return true;
1560 }
1561 
LowerTypedStObjByIndex(GateRef gate)1562 void TypedBytecodeLowering::LowerTypedStObjByIndex(GateRef gate)
1563 {
1564     if (TryLowerTypedStObjByIndexForBuiltin(gate)) {
1565         return;
1566     }
1567 }
1568 
TryLowerTypedLdObjByValueForBuiltin(GateRef gate)1569 bool TypedBytecodeLowering::TryLowerTypedLdObjByValueForBuiltin(GateRef gate)
1570 {
1571     LoadBuiltinObjTypeInfoAccessor tacc(compilationEnv_, circuit_, gate, chunk_);
1572     GateRef result = Circuit::NullGate();
1573     // Just supported mono.
1574     if (tacc.IsMono()) {
1575         if (tacc.IsBuiltinsString()) {
1576             AddProfiling(gate);
1577             result = LoadStringByIndex(tacc);
1578             acc_.ReplaceHirAndReplaceDeadIfException(gate, builder_.GetStateDepend(), result);
1579             return true;
1580         } else if (tacc.IsBuiltinsArray()) {
1581             AddProfiling(gate);
1582             result = LoadJSArrayByIndex(tacc);
1583             acc_.ReplaceHirAndReplaceDeadIfException(gate, builder_.GetStateDepend(), result);
1584             return true;
1585         } else if (tacc.IsBuiltinsTypeArray()) {
1586             AddProfiling(gate);
1587             result = LoadTypedArrayByIndex(tacc);
1588             acc_.ReplaceHirAndReplaceDeadIfException(gate, builder_.GetStateDepend(), result);
1589             return true;
1590         }
1591     }
1592     return false;
1593 }
1594 
LowerTypedLdObjByValue(GateRef gate)1595 void TypedBytecodeLowering::LowerTypedLdObjByValue(GateRef gate)
1596 {
1597     if (TryLowerTypedLdObjByValueForBuiltin(gate)) {
1598         return;
1599     }
1600     if (!compilationEnv_->SupportHeapConstant() || !compilationEnv_->GetJSOptions().IsLdObjValueOpt()) {
1601         return;
1602     }
1603     LoadObjPropertyTypeInfoAccessor tacc(compilationEnv_, circuit_, gate, chunk_, true);
1604     // only support for string named key.
1605     if (tacc.TypesIsEmpty() || tacc.HasIllegalType()) {
1606         return;
1607     }
1608     DEFVALUE(result, (&builder_), VariableType::JS_ANY(), builder_.Hole());
1609     AddProfiling(gate);
1610     GateRef frameState = acc_.FindNearestFrameState(gate);
1611     if (tacc.IsMono()) {
1612         if (!tacc.GetName()->IsString()) {
1613             return;
1614         }
1615         GateRef receiver = tacc.GetReceiver();
1616         EcmaString* ecmaString = EcmaString::Cast(tacc.GetName()->GetTaggedObject());
1617         EcmaStringAccessor ecmaStringAccessor(ecmaString);
1618         if (ecmaStringAccessor.IsInternString()) {
1619             builder_.InternStringKeyCheck(tacc.GetKey(), builder_.HeapConstant(tacc.GetNameIdx()));
1620         } else {
1621             builder_.StringKeyCheck(tacc.GetKey(), builder_.HeapConstant(tacc.GetNameIdx()));
1622         }
1623         builder_.ObjectTypeCheck(false, receiver,
1624                                  builder_.Int32(tacc.GetExpectedHClassIndex(0)), frameState);
1625         if (tacc.IsReceiverEqHolder(0)) {
1626             result = BuildNamedPropertyAccess(gate, receiver, receiver, tacc.GetAccessInfo(0).Plr());
1627         } else {
1628             builder_.ProtoChangeMarkerCheck(receiver, frameState);
1629             PropertyLookupResult plr = tacc.GetAccessInfo(0).Plr();
1630             GateRef plrGate = builder_.Int32(plr.GetData());
1631             GateRef unsharedConstPoool = argAcc_->GetFrameArgsIn(gate, FrameArgIdx::UNSHARED_CONST_POOL);
1632             size_t holderHClassIndex = static_cast<size_t>(tacc.GetAccessInfo(0).HClassIndex());
1633             if (LIKELY(!plr.IsAccessor())) {
1634                 result = builder_.MonoLoadPropertyOnProto(receiver, plrGate, unsharedConstPoool, holderHClassIndex);
1635             } else {
1636                 result = builder_.MonoCallGetterOnProto(gate, receiver, plrGate, unsharedConstPoool, holderHClassIndex);
1637             }
1638         }
1639         ReplaceHirWithCheckingAccessor(glue_, gate, builder_.GetStateDepend(), *result,
1640             tacc.GetAccessInfo(0).Plr().IsAccessor());
1641         return;
1642     }
1643 }
1644 
LoadStringByIndex(const LoadBuiltinObjTypeInfoAccessor & tacc)1645 GateRef TypedBytecodeLowering::LoadStringByIndex(const LoadBuiltinObjTypeInfoAccessor &tacc)
1646 {
1647     GateRef receiver = tacc.GetReceiver();
1648     GateRef propKey = tacc.GetKey();
1649     acc_.SetGateType(propKey, GateType::NumberType());
1650     if (!Uncheck()) {
1651         if (!TypeInfoAccessor::IsTrustedStringType(compilationEnv_, circuit_, chunk_, acc_, receiver)) {
1652             builder_.EcmaStringCheck(receiver);
1653         }
1654         GateRef length = builder_.LoadStringLength(receiver);
1655         propKey = builder_.IndexCheck(length, propKey);
1656         receiver = builder_.FlattenTreeStringCheck(receiver);
1657     }
1658     return builder_.LoadElement<TypedLoadOp::STRING_LOAD_ELEMENT>(receiver, propKey);
1659 }
1660 
LoadJSArrayByIndex(const LoadBuiltinObjTypeInfoAccessor & tacc)1661 GateRef TypedBytecodeLowering::LoadJSArrayByIndex(const LoadBuiltinObjTypeInfoAccessor &tacc)
1662 {
1663     GateRef receiver = tacc.GetReceiver();
1664     GateRef propKey = tacc.GetKey();
1665     acc_.SetGateType(propKey, GateType::NumberType());
1666     ElementsKind kind = tacc.TryGetArrayElementsKind();
1667     if (!Uncheck()) {
1668         if (!acc_.IsCreateArray(receiver)) {
1669             builder_.StableArrayCheck(receiver, kind, ArrayMetaDataAccessor::Mode::LOAD_ELEMENT);
1670             builder_.ElementsKindCheck(receiver, kind, ArrayMetaDataAccessor::Mode::LOAD_ELEMENT);
1671         }
1672         GateRef length = builder_.LoadArrayLength(receiver, kind, ArrayMetaDataAccessor::Mode::LOAD_LENGTH);
1673         propKey = builder_.IndexCheck(length, propKey);
1674     }
1675 
1676     GateRef result = Circuit::NullGate();
1677     if (Elements::IsInt(kind)) {
1678         // When elementskind switch on, need to add retype for loadInt
1679         result = builder_.LoadElement<TypedLoadOp::ARRAY_LOAD_INT_ELEMENT>(receiver, propKey);
1680     } else if (Elements::IsNumber(kind)) {
1681         // When elementskind switch on, need to add retype for loadNumber
1682         result = builder_.LoadElement<TypedLoadOp::ARRAY_LOAD_DOUBLE_ELEMENT>(receiver, propKey);
1683     } else if (Elements::IsObject(kind)) {
1684         result = builder_.LoadElement<TypedLoadOp::ARRAY_LOAD_OBJECT_ELEMENT>(receiver, propKey);
1685     } else if (!Elements::IsHole(kind)) {
1686         result = builder_.LoadElement<TypedLoadOp::ARRAY_LOAD_TAGGED_ELEMENT>(receiver, propKey);
1687     } else {
1688         result = builder_.LoadElement<TypedLoadOp::ARRAY_LOAD_HOLE_TAGGED_ELEMENT>(receiver, propKey);
1689     }
1690     return result;
1691 }
1692 
LoadElmentFromFloat64Array(const LoadBuiltinObjTypeInfoAccessor & tacc)1693 GateRef TypedBytecodeLowering::LoadElmentFromFloat64Array(const LoadBuiltinObjTypeInfoAccessor &tacc)
1694 {
1695     GateRef receiver = tacc.GetReceiver();
1696     GateRef propKey = tacc.GetKey();
1697     OnHeapMode onHeap = tacc.TryGetHeapMode();
1698     auto resTemp = builder_.LoadElement<TypedLoadOp::FLOAT64ARRAY_LOAD_ELEMENT>(receiver, propKey, onHeap);
1699     Label entry(&builder_);
1700     builder_.SubCfgEntry(&entry);
1701     Label ifTrue(&builder_);
1702     Label ifFalse(&builder_);
1703     Label exit(&builder_);
1704     Variable result(builder_.GetCurrentEnvironment(),
1705         VariableType::JS_ANY(), builder_.NextVariableId(), builder_.Undefined());
1706 
1707     builder_.Branch(builder_.DoubleIsImpureNaN(resTemp), &ifTrue, &ifFalse);
1708     builder_.Bind(&ifTrue);
1709     {
1710         result = builder_.Double(base::NAN_VALUE);
1711         builder_.Jump(&exit);
1712     }
1713     builder_.Bind(&ifFalse);
1714     {
1715         result = resTemp;
1716         builder_.Jump(&exit);
1717     }
1718     builder_.Bind(&exit);
1719     auto res = *result;
1720     builder_.SubCfgExit();
1721     return res;
1722 }
1723 
LoadTypedArrayByIndex(const LoadBuiltinObjTypeInfoAccessor & tacc)1724 GateRef TypedBytecodeLowering::LoadTypedArrayByIndex(const LoadBuiltinObjTypeInfoAccessor &tacc)
1725 {
1726     GateRef receiver = tacc.GetReceiver();
1727     ParamType receiverType = tacc.GetParamType();
1728     GateRef propKey = tacc.GetKey();
1729     OnHeapMode onHeap = tacc.TryGetHeapMode();
1730     JSType builtinsType = tacc.GetBuiltinsJSType();
1731     if (!Uncheck()) {
1732         builder_.TypedArrayCheck(receiver, receiverType, TypedArrayMetaDataAccessor::Mode::ACCESS_ELEMENT, onHeap);
1733         GateRef length = builder_.LoadTypedArrayLength(receiver, receiverType, onHeap);
1734         propKey = builder_.IndexCheck(length, propKey);
1735     }
1736     switch (builtinsType) {
1737         case JSType::JS_INT8_ARRAY:
1738             return builder_.LoadElement<TypedLoadOp::INT8ARRAY_LOAD_ELEMENT>(receiver, propKey, onHeap);
1739         case JSType::JS_UINT8_ARRAY:
1740             return builder_.LoadElement<TypedLoadOp::UINT8ARRAY_LOAD_ELEMENT>(receiver, propKey, onHeap);
1741         case JSType::JS_UINT8_CLAMPED_ARRAY:
1742             return builder_.LoadElement<TypedLoadOp::UINT8CLAMPEDARRAY_LOAD_ELEMENT>(receiver, propKey, onHeap);
1743         case JSType::JS_INT16_ARRAY:
1744             return builder_.LoadElement<TypedLoadOp::INT16ARRAY_LOAD_ELEMENT>(receiver, propKey, onHeap);
1745         case JSType::JS_UINT16_ARRAY:
1746             return builder_.LoadElement<TypedLoadOp::UINT16ARRAY_LOAD_ELEMENT>(receiver, propKey, onHeap);
1747         case JSType::JS_INT32_ARRAY:
1748             return builder_.LoadElement<TypedLoadOp::INT32ARRAY_LOAD_ELEMENT>(receiver, propKey, onHeap);
1749         case JSType::JS_UINT32_ARRAY:
1750             return builder_.LoadElement<TypedLoadOp::UINT32ARRAY_LOAD_ELEMENT>(receiver, propKey, onHeap);
1751         case JSType::JS_FLOAT32_ARRAY:
1752             return builder_.LoadElement<TypedLoadOp::FLOAT32ARRAY_LOAD_ELEMENT>(receiver, propKey, onHeap);
1753         case JSType::JS_FLOAT64_ARRAY: {
1754             return LoadElmentFromFloat64Array(tacc);
1755         }
1756         default:
1757             LOG_ECMA(FATAL) << "this branch is unreachable";
1758             UNREACHABLE();
1759     }
1760 
1761     return Circuit::NullGate();
1762 }
1763 
StoreJSArrayByIndex(const StoreBuiltinObjTypeInfoAccessor & tacc)1764 void TypedBytecodeLowering::StoreJSArrayByIndex(const StoreBuiltinObjTypeInfoAccessor &tacc)
1765 {
1766     GateRef receiver = tacc.GetReceiver();
1767     GateRef propKey = tacc.GetKey();
1768     GateRef value = tacc.GetValue();
1769     ElementsKind kind = tacc.TryGetArrayElementsKind();
1770     if (!Uncheck()) {
1771         if (!acc_.IsCreateArray(receiver)) {
1772             builder_.StableArrayCheck(receiver, kind, ArrayMetaDataAccessor::Mode::STORE_ELEMENT);
1773         }
1774         GateRef length = builder_.LoadArrayLength(receiver, kind, ArrayMetaDataAccessor::Mode::LOAD_LENGTH);
1775         builder_.IndexCheck(length, propKey);
1776         builder_.COWArrayCheck(receiver);
1777 
1778         if (Elements::IsObject(kind)) {
1779             GateRef frameState = acc_.FindNearestFrameState(builder_.GetDepend());
1780             builder_.HeapObjectCheck(value, frameState);
1781         }
1782     }
1783     builder_.StoreElement<TypedStoreOp::ARRAY_STORE_ELEMENT>(receiver, propKey, value);
1784 }
1785 
StoreTypedArrayByIndex(const StoreBuiltinObjTypeInfoAccessor & tacc)1786 void TypedBytecodeLowering::StoreTypedArrayByIndex(const StoreBuiltinObjTypeInfoAccessor &tacc)
1787 {
1788     GateRef receiver = tacc.GetReceiver();
1789     ParamType receiverType = tacc.GetParamType();
1790     GateRef propKey = tacc.GetKey();
1791     GateRef value = tacc.GetValue();
1792     OnHeapMode onHeap = tacc.TryGetHeapMode();
1793     if (!Uncheck()) {
1794         builder_.TypedArrayCheck(receiver, receiverType, TypedArrayMetaDataAccessor::Mode::ACCESS_ELEMENT, onHeap);
1795         GateRef length = builder_.LoadTypedArrayLength(receiver, receiverType, onHeap);
1796         propKey = builder_.IndexCheck(length, propKey);
1797     }
1798 
1799     JSType builtinsType = tacc.GetBuiltinsJSType();
1800     switch (builtinsType) {
1801         case JSType::JS_INT8_ARRAY:
1802             builder_.StoreElement<TypedStoreOp::INT8ARRAY_STORE_ELEMENT>(receiver, propKey, value, onHeap);
1803             break;
1804         case JSType::JS_UINT8_ARRAY:
1805             builder_.StoreElement<TypedStoreOp::UINT8ARRAY_STORE_ELEMENT>(receiver, propKey, value, onHeap);
1806             break;
1807         case JSType::JS_UINT8_CLAMPED_ARRAY:
1808             builder_.StoreElement<TypedStoreOp::UINT8CLAMPEDARRAY_STORE_ELEMENT>(receiver, propKey, value, onHeap);
1809             break;
1810         case JSType::JS_INT16_ARRAY:
1811             builder_.StoreElement<TypedStoreOp::INT16ARRAY_STORE_ELEMENT>(receiver, propKey, value, onHeap);
1812             break;
1813         case JSType::JS_UINT16_ARRAY:
1814             builder_.StoreElement<TypedStoreOp::UINT16ARRAY_STORE_ELEMENT>(receiver, propKey, value, onHeap);
1815             break;
1816         case JSType::JS_INT32_ARRAY:
1817             builder_.StoreElement<TypedStoreOp::INT32ARRAY_STORE_ELEMENT>(receiver, propKey, value, onHeap);
1818             break;
1819         case JSType::JS_UINT32_ARRAY:
1820             builder_.StoreElement<TypedStoreOp::UINT32ARRAY_STORE_ELEMENT>(receiver, propKey, value, onHeap);
1821             break;
1822         case JSType::JS_FLOAT32_ARRAY:
1823             builder_.StoreElement<TypedStoreOp::FLOAT32ARRAY_STORE_ELEMENT>(receiver, propKey, value, onHeap);
1824             break;
1825         case JSType::JS_FLOAT64_ARRAY:
1826             builder_.StoreElement<TypedStoreOp::FLOAT64ARRAY_STORE_ELEMENT>(receiver, propKey, value, onHeap);
1827             break;
1828         default:
1829             LOG_ECMA(FATAL) << "this branch is unreachable";
1830             UNREACHABLE();
1831     }
1832 }
1833 
TryLowerTypedStObjByValueForBuiltin(GateRef gate)1834 bool TypedBytecodeLowering::TryLowerTypedStObjByValueForBuiltin(GateRef gate)
1835 {
1836     StoreBuiltinObjTypeInfoAccessor tacc(compilationEnv_, circuit_, gate, chunk_);
1837     // Just supported mono.
1838     if (tacc.IsMono() && !tacc.IsStoreOutOfBounds()) {
1839         if (tacc.IsBuiltinsArray()) {
1840             AddProfiling(gate);
1841             StoreJSArrayByIndex(tacc);
1842             acc_.ReplaceHirAndReplaceDeadIfException(gate, builder_.GetStateDepend(), Circuit::NullGate());
1843             return true;
1844         } else if (tacc.IsBuiltinsTypeArray()) {
1845             AddProfiling(gate);
1846             StoreTypedArrayByIndex(tacc);
1847             acc_.ReplaceHirAndReplaceDeadIfException(gate, builder_.GetStateDepend(), Circuit::NullGate());
1848             return true;
1849         }
1850     }
1851 
1852     return false;
1853 }
1854 
LowerTypedStObjByValue(GateRef gate)1855 void TypedBytecodeLowering::LowerTypedStObjByValue(GateRef gate)
1856 {
1857     if (TryLowerTypedStObjByValueForBuiltin(gate)) {
1858         return;
1859     }
1860 }
1861 
IsTrueOrFalseHasProfileType(GateRef gate) const1862 bool TypedBytecodeLowering::IsTrueOrFalseHasProfileType(GateRef gate) const
1863 {
1864     ASSERT(acc_.GetOpCode(gate) == OpCode::JS_BYTECODE);
1865     return acc_.GetByteCodeOpcode(gate) == EcmaOpcode::CALLRUNTIME_ISTRUE_PREF_IMM8 ||
1866            acc_.GetByteCodeOpcode(gate) == EcmaOpcode::CALLRUNTIME_ISFALSE_PREF_IMM8;
1867 }
1868 
LowerTypedIsTrueOrFalse(GateRef gate,bool flag)1869 void TypedBytecodeLowering::LowerTypedIsTrueOrFalse(GateRef gate, bool flag)
1870 {
1871     UnOpTypeInfoAccessor tacc(compilationEnv_, circuit_, gate);
1872     ParamType paramType;
1873     if (TypeInfoAccessor::IsTrustedBooleanType(acc_, tacc.GetValue()) ||
1874     (IsTrueOrFalseHasProfileType(gate) && tacc.IsBooleanType())) {
1875         paramType = ParamType::BooleanType();
1876     } else if (TypeInfoAccessor::IsTrustedNumberType(acc_, tacc.GetValue()) ||
1877     (IsTrueOrFalseHasProfileType(gate) && tacc.HasNumberType())) {
1878         paramType = ParamType::NumberType();
1879     } else {
1880         return;
1881     }
1882     AddProfiling(gate);
1883     GateRef result;
1884     if (!flag) {
1885         result = builder_.TypedUnaryOp<TypedUnOp::TYPED_ISFALSE>(tacc.GetValue(), paramType);
1886     } else {
1887         result = builder_.TypedUnaryOp<TypedUnOp::TYPED_ISTRUE>(tacc.GetValue(), paramType);
1888     }
1889 
1890     acc_.ReplaceHirAndReplaceDeadIfException(gate, builder_.GetStateDepend(), result);
1891 }
1892 
TryLowerNewNumber(CircuitBuilder * builder,GateAccessor acc,GateRef gate)1893 bool TryLowerNewNumber(CircuitBuilder *builder, GateAccessor acc, GateRef gate)
1894 {
1895     auto loadBuiltin = acc.GetValueIn(gate, 0);
1896     if ((acc.GetOpCode(loadBuiltin) == OpCode::LOAD_BUILTIN_OBJECT) &&
1897             (acc.GetIndex(loadBuiltin) == static_cast<size_t>(BuiltinType::BT_NUMBER))) {
1898         auto arg = builder->ToTaggedIntPtr(builder->Int32(0));
1899         if (acc.GetNumValueIn(gate) > 1) {
1900             arg = acc.GetValueIn(gate, 1);
1901         }
1902 
1903         auto currentLabel = builder->GetCurrentEnvironment()->GetCurrentLabel();
1904         auto currentControl = currentLabel->GetControl();
1905         auto currentDepend = currentLabel->GetDepend();
1906         GateRef frameState = acc.FindNearestFrameState(gate);
1907         GateRef newNumber = acc.GetCircuit()->NewGate(acc.GetCircuit()->NewNumber(),
1908             MachineType::I64,
1909             {currentControl, currentDepend, loadBuiltin, arg, frameState},
1910             GateType::TaggedPointer());
1911 
1912         currentLabel->SetControl(newNumber);
1913         currentLabel->SetDepend(newNumber);
1914 
1915         acc.ReplaceHirAndReplaceDeadIfException(gate, builder->GetStateDepend(), newNumber);
1916         return true;
1917     }
1918     return false;
1919 }
1920 
LowerTypedNewObjRange(GateRef gate)1921 void TypedBytecodeLowering::LowerTypedNewObjRange(GateRef gate)
1922 {
1923     if (TryLowerNewNumber(&builder_, acc_, gate) || TryLowerNewBuiltinConstructor(gate)) {
1924         return;
1925     }
1926     NewObjRangeTypeInfoAccessor tacc(compilationEnv_, circuit_, gate, chunk_);
1927     if (!tacc.FindHClass() || !tacc.IsValidCallMethodId()) {
1928         return;
1929     }
1930     size_t methodId = tacc.GetCallMethodId();
1931     MethodLiteral* method = ctx_->GetJSPandaFile()->FindMethodLiteral(methodId);
1932     JSTaggedValue value = tacc.GetHClass();
1933     JSHClass *hclass = JSHClass::Cast(value.GetTaggedObject());
1934     if (method == nullptr || !value.IsJSHClass() || hclass->GetObjectType() != JSType::JS_OBJECT) {
1935         return ;
1936     }
1937     AddProfiling(gate);
1938     GateRef ctor = tacc.GetValue();
1939     GateRef hclassIndex = tacc.GetHClassIndex();
1940     GateRef stateSplit = acc_.GetDep(gate);
1941     GateRef frameState = acc_.FindNearestFrameState(stateSplit);
1942     GateRef ihclass = builder_.GetHClassGateFromIndex(frameState, hclassIndex);
1943     GateRef size = builder_.IntPtr(hclass->GetObjectSize());
1944 
1945     auto heapConstantIndex = tacc.TryGetHeapConstantConstructorIndex(methodId);
1946     if (heapConstantIndex != JitCompilationEnv::INVALID_HEAP_CONSTANT_INDEX) {
1947         GateRef res = builder_.HeapConstant(heapConstantIndex);
1948         builder_.DeoptCheck(builder_.Equal(ctor, res), frameState, DeoptType::NOTCALLTARGETHEAPOBJECT);
1949     } else {
1950         // call target check
1951         builder_.JSCallTargetTypeCheck<TypedCallTargetCheckOp::JS_NEWOBJRANGE>(ctor,
1952             builder_.IntPtr(INVALID_INDEX), gate);
1953     }
1954     // check IHC
1955     GateRef protoOrHclass = builder_.LoadConstOffset(VariableType::JS_ANY(), ctor,
1956         JSFunction::PROTO_OR_DYNCLASS_OFFSET);
1957     GateRef checkProto = builder_.Equal(ihclass, protoOrHclass);
1958     builder_.DeoptCheck(checkProto, frameState, DeoptType::NOTNEWOBJ2);
1959     // construct
1960     GateRef thisObj = builder_.TypedNewAllocateThis(ctor, ihclass, size, frameState);
1961     size_t range = acc_.GetNumValueIn(gate);
1962     size_t expectedArgc = method->GetNumArgs();
1963     size_t actualArgc = static_cast<size_t>(BytecodeCallArgc::ComputeCallArgc(acc_.GetNumValueIn(gate),
1964         EcmaOpcode::NEWOBJRANGE_IMM8_IMM8_V8));
1965     std::vector<GateRef> args {glue_,  builder_.Int64(actualArgc), builder_.IntPtr(0), ctor, ctor,
1966                                thisObj};
1967     for (size_t i = 1; i < range; ++i) { // 1:skip ctor
1968         args.emplace_back(acc_.GetValueIn(gate, i));
1969     }
1970     bool needPushArgv = (expectedArgc != actualArgc);
1971     bool isFastCall = method->IsFastCall();
1972     GateRef result = builder_.CallNew(gate, args, needPushArgv, isFastCall);
1973     ReplaceGateWithPendingException(glue_, gate, builder_.GetState(), builder_.GetDepend(), result);
1974 }
1975 
TryLowerNewBuiltinConstructor(GateRef gate)1976 bool TypedBytecodeLowering::TryLowerNewBuiltinConstructor(GateRef gate)
1977 {
1978     NewBuiltinCtorTypeInfoAccessor tacc(compilationEnv_, circuit_, gate);
1979     auto id = tacc.GetPGOBuiltinMethodId();
1980     if (id == BuiltinsStubCSigns::ID::NONE) {
1981         return false;
1982     }
1983 
1984     GateRef ctor = tacc.GetValue();
1985     GateRef constructGate = Circuit::NullGate();
1986     if (tacc.IsBuiltinId(BuiltinsStubCSigns::ID::ObjectConstructor)) {
1987         AddProfiling(gate);
1988         if (!Uncheck()) {
1989             builder_.ObjectConstructorCheck(ctor);
1990         }
1991         constructGate = builder_.BuiltinConstructor(BuiltinsStubCSigns::ID::ObjectConstructor, gate);
1992     } else if (tacc.IsBuiltinId(BuiltinsStubCSigns::ID::BooleanConstructor)) {
1993         if (acc_.GetNumValueIn(gate) <= 2) { // 2: ctor and first arg
1994             AddProfiling(gate);
1995             if (!Uncheck()) {
1996                 builder_.BooleanConstructorCheck(ctor);
1997             }
1998             constructGate = builder_.BuiltinConstructor(BuiltinsStubCSigns::ID::BooleanConstructor, gate);
1999         }
2000     } else if (tacc.IsBuiltinId(BuiltinsStubCSigns::ID::Float32ArrayConstructor)) {
2001         if (acc_.GetNumValueIn(gate) <= 2) { // 2: ctor and first arg
2002             AddProfiling(gate);
2003             if (!Uncheck()) {
2004                 builder_.Float32ArrayConstructorCheck(ctor);
2005             }
2006             constructGate = builder_.BuiltinConstructor(BuiltinsStubCSigns::ID::Float32ArrayConstructor, gate);
2007         }
2008     }
2009     if (constructGate == Circuit::NullGate()) {
2010         // for other builtin constructor, do necessory check and just call runtime JSCallNew.
2011         AddProfiling(gate);
2012         if (!Uncheck()) {
2013             builder_.TypedConstructorCheck(ctor, GET_TYPED_GLOBAL_ENV_INDEX(id));
2014         }
2015         GateRef actualArgc = builder_.Int64(
2016             BytecodeCallArgc::ComputeCallArgc(acc_.GetNumValueIn(gate), EcmaOpcode::NEWOBJRANGE_IMM8_IMM8_V8));
2017         GateRef actualArgv = builder_.IntPtr(0);
2018         GateRef thisObj = builder_.Undefined();
2019         size_t range = acc_.GetNumValueIn(gate);
2020         std::vector<GateRef> args {glue_, actualArgc, actualArgv, ctor, ctor, thisObj};
2021         for (size_t i = 1; i < range; ++i) {
2022             args.emplace_back(acc_.GetValueIn(gate, i));
2023         }
2024         constructGate = builder_.CallNewBuiltin(gate, args);
2025     }
2026     ReplaceGateWithPendingException(glue_, gate, builder_.GetState(), builder_.GetDepend(), constructGate);
2027     return true;
2028 }
2029 
LowerTypedSuperCall(GateRef gate)2030 void TypedBytecodeLowering::LowerTypedSuperCall(GateRef gate)
2031 {
2032     SuperCallTypeInfoAccessor tacc(compilationEnv_, circuit_, gate, GetCalleePandaFile(gate), callMethodFlagMap_);
2033 
2034     auto methodId = tacc.GetMethodId();
2035     if (methodId == 0) {
2036         return;
2037     }
2038     auto *methodLiteral = ctx_->GetJSPandaFile()->FindMethodLiteral(methodId);
2039     if (methodLiteral == nullptr || !methodLiteral->IsTypedCall()) {
2040         return;
2041     }
2042     if (!tacc.IsValidCallMethodId()) {
2043         return;
2044     }
2045     AddProfiling(gate);
2046 
2047     GateRef ctor = tacc.GetCtor();
2048 
2049     GateRef superCtor = builder_.GetSuperConstructor(ctor);
2050     GateRef newTarget = argAcc_->GetFrameArgsIn(gate, FrameArgIdx::NEW_TARGET);
2051     GateRef thisObj = builder_.TypedSuperAllocateThis(superCtor, newTarget);
2052 
2053     // call constructor
2054     size_t range = acc_.GetNumValueIn(gate);
2055     GateRef actualArgc = builder_.Int64(range + 3);  // 3: ctor, newTaget, this
2056     GateRef actualArgv = builder_.IntPtr(0);
2057     std::vector<GateRef> args { glue_, actualArgc, actualArgv, superCtor, newTarget, thisObj };
2058     for (size_t i = 0; i < range; ++i) {
2059         args.emplace_back(acc_.GetValueIn(gate, i));
2060     }
2061 
2062     GateRef constructGate = builder_.Construct(gate, args);
2063     ReplaceGateWithPendingException(glue_, gate, builder_.GetState(),
2064         builder_.GetDepend(), constructGate);
2065 }
2066 
SpeculateCallBuiltin(GateRef gate,GateRef func,const std::vector<GateRef> & args,BuiltinsStubCSigns::ID id,bool isThrow)2067 void TypedBytecodeLowering::SpeculateCallBuiltin(GateRef gate, GateRef func, const std::vector<GateRef> &args,
2068                                                  BuiltinsStubCSigns::ID id, bool isThrow)
2069 {
2070     if (!Uncheck()) {
2071         builder_.CallTargetCheck(gate, func, builder_.IntPtr(static_cast<int64_t>(id)), {args[0]});
2072     }
2073 
2074     GateRef result = builder_.TypedCallBuiltin(gate, args, id, IS_SIDE_EFFECT_BUILTINS_ID(id));
2075 
2076     if (isThrow) {
2077         ReplaceGateWithPendingException(glue_, gate, builder_.GetState(),
2078             builder_.GetDepend(), result);
2079     } else {
2080         acc_.ReplaceHirAndReplaceDeadIfException(gate, builder_.GetStateDepend(), result);
2081     }
2082 }
2083 
SpeculateCallBuiltinFromGlobal(GateRef gate,const std::vector<GateRef> & args,BuiltinsStubCSigns::ID id,bool isThrow,bool isSideEffect)2084 void TypedBytecodeLowering::SpeculateCallBuiltinFromGlobal(GateRef gate, const std::vector<GateRef> &args,
2085                                                            BuiltinsStubCSigns::ID id, bool isThrow, bool isSideEffect)
2086 {
2087     GateRef result = builder_.TypedCallBuiltin(gate, args, id, isSideEffect);
2088 
2089     if (isThrow) {
2090         ReplaceGateWithPendingException(glue_, gate, builder_.GetState(),
2091             builder_.GetDepend(), result);
2092     } else {
2093         acc_.ReplaceHirAndReplaceDeadIfException(gate, builder_.GetStateDepend(), result);
2094     }
2095 }
2096 
LowerFastCall(GateRef gate,GateRef func,const std::vector<GateRef> & argsFastCall,bool isNoGC)2097 void TypedBytecodeLowering::LowerFastCall(GateRef gate, GateRef func,
2098     const std::vector<GateRef> &argsFastCall, bool isNoGC)
2099 {
2100     builder_.StartCallTimer(glue_, gate, {glue_, func, builder_.True()}, true);
2101     GateRef result = builder_.TypedFastCall(gate, argsFastCall, isNoGC);
2102     builder_.EndCallTimer(glue_, gate, {glue_, func}, true);
2103     ReplaceGateWithPendingException(glue_, gate, builder_.GetState(),
2104         builder_.GetDepend(), result);
2105 }
2106 
LowerCall(GateRef gate,GateRef func,const std::vector<GateRef> & args,bool isNoGC)2107 void TypedBytecodeLowering::LowerCall(GateRef gate, GateRef func,
2108     const std::vector<GateRef> &args, bool isNoGC)
2109 {
2110     builder_.StartCallTimer(glue_, gate, {glue_, func, builder_.True()}, true);
2111     GateRef result = builder_.TypedCall(gate, args, isNoGC);
2112     builder_.EndCallTimer(glue_, gate, {glue_, func}, true);
2113     ReplaceGateWithPendingException(glue_, gate, builder_.GetState(),
2114         builder_.GetDepend(), result);
2115 }
2116 
2117 template<class TypeAccessor>
CheckFastCallThisCallTarget(const TypeAccessor & tacc)2118 void TypedBytecodeLowering::CheckFastCallThisCallTarget(const TypeAccessor &tacc)
2119 {
2120     if (noCheck_) {
2121         return;
2122     }
2123     GateRef func = tacc.GetFunc();
2124     GateRef gate = tacc.GetGate();
2125     GateRef methodIndex = builder_.IntPtr(tacc.GetFuncMethodOffset());
2126     if (tacc.IsNoGC()) {
2127         builder_.JSNoGCCallThisTargetTypeCheck<TypedCallTargetCheckOp::JSCALLTHIS_FAST_NOGC>(func, methodIndex, gate);
2128     } else {
2129         builder_.JSCallTargetTypeCheck<TypedCallTargetCheckOp::JSCALLTHIS_FAST>(func, methodIndex, gate);
2130     }
2131 }
2132 
2133 template<class TypeAccessor>
CheckCallThisCallTarget(const TypeAccessor & tacc)2134 void TypedBytecodeLowering::CheckCallThisCallTarget(const TypeAccessor &tacc)
2135 {
2136     if (noCheck_) {
2137         return;
2138     }
2139     GateRef func = tacc.GetFunc();
2140     GateRef gate = tacc.GetGate();
2141     GateRef methodIndex = builder_.IntPtr(tacc.GetFuncMethodOffset());
2142     if (tacc.IsNoGC()) {
2143         builder_.JSNoGCCallThisTargetTypeCheck<TypedCallTargetCheckOp::JSCALLTHIS_NOGC>(func, methodIndex, gate);
2144     } else {
2145         builder_.JSCallTargetTypeCheck<TypedCallTargetCheckOp::JSCALLTHIS>(func, methodIndex, gate);
2146     }
2147 }
2148 
2149 template<class TypeAccessor>
CheckThisCallTargetAndLowerCall(const TypeAccessor & tacc,const std::vector<GateRef> & args,const std::vector<GateRef> & argsFastCall)2150 void TypedBytecodeLowering::CheckThisCallTargetAndLowerCall(const TypeAccessor &tacc,
2151     const std::vector<GateRef> &args, const std::vector<GateRef> &argsFastCall)
2152 {
2153     GateRef func = tacc.GetFunc();
2154     GateRef gate = tacc.GetGate();
2155     bool isNoGC = tacc.IsNoGC();
2156     auto heapConstantIndex = tacc.TryGetHeapConstantFunctionIndex(tacc.GetMethodId());
2157     if (heapConstantIndex != JitCompilationEnv::INVALID_HEAP_CONSTANT_INDEX) {
2158         ConvertCallTargetCheckToHeapConstantCheckAndLowerCall(tacc, args, argsFastCall, heapConstantIndex, isNoGC);
2159         return;
2160     }
2161     if (tacc.CanFastCall()) {
2162         CheckFastCallThisCallTarget(tacc);
2163         LowerFastCall(gate, func, argsFastCall, isNoGC);
2164     } else {
2165         CheckCallThisCallTarget(tacc);
2166         LowerCall(gate, func, args, isNoGC);
2167     }
2168 }
2169 
2170 template<class TypeAccessor>
CheckCallTargetFromDefineFuncAndLowerCall(const TypeAccessor & tacc,const std::vector<GateRef> & args,const std::vector<GateRef> & argsFastCall,bool isNoGC)2171 void TypedBytecodeLowering::CheckCallTargetFromDefineFuncAndLowerCall(const TypeAccessor &tacc,
2172     const std::vector<GateRef> &args, const std::vector<GateRef> &argsFastCall, bool isNoGC)
2173 {
2174     GateRef func = tacc.GetFunc();
2175     GateRef gate = tacc.GetGate();
2176     auto heapConstantIndex = tacc.TryGetHeapConstantFunctionIndex(tacc.GetMethodId());
2177     if (heapConstantIndex != JitCompilationEnv::INVALID_HEAP_CONSTANT_INDEX) {
2178         ConvertCallTargetCheckToHeapConstantCheckAndLowerCall(tacc, args, argsFastCall, heapConstantIndex, isNoGC);
2179         return;
2180     }
2181     // NO CHECK
2182     if (!Uncheck()) {
2183         builder_.CallTargetIsCompiledCheck(func, gate);
2184     }
2185     if (tacc.CanFastCall()) {
2186         LowerFastCall(gate, func, argsFastCall, isNoGC);
2187     } else {
2188         LowerCall(gate, func, args, isNoGC);
2189     }
2190 }
2191 
2192 template<class TypeAccessor>
InSameConstPool(const TypeAccessor & tacc) const2193 bool TypedBytecodeLowering::InSameConstPool(const TypeAccessor &tacc) const
2194 {
2195     auto pandaFile = ctx_->GetJSPandaFile();
2196     auto targetPandaFile = tacc.GetPandaFile();
2197     if (pandaFile != targetPandaFile) {
2198         return false;
2199     }
2200     auto targetMethodId = tacc.GetMethodId();
2201     panda_file::IndexAccessor indexAccessor(*(targetPandaFile->GetPandaFile()),
2202                                             panda_file::File::EntityId(targetMethodId));
2203     auto targetCpId = static_cast<uint32_t>(indexAccessor.GetHeaderIndex());
2204     if (constPoolId_ != targetCpId) {
2205         return false;
2206     }
2207     return true;
2208 }
2209 
2210 template<class TypeAccessor>
ConvertCallTargetCheckToHeapConstantCheckAndLowerCall(const TypeAccessor & tacc,const std::vector<GateRef> & args,const std::vector<GateRef> & argsFastCall,uint32_t heapConstantIndex,bool isNoGC)2211 void TypedBytecodeLowering::ConvertCallTargetCheckToHeapConstantCheckAndLowerCall(const TypeAccessor &tacc,
2212     const std::vector<GateRef> &args, const std::vector<GateRef> &argsFastCall,
2213     uint32_t heapConstantIndex, bool isNoGC)
2214 {
2215     GateRef func = tacc.GetFunc();
2216     GateRef gate = tacc.GetGate();
2217     if (!Uncheck()) {
2218         GateRef frameState = acc_.GetFrameState(gate);
2219         GateRef res = builder_.HeapConstant(heapConstantIndex);
2220 #if DUMP_HEAP_OBJECT_DFX
2221         Label exit(&builder_);
2222         Label notEqual(&builder_);
2223         buidler_.Branch(builder_.Equal(func, res), &exit, &notEqual,
2224             BranchWeight::ONE_WEIGHT, BranchWeight::ONE_WEIGHT, "isEqualObject");
2225         builder_.Bind(&notEqual);
2226         {
2227             std::vector<GateRef> params;
2228             params.push_back(func);
2229             builder_.CallRuntime(glue_, RTSTUB_ID(DumpHeapObjectAddress), Gate::InvalidGateRef, params, gate);
2230             params.clear();
2231             params.push_back(res);
2232             builder_.CallRuntime(glue_, RTSTUB_ID(DumpHeapObjectAddress), Gate::InvalidGateRef, params, gate);
2233             builder_.Jump(&exit);
2234         }
2235         builder_.Bind(&exit);
2236 #endif
2237         builder_.DeoptCheck(builder_.Equal(func, res), frameState, DeoptType::NOTCALLTARGETHEAPOBJECT);
2238     }
2239     auto *jitCompilationEnv = static_cast<const JitCompilationEnv*>(compilationEnv_);
2240     JSHandle<JSTaggedValue> heapObject = jitCompilationEnv->GetHeapConstantHandle(heapConstantIndex);
2241     JSHandle<JSFunction> jsFunc = JSHandle<JSFunction>::Cast(heapObject);
2242     Method *calleeMethod = Method::Cast(jsFunc->GetMethod(compilationEnv_->GetJSThread()));
2243     ASSERT(calleeMethod->GetMethodLiteral(compilationEnv_->GetJSThread()) != nullptr);
2244     if (calleeMethod->GetMethodLiteral(compilationEnv_->GetJSThread())->IsFastCall()) {
2245         LowerFastCall(gate, func, argsFastCall, isNoGC);
2246     } else {
2247         LowerCall(gate, func, args, isNoGC);
2248     }
2249 }
2250 
2251 template<class TypeAccessor>
CheckCallTargetAndLowerCall(const TypeAccessor & tacc,const std::vector<GateRef> & args,const std::vector<GateRef> & argsFastCall)2252 void TypedBytecodeLowering::CheckCallTargetAndLowerCall(const TypeAccessor &tacc,
2253     const std::vector<GateRef> &args, const std::vector<GateRef> &argsFastCall)
2254 {
2255     GateRef func = tacc.GetFunc();
2256     if (IsLoadVtable(func)) {
2257         CheckThisCallTargetAndLowerCall(tacc, args, argsFastCall); // func = a.foo, func()
2258         return;
2259     }
2260     bool isNoGC = tacc.IsNoGC();
2261     auto op = acc_.GetOpCode(func);
2262     if (op == OpCode::JS_BYTECODE && (acc_.GetByteCodeOpcode(func) == EcmaOpcode::DEFINEFUNC_IMM8_ID16_IMM8 ||
2263                                       acc_.GetByteCodeOpcode(func) == EcmaOpcode::DEFINEFUNC_IMM16_ID16_IMM8)) {
2264         CheckCallTargetFromDefineFuncAndLowerCall(tacc, args, argsFastCall, isNoGC);
2265         return;
2266     }
2267 
2268     if (!tacc.MethodOffsetIsVaild()) {
2269         return;
2270     }
2271     if (!InSameConstPool(tacc)) {
2272         return;
2273     }
2274 
2275     auto heapConstantIndex = tacc.TryGetHeapConstantFunctionIndex(tacc.GetMethodId());
2276     if (heapConstantIndex != JitCompilationEnv::INVALID_HEAP_CONSTANT_INDEX) {
2277         ConvertCallTargetCheckToHeapConstantCheckAndLowerCall(tacc, args, argsFastCall, heapConstantIndex, isNoGC);
2278         return;
2279     }
2280 
2281     int methodIndex = tacc.GetMethodIndex();
2282     if (methodIndex == -1) {
2283         return;
2284     }
2285 
2286     GateRef gate = tacc.GetGate();
2287     if (tacc.CanFastCall()) {
2288         if (!Uncheck()) {
2289             builder_.JSCallTargetTypeCheck<TypedCallTargetCheckOp::JSCALL_FAST>(func,
2290                 builder_.IntPtr(methodIndex), gate);
2291         }
2292         LowerFastCall(gate, func, argsFastCall, isNoGC);
2293     } else {
2294         if (!Uncheck()) {
2295             builder_.JSCallTargetTypeCheck<TypedCallTargetCheckOp::JSCALL>(func,
2296                 builder_.IntPtr(methodIndex), gate);
2297         }
2298         LowerCall(gate, func, args, isNoGC);
2299     }
2300 }
2301 
2302 template<EcmaOpcode Op, class TypeAccessor>
LowerTypedCall(const TypeAccessor & tacc)2303 void TypedBytecodeLowering::LowerTypedCall(const TypeAccessor &tacc)
2304 {
2305     auto heapConstantIndex = tacc.TryGetHeapConstantFunctionIndex(tacc.GetMethodId());
2306     if (!tacc.IsHotnessFunc() &&
2307         heapConstantIndex == JitCompilationEnv::INVALID_HEAP_CONSTANT_INDEX) {
2308         return;
2309     }
2310     auto methodId = tacc.GetMethodId();
2311     if (methodId == 0) {
2312         return;
2313     }
2314     auto *methodLiteral = ctx_->GetJSPandaFile()->FindMethodLiteral(methodId);
2315     if (methodLiteral == nullptr || !methodLiteral->IsTypedCall()) {
2316         return;
2317     }
2318     uint32_t argc = tacc.GetArgc();
2319     GateRef gate = tacc.GetGate();
2320     GateRef actualArgc = Circuit::NullGate();
2321     GateRef actualArgv = builder_.IntPtr(0);
2322     switch (Op) {
2323         case EcmaOpcode::CALLARG0_IMM8: {
2324             actualArgc = builder_.Int64(BytecodeCallArgc::ComputeCallArgc(acc_.GetNumValueIn(gate),
2325                 EcmaOpcode::CALLARG0_IMM8));
2326             break;
2327         }
2328         case EcmaOpcode::CALLARG1_IMM8_V8: {
2329             actualArgc = builder_.Int64(BytecodeCallArgc::ComputeCallArgc(acc_.GetNumValueIn(gate),
2330                 EcmaOpcode::CALLARG1_IMM8_V8));
2331             break;
2332         }
2333         case EcmaOpcode::CALLARGS2_IMM8_V8_V8: {
2334             actualArgc = builder_.Int64(BytecodeCallArgc::ComputeCallArgc(acc_.GetNumValueIn(gate),
2335                 EcmaOpcode::CALLARGS2_IMM8_V8_V8));
2336             break;
2337         }
2338         case EcmaOpcode::CALLARGS3_IMM8_V8_V8_V8: {
2339             actualArgc = builder_.Int64(BytecodeCallArgc::ComputeCallArgc(acc_.GetNumValueIn(gate),
2340                 EcmaOpcode::CALLARGS3_IMM8_V8_V8_V8));
2341             break;
2342         }
2343         case EcmaOpcode::CALLRANGE_IMM8_IMM8_V8: {
2344             actualArgc = builder_.Int64(BytecodeCallArgc::ComputeCallArgc(acc_.GetNumValueIn(gate),
2345                 EcmaOpcode::CALLRANGE_IMM8_IMM8_V8));
2346             break;
2347         }
2348         default:
2349             UNREACHABLE();
2350     }
2351     uint32_t len = tacc.GetFunctionTypeLength();
2352     if (len == tacc.INVALID_LEN) {
2353         return;
2354     }
2355     GateRef func = tacc.GetFunc();
2356     GateRef newTarget = builder_.Undefined();
2357     GateRef thisObj = builder_.Undefined();
2358     std::vector<GateRef> argsFastCall { glue_, func, thisObj};
2359     std::vector<GateRef> args { glue_, actualArgc, actualArgv, func, newTarget, thisObj };
2360     for (uint32_t i = 0; i < argc; i++) {
2361         GateRef value = acc_.GetValueIn(gate, i);
2362         argsFastCall.emplace_back(value);
2363         args.emplace_back(value);
2364     }
2365     for (uint32_t i = argc; i < len; i++) {
2366         argsFastCall.emplace_back(builder_.Undefined());
2367         args.emplace_back(builder_.Undefined());
2368     }
2369     if (argc != len) {
2370         return ;
2371     }
2372     AddProfiling(gate);
2373     CheckCallTargetAndLowerCall(tacc, args, argsFastCall);
2374 }
2375 
GetCalleePandaFile(GateRef gate)2376 const JSPandaFile* TypedBytecodeLowering::GetCalleePandaFile(GateRef gate)
2377 {
2378     auto profileType = acc_.TryGetPGOType(gate).GetPGOSampleType();
2379     bool haveProfileType = profileType->IsProfileType() && !profileType->IsProfileTypeNone();
2380     if (haveProfileType) {
2381         if (compilationEnv_->IsJitCompiler()) {
2382             return compilationEnv_->GetJSPandaFile();
2383         }
2384         auto abcId = profileType->GetProfileType().GetAbcId();
2385         CString fileDesc;
2386         if (!decoder_->GetAbcNameById(abcId, fileDesc)) {
2387             UNREACHABLE();
2388         }
2389         fileDesc = JSPandaFile::GetNormalizedFileDesc(fileDesc);
2390         return JSPandaFileManager::GetInstance()->FindJSPandaFileByNormalizedName(fileDesc).get();
2391     }
2392     // nullptr if no pgo info
2393     return nullptr;
2394 }
2395 
LowerTypedCallArg0(GateRef gate)2396 void TypedBytecodeLowering::LowerTypedCallArg0(GateRef gate)
2397 {
2398     if (GetCalleePandaFile(gate) == nullptr) {
2399         return;
2400     }
2401     CallArg0TypeInfoAccessor tacc(compilationEnv_, circuit_, gate, GetCalleePandaFile(gate), callMethodFlagMap_);
2402     if (!tacc.IsValidCallMethodId()) {
2403         return;
2404     }
2405     LowerTypedCall<EcmaOpcode::CALLARG0_IMM8>(tacc);
2406 }
2407 
LowerTypedCallArg1(GateRef gate)2408 void TypedBytecodeLowering::LowerTypedCallArg1(GateRef gate)
2409 {
2410     if (GetCalleePandaFile(gate) == nullptr) {
2411         return;
2412     }
2413     CallArg1TypeInfoAccessor tacc(compilationEnv_, circuit_, gate, GetCalleePandaFile(gate), callMethodFlagMap_);
2414     GateRef func = tacc.GetFunc();
2415     GateRef a0Value = tacc.GetValue();
2416     BuiltinsStubCSigns::ID id = tacc.TryGetPGOBuiltinMethodId();
2417     if (!IS_INVALID_ID(id) && (IS_TYPED_BUILTINS_NUMBER_ID(id) || IS_TYPED_BUILTINS_GLOBAL_ID(id))) {
2418         if (IS_TYPED_INLINE_BUILTINS_ID(id)) {
2419             return;
2420         }
2421         AddProfiling(gate);
2422         if (IsFuncFromGlobal(func)) {
2423             // No need to do CallTargetCheck if func is from LOAD_BUILTIN_OBJECT.
2424             SpeculateCallBuiltinFromGlobal(gate, { a0Value }, id, true);
2425         } else {
2426             SpeculateCallBuiltin(gate, func, { a0Value }, id, true);
2427         }
2428     } else {
2429         if (!tacc.IsValidCallMethodId()) {
2430             return;
2431         }
2432         LowerTypedCall<EcmaOpcode::CALLARG1_IMM8_V8>(tacc);
2433     }
2434 }
2435 
LowerTypedCallArg2(GateRef gate)2436 void TypedBytecodeLowering::LowerTypedCallArg2(GateRef gate)
2437 {
2438     if (GetCalleePandaFile(gate) == nullptr) {
2439         return;
2440     }
2441     CallArg2TypeInfoAccessor tacc(compilationEnv_, circuit_, gate, GetCalleePandaFile(gate), callMethodFlagMap_);
2442     if (!tacc.IsValidCallMethodId()) {
2443         return;
2444     }
2445     LowerTypedCall<EcmaOpcode::CALLARGS2_IMM8_V8_V8>(tacc);
2446 }
2447 
LowerTypedCallArg3(GateRef gate)2448 void TypedBytecodeLowering::LowerTypedCallArg3(GateRef gate)
2449 {
2450     if (GetCalleePandaFile(gate) == nullptr) {
2451         return;
2452     }
2453     CallArg3TypeInfoAccessor tacc(compilationEnv_, circuit_, gate, GetCalleePandaFile(gate), callMethodFlagMap_);
2454     if (!tacc.IsValidCallMethodId()) {
2455         return;
2456     }
2457     LowerTypedCall<EcmaOpcode::CALLARGS3_IMM8_V8_V8_V8>(tacc);
2458 }
2459 
LowerTypedCallrange(GateRef gate)2460 void TypedBytecodeLowering::LowerTypedCallrange(GateRef gate)
2461 {
2462     if (GetCalleePandaFile(gate) == nullptr) {
2463         return;
2464     }
2465     CallRangeTypeInfoAccessor tacc(compilationEnv_, circuit_, gate, GetCalleePandaFile(gate), callMethodFlagMap_);
2466     if (!tacc.IsValidCallMethodId()) {
2467         return;
2468     }
2469     LowerTypedCall<EcmaOpcode::CALLRANGE_IMM8_IMM8_V8>(tacc);
2470 }
2471 
IsLoadVtable(GateRef func)2472 bool TypedBytecodeLowering::IsLoadVtable(GateRef func)
2473 {
2474     auto op = acc_.GetOpCode(func);
2475     if (op != OpCode::LOAD_PROPERTY) {
2476         return false;
2477     }
2478     return true;
2479 }
2480 
2481 template<EcmaOpcode Op, class TypeAccessor>
LowerTypedThisCall(const TypeAccessor & tacc)2482 void TypedBytecodeLowering::LowerTypedThisCall(const TypeAccessor &tacc)
2483 {
2484     auto methodId = tacc.GetMethodId();
2485     if (methodId == 0) {
2486         return;
2487     }
2488     auto *methodLiteral = ctx_->GetJSPandaFile()->FindMethodLiteral(methodId);
2489     if (methodLiteral == nullptr || !methodLiteral->IsTypedCall()) {
2490         return;
2491     }
2492     auto heapConstantIndex = tacc.TryGetHeapConstantFunctionIndex(methodId);
2493     if (!tacc.IsHotnessFunc() &&
2494         heapConstantIndex == JitCompilationEnv::INVALID_HEAP_CONSTANT_INDEX) {
2495         return;
2496     }
2497     uint32_t argc = tacc.GetArgc();
2498     GateRef gate = tacc.GetGate();
2499     GateRef actualArgc = Circuit::NullGate();
2500     GateRef actualArgv = builder_.IntPtr(0);
2501     switch (Op) {
2502         case EcmaOpcode::CALLTHIS0_IMM8_V8: {
2503             actualArgc = builder_.Int64(BytecodeCallArgc::ComputeCallArgc(acc_.GetNumValueIn(gate),
2504                 EcmaOpcode::CALLTHIS0_IMM8_V8));
2505             break;
2506         }
2507         case EcmaOpcode::CALLTHIS1_IMM8_V8_V8: {
2508             actualArgc = builder_.Int64(BytecodeCallArgc::ComputeCallArgc(acc_.GetNumValueIn(gate),
2509                 EcmaOpcode::CALLTHIS1_IMM8_V8_V8));
2510             break;
2511         }
2512         case EcmaOpcode::CALLTHIS2_IMM8_V8_V8_V8: {
2513             actualArgc = builder_.Int64(BytecodeCallArgc::ComputeCallArgc(acc_.GetNumValueIn(gate),
2514                 EcmaOpcode::CALLTHIS2_IMM8_V8_V8_V8));
2515             break;
2516         }
2517         case EcmaOpcode::CALLTHIS3_IMM8_V8_V8_V8_V8: {
2518             actualArgc = builder_.Int64(BytecodeCallArgc::ComputeCallArgc(acc_.GetNumValueIn(gate),
2519                 EcmaOpcode::CALLTHIS3_IMM8_V8_V8_V8_V8));
2520             break;
2521         }
2522         case EcmaOpcode::CALLTHISRANGE_IMM8_IMM8_V8: {
2523             actualArgc = builder_.Int64(BytecodeCallArgc::ComputeCallArgc(acc_.GetNumValueIn(gate),
2524                 EcmaOpcode::CALLTHISRANGE_IMM8_IMM8_V8));
2525             break;
2526         }
2527         default:
2528             UNREACHABLE();
2529     }
2530 
2531     uint32_t len = tacc.GetFunctionTypeLength();
2532     if (len == tacc.INVALID_LEN) {
2533         return;
2534     }
2535     GateRef func = tacc.GetFunc();
2536     GateRef newTarget = builder_.Undefined();
2537     GateRef thisObj = tacc.GetThisObj();
2538     std::vector<GateRef> argsFastCall { glue_, func, thisObj};
2539     std::vector<GateRef> args { glue_, actualArgc, actualArgv, func, newTarget, thisObj };
2540     for (uint32_t i = 0; i < argc; i++) {
2541         GateRef value = acc_.GetValueIn(gate, i + 1);
2542         argsFastCall.emplace_back(value);
2543         args.emplace_back(value);
2544     }
2545     for (uint32_t i = argc; i < len; i++) {
2546         argsFastCall.emplace_back(builder_.Undefined());
2547         args.emplace_back(builder_.Undefined());
2548     }
2549     AddProfiling(gate);
2550     CheckThisCallTargetAndLowerCall(tacc, args, argsFastCall);
2551 }
2552 
LowerTypedCallthis0(GateRef gate)2553 void TypedBytecodeLowering::LowerTypedCallthis0(GateRef gate)
2554 {
2555     if (GetCalleePandaFile(gate) == nullptr) {
2556         return;
2557     }
2558     CallThis0TypeInfoAccessor tacc(compilationEnv_, circuit_, gate, GetCalleePandaFile(gate), callMethodFlagMap_);
2559     BuiltinsStubCSigns::ID pgoFuncId = tacc.TryGetPGOBuiltinMethodId();
2560     if (!IS_INVALID_ID(pgoFuncId) && IS_TYPED_BUILTINS_ID_CALL_THIS0(pgoFuncId)) {
2561         AddProfiling(gate);
2562         SpeculateCallBuiltin(gate, tacc.GetFunc(), {tacc.GetThisObj()}, pgoFuncId, true);
2563         return;
2564     }
2565     if (!tacc.CanOptimizeAsFastCall()) {
2566         return;
2567     }
2568     LowerTypedThisCall<EcmaOpcode::CALLTHIS0_IMM8_V8>(tacc);
2569 }
2570 
LowerTypedCallthis1(GateRef gate)2571 void TypedBytecodeLowering::LowerTypedCallthis1(GateRef gate)
2572 {
2573     if (GetCalleePandaFile(gate) == nullptr) {
2574         return;
2575     }
2576     CallThis1TypeInfoAccessor tacc(compilationEnv_, circuit_, gate, GetCalleePandaFile(gate), callMethodFlagMap_);
2577     BuiltinsStubCSigns::ID pgoFuncId = tacc.TryGetPGOBuiltinMethodId();
2578     if (!IS_INVALID_ID(pgoFuncId) && IS_TYPED_BUILTINS_ID_CALL_THIS1(pgoFuncId)) {
2579         AddProfiling(gate);
2580         SpeculateCallBuiltin(gate, tacc.GetFunc(), {tacc.GetArgs()}, pgoFuncId, true);
2581         return;
2582     }
2583     if (!tacc.CanOptimizeAsFastCall()) {
2584         return;
2585     }
2586     LowerTypedThisCall<EcmaOpcode::CALLTHIS1_IMM8_V8_V8>(tacc);
2587 }
2588 
LowerTypedCallthis2(GateRef gate)2589 void TypedBytecodeLowering::LowerTypedCallthis2(GateRef gate)
2590 {
2591     if (GetCalleePandaFile(gate) == nullptr) {
2592         return;
2593     }
2594     CallThis2TypeInfoAccessor tacc(compilationEnv_, circuit_, gate, GetCalleePandaFile(gate), callMethodFlagMap_);
2595     BuiltinsStubCSigns::ID pgoFuncId = tacc.TryGetPGOBuiltinMethodId();
2596     if (!IS_INVALID_ID(pgoFuncId) && IS_TYPED_BUILTINS_ID_CALL_THIS2(pgoFuncId)) {
2597         AddProfiling(gate);
2598         SpeculateCallBuiltin(gate, tacc.GetFunc(), { tacc.GetArgs() }, pgoFuncId, true);
2599         return;
2600     }
2601     if (!tacc.CanOptimizeAsFastCall()) {
2602         return;
2603     }
2604     LowerTypedThisCall<EcmaOpcode::CALLTHIS2_IMM8_V8_V8_V8>(tacc);
2605 }
2606 
LowerTypedCallthis3(GateRef gate)2607 void TypedBytecodeLowering::LowerTypedCallthis3(GateRef gate)
2608 {
2609     if (GetCalleePandaFile(gate) == nullptr) {
2610         return;
2611     }
2612     CallThis3TypeInfoAccessor tacc(compilationEnv_, circuit_, gate, GetCalleePandaFile(gate), callMethodFlagMap_);
2613     BuiltinsStubCSigns::ID pgoFuncId = tacc.TryGetPGOBuiltinMethodId();
2614     if (!IS_INVALID_ID(pgoFuncId) && IS_TYPED_BUILTINS_ID_CALL_THIS3(pgoFuncId)) {
2615         AddProfiling(gate);
2616         SpeculateCallBuiltin(gate, tacc.GetFunc(), { tacc.GetArgs() }, pgoFuncId, true);
2617         return;
2618     }
2619     if (!tacc.CanOptimizeAsFastCall()) {
2620         return;
2621     }
2622     LowerTypedThisCall<EcmaOpcode::CALLTHIS3_IMM8_V8_V8_V8_V8>(tacc);
2623 }
2624 
LowerTypedCallthisrange(GateRef gate)2625 void TypedBytecodeLowering::LowerTypedCallthisrange(GateRef gate)
2626 {
2627     if (GetCalleePandaFile(gate) == nullptr) {
2628         return;
2629     }
2630     CallThisRangeTypeInfoAccessor tacc(compilationEnv_, circuit_, gate, GetCalleePandaFile(gate), callMethodFlagMap_);
2631     if (!tacc.CanOptimizeAsFastCall()) {
2632         return;
2633     }
2634     LowerTypedThisCall<EcmaOpcode::CALLTHISRANGE_IMM8_IMM8_V8>(tacc);
2635 }
2636 
LowerTypedCallInit(GateRef gate)2637 void TypedBytecodeLowering::LowerTypedCallInit(GateRef gate)
2638 {
2639     // same as callthis0
2640     LowerTypedCallthis0(gate);
2641 }
2642 
AddProfiling(GateRef gate)2643 void TypedBytecodeLowering::AddProfiling(GateRef gate)
2644 {
2645     hitTypedOpCount_++;
2646     AddHitBytecodeCount();
2647     if (IsTraceBC()) {
2648         // see stateSplit as a part of JSByteCode if exists
2649         GateRef maybeStateSplit = acc_.GetDep(gate);
2650         GateRef current = Circuit::NullGate();
2651         if (acc_.GetOpCode(maybeStateSplit) == OpCode::STATE_SPLIT) {
2652             current = maybeStateSplit;
2653         } else {
2654             current = gate;
2655         }
2656 
2657         EcmaOpcode ecmaOpcode = acc_.GetByteCodeOpcode(gate);
2658         auto ecmaOpcodeGate = builder_.Int32(static_cast<uint32_t>(ecmaOpcode));
2659         GateRef constOpcode = builder_.Int32ToTaggedInt(ecmaOpcodeGate);
2660         GateRef typedPath = builder_.Int32ToTaggedInt(builder_.Int32(1));
2661         GateRef traceGate = builder_.CallRuntime(glue_, RTSTUB_ID(DebugAOTPrint), acc_.GetDep(current),
2662                                                  { constOpcode, typedPath }, gate);
2663         acc_.SetDep(current, traceGate);
2664         builder_.SetDepend(acc_.GetDep(gate));  // set gate depend: trace or STATE_SPLIT
2665     }
2666 
2667     if (IsProfiling()) {
2668         // see stateSplit as a part of JSByteCode if exists
2669         GateRef maybeStateSplit = acc_.GetDep(gate);
2670         GateRef current = Circuit::NullGate();
2671         if (acc_.GetOpCode(maybeStateSplit) == OpCode::STATE_SPLIT) {
2672             current = maybeStateSplit;
2673         } else {
2674             current = gate;
2675         }
2676 
2677         GateRef func = builder_.Undefined();
2678         if (acc_.HasFrameState(gate)) {
2679             func = argAcc_->GetFrameArgsIn(gate, FrameArgIdx::FUNC);
2680         }
2681 
2682         GateRef bcIndex = builder_.Int32ToTaggedInt(builder_.Int32(acc_.TryGetBcIndex(gate)));
2683         EcmaOpcode ecmaOpcode = acc_.GetByteCodeOpcode(gate);
2684         auto ecmaOpcodeGate = builder_.Int32(static_cast<uint32_t>(ecmaOpcode));
2685         GateRef constOpcode = builder_.Int32ToTaggedInt(ecmaOpcodeGate);
2686         GateRef mode =
2687             builder_.Int32ToTaggedInt(builder_.Int32(static_cast<int32_t>(OptCodeProfiler::Mode::TYPED_PATH)));
2688         GateRef profiling = builder_.CallRuntime(glue_, RTSTUB_ID(ProfileOptimizedCode), acc_.GetDep(current),
2689             { func, bcIndex, constOpcode, mode }, gate);
2690         acc_.SetDep(current, profiling);
2691         builder_.SetDepend(acc_.GetDep(gate));  // set gate depend: profiling or STATE_SPLIT
2692     }
2693 }
2694 
AddBytecodeCount(EcmaOpcode op)2695 void TypedBytecodeLowering::AddBytecodeCount(EcmaOpcode op)
2696 {
2697     currentOp_ = op;
2698     if (bytecodeMap_.find(op) != bytecodeMap_.end()) {
2699         bytecodeMap_[op]++;
2700     } else {
2701         bytecodeMap_[op] = 1;
2702     }
2703 }
2704 
DeleteBytecodeCount(EcmaOpcode op)2705 void TypedBytecodeLowering::DeleteBytecodeCount(EcmaOpcode op)
2706 {
2707     bytecodeMap_.erase(op);
2708 }
2709 
AddHitBytecodeCount()2710 void TypedBytecodeLowering::AddHitBytecodeCount()
2711 {
2712     if (bytecodeHitTimeMap_.find(currentOp_) != bytecodeHitTimeMap_.end()) {
2713         bytecodeHitTimeMap_[currentOp_]++;
2714     } else {
2715         bytecodeHitTimeMap_[currentOp_] = 1;
2716     }
2717 }
2718 
LowerTypedTypeOf(GateRef gate)2719 void TypedBytecodeLowering::LowerTypedTypeOf(GateRef gate)
2720 {
2721     TypeOfTypeInfoAccessor tacc(compilationEnv_, circuit_, gate);
2722     if (tacc.IsIllegalType()) {
2723         return;
2724     }
2725     AddProfiling(gate);
2726     if (!Uncheck()) {
2727         builder_.TypeOfCheck(tacc.GetValue(), tacc.GetParamType());
2728     }
2729     GateRef result = builder_.TypedTypeOf(tacc.GetParamType());
2730     acc_.ReplaceHirAndReplaceDeadIfException(gate, builder_.GetStateDepend(), result);
2731 }
2732 
LowerGetIterator(GateRef gate)2733 void TypedBytecodeLowering::LowerGetIterator(GateRef gate)
2734 {
2735     if (GetCalleePandaFile(gate) == nullptr) {
2736         return;
2737     }
2738     GetIteratorTypeInfoAccessor tacc(compilationEnv_, circuit_, gate, GetCalleePandaFile(gate), callMethodFlagMap_);
2739     BuiltinsStubCSigns::ID id = tacc.TryGetPGOBuiltinMethodId();
2740     if (IS_INVALID_ID(id) || id == BuiltinsStubCSigns::ID::NONE) {
2741         return;
2742     }
2743     AddProfiling(gate);
2744     GateRef obj = tacc.GetCallee();
2745     SpeculateCallBuiltin(gate, obj, { obj }, id, true);
2746 }
2747 
LowerTypedTryLdGlobalByName(GateRef gate)2748 void TypedBytecodeLowering::LowerTypedTryLdGlobalByName(GateRef gate)
2749 {
2750     if (!enableLoweringBuiltin_) {
2751         return;
2752     }
2753     LoadGlobalObjByNameTypeInfoAccessor tacc(compilationEnv_, circuit_, gate);
2754     JSTaggedValue key = tacc.GetKeyTaggedValue();
2755     if (key.IsUndefined()) {
2756         return;
2757     }
2758 
2759     BuiltinIndex& builtin = BuiltinIndex::GetInstance();
2760     auto index = builtin.GetBuiltinIndex(compilationEnv_->GetJSThread(), key);
2761     if (index != builtin.NOT_FOUND) {
2762         AddProfiling(gate);
2763         GateRef result = builder_.LoadBuiltinObject(index);
2764         acc_.ReplaceHirAndReplaceDeadIfException(gate, builder_.GetStateDepend(), result);
2765         DeleteConstDataIfNoUser(tacc.GetKey());
2766         return;
2767     }
2768 
2769     if (compilationEnv_->IsJitCompiler()) {
2770         uint32_t pcOffset = acc_.TryGetPcOffset(gate);
2771         uint32_t methodOffset = acc_.TryGetMethodOffset(gate);
2772         uint32_t heapConstantIndex = static_cast<const JitCompilationEnv*>(compilationEnv_)->
2773                 GetLdGlobalByNameBcOffset2HeapConstantIndex(methodOffset, pcOffset);
2774         if (heapConstantIndex == JitCompilationEnv::INVALID_HEAP_CONSTANT_INDEX) {
2775             return;
2776         }
2777         AddProfiling(gate);
2778         GateRef frameState = acc_.FindNearestFrameState(builder_.GetDepend());
2779         GateRef propertyBoxConst = builder_.HeapConstant(heapConstantIndex);
2780         GateRef boxValue = builder_.LoadConstOffset(
2781             VariableType::JS_ANY(), propertyBoxConst, PropertyBox::VALUE_OFFSET);
2782         builder_.DeoptCheck(builder_.TaggedIsNotHole(boxValue), frameState, DeoptType::PROPERTYBOXINVALID);
2783         acc_.ReplaceHirAndReplaceDeadIfException(gate, builder_.GetStateDepend(), boxValue);
2784         DeleteConstDataIfNoUser(tacc.GetKey());
2785     }
2786 }
2787 
LowerInstanceOf(GateRef gate)2788 void TypedBytecodeLowering::LowerInstanceOf(GateRef gate)
2789 {
2790     InstanceOfTypeInfoAccessor tacc(compilationEnv_, circuit_, gate, chunk_);
2791     if (tacc.TypesIsEmpty() || tacc.HasIllegalType()) {
2792         return;
2793     }
2794     AddProfiling(gate);
2795     size_t typeCount = tacc.GetTypeCount();
2796     std::vector<GateRef> expectedHCIndexes;
2797     for (size_t i = 0; i < typeCount; ++i) {
2798         GateRef temp = builder_.Int32(tacc.GetExpectedHClassIndex(i));
2799         expectedHCIndexes.emplace_back(temp);
2800     }
2801     DEFVALUE(result, (&builder_), VariableType::JS_ANY(), builder_.Hole());
2802     // RuntimeCheck -
2803     // 1. pgo.hclass == ctor.hclass
2804     // 2. ctor.hclass has a prototype chain up to Function.prototype
2805     GateRef obj = tacc.GetReceiver();
2806     GateRef target = tacc.GetTarget();
2807 
2808     builder_.ObjectTypeCheck(false, target, expectedHCIndexes[0]);
2809     builder_.ProtoChangeMarkerCheck(target);
2810 
2811     result = builder_.OrdinaryHasInstance(obj, target);
2812     acc_.ReplaceHirAndReplaceDeadIfException(gate, builder_.GetStateDepend(), *result);
2813 }
2814 
LowerCreateEmptyObject(GateRef gate)2815 void TypedBytecodeLowering::LowerCreateEmptyObject(GateRef gate)
2816 {
2817     AddProfiling(gate);
2818     GateRef globalEnv = circuit_->GetGlobalEnvCache();
2819     GateRef hclass = builder_.GetGlobalEnvObjHClass(globalEnv, GlobalEnv::OBJECT_FUNCTION_INDEX);
2820 
2821     JSHandle<JSFunction> objectFunc(compilationEnv_->GetGlobalEnv()->GetObjectFunction());
2822     JSTaggedValue protoOrHClass = objectFunc->GetProtoOrHClass(compilationEnv_->GetJSThread());
2823     JSHClass *objectHC = JSHClass::Cast(protoOrHClass.GetTaggedObject());
2824     size_t objectSize = objectHC->GetObjectSize();
2825 
2826     GateRef emptyArray = builder_.GetGlobalConstantValue(ConstantIndex::EMPTY_ARRAY_OBJECT_INDEX);
2827     GateRef size = builder_.IntPtr(objectHC->GetObjectSize());
2828 
2829     builder_.StartAllocate();
2830     GateRef object = builder_.HeapAlloc(glue_, size, GateType::TaggedValue(), RegionSpaceFlag::IN_YOUNG_SPACE);
2831 
2832     // initialization
2833     for (size_t offset = JSObject::SIZE; offset < objectSize; offset += JSTaggedValue::TaggedTypeSize()) {
2834         builder_.StoreConstOffset(VariableType::INT64(), object, offset, builder_.Undefined());
2835     }
2836     builder_.StoreHClass(glue_, object, hclass, MemoryAttribute::NeedBarrierAndAtomic());
2837     builder_.StoreConstOffset(VariableType::INT64(), object, JSObject::HASH_OFFSET,
2838                               builder_.Int64(JSTaggedValue(0).GetRawData()));
2839     builder_.StoreConstOffset(VariableType::JS_POINTER(), object, JSObject::PROPERTIES_OFFSET, emptyArray,
2840                               MemoryAttribute::NoBarrier());
2841     builder_.StoreConstOffset(VariableType::JS_POINTER(), object, JSObject::ELEMENTS_OFFSET, emptyArray,
2842                               MemoryAttribute::NoBarrier());
2843     GateRef result = builder_.FinishAllocate(object);
2844 
2845     acc_.ReplaceHirAndReplaceDeadIfException(gate, builder_.GetStateDepend(), result);
2846 }
2847 
LowerTypedStOwnByValue(GateRef gate)2848 void TypedBytecodeLowering::LowerTypedStOwnByValue(GateRef gate)
2849 {
2850     // StOwnByValue is rarely used, so the callruntime solution is used
2851     AddProfiling(gate);
2852     return;
2853 }
2854 
LowerCreateObjectWithBuffer(GateRef gate)2855 void TypedBytecodeLowering::LowerCreateObjectWithBuffer(GateRef gate)
2856 {
2857     CreateObjWithBufferTypeInfoAccessor tacc(compilationEnv_, circuit_, gate, recordName_, chunk_);
2858     JSThread *thread = compilationEnv_->GetJSThread();
2859     if (!tacc.CanOptimize(thread)) {
2860         return;
2861     }
2862     JSTaggedValue hclassVal = tacc.GetHClass();
2863     if (hclassVal.IsUndefined()) {
2864         return;
2865     }
2866     JSHClass *newClass = JSHClass::Cast(hclassVal.GetTaggedObject());
2867     GateRef index = tacc.GetIndex();
2868     JSTaggedValue obj = tacc.GetObject();
2869     if (obj.IsUndefined()) {
2870         return;
2871     }
2872     JSObject *objhandle = JSObject::Cast(obj);
2873     std::vector<uint64_t> inlinedProps;
2874     auto layout = LayoutInfo::Cast(newClass->GetLayout(thread).GetTaggedObject());
2875     uint32_t numOfProps = newClass->NumberOfProps();
2876     uint32_t numInlinedProps = newClass->GetInlinedProperties();
2877     for (uint32_t i = 0; i < numOfProps; i++) {
2878         auto attr = layout->GetAttr(thread, i);
2879         JSTaggedValue value = objhandle->GetPropertyInlinedProps(thread, i);
2880         if ((!attr.IsTaggedRep()) || value.IsUndefinedOrNull() ||
2881             value.IsNumber() || value.IsBoolean() || value.IsException()) {
2882             auto converted = JSObject::ConvertValueWithRep(attr, value);
2883             if (!converted.first) {
2884                 return;
2885             }
2886             // CanOptimize.GetObject had convert value, just used directly
2887             inlinedProps.emplace_back(value.GetRawData());
2888         } else {
2889             return;
2890         }
2891     }
2892 
2893     AddProfiling(gate);
2894     auto size = newClass->GetObjectSize();
2895     std::vector<GateRef> valueIn;
2896     valueIn.emplace_back(builder_.IntPtr(size));
2897     valueIn.emplace_back(index);
2898     valueIn.emplace_back(builder_.Int64(JSTaggedValue(newClass).GetRawData()));
2899     valueIn.emplace_back(acc_.GetValueIn(gate, 1));
2900     for (uint32_t i = 0; i < numOfProps; i++) {
2901         auto attr = layout->GetAttr(thread, i);
2902         GateRef prop;
2903         if (attr.IsIntRep()) {
2904             prop = builder_.Int32(inlinedProps.at(i));
2905         } else if (attr.IsTaggedRep()) {
2906             prop = circuit_->NewGate(circuit_->GetMetaBuilder()->Constant(inlinedProps.at(i)),
2907                                      MachineType::I64, GateType::AnyType());
2908         } else if (attr.IsDoubleRep()) {
2909             prop = circuit_->NewGate(circuit_->GetMetaBuilder()->Constant(inlinedProps.at(i)),
2910                                      MachineType::F64, GateType::NJSValue());
2911         } else {
2912             prop = builder_.Int64(inlinedProps.at(i));
2913         }
2914         valueIn.emplace_back(prop);
2915         valueIn.emplace_back(builder_.Int32(newClass->GetInlinedPropertiesOffset(i)));
2916     }
2917     GateRef prop = newClass->IsAOT() ? builder_.Hole() : builder_.Undefined();
2918     for (uint32_t i = numOfProps; i < numInlinedProps; i++) {
2919         valueIn.emplace_back(prop);
2920         valueIn.emplace_back(builder_.Int32(newClass->GetInlinedPropertiesOffset(i)));
2921     }
2922     GateRef ret = builder_.TypedCreateObjWithBuffer(valueIn);
2923     if (compilationEnv_->SupportHeapConstant()) {
2924         auto *jitCompilationEnv = static_cast<JitCompilationEnv*>(compilationEnv_);
2925         JSHandle<JSTaggedValue> jsObjectHandle = jitCompilationEnv->NewJSHandle(obj);
2926         auto methodOffset = acc_.TryGetMethodOffset(gate);
2927         auto objIndex = acc_.GetConstantValue(index);
2928         auto constpool = jitCompilationEnv->GetConstantPoolByMethodOffset(methodOffset);
2929         ASSERT(!constpool.IsUndefined());
2930         auto constpoolId = static_cast<uint32_t>(
2931             ConstantPool::Cast(constpool.GetTaggedObject())->GetSharedConstpoolId().GetInt());
2932         uint32_t indexInConstantTable = jitCompilationEnv->RecordHeapConstant(
2933             { constpoolId, objIndex, JitCompilationEnv::IN_UNSHARED_CONSTANTPOOL }, jsObjectHandle);
2934         jitCompilationEnv->RecordGate2HeapConstantIndex(ret, indexInConstantTable);
2935     }
2936     acc_.ReplaceHirAndReplaceDeadIfException(gate, builder_.GetStateDepend(), ret);
2937 }
2938 
ReplaceGateWithPendingException(GateRef glue,GateRef gate,GateRef state,GateRef depend,GateRef value)2939 void TypedBytecodeLowering::ReplaceGateWithPendingException(GateRef glue, GateRef gate, GateRef state, GateRef depend,
2940                                                             GateRef value)
2941 {
2942     auto condition = builder_.HasPendingException(glue, compilationEnv_);
2943     GateRef ifBranch = builder_.Branch(state, condition, 1, BranchWeight::DEOPT_WEIGHT, "checkException");
2944     GateRef ifTrue = builder_.IfTrue(ifBranch);
2945     GateRef ifFalse = builder_.IfFalse(ifBranch);
2946     GateRef eDepend = builder_.DependRelay(ifTrue, depend);
2947     GateRef sDepend = builder_.DependRelay(ifFalse, depend);
2948 
2949     StateDepend success(ifFalse, sDepend);
2950     StateDepend exception(ifTrue, eDepend);
2951     acc_.ReplaceHirWithIfBranch(gate, success, exception, value);
2952 }
2953 
ReplaceHirWithCheckingAccessor(GateRef glue,GateRef hirGate,StateDepend replacement,GateRef value,bool isAccessor)2954 void TypedBytecodeLowering::ReplaceHirWithCheckingAccessor(GateRef glue, GateRef hirGate, StateDepend replacement,
2955     GateRef value, bool isAccessor)
2956 {
2957     if (isAccessor) {
2958         ReplaceGateWithPendingException(glue, hirGate, replacement.State(), replacement.Depend(), value);
2959     } else {
2960         acc_.ReplaceHirAndReplaceDeadIfException(hirGate, replacement, value);
2961     }
2962 }
2963 }  // namespace panda::ecmascript
2964