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