• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "ecmascript/compiler/typed_bytecode_lowering.h"
17 #include "ecmascript/builtin_entries.h"
18 #include "ecmascript/compiler/builtins_lowering.h"
19 #include "ecmascript/compiler/bytecodes.h"
20 #include "ecmascript/compiler/circuit.h"
21 #include "ecmascript/dfx/vmstat/opt_code_profiler.h"
22 #include "ecmascript/enum_conversion.h"
23 #include "ecmascript/js_tagged_value.h"
24 #include "ecmascript/jspandafile/program_object.h"
25 #include "ecmascript/stackmap/llvm_stackmap_parser.h"
26 
27 namespace panda::ecmascript::kungfu {
RunTypedBytecodeLowering()28 bool TypedBytecodeLowering::RunTypedBytecodeLowering()
29 {
30     std::vector<GateRef> gateList;
31     circuit_->GetAllGates(gateList);
32     for (const auto &gate : gateList) {
33         auto op = acc_.GetOpCode(gate);
34         if (op == OpCode::JS_BYTECODE) {
35             Lower(gate);
36             allJSBcCount_++;
37         }
38     }
39 
40     bool success = true;
41     double typeHitRate = 0.0;
42     auto allTypedOpCount = allJSBcCount_ - allNonTypedOpCount_;
43     if (allTypedOpCount != 0) {
44         typeHitRate = static_cast<double>(hitTypedOpCount_) / static_cast<double>(allTypedOpCount);
45         auto typeThreshold = tsManager_->GetTypeThreshold();
46         if (typeHitRate <= typeThreshold) {
47             success = false;
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         circuit_->PrintAllGatesWithBytecode();
64         LOG_COMPILER(INFO) << "\033[34m" << " =========================== End typeHitRate: "
65                            << std::to_string(typeHitRate)
66                            << " ===========================" << "\033[0m";
67         for (auto a : bytecodeMap_) {
68             if (bytecodeHitTimeMap_.find(a.first) != bytecodeHitTimeMap_.end()) {
69                 double rate = static_cast<double>(bytecodeHitTimeMap_[a.first]) / static_cast<double>(a.second);
70                 LOG_COMPILER(INFO) << "\033[34m" << " =========================== End opHitRate: "
71                                    << GetEcmaOpcodeStr(a.first) << " rate: " << std::to_string(rate)
72                                    << "(" << std::to_string(bytecodeHitTimeMap_[a.first])
73                                    << " / " << std::to_string(a.second) << ")"
74                                    << " ===========================" << "\033[0m";
75             } else {
76                 LOG_COMPILER(INFO) << "\033[34m" << " =========================== End opHitRate: "
77                                    << GetEcmaOpcodeStr(a.first) << " rate: " << std::to_string(0)
78                                    << "(" << std::to_string(0)
79                                    << " / " << std::to_string(a.second) << ")"
80                                    << " ===========================" << "\033[0m";
81             }
82         }
83     }
84 
85     return success;
86 }
87 
Lower(GateRef gate)88 void TypedBytecodeLowering::Lower(GateRef gate)
89 {
90     EcmaOpcode ecmaOpcode = acc_.GetByteCodeOpcode(gate);
91     // initialize label manager
92     Environment env(gate, circuit_, &builder_);
93     AddBytecodeCount(ecmaOpcode);
94     switch (ecmaOpcode) {
95         case EcmaOpcode::ADD2_IMM8_V8:
96             LowerTypedBinOp<TypedBinOp::TYPED_ADD>(gate);
97             break;
98         case EcmaOpcode::SUB2_IMM8_V8:
99             LowerTypedBinOp<TypedBinOp::TYPED_SUB>(gate);
100             break;
101         case EcmaOpcode::MUL2_IMM8_V8:
102             LowerTypedBinOp<TypedBinOp::TYPED_MUL>(gate);
103             break;
104         case EcmaOpcode::DIV2_IMM8_V8:
105             LowerTypedBinOp<TypedBinOp::TYPED_DIV>(gate);
106             break;
107         case EcmaOpcode::MOD2_IMM8_V8:
108             LowerTypedBinOp<TypedBinOp::TYPED_MOD>(gate);
109             break;
110         case EcmaOpcode::LESS_IMM8_V8:
111             LowerTypedBinOp<TypedBinOp::TYPED_LESS>(gate);
112             break;
113         case EcmaOpcode::LESSEQ_IMM8_V8:
114             LowerTypedBinOp<TypedBinOp::TYPED_LESSEQ>(gate);
115             break;
116         case EcmaOpcode::GREATER_IMM8_V8:
117             LowerTypedBinOp<TypedBinOp::TYPED_GREATER>(gate);
118             break;
119         case EcmaOpcode::GREATEREQ_IMM8_V8:
120             LowerTypedBinOp<TypedBinOp::TYPED_GREATEREQ>(gate);
121             break;
122         case EcmaOpcode::EQ_IMM8_V8:
123             LowerTypedEqOrNotEq<TypedBinOp::TYPED_EQ>(gate);
124             break;
125         case EcmaOpcode::STRICTEQ_IMM8_V8:
126             LowerTypedEqOrNotEq<TypedBinOp::TYPED_STRICTEQ>(gate);
127             break;
128         case EcmaOpcode::NOTEQ_IMM8_V8:
129             LowerTypedEqOrNotEq<TypedBinOp::TYPED_NOTEQ>(gate);
130             break;
131         case EcmaOpcode::STRICTNOTEQ_IMM8_V8:
132             LowerTypedEqOrNotEq<TypedBinOp::TYPED_STRICTNOTEQ>(gate);
133             break;
134         case EcmaOpcode::SHL2_IMM8_V8:
135             LowerTypedBinOp<TypedBinOp::TYPED_SHL>(gate);
136             break;
137         case EcmaOpcode::SHR2_IMM8_V8:
138             LowerTypedBinOp<TypedBinOp::TYPED_SHR>(gate);
139             break;
140         case EcmaOpcode::ASHR2_IMM8_V8:
141             LowerTypedBinOp<TypedBinOp::TYPED_ASHR>(gate);
142             break;
143         case EcmaOpcode::AND2_IMM8_V8:
144             LowerTypedBinOp<TypedBinOp::TYPED_AND>(gate);
145             break;
146         case EcmaOpcode::OR2_IMM8_V8:
147             LowerTypedBinOp<TypedBinOp::TYPED_OR>(gate);
148             break;
149         case EcmaOpcode::XOR2_IMM8_V8:
150             LowerTypedBinOp<TypedBinOp::TYPED_XOR>(gate);
151             break;
152         case EcmaOpcode::TONUMERIC_IMM8:
153             LowerTypeToNumeric(gate);
154             break;
155         case EcmaOpcode::NEG_IMM8:
156             LowerTypedUnOp<TypedUnOp::TYPED_NEG>(gate);
157             break;
158         case EcmaOpcode::NOT_IMM8:
159             LowerTypedUnOp<TypedUnOp::TYPED_NOT>(gate);
160             break;
161         case EcmaOpcode::INC_IMM8:
162             LowerTypedUnOp<TypedUnOp::TYPED_INC>(gate);
163             break;
164         case EcmaOpcode::DEC_IMM8:
165             LowerTypedUnOp<TypedUnOp::TYPED_DEC>(gate);
166             break;
167         case EcmaOpcode::ISTRUE:
168             LowerTypedIsTrueOrFalse(gate, true);
169             break;
170         case EcmaOpcode::ISFALSE:
171             LowerTypedIsTrueOrFalse(gate, false);
172             break;
173         case EcmaOpcode::JEQZ_IMM8:
174         case EcmaOpcode::JEQZ_IMM16:
175         case EcmaOpcode::JEQZ_IMM32:
176             LowerConditionJump(gate, false);
177             break;
178         case EcmaOpcode::JNEZ_IMM8:
179         case EcmaOpcode::JNEZ_IMM16:
180         case EcmaOpcode::JNEZ_IMM32:
181             LowerConditionJump(gate, true);
182             break;
183         case EcmaOpcode::LDOBJBYNAME_IMM8_ID16:
184         case EcmaOpcode::LDOBJBYNAME_IMM16_ID16:
185         case EcmaOpcode::LDTHISBYNAME_IMM8_ID16:
186         case EcmaOpcode::LDTHISBYNAME_IMM16_ID16:
187             LowerTypedLdObjByName(gate);
188             break;
189         case EcmaOpcode::STOBJBYNAME_IMM8_ID16_V8:
190         case EcmaOpcode::STOBJBYNAME_IMM16_ID16_V8:
191         case EcmaOpcode::STTHISBYNAME_IMM8_ID16:
192         case EcmaOpcode::STTHISBYNAME_IMM16_ID16:
193         case EcmaOpcode::DEFINEFIELDBYNAME_IMM8_ID16_V8:
194             LowerTypedStObjByName(gate);
195             break;
196         case EcmaOpcode::STOWNBYNAME_IMM8_ID16_V8:
197         case EcmaOpcode::STOWNBYNAME_IMM16_ID16_V8:
198             LowerTypedStOwnByName(gate);
199             break;
200         case EcmaOpcode::LDOBJBYINDEX_IMM8_IMM16:
201         case EcmaOpcode::LDOBJBYINDEX_IMM16_IMM16:
202         case EcmaOpcode::WIDE_LDOBJBYINDEX_PREF_IMM32:
203             LowerTypedLdObjByIndex(gate);
204             break;
205         case EcmaOpcode::STOBJBYINDEX_IMM8_V8_IMM16:
206         case EcmaOpcode::STOBJBYINDEX_IMM16_V8_IMM16:
207         case EcmaOpcode::WIDE_STOBJBYINDEX_PREF_V8_IMM32:
208             LowerTypedStObjByIndex(gate);
209             break;
210         case EcmaOpcode::LDOBJBYVALUE_IMM8_V8:
211         case EcmaOpcode::LDOBJBYVALUE_IMM16_V8:
212         case EcmaOpcode::LDTHISBYVALUE_IMM8:
213         case EcmaOpcode::LDTHISBYVALUE_IMM16:
214             LowerTypedLdObjByValue(gate);
215             break;
216         case EcmaOpcode::STOBJBYVALUE_IMM8_V8_V8:
217         case EcmaOpcode::STOBJBYVALUE_IMM16_V8_V8:
218             LowerTypedStObjByValue(gate);
219             break;
220         case EcmaOpcode::STOWNBYVALUE_IMM8_V8_V8:
221         case EcmaOpcode::STOWNBYVALUE_IMM16_V8_V8:
222             LowerTypedStOwnByValue(gate);
223             break;
224         case EcmaOpcode::NEWOBJRANGE_IMM8_IMM8_V8:
225         case EcmaOpcode::NEWOBJRANGE_IMM16_IMM8_V8:
226         case EcmaOpcode::WIDE_NEWOBJRANGE_PREF_IMM16_V8:
227             LowerTypedNewObjRange(gate);
228             break;
229         case EcmaOpcode::SUPERCALLTHISRANGE_IMM8_IMM8_V8:
230         case EcmaOpcode::WIDE_SUPERCALLTHISRANGE_PREF_IMM16_V8:
231             LowerTypedSuperCall(gate);
232             break;
233         case EcmaOpcode::CALLARG0_IMM8:
234             LowerTypedCallArg0(gate);
235             break;
236         case EcmaOpcode::CALLARG1_IMM8_V8:
237             LowerTypedCallArg1(gate);
238             break;
239         case EcmaOpcode::CALLARGS2_IMM8_V8_V8:
240             LowerTypedCallArg2(gate);
241             break;
242         case EcmaOpcode::CALLARGS3_IMM8_V8_V8_V8:
243             LowerTypedCallArg3(gate);
244             break;
245         case EcmaOpcode::CALLRANGE_IMM8_IMM8_V8:
246             LowerTypedCallrange(gate);
247             break;
248         case EcmaOpcode::CALLTHIS0_IMM8_V8:
249             LowerTypedCallthis0(gate);
250             break;
251         case EcmaOpcode::CALLTHIS1_IMM8_V8_V8:
252             LowerTypedCallthis1(gate);
253             break;
254         case EcmaOpcode::CALLTHIS2_IMM8_V8_V8_V8:
255             LowerTypedCallthis2(gate);
256             break;
257         case EcmaOpcode::CALLTHIS3_IMM8_V8_V8_V8_V8:
258             LowerTypedCallthis3(gate);
259             break;
260         case EcmaOpcode::CALLTHISRANGE_IMM8_IMM8_V8:
261             LowerTypedCallthisrange(gate);
262             break;
263         case EcmaOpcode::CALLRUNTIME_CALLINIT_PREF_IMM8_V8:
264             LowerTypedCallInit(gate);
265             break;
266         case EcmaOpcode::TYPEOF_IMM8:
267         case EcmaOpcode::TYPEOF_IMM16:
268             LowerTypedTypeOf(gate);
269             break;
270         case EcmaOpcode::GETITERATOR_IMM8:
271         case EcmaOpcode::GETITERATOR_IMM16:
272             LowerGetIterator(gate);
273             break;
274         case EcmaOpcode::TRYLDGLOBALBYNAME_IMM8_ID16:
275         case EcmaOpcode::TRYLDGLOBALBYNAME_IMM16_ID16:
276             LowerTypedTryLdGlobalByName(gate);
277             break;
278         case EcmaOpcode::INSTANCEOF_IMM8_V8:
279             LowerInstanceOf(gate);
280             break;
281         case EcmaOpcode::CREATEEMPTYOBJECT:
282             LowerCreateEmptyObject(gate);
283             break;
284         case EcmaOpcode::CREATEOBJECTWITHBUFFER_IMM8_ID16:
285         case EcmaOpcode::CREATEOBJECTWITHBUFFER_IMM16_ID16:
286             LowerCreateObjectWithBuffer(gate);
287             break;
288         default:
289             DeleteBytecodeCount(ecmaOpcode);
290             allNonTypedOpCount_++;
291             break;
292     }
293 }
294 
295 template<TypedBinOp Op>
LowerTypedBinOp(GateRef gate,bool convertNumberType)296 void TypedBytecodeLowering::LowerTypedBinOp(GateRef gate, bool convertNumberType)
297 {
298     BinOpTypeInfoAccessor tacc(thread_, circuit_, gate, convertNumberType);
299     if (tacc.HasNumberType()) {
300         SpeculateNumbers<Op>(gate);
301     } else if (tacc.HasStringType()) {
302         SpeculateStrings<Op>(gate);
303     }
304 }
305 
306 template<TypedUnOp Op>
LowerTypedUnOp(GateRef gate)307 void TypedBytecodeLowering::LowerTypedUnOp(GateRef gate)
308 {
309     UnOpTypeInfoAccessor tacc(thread_, circuit_, gate);
310     if (tacc.ValueIsNumberType()) {
311         SpeculateNumber<Op>(gate);
312     }
313 }
314 
315 template<TypedBinOp Op>
LowerTypedEqOrNotEq(GateRef gate)316 void TypedBytecodeLowering::LowerTypedEqOrNotEq(GateRef gate)
317 {
318     GateRef left = acc_.GetValueIn(gate, 0);
319     GateRef right = acc_.GetValueIn(gate, 1);
320     GateType leftType = acc_.GetGateType(left);
321     GateType rightType = acc_.GetGateType(right);
322     GateType gateType = acc_.GetGateType(gate);
323     PGOTypeRef pgoType = acc_.TryGetPGOType(gate);
324 
325     BinOpTypeInfoAccessor tacc(thread_, circuit_, gate);
326     if (tacc.LeftOrRightIsUndefinedOrNull() || tacc.HasNumberType()) {
327         AddProfiling(gate);
328         GateRef result = builder_.TypedBinaryOp<Op>(
329             left, right, leftType, rightType, gateType, pgoType);
330         acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), result);
331     } else if (tacc.HasStringType()) {
332         SpeculateStrings<Op>(gate);
333     }
334 }
335 
336 template<TypedBinOp Op>
SpeculateStrings(GateRef gate)337 void TypedBytecodeLowering::SpeculateStrings(GateRef gate)
338 {
339     if (Op == TypedBinOp::TYPED_EQ || Op == TypedBinOp::TYPED_ADD) {
340         AddProfiling(gate);
341         GateRef left = acc_.GetValueIn(gate, 0);
342         GateRef right = acc_.GetValueIn(gate, 1);
343         if (!TypeInfoAccessor::IsTrustedStringType(thread_, circuit_, chunk_, acc_, left)) {
344             builder_.EcmaStringCheck(left);
345         }
346         if (!TypeInfoAccessor::IsTrustedStringType(thread_, circuit_, chunk_, acc_, right)) {
347             builder_.EcmaStringCheck(right);
348         }
349         GateType leftType = acc_.GetGateType(left);
350         GateType rightType = acc_.GetGateType(right);
351         GateType gateType = acc_.GetGateType(gate);
352         PGOTypeRef pgoType = acc_.TryGetPGOType(gate);
353         pgoTypeLog_.CollectGateTypeLogInfo(gate, true);
354 
355         GateRef result = builder_.TypedBinaryOp<Op>(left, right, leftType, rightType, gateType, pgoType);
356         acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), result);
357     }
358 }
359 
360 template<TypedBinOp Op>
SpeculateNumbers(GateRef gate)361 void TypedBytecodeLowering::SpeculateNumbers(GateRef gate)
362 {
363     AddProfiling(gate);
364     GateRef left = acc_.GetValueIn(gate, 0);
365     GateRef right = acc_.GetValueIn(gate, 1);
366     GateType leftType = acc_.GetGateType(left);
367     GateType rightType = acc_.GetGateType(right);
368     GateType gateType = acc_.GetGateType(gate);
369     PGOTypeRef pgoType = acc_.TryGetPGOType(gate);
370     pgoTypeLog_.CollectGateTypeLogInfo(gate, true);
371 
372     GateRef result = builder_.TypedBinaryOp<Op>(left, right, leftType, rightType, gateType, pgoType);
373     acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), result);
374 }
375 
376 template<TypedUnOp Op>
SpeculateNumber(GateRef gate)377 void TypedBytecodeLowering::SpeculateNumber(GateRef gate)
378 {
379     AddProfiling(gate);
380     GateRef value = acc_.GetValueIn(gate, 0);
381     GateType valueType = acc_.GetGateType(value);
382     GateType gateType = acc_.GetGateType(gate);
383     pgoTypeLog_.CollectGateTypeLogInfo(gate, false);
384 
385     const PGOSampleType *sampleType = acc_.TryGetPGOType(gate).GetPGOSampleType();
386     if (sampleType->IsNumber()) {
387         if (sampleType->IsInt()) {
388             gateType = GateType::IntType();
389         } else if (sampleType->IsDouble()) {
390             gateType = GateType::DoubleType();
391         } else {
392             gateType = GateType::NumberType();
393         }
394         valueType = gateType;
395     }
396 
397     GateRef result = builder_.TypedUnaryOp<Op>(value, valueType, gateType);
398 
399     acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), result);
400 }
401 
LowerTypeToNumeric(GateRef gate)402 void TypedBytecodeLowering::LowerTypeToNumeric(GateRef gate)
403 {
404     UnOpTypeInfoAccessor tacc(thread_, circuit_, gate);
405     if (tacc.ValueIsNumberType()) {
406         AddProfiling(gate);
407         LowerPrimitiveTypeToNumber(tacc);
408     }
409 }
410 
LowerPrimitiveTypeToNumber(const UnOpTypeInfoAccessor & tacc)411 void TypedBytecodeLowering::LowerPrimitiveTypeToNumber(const UnOpTypeInfoAccessor &tacc)
412 {
413     GateRef result = builder_.PrimitiveToNumber(tacc.GetValue(),
414                                                 VariableType(MachineType::I64, tacc.GetValueGateType()));
415     acc_.ReplaceHirAndDeleteIfException(tacc.GetGate(), builder_.GetStateDepend(), result);
416 }
417 
LowerConditionJump(GateRef gate,bool flag)418 void TypedBytecodeLowering::LowerConditionJump(GateRef gate, bool flag)
419 {
420     ConditionJumpTypeInfoAccessor tacc(thread_, circuit_, gate);
421     if (tacc.ValueIsBooleanType() && TypeInfoAccessor::IsTrustedType(acc_, tacc.GetValue())) {
422         AddProfiling(gate);
423         SpeculateConditionJump(tacc, flag);
424     }
425 }
426 
SpeculateConditionJump(const ConditionJumpTypeInfoAccessor & tacc,bool flag)427 void TypedBytecodeLowering::SpeculateConditionJump(const ConditionJumpTypeInfoAccessor &tacc, bool flag)
428 {
429     GateRef value = tacc.GetValue();
430     GateType valueType = tacc.GetValueGateType();
431     uint32_t weight = tacc.GetBranchWeight();
432     GateRef jump = Circuit::NullGate();
433     if (flag) {
434         jump = builder_.TypedConditionJump<TypedJumpOp::TYPED_JNEZ>(value, valueType, weight);
435     } else {
436         jump = builder_.TypedConditionJump<TypedJumpOp::TYPED_JEQZ>(value, valueType, weight);
437     }
438     acc_.ReplaceGate(tacc.GetGate(), jump, jump, Circuit::NullGate());
439 }
440 
DeleteConstDataIfNoUser(GateRef gate)441 void TypedBytecodeLowering::DeleteConstDataIfNoUser(GateRef gate)
442 {
443     auto uses = acc_.Uses(gate);
444     if (uses.begin() == uses.end()) {
445         builder_.ClearConstantCache(gate);
446         acc_.DeleteGate(gate);
447     }
448 }
449 
LowerTypedLdObjByName(GateRef gate)450 void TypedBytecodeLowering::LowerTypedLdObjByName(GateRef gate)
451 {
452     DISALLOW_GARBAGE_COLLECTION;
453     LoadObjByNameTypeInfoAccessor tacc(thread_, circuit_, gate, chunk_);
454 
455     if (TryLowerTypedLdobjBynameFromGloablBuiltin(gate)) {
456         return;
457     }
458     if (TryLowerTypedLdObjByNameForBuiltin(gate)) {
459         return;
460     }
461     if (tacc.TypesIsEmpty() || tacc.HasIllegalType()) {
462         return;
463     }
464 
465     DEFVALUE(result, (&builder_), VariableType::JS_ANY(), builder_.Hole());
466     size_t typeCount = tacc.GetTypeCount();
467     std::vector<Label> loaders;
468     std::vector<Label> fails;
469     for (size_t i = 0; i < typeCount - 1; ++i) {
470         loaders.emplace_back(Label(&builder_));
471         fails.emplace_back(Label(&builder_));
472     }
473     Label exit(&builder_);
474     AddProfiling(gate);
475     GateRef frameState = acc_.GetFrameState(gate);
476     if (tacc.IsMono()) {
477         GateRef receiver = tacc.GetReceiver();
478         builder_.ObjectTypeCheck(acc_.GetGateType(gate), true, receiver,
479                                  builder_.Int32(tacc.GetExpectedHClassIndex(0)), frameState);
480         if (tacc.IsReceiverEqHolder(0)) {
481             result = BuildNamedPropertyAccess(gate, receiver, receiver, tacc.GetAccessInfo(0).Plr());
482         } else {
483             builder_.ProtoChangeMarkerCheck(receiver, frameState);
484             PropertyLookupResult plr = tacc.GetAccessInfo(0).Plr();
485             GateRef plrGate = builder_.Int32(plr.GetData());
486             GateRef jsFunc = argAcc_.GetFrameArgsIn(gate, FrameArgIdx::FUNC);
487             size_t holderHClassIndex = tacc.GetAccessInfo(0).HClassIndex();
488             if (LIKELY(!plr.IsAccessor())) {
489                 result = builder_.MonoLoadPropertyOnProto(receiver, plrGate, jsFunc, holderHClassIndex);
490             } else {
491                 result = builder_.MonoCallGetterOnProto(gate, receiver, plrGate, jsFunc, holderHClassIndex);
492             }
493         }
494         acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), *result);
495         DeleteConstDataIfNoUser(tacc.GetKey());
496         return;
497     }
498     auto receiverHC = builder_.LoadConstOffset(VariableType::JS_POINTER(), tacc.GetReceiver(),
499                                                TaggedObject::HCLASS_OFFSET);
500     for (size_t i = 0; i < typeCount; ++i) {
501         auto expected = builder_.GetHClassGateFromIndex(gate, tacc.GetExpectedHClassIndex(i));
502         if (i != typeCount - 1) {
503             builder_.Branch(builder_.Equal(receiverHC, expected), &loaders[i], &fails[i]);
504             builder_.Bind(&loaders[i]);
505         } else {
506             // Deopt if fails at last hclass compare
507             builder_.DeoptCheck(builder_.Equal(receiverHC, expected), frameState, DeoptType::INCONSISTENTHCLASS1);
508         }
509 
510         if (tacc.IsReceiverEqHolder(i)) {
511             result = BuildNamedPropertyAccess(gate, tacc.GetReceiver(), tacc.GetReceiver(),
512                                               tacc.GetAccessInfo(i).Plr());
513             builder_.Jump(&exit);
514         } else {
515             // prototype change marker check
516             builder_.ProtoChangeMarkerCheck(tacc.GetReceiver(), frameState);
517             // lookup from receiver for holder
518             auto prototype = builder_.LoadConstOffset(VariableType::JS_ANY(), receiverHC, JSHClass::PROTOTYPE_OFFSET);
519             // lookup from receiver for holder
520             ObjectAccessTypeInfoAccessor::ObjectAccessInfo info = tacc.GetAccessInfo(i);
521             auto holderHC = builder_.GetHClassGateFromIndex(gate, info.HClassIndex());
522             DEFVALUE(current, (&builder_), VariableType::JS_ANY(), prototype);
523             Label loopHead(&builder_);
524             Label loadHolder(&builder_);
525             Label lookUpProto(&builder_);
526             builder_.Jump(&loopHead);
527 
528             builder_.LoopBegin(&loopHead);
529             builder_.DeoptCheck(builder_.TaggedIsNotNull(*current), frameState, DeoptType::INCONSISTENTHCLASS2);
530             auto curHC = builder_.LoadConstOffset(VariableType::JS_POINTER(), *current, TaggedObject::HCLASS_OFFSET);
531             builder_.Branch(builder_.Equal(curHC, holderHC), &loadHolder, &lookUpProto);
532 
533             builder_.Bind(&lookUpProto);
534             current = builder_.LoadConstOffset(VariableType::JS_ANY(), curHC, JSHClass::PROTOTYPE_OFFSET);
535             builder_.LoopEnd(&loopHead);
536 
537             builder_.Bind(&loadHolder);
538             result = BuildNamedPropertyAccess(gate, tacc.GetReceiver(), *current, tacc.GetAccessInfo(i).Plr());
539             builder_.Jump(&exit);
540         }
541         if (i != typeCount - 1) {
542             builder_.Bind(&fails[i]);
543         }
544     }
545     builder_.Bind(&exit);
546     acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), *result);
547     DeleteConstDataIfNoUser(tacc.GetKey());
548 }
549 
LowerTypedStObjByName(GateRef gate)550 void TypedBytecodeLowering::LowerTypedStObjByName(GateRef gate)
551 {
552     DISALLOW_GARBAGE_COLLECTION;
553     StoreObjByNameTypeInfoAccessor tacc(thread_, circuit_, gate, chunk_);
554     if (tacc.TypesIsEmpty() || tacc.HasIllegalType()) {
555         return;
556     }
557     size_t typeCount = tacc.GetTypeCount();
558     std::vector<Label> loaders;
559     std::vector<Label> fails;
560     for (size_t i = 0; i < typeCount - 1; ++i) {
561         loaders.emplace_back(Label(&builder_));
562         fails.emplace_back(Label(&builder_));
563     }
564     Label exit(&builder_);
565     AddProfiling(gate);
566     GateRef frameState = Circuit::NullGate();
567     auto opcode = acc_.GetByteCodeOpcode(gate);
568 
569     // The framestate of Call and Accessor related instructions directives is placed on IR. Using the depend edge to
570     // climb up and find the nearest framestate for other instructions
571     if (opcode == EcmaOpcode::DEFINEFIELDBYNAME_IMM8_ID16_V8 ||
572         opcode == EcmaOpcode::STOWNBYNAME_IMM8_ID16_V8 ||
573         opcode == EcmaOpcode::STOWNBYNAME_IMM16_ID16_V8) {
574         frameState = acc_.FindNearestFrameState(builder_.GetDepend());
575     } else if (opcode == EcmaOpcode::STOBJBYNAME_IMM8_ID16_V8 ||
576                opcode == EcmaOpcode::STOBJBYNAME_IMM16_ID16_V8 ||
577                opcode == EcmaOpcode::STTHISBYNAME_IMM8_ID16 ||
578                opcode == EcmaOpcode::STTHISBYNAME_IMM16_ID16) {
579         frameState = acc_.GetFrameState(gate);
580     } else {
581         UNREACHABLE();
582     }
583 
584     if (tacc.IsMono()) {
585         GateRef receiver = tacc.GetReceiver();
586         builder_.ObjectTypeCheck(acc_.GetGateType(gate), true, receiver,
587                                  builder_.Int32(tacc.GetExpectedHClassIndex(0)), frameState);
588         if (tacc.IsReceiverNoEqNewHolder(0)) {
589             builder_.ProtoChangeMarkerCheck(tacc.GetReceiver(), frameState);
590             PropertyLookupResult plr = tacc.GetAccessInfo(0).Plr();
591             GateRef plrGate = builder_.Int32(plr.GetData());
592             GateRef jsFunc = argAcc_.GetFrameArgsIn(gate, FrameArgIdx::FUNC);
593             size_t holderHClassIndex = tacc.GetAccessInfo(0).HClassIndex();
594             GateRef value = tacc.GetValue();
595             if (tacc.IsHolderEqNewHolder(0)) {
596                 builder_.MonoStorePropertyLookUpProto(tacc.GetReceiver(), plrGate, jsFunc, holderHClassIndex, value);
597             } else {
598                 auto propKey = builder_.LoadObjectFromConstPool(argAcc_.GetFrameArgsIn(gate, FrameArgIdx::FUNC),
599                                                                 tacc.GetKey());
600                 builder_.MonoStoreProperty(tacc.GetReceiver(), plrGate, jsFunc, holderHClassIndex, value,
601                                            propKey);
602             }
603         } else if (tacc.IsReceiverEqHolder(0)) {
604             BuildNamedPropertyAccess(gate, tacc.GetReceiver(), tacc.GetReceiver(),
605                                      tacc.GetValue(), tacc.GetAccessInfo(0).Plr(), tacc.GetExpectedHClassIndex(0));
606         }
607         acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), Circuit::NullGate());
608         DeleteConstDataIfNoUser(tacc.GetKey());
609         return;
610     }
611 
612     auto receiverHC = builder_.LoadConstOffset(VariableType::JS_POINTER(), tacc.GetReceiver(),
613                                                TaggedObject::HCLASS_OFFSET);
614     for (size_t i = 0; i < typeCount; ++i) {
615         auto expected = builder_.GetHClassGateFromIndex(gate, tacc.GetExpectedHClassIndex(i));
616         if (i != typeCount - 1) {
617             builder_.Branch(builder_.Equal(receiverHC, expected),
618                 &loaders[i], &fails[i]);
619             builder_.Bind(&loaders[i]);
620         } else {
621             builder_.DeoptCheck(builder_.Equal(receiverHC, expected), frameState, DeoptType::INCONSISTENTHCLASS3);
622         }
623         if (tacc.IsReceiverNoEqNewHolder(i)) {
624             builder_.ProtoChangeMarkerCheck(tacc.GetReceiver(), frameState);
625             auto prototype = builder_.LoadConstOffset(VariableType::JS_ANY(), receiverHC, JSHClass::PROTOTYPE_OFFSET);
626             if (tacc.IsHolderEqNewHolder(i)) {
627                 // lookup from receiver for holder
628                 auto holderHC = builder_.GetHClassGateFromIndex(gate, tacc.GetAccessInfo(i).HClassIndex());
629                 DEFVALUE(current, (&builder_), VariableType::JS_ANY(), prototype);
630                 Label loopHead(&builder_);
631                 Label loadHolder(&builder_);
632                 Label lookUpProto(&builder_);
633                 builder_.Jump(&loopHead);
634 
635                 builder_.LoopBegin(&loopHead);
636                 builder_.DeoptCheck(builder_.TaggedIsNotNull(*current), frameState, DeoptType::INCONSISTENTHCLASS4);
637                 auto curHC = builder_.LoadConstOffset(VariableType::JS_POINTER(), *current,
638                                                       TaggedObject::HCLASS_OFFSET);
639                 builder_.Branch(builder_.Equal(curHC, holderHC), &loadHolder, &lookUpProto);
640 
641                 builder_.Bind(&lookUpProto);
642                 current = builder_.LoadConstOffset(VariableType::JS_ANY(), curHC, JSHClass::PROTOTYPE_OFFSET);
643                 builder_.LoopEnd(&loopHead);
644 
645                 builder_.Bind(&loadHolder);
646                 BuildNamedPropertyAccess(gate, tacc.GetReceiver(), *current, tacc.GetValue(),
647                                          tacc.GetAccessInfo(i).Plr());
648                 builder_.Jump(&exit);
649             } else {
650                 // transition happened
651                 Label notProto(&builder_);
652                 Label isProto(&builder_);
653                 auto newHolderHC = builder_.GetHClassGateFromIndex(gate, tacc.GetAccessInfo(i).HClassIndex());
654                 builder_.StoreConstOffset(VariableType::JS_ANY(), newHolderHC, JSHClass::PROTOTYPE_OFFSET, prototype);
655                 builder_.Branch(builder_.IsProtoTypeHClass(receiverHC), &isProto, &notProto,
656                     BranchWeight::ONE_WEIGHT, BranchWeight::DEOPT_WEIGHT);
657                 builder_.Bind(&isProto);
658                 auto propKey = builder_.LoadObjectFromConstPool(argAcc_.GetFrameArgsIn(gate, FrameArgIdx::FUNC),
659                                                                 tacc.GetKey());
660                 builder_.CallRuntime(glue_, RTSTUB_ID(UpdateAOTHClass), Gate::InvalidGateRef,
661                     { receiverHC, newHolderHC, propKey }, gate);
662                 builder_.Jump(&notProto);
663                 builder_.Bind(&notProto);
664                 MemoryOrder order = MemoryOrder::Create(MemoryOrder::MEMORY_ORDER_RELEASE);
665                 builder_.StoreConstOffset(VariableType::JS_ANY(), tacc.GetReceiver(),
666                     TaggedObject::HCLASS_OFFSET, newHolderHC, order);
667                 if (!tacc.GetAccessInfo(i).Plr().IsInlinedProps()) {
668                     auto properties = builder_.LoadConstOffset(VariableType::JS_ANY(), tacc.GetReceiver(),
669                                                                JSObject::PROPERTIES_OFFSET);
670                     auto capacity =
671                         builder_.LoadConstOffset(VariableType::INT32(), properties, TaggedArray::LENGTH_OFFSET);
672                     auto index = builder_.Int32(tacc.GetAccessInfo(i).Plr().GetOffset());
673                     Label needExtend(&builder_);
674                     Label notExtend(&builder_);
675                     builder_.Branch(builder_.Int32UnsignedLessThan(index, capacity), &notExtend, &needExtend);
676                     builder_.Bind(&notExtend);
677                     {
678                         BuildNamedPropertyAccess(gate, tacc.GetReceiver(), tacc.GetReceiver(),
679                             tacc.GetValue(), tacc.GetAccessInfo(i).Plr());
680                         builder_.Jump(&exit);
681                     }
682                     builder_.Bind(&needExtend);
683                     {
684                         builder_.CallRuntime(glue_,
685                             RTSTUB_ID(PropertiesSetValue),
686                             Gate::InvalidGateRef,
687                             { tacc.GetReceiver(), tacc.GetValue(), properties, builder_.Int32ToTaggedInt(capacity),
688                             builder_.Int32ToTaggedInt(index) }, gate);
689                         builder_.Jump(&exit);
690                     }
691                 } else {
692                     BuildNamedPropertyAccess(gate, tacc.GetReceiver(), tacc.GetReceiver(),
693                         tacc.GetValue(), tacc.GetAccessInfo(i).Plr());
694                     builder_.Jump(&exit);
695                 }
696             }
697         } else if (tacc.IsReceiverEqHolder(i)) {
698             // Local
699             BuildNamedPropertyAccess(gate, tacc.GetReceiver(), tacc.GetReceiver(),
700                                      tacc.GetValue(), tacc.GetAccessInfo(i).Plr());
701             builder_.Jump(&exit);
702         } else {
703             // find in prototype, same as transition
704             UNREACHABLE();
705             return;
706         }
707         if (i != typeCount - 1) {
708             // process fastpath for next type
709             builder_.Bind(&fails[i]);
710         }
711     }
712 
713     builder_.Bind(&exit);
714     acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), Circuit::NullGate());
715     DeleteConstDataIfNoUser(tacc.GetKey());
716 }
717 
LowerTypedStOwnByName(GateRef gate)718 void TypedBytecodeLowering::LowerTypedStOwnByName(GateRef gate)
719 {
720     LowerTypedStObjByName(gate);
721 }
722 
BuildNamedPropertyAccess(GateRef hir,GateRef receiver,GateRef holder,PropertyLookupResult plr)723 GateRef TypedBytecodeLowering::BuildNamedPropertyAccess(
724     GateRef hir, GateRef receiver, GateRef holder, PropertyLookupResult plr)
725 {
726     GateRef plrGate = builder_.Int32(plr.GetData());
727     GateRef result = Circuit::NullGate();
728     if (LIKELY(!plr.IsAccessor())) {
729         result = builder_.LoadProperty(holder, plrGate, plr.IsFunction());
730     } else {
731         result = builder_.CallGetter(hir, receiver, holder, plrGate);
732     }
733     return result;
734 }
735 
BuildNamedPropertyAccess(GateRef hir,GateRef receiver,GateRef holder,GateRef value,PropertyLookupResult plr,uint32_t receiverHClassIndex)736 GateRef TypedBytecodeLowering::BuildNamedPropertyAccess(
737     GateRef hir, GateRef receiver, GateRef holder, GateRef value, PropertyLookupResult plr,
738     uint32_t receiverHClassIndex)
739 {
740     GateRef plrGate = builder_.Int32(plr.GetData());
741     GateRef result = Circuit::NullGate();
742     if (LIKELY(!plr.IsAccessor())) {
743         builder_.StoreProperty(receiver, plrGate, value, receiverHClassIndex);
744     } else {
745         builder_.CallSetter(hir, receiver, holder, plrGate, value);
746     }
747     return result;
748 }
749 
TryLowerTypedLdObjByNameForBuiltin(GateRef gate)750 bool TypedBytecodeLowering::TryLowerTypedLdObjByNameForBuiltin(GateRef gate)
751 {
752     LoadBulitinObjTypeInfoAccessor tacc(thread_, circuit_, gate, chunk_);
753     // Just supported mono.
754     if (tacc.IsMono()) {
755         if (tacc.IsBuiltinsString()) {
756             return TryLowerTypedLdObjByNameForBuiltin(tacc, BuiltinTypeId::STRING);
757         }
758         if (tacc.IsBuiltinsArray()) {
759             return TryLowerTypedLdObjByNameForBuiltin(tacc, BuiltinTypeId::ARRAY);
760         }
761     }
762 
763     // String: primitive string type only
764     /* e.g. let s1 = "ABC"; -> OK
765      * e.g. let s2 = new String("DEF"); -> Not included, whose type is JSType::JS_PRIMITIVE_REF */
766     if (tacc.IsStringType()) {
767         return TryLowerTypedLdObjByNameForBuiltin(tacc, BuiltinTypeId::STRING);
768     }
769     // Array: created via either array literal or new Array(...)
770     /* e.g. let a1 = [1, 2, 3]; -> OK
771      * e.g. let a2 = new Array(1, 2, 3); -> OK */
772     if (tacc.IsArrayType()) {
773         return TryLowerTypedLdObjByNameForBuiltin(tacc, BuiltinTypeId::ARRAY);
774     }
775     // Other valid types: let x = new X(...);
776     const auto hclassEntries = thread_->GetBuiltinHClassEntries();
777     for (BuiltinTypeId type: BuiltinHClassEntries::BUILTIN_TYPES) {
778         if (type == BuiltinTypeId::ARRAY || type == BuiltinTypeId::STRING || !hclassEntries.EntryIsValid(type)) {
779             continue; // Checked before or invalid
780         }
781         if (!tacc.IsBuiltinInstanceType(type)) {
782             continue; // Type mismatch
783         }
784         return TryLowerTypedLdObjByNameForBuiltin(tacc, type);
785     }
786     return false; // No lowering performed
787 }
788 
TryLowerTypedLdObjByNameForBuiltin(const LoadBulitinObjTypeInfoAccessor & tacc,BuiltinTypeId type)789 bool TypedBytecodeLowering::TryLowerTypedLdObjByNameForBuiltin(const LoadBulitinObjTypeInfoAccessor &tacc,
790                                                                BuiltinTypeId type)
791 {
792     EcmaString *propString = EcmaString::Cast(tacc.GetKeyTaggedValue().GetTaggedObject());
793     // (1) get length
794     EcmaString *lengthString = EcmaString::Cast(thread_->GlobalConstants()->GetLengthString().GetTaggedObject());
795     if (propString == lengthString) {
796         if (type == BuiltinTypeId::ARRAY) {
797             LowerTypedLdArrayLength(tacc);
798             return true;
799         }
800         if (type == BuiltinTypeId::STRING) {
801             LowerTypedLdStringLength(tacc);
802             return true;
803         }
804         if (IsTypedArrayType(type)) {
805             LowerTypedLdTypedArrayLength(tacc);
806             return true;
807         }
808     }
809     // (2) other functions
810     return false;
811 }
812 
TryLowerTypedLdobjBynameFromGloablBuiltin(GateRef gate)813 bool TypedBytecodeLowering::TryLowerTypedLdobjBynameFromGloablBuiltin(GateRef gate)
814 {
815     LoadBulitinObjTypeInfoAccessor tacc(thread_, circuit_, gate, chunk_);
816     GateRef receiver = tacc.GetReceiver();
817     if (acc_.GetOpCode(receiver) != OpCode::LOAD_BUILTIN_OBJECT) {
818         return false;
819     }
820     JSHandle<GlobalEnv> globalEnv = thread_->GetEcmaVM()->GetGlobalEnv();
821     uint64_t index = acc_.TryGetValue(receiver);
822     BuiltinType type = static_cast<BuiltinType>(index);
823     if (type == BuiltinType::BT_MATH) {
824         auto math = globalEnv->GetMathFunction();
825         JSHClass *hclass = math.GetTaggedValue().GetTaggedObject()->GetClass();
826         JSTaggedValue key = tacc.GetKeyTaggedValue();
827         PropertyLookupResult plr = JSHClass::LookupPropertyInBuiltinHClass(thread_, hclass, key);
828         if (!plr.IsFound() || plr.IsAccessor()) {
829             return false;
830         }
831         AddProfiling(gate);
832         GateRef plrGate = builder_.Int32(plr.GetData());
833         GateRef result = builder_.LoadProperty(receiver, plrGate, plr.IsFunction());
834         acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), result);
835         DeleteConstDataIfNoUser(tacc.GetKey());
836         return true;
837     }
838     return false;
839 }
840 
LowerTypedLdArrayLength(const LoadBulitinObjTypeInfoAccessor & tacc)841 void TypedBytecodeLowering::LowerTypedLdArrayLength(const LoadBulitinObjTypeInfoAccessor &tacc)
842 {
843     GateRef gate = tacc.GetGate();
844     GateRef array = tacc.GetReceiver();
845     AddProfiling(gate);
846     if (!Uncheck()) {
847         ElementsKind kind = acc_.TryGetElementsKind(gate);
848         if (!acc_.IsCreateArray(array)) {
849             builder_.StableArrayCheck(array, kind, ArrayMetaDataAccessor::Mode::LOAD_LENGTH);
850         }
851     }
852 
853     GateRef result = builder_.LoadArrayLength(array);
854     acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), result);
855 }
856 
LowerTypedLdTypedArrayLength(const LoadBulitinObjTypeInfoAccessor & tacc)857 void TypedBytecodeLowering::LowerTypedLdTypedArrayLength(const LoadBulitinObjTypeInfoAccessor &tacc)
858 {
859     GateRef gate = tacc.GetGate();
860     GateRef array = tacc.GetReceiver();
861     AddProfiling(gate);
862     GateType arrayType = tacc.GetReceiverGateType();
863     OnHeapMode onHeap = acc_.TryGetOnHeapMode(gate);
864     if (!Uncheck()) {
865         builder_.TypedArrayCheck(array, arrayType, TypedArrayMetaDateAccessor::Mode::LOAD_LENGTH, onHeap);
866     }
867     GateRef result = builder_.LoadTypedArrayLength(array, arrayType, onHeap);
868     acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), result);
869 }
870 
LowerTypedLdStringLength(const LoadBulitinObjTypeInfoAccessor & tacc)871 void TypedBytecodeLowering::LowerTypedLdStringLength(const LoadBulitinObjTypeInfoAccessor &tacc)
872 {
873     GateRef gate = tacc.GetGate();
874     GateRef str = tacc.GetReceiver();
875     AddProfiling(gate);
876     if (!Uncheck()) {
877         builder_.EcmaStringCheck(str);
878     }
879     GateRef result = builder_.LoadStringLength(str);
880     acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), result);
881 }
882 
TryLowerTypedLdObjByNameForBuiltinMethod(GateRef gate,JSTaggedValue key,BuiltinTypeId type)883 bool TypedBytecodeLowering::TryLowerTypedLdObjByNameForBuiltinMethod(
884     GateRef gate, JSTaggedValue key, BuiltinTypeId type)
885 {
886     AddProfiling(gate);
887     std::optional<GlobalEnvField> protoField = ToGlobelEnvPrototypeField(type);
888     if (!protoField.has_value()) {
889         return false;
890     }
891     size_t protoFieldIndex = static_cast<size_t>(*protoField);
892     JSHandle<GlobalEnv> globalEnv = thread_->GetEcmaVM()->GetGlobalEnv();
893     JSHClass *prototypeHClass = globalEnv->GetGlobalEnvObjectByIndex(protoFieldIndex)->GetTaggedObject()->GetClass();
894     PropertyLookupResult plr = JSHClass::LookupPropertyInBuiltinPrototypeHClass(thread_, prototypeHClass, key);
895     // Unable to handle accessor at the moment
896     if (!plr.IsFound() || plr.IsAccessor()) {
897         return false;
898     }
899     GateRef receiver = acc_.GetValueIn(gate, 2);
900     if (!Uncheck()) {
901         // For Array type only: array stability shall be ensured.
902         if (type == BuiltinTypeId::ARRAY) {
903             builder_.StableArrayCheck(receiver, ElementsKind::GENERIC, ArrayMetaDataAccessor::CALL_BUILTIN_METHOD);
904         }
905         // This check is not required by String, since string is a primitive type.
906         if (type != BuiltinTypeId::STRING) {
907             builder_.BuiltinPrototypeHClassCheck(receiver, type);
908         }
909     }
910     // Successfully goes to typed path
911     GateRef plrGate = builder_.Int32(plr.GetData());
912     GateRef prototype = builder_.GetGlobalEnvObj(builder_.GetGlobalEnv(), static_cast<size_t>(*protoField));
913     GateRef result = builder_.LoadProperty(prototype, plrGate, plr.IsFunction());
914     acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), result);
915     return true;
916 }
917 
TryLowerTypedLdObjByIndexForBuiltin(GateRef gate)918 bool TypedBytecodeLowering::TryLowerTypedLdObjByIndexForBuiltin(GateRef gate)
919 {
920     LoadBulitinObjTypeInfoAccessor tacc(thread_, circuit_, gate, chunk_);
921     GateRef result = Circuit::NullGate();
922     if (tacc.IsValidTypedArrayType()) {
923         AddProfiling(gate);
924         result = LoadTypedArrayByIndex(tacc);
925         acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), result);
926         return true;
927     }
928     return false;
929 }
930 
LowerTypedLdObjByIndex(GateRef gate)931 void TypedBytecodeLowering::LowerTypedLdObjByIndex(GateRef gate)
932 {
933     if (TryLowerTypedLdObjByIndexForBuiltin(gate)) {
934         return;
935     }
936 }
937 
TryLowerTypedStObjByIndexForBuiltin(GateRef gate)938 bool TypedBytecodeLowering::TryLowerTypedStObjByIndexForBuiltin(GateRef gate)
939 {
940     StoreBulitinObjTypeInfoAccessor tacc(thread_, circuit_, gate, chunk_);
941     if (!tacc.IsBuiltinInstanceType(BuiltinTypeId::FLOAT32_ARRAY) ||
942         !tacc.ValueIsNumberType()) {
943         return false;
944     }
945     AddProfiling(gate);
946     GateRef receiver = tacc.GetReceiver();
947     GateType receiverType = tacc.GetReceiverGateType();
948     if (!Uncheck()) {
949         OnHeapMode onHeap = tacc.TryGetHeapMode();
950         builder_.TypedArrayCheck(receiver, receiverType, TypedArrayMetaDateAccessor::Mode::ACCESS_ELEMENT, onHeap);
951     }
952     GateRef index = builder_.Int32(tacc.TryConvertKeyToInt());
953     GateRef value = tacc.GetValue();
954     OnHeapMode onHeap = tacc.TryGetHeapMode();
955     auto length = builder_.LoadTypedArrayLength(receiver, receiverType, onHeap);
956     if (!Uncheck()) {
957         builder_.IndexCheck(length, index);
958     }
959     builder_.StoreElement<TypedStoreOp::FLOAT32ARRAY_STORE_ELEMENT>(receiver, index, value, onHeap);
960     acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), Circuit::NullGate());
961     return true;
962 }
963 
LowerTypedStObjByIndex(GateRef gate)964 void TypedBytecodeLowering::LowerTypedStObjByIndex(GateRef gate)
965 {
966     if (TryLowerTypedStObjByIndexForBuiltin(gate)) {
967         return;
968     }
969 }
970 
TryLowerTypedLdObjByValueForBuiltin(GateRef gate)971 bool TypedBytecodeLowering::TryLowerTypedLdObjByValueForBuiltin(GateRef gate)
972 {
973     LoadBulitinObjTypeInfoAccessor tacc(thread_, circuit_, gate, chunk_);
974     GateRef result = Circuit::NullGate();
975     // Just supported mono.
976     if (tacc.IsMono()) {
977         if (tacc.IsBuiltinsString()) {
978             AddProfiling(gate);
979             result = LoadStringByIndex(tacc);
980             acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), result);
981             return true;
982         } else if (tacc.IsBuiltinsArray()) {
983             AddProfiling(gate);
984             result = LoadJSArrayByIndex(tacc);
985             acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), result);
986             return true;
987         }
988     }
989 
990     if (!tacc.KeyIsNumberType()) {
991         return false;
992     }
993     if (tacc.IsValidTypedArrayType()) {
994         AddProfiling(gate);
995         result = LoadTypedArrayByIndex(tacc);
996         acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), result);
997         return true;
998     }
999     return false;
1000 }
1001 
LowerTypedLdObjByValue(GateRef gate)1002 void TypedBytecodeLowering::LowerTypedLdObjByValue(GateRef gate)
1003 {
1004     if (TryLowerTypedLdObjByValueForBuiltin(gate)) {
1005         return;
1006     }
1007 }
1008 
LoadStringByIndex(const LoadBulitinObjTypeInfoAccessor & tacc)1009 GateRef TypedBytecodeLowering::LoadStringByIndex(const LoadBulitinObjTypeInfoAccessor &tacc)
1010 {
1011     GateRef receiver = tacc.GetReceiver();
1012     GateRef propKey = tacc.GetKey();
1013     acc_.SetGateType(propKey, GateType::NumberType());
1014     if (!Uncheck()) {
1015         builder_.EcmaStringCheck(receiver);
1016         GateRef length = builder_.LoadStringLength(receiver);
1017         propKey = builder_.IndexCheck(length, propKey);
1018         receiver = builder_.FlattenTreeStringCheck(receiver);
1019     }
1020     return builder_.LoadElement<TypedLoadOp::STRING_LOAD_ELEMENT>(receiver, propKey);
1021 }
1022 
LoadJSArrayByIndex(const LoadBulitinObjTypeInfoAccessor & tacc)1023 GateRef TypedBytecodeLowering::LoadJSArrayByIndex(const LoadBulitinObjTypeInfoAccessor &tacc)
1024 {
1025     GateRef receiver = tacc.GetReceiver();
1026     GateRef propKey = tacc.GetKey();
1027     acc_.SetGateType(propKey, GateType::NumberType());
1028     ElementsKind kind = tacc.TryGetArrayElementsKind();
1029     if (!Uncheck()) {
1030         if (!acc_.IsCreateArray(receiver)) {
1031             builder_.StableArrayCheck(receiver, kind, ArrayMetaDataAccessor::Mode::LOAD_ELEMENT);
1032         }
1033         GateRef length = builder_.LoadArrayLength(receiver);
1034         propKey = builder_.IndexCheck(length, propKey);
1035     }
1036 
1037     GateRef result = Circuit::NullGate();
1038     if (Elements::IsInt(kind)) {
1039         result = builder_.LoadElement<TypedLoadOp::ARRAY_LOAD_INT_ELEMENT>(receiver, propKey);
1040     } else if (Elements::IsNumber(kind)) {
1041         result = builder_.LoadElement<TypedLoadOp::ARRAY_LOAD_DOUBLE_ELEMENT>(receiver, propKey);
1042     } else if (Elements::IsObject(kind)) {
1043         result = builder_.LoadElement<TypedLoadOp::ARRAY_LOAD_OBJECT_ELEMENT>(receiver, propKey);
1044     } else if (!Elements::IsHole(kind)) {
1045         result = builder_.LoadElement<TypedLoadOp::ARRAY_LOAD_TAGGED_ELEMENT>(receiver, propKey);
1046     } else {
1047         result = builder_.LoadElement<TypedLoadOp::ARRAY_LOAD_HOLE_TAGGED_ELEMENT>(receiver, propKey);
1048     }
1049     return result;
1050 }
1051 
LoadTypedArrayByIndex(const LoadBulitinObjTypeInfoAccessor & tacc)1052 GateRef TypedBytecodeLowering::LoadTypedArrayByIndex(const LoadBulitinObjTypeInfoAccessor &tacc)
1053 {
1054     GateRef receiver = tacc.GetReceiver();
1055     GateType receiverType = tacc.GetReceiverGateType();
1056     GateRef propKey = tacc.GetKey();
1057     OnHeapMode onHeap = tacc.TryGetHeapMode();
1058     BuiltinTypeId builtinTypeId = tacc.GetTypedArrayBuiltinId();
1059     if (!Uncheck()) {
1060         builder_.TypedArrayCheck(receiver, receiverType, TypedArrayMetaDateAccessor::Mode::ACCESS_ELEMENT, onHeap);
1061         GateRef length = builder_.LoadTypedArrayLength(receiver, receiverType, onHeap);
1062         propKey = builder_.IndexCheck(length, propKey);
1063     }
1064     switch (builtinTypeId) {
1065         case BuiltinTypeId::INT8_ARRAY:
1066             return builder_.LoadElement<TypedLoadOp::INT8ARRAY_LOAD_ELEMENT>(receiver, propKey, onHeap);
1067         case BuiltinTypeId::UINT8_ARRAY:
1068             return builder_.LoadElement<TypedLoadOp::UINT8ARRAY_LOAD_ELEMENT>(receiver, propKey, onHeap);
1069         case BuiltinTypeId::UINT8_CLAMPED_ARRAY:
1070             return builder_.LoadElement<TypedLoadOp::UINT8CLAMPEDARRAY_LOAD_ELEMENT>(receiver, propKey, onHeap);
1071         case BuiltinTypeId::INT16_ARRAY:
1072             return builder_.LoadElement<TypedLoadOp::INT16ARRAY_LOAD_ELEMENT>(receiver, propKey, onHeap);
1073         case BuiltinTypeId::UINT16_ARRAY:
1074             return builder_.LoadElement<TypedLoadOp::UINT16ARRAY_LOAD_ELEMENT>(receiver, propKey, onHeap);
1075         case BuiltinTypeId::INT32_ARRAY:
1076             return builder_.LoadElement<TypedLoadOp::INT32ARRAY_LOAD_ELEMENT>(receiver, propKey, onHeap);
1077         case BuiltinTypeId::UINT32_ARRAY:
1078             return builder_.LoadElement<TypedLoadOp::UINT32ARRAY_LOAD_ELEMENT>(receiver, propKey, onHeap);
1079         case BuiltinTypeId::FLOAT32_ARRAY:
1080             return builder_.LoadElement<TypedLoadOp::FLOAT32ARRAY_LOAD_ELEMENT>(receiver, propKey, onHeap);
1081         case BuiltinTypeId::FLOAT64_ARRAY:
1082             return builder_.LoadElement<TypedLoadOp::FLOAT64ARRAY_LOAD_ELEMENT>(receiver, propKey, onHeap);
1083         default:
1084             LOG_ECMA(FATAL) << "this branch is unreachable";
1085             UNREACHABLE();
1086     }
1087 
1088     return Circuit::NullGate();
1089 }
1090 
StoreJSArrayByIndex(const StoreBulitinObjTypeInfoAccessor & tacc)1091 void TypedBytecodeLowering::StoreJSArrayByIndex(const StoreBulitinObjTypeInfoAccessor &tacc)
1092 {
1093     GateRef receiver = tacc.GetReceiver();
1094     GateRef propKey = tacc.GetKey();
1095     GateRef value = tacc.GetValue();
1096     ElementsKind kind = tacc.TryGetArrayElementsKind();
1097     if (!Uncheck()) {
1098         if (!acc_.IsCreateArray(receiver)) {
1099             builder_.StableArrayCheck(receiver, kind, ArrayMetaDataAccessor::Mode::STORE_ELEMENT);
1100         }
1101         GateRef length = builder_.LoadArrayLength(receiver);
1102         builder_.IndexCheck(length, propKey);
1103         builder_.COWArrayCheck(receiver);
1104 
1105         if (Elements::IsObject(kind)) {
1106             GateRef frameState = acc_.FindNearestFrameState(builder_.GetDepend());
1107             builder_.HeapObjectCheck(value, frameState);
1108         }
1109     }
1110     builder_.StoreElement<TypedStoreOp::ARRAY_STORE_ELEMENT>(receiver, propKey, value);
1111 }
1112 
StoreTypedArrayByIndex(const StoreBulitinObjTypeInfoAccessor & tacc)1113 void TypedBytecodeLowering::StoreTypedArrayByIndex(const StoreBulitinObjTypeInfoAccessor &tacc)
1114 {
1115     GateRef receiver = tacc.GetReceiver();
1116     GateType receiverType = tacc.GetReceiverGateType();
1117     GateRef propKey = tacc.GetKey();
1118     GateRef value = tacc.GetValue();
1119     OnHeapMode onHeap = tacc.TryGetHeapMode();
1120     if (!Uncheck()) {
1121         builder_.TypedArrayCheck(receiver, receiverType, TypedArrayMetaDateAccessor::Mode::ACCESS_ELEMENT, onHeap);
1122         GateRef length = builder_.LoadTypedArrayLength(receiver, receiverType, onHeap);
1123         propKey = builder_.IndexCheck(length, propKey);
1124     }
1125 
1126     auto builtinTypeId = tsManager_->GetTypedArrayBuiltinId(receiverType);
1127     switch (builtinTypeId) {
1128         case BuiltinTypeId::INT8_ARRAY:
1129             builder_.StoreElement<TypedStoreOp::INT8ARRAY_STORE_ELEMENT>(receiver, propKey, value, onHeap);
1130             break;
1131         case BuiltinTypeId::UINT8_ARRAY:
1132             builder_.StoreElement<TypedStoreOp::UINT8ARRAY_STORE_ELEMENT>(receiver, propKey, value, onHeap);
1133             break;
1134         case BuiltinTypeId::UINT8_CLAMPED_ARRAY:
1135             builder_.StoreElement<TypedStoreOp::UINT8CLAMPEDARRAY_STORE_ELEMENT>(receiver, propKey, value, onHeap);
1136             break;
1137         case BuiltinTypeId::INT16_ARRAY:
1138             builder_.StoreElement<TypedStoreOp::INT16ARRAY_STORE_ELEMENT>(receiver, propKey, value, onHeap);
1139             break;
1140         case BuiltinTypeId::UINT16_ARRAY:
1141             builder_.StoreElement<TypedStoreOp::UINT16ARRAY_STORE_ELEMENT>(receiver, propKey, value, onHeap);
1142             break;
1143         case BuiltinTypeId::INT32_ARRAY:
1144             builder_.StoreElement<TypedStoreOp::INT32ARRAY_STORE_ELEMENT>(receiver, propKey, value, onHeap);
1145             break;
1146         case BuiltinTypeId::UINT32_ARRAY:
1147             builder_.StoreElement<TypedStoreOp::UINT32ARRAY_STORE_ELEMENT>(receiver, propKey, value, onHeap);
1148             break;
1149         case BuiltinTypeId::FLOAT32_ARRAY:
1150             builder_.StoreElement<TypedStoreOp::FLOAT32ARRAY_STORE_ELEMENT>(receiver, propKey, value, onHeap);
1151             break;
1152         case BuiltinTypeId::FLOAT64_ARRAY:
1153             builder_.StoreElement<TypedStoreOp::FLOAT64ARRAY_STORE_ELEMENT>(receiver, propKey, value, onHeap);
1154             break;
1155         default:
1156             LOG_ECMA(FATAL) << "this branch is unreachable";
1157             UNREACHABLE();
1158     }
1159 }
1160 
TryLowerTypedStObjByValueForBuiltin(GateRef gate)1161 bool TypedBytecodeLowering::TryLowerTypedStObjByValueForBuiltin(GateRef gate)
1162 {
1163     StoreBulitinObjTypeInfoAccessor tacc(thread_, circuit_, gate, chunk_);
1164     // Just supported mono.
1165     if (tacc.IsMono()) {
1166         if (tacc.IsBuiltinsArray()) {
1167             AddProfiling(gate);
1168             StoreJSArrayByIndex(tacc);
1169             acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), Circuit::NullGate());
1170             return true;
1171         }
1172     }
1173 
1174     if (!tacc.KeyIsNumberType()) {
1175         return false;
1176     }
1177 
1178     if (tacc.IsValidTypedArrayType()) {
1179         AddProfiling(gate);
1180         StoreTypedArrayByIndex(tacc);
1181         acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), Circuit::NullGate());
1182         return true;
1183     }
1184 
1185     return false;
1186 }
1187 
LowerTypedStObjByValue(GateRef gate)1188 void TypedBytecodeLowering::LowerTypedStObjByValue(GateRef gate)
1189 {
1190     if (TryLowerTypedStObjByValueForBuiltin(gate)) {
1191         return;
1192     }
1193 }
1194 
LowerTypedIsTrueOrFalse(GateRef gate,bool flag)1195 void TypedBytecodeLowering::LowerTypedIsTrueOrFalse(GateRef gate, bool flag)
1196 {
1197     UnOpTypeInfoAccessor tacc(thread_, circuit_, gate);
1198     if (!tacc.ValueIsPrimitiveNumberType() && !tacc.ValueIsBooleanType()) {
1199         return;
1200     }
1201     AddProfiling(gate);
1202     GateRef value = tacc.GetValue();
1203     GateType valueType = tacc.GetValueGateType();
1204     GateRef result;
1205     if (!flag) {
1206         result = builder_.TypedUnaryOp<TypedUnOp::TYPED_ISFALSE>(value, valueType, GateType::TaggedValue());
1207     } else {
1208         result = builder_.TypedUnaryOp<TypedUnOp::TYPED_ISTRUE>(value, valueType, GateType::TaggedValue());
1209     }
1210 
1211     acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), result);
1212 }
1213 
LowerTypedNewObjRange(GateRef gate)1214 void TypedBytecodeLowering::LowerTypedNewObjRange(GateRef gate)
1215 {
1216     if (TryLowerNewBuiltinConstructor(gate)) {
1217         return;
1218     }
1219     NewObjRangeTypeInfoAccessor tacc(thread_, circuit_, gate);
1220     if (!tacc.FindHClass()) {
1221         return;
1222     }
1223     AddProfiling(gate);
1224     GateRef hclassIndex = builder_.IntPtr(tacc.GetHClassIndex());
1225     GateRef ctor = tacc.GetValue();
1226 
1227     GateRef stateSplit = acc_.GetDep(gate);
1228     GateRef frameState = acc_.FindNearestFrameState(stateSplit);
1229     GateRef thisObj = builder_.TypedNewAllocateThis(ctor, hclassIndex, frameState);
1230 
1231     // call constructor
1232     size_t range = acc_.GetNumValueIn(gate);
1233     GateRef actualArgc = builder_.Int64(BytecodeCallArgc::ComputeCallArgc(range,
1234         EcmaOpcode::NEWOBJRANGE_IMM8_IMM8_V8));
1235     std::vector<GateRef> args { glue_, actualArgc, ctor, ctor, thisObj };
1236     for (size_t i = 1; i < range; ++i) {  // 1:skip ctor
1237         args.emplace_back(acc_.GetValueIn(gate, i));
1238     }
1239     GateRef constructGate = builder_.Construct(gate, args);
1240     acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), constructGate);
1241 }
1242 
TryLowerNewBuiltinConstructor(GateRef gate)1243 bool TypedBytecodeLowering::TryLowerNewBuiltinConstructor(GateRef gate)
1244 {
1245     NewBuiltinCtorTypeInfoAccessor tacc(thread_, circuit_, gate);
1246     if (!tacc.IsBuiltinModule()) {
1247         return false;
1248     }
1249     GateRef ctor = tacc.GetValue();
1250     GateRef constructGate = Circuit::NullGate();
1251     if (tacc.IsBuiltinConstructor(BuiltinTypeId::ARRAY)) {
1252         if (acc_.GetNumValueIn(gate) <= 2) { // 2: ctor and first arg
1253             AddProfiling(gate);
1254             if (!Uncheck()) {
1255                 builder_.ArrayConstructorCheck(ctor);
1256             }
1257             constructGate = builder_.BuiltinConstructor(BuiltinTypeId::ARRAY, gate);
1258         }
1259     } else if (tacc.IsBuiltinConstructor(BuiltinTypeId::OBJECT)) {
1260         AddProfiling(gate);
1261         if (!Uncheck()) {
1262             builder_.ObjectConstructorCheck(ctor);
1263         }
1264         constructGate = builder_.BuiltinConstructor(BuiltinTypeId::OBJECT, gate);
1265     }
1266     if (constructGate == Circuit::NullGate()) {
1267         return false;
1268     }
1269     acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), constructGate);
1270     return true;
1271 }
1272 
LowerTypedSuperCall(GateRef gate)1273 void TypedBytecodeLowering::LowerTypedSuperCall(GateRef gate)
1274 {
1275     SuperCallTypeInfoAccessor tacc(thread_, circuit_, gate);
1276     if (!tacc.IsClassTypeKind() && !tacc.IsFunctionTypeKind()) {
1277         return;
1278     }
1279     AddProfiling(gate);
1280 
1281     GateRef ctor = tacc.GetCtor();
1282     // stateSplit maybe not a STATE_SPLIT
1283     GateRef stateSplit = acc_.GetDep(gate);
1284 
1285     GateRef frameState = acc_.FindNearestFrameState(stateSplit);
1286     GateRef superCtor = builder_.GetSuperConstructor(ctor);
1287     GateRef newTarget = argAcc_.GetFrameArgsIn(gate, FrameArgIdx::NEW_TARGET);
1288     GateRef thisObj = builder_.TypedSuperAllocateThis(superCtor, newTarget, frameState);
1289 
1290     // call constructor
1291     size_t range = acc_.GetNumValueIn(gate);
1292     GateRef actualArgc = builder_.Int64(range + 3);  // 3: ctor, newTaget, this
1293     std::vector<GateRef> args { glue_, actualArgc, superCtor, newTarget, thisObj };
1294     for (size_t i = 0; i < range; ++i) {
1295         args.emplace_back(acc_.GetValueIn(gate, i));
1296     }
1297 
1298     GateRef constructGate = builder_.Construct(gate, args);
1299     acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), constructGate);
1300 }
1301 
SpeculateCallBuiltin(GateRef gate,GateRef func,const std::vector<GateRef> & args,BuiltinsStubCSigns::ID id,bool isThrow)1302 void TypedBytecodeLowering::SpeculateCallBuiltin(GateRef gate, GateRef func, const std::vector<GateRef> &args,
1303                                                  BuiltinsStubCSigns::ID id, bool isThrow)
1304 {
1305     if (!Uncheck()) {
1306         builder_.CallTargetCheck(gate, func, builder_.IntPtr(static_cast<int64_t>(id)), args[0]);
1307     }
1308 
1309     GateRef result = builder_.TypedCallBuiltin(gate, args, id);
1310 
1311     if (isThrow) {
1312         acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), result);
1313     } else {
1314         acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), result);
1315     }
1316 }
1317 
LowerFastCall(GateRef gate,GateRef func,const std::vector<GateRef> & argsFastCall,bool isNoGC)1318 void TypedBytecodeLowering::LowerFastCall(GateRef gate, GateRef func,
1319     const std::vector<GateRef> &argsFastCall, bool isNoGC)
1320 {
1321     builder_.StartCallTimer(glue_, gate, {glue_, func, builder_.True()}, true);
1322     GateRef result = builder_.TypedFastCall(gate, argsFastCall, isNoGC);
1323     builder_.EndCallTimer(glue_, gate, {glue_, func}, true);
1324     acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), result);
1325 }
1326 
LowerCall(GateRef gate,GateRef func,const std::vector<GateRef> & args,bool isNoGC)1327 void TypedBytecodeLowering::LowerCall(GateRef gate, GateRef func,
1328     const std::vector<GateRef> &args, bool isNoGC)
1329 {
1330     builder_.StartCallTimer(glue_, gate, {glue_, func, builder_.True()}, true);
1331     GateRef result = builder_.TypedCall(gate, args, isNoGC);
1332     builder_.EndCallTimer(glue_, gate, {glue_, func}, true);
1333     acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), result);
1334 }
1335 
1336 template<class TypeAccessor>
CheckFastCallThisCallTarget(const TypeAccessor & tacc)1337 void TypedBytecodeLowering::CheckFastCallThisCallTarget(const TypeAccessor &tacc)
1338 {
1339     if (noCheck_) {
1340         return;
1341     }
1342     GateRef func = tacc.GetFunc();
1343     GateRef gate = tacc.GetGate();
1344     GateType funcType = tacc.GetFuncGateType();
1345     if (tacc.IsNoGC()) {
1346         uint32_t methodOffset = tacc.GetFuncMethodOffset();
1347         builder_.JSNoGCCallThisTargetTypeCheck<TypedCallTargetCheckOp::JSCALLTHIS_FAST_NOGC>(funcType,
1348             func, builder_.IntPtr(methodOffset), gate);
1349     } else {
1350         builder_.JSCallThisTargetTypeCheck<TypedCallTargetCheckOp::JSCALLTHIS_FAST>(funcType,
1351             func, gate);
1352     }
1353 }
1354 
1355 template<class TypeAccessor>
CheckCallThisCallTarget(const TypeAccessor & tacc)1356 void TypedBytecodeLowering::CheckCallThisCallTarget(const TypeAccessor &tacc)
1357 {
1358     if (noCheck_) {
1359         return;
1360     }
1361     GateRef func = tacc.GetFunc();
1362     GateRef gate = tacc.GetGate();
1363     GateType funcType = tacc.GetFuncGateType();
1364     if (tacc.IsNoGC()) {
1365         auto methodOffset = tacc.GetFuncMethodOffset();
1366         builder_.JSNoGCCallThisTargetTypeCheck<TypedCallTargetCheckOp::JSCALLTHIS_NOGC>(funcType,
1367             func, builder_.IntPtr(methodOffset), gate);
1368     } else {
1369         builder_.JSCallThisTargetTypeCheck<TypedCallTargetCheckOp::JSCALLTHIS>(funcType,
1370             func, gate);
1371     }
1372 }
1373 
1374 template<class TypeAccessor>
CheckThisCallTargetAndLowerCall(const TypeAccessor & tacc,const std::vector<GateRef> & args,const std::vector<GateRef> & argsFastCall)1375 void TypedBytecodeLowering::CheckThisCallTargetAndLowerCall(const TypeAccessor &tacc,
1376     const std::vector<GateRef> &args, const std::vector<GateRef> &argsFastCall)
1377 {
1378     if (!tacc.FastCallFlagIsVaild()) {
1379         return;
1380     }
1381     GateRef func = tacc.GetFunc();
1382     GateRef gate = tacc.GetGate();
1383     bool isNoGC = tacc.IsNoGC();
1384     if (tacc.CanFastCall()) {
1385         CheckFastCallThisCallTarget(tacc);
1386         LowerFastCall(gate, func, argsFastCall, isNoGC);
1387     } else {
1388         CheckCallThisCallTarget(tacc);
1389         LowerCall(gate, func, args, isNoGC);
1390     }
1391 }
1392 
1393 template<class TypeAccessor>
CheckCallTargetFromDefineFuncAndLowerCall(const TypeAccessor & tacc,const std::vector<GateRef> & args,const std::vector<GateRef> & argsFastCall,bool isNoGC)1394 void TypedBytecodeLowering::CheckCallTargetFromDefineFuncAndLowerCall(const TypeAccessor &tacc,
1395     const std::vector<GateRef> &args, const std::vector<GateRef> &argsFastCall, bool isNoGC)
1396 {
1397     GateRef func = tacc.GetFunc();
1398     GateRef gate = tacc.GetGate();
1399     GateType funcType = tacc.GetFuncGateType();
1400     if (!Uncheck()) {
1401         builder_.JSCallTargetFromDefineFuncCheck(funcType, func, gate);
1402     }
1403     if (tacc.CanFastCall()) {
1404         LowerFastCall(gate, func, argsFastCall, isNoGC);
1405     } else {
1406         LowerCall(gate, func, args, isNoGC);
1407     }
1408 }
1409 
1410 template<class TypeAccessor>
CheckCallTargetAndLowerCall(const TypeAccessor & tacc,const std::vector<GateRef> & args,const std::vector<GateRef> & argsFastCall)1411 void TypedBytecodeLowering::CheckCallTargetAndLowerCall(const TypeAccessor &tacc,
1412     const std::vector<GateRef> &args, const std::vector<GateRef> &argsFastCall)
1413 {
1414     GateRef func = tacc.GetFunc();
1415     if (IsLoadVtable(func)) {
1416         CheckThisCallTargetAndLowerCall(tacc, args, argsFastCall); // func = a.foo, func()
1417     } else {
1418         bool isNoGC = tacc.IsNoGC();
1419         auto op = acc_.GetOpCode(func);
1420         if (!tacc.FastCallFlagIsVaild()) {
1421             return;
1422         }
1423         if (op == OpCode::JS_BYTECODE && (acc_.GetByteCodeOpcode(func) == EcmaOpcode::DEFINEFUNC_IMM8_ID16_IMM8 ||
1424                                           acc_.GetByteCodeOpcode(func) == EcmaOpcode::DEFINEFUNC_IMM16_ID16_IMM8)) {
1425             CheckCallTargetFromDefineFuncAndLowerCall(tacc, args, argsFastCall, isNoGC);
1426             return;
1427         }
1428         int methodIndex = tacc.GetMethodIndex();
1429         if (!tacc.MethodOffsetIsVaild() || methodIndex == -1) {
1430             return;
1431         }
1432 
1433         GateRef gate = tacc.GetGate();
1434         GateType funcType = tacc.GetFuncGateType();
1435         if (tacc.CanFastCall()) {
1436             if (!Uncheck()) {
1437                 builder_.JSCallTargetTypeCheck<TypedCallTargetCheckOp::JSCALL_FAST>(funcType,
1438                     func, builder_.IntPtr(methodIndex), gate);
1439             }
1440             LowerFastCall(gate, func, argsFastCall, isNoGC);
1441         } else {
1442             if (!Uncheck()) {
1443                 builder_.JSCallTargetTypeCheck<TypedCallTargetCheckOp::JSCALL>(funcType,
1444                     func, builder_.IntPtr(methodIndex), gate);
1445             }
1446             LowerCall(gate, func, args, isNoGC);
1447         }
1448     }
1449 }
1450 
1451 template<EcmaOpcode Op, class TypeAccessor>
LowerTypedCall(const TypeAccessor & tacc)1452 void TypedBytecodeLowering::LowerTypedCall(const TypeAccessor &tacc)
1453 {
1454     uint32_t argc = tacc.GetArgc();
1455     GateRef gate = tacc.GetGate();
1456     GateRef actualArgc = Circuit::NullGate();
1457     switch (Op) {
1458         case EcmaOpcode::CALLARG0_IMM8: {
1459             actualArgc = builder_.Int64(BytecodeCallArgc::ComputeCallArgc(acc_.GetNumValueIn(gate),
1460                 EcmaOpcode::CALLARG0_IMM8));
1461             break;
1462         }
1463         case EcmaOpcode::CALLARG1_IMM8_V8: {
1464             actualArgc = builder_.Int64(BytecodeCallArgc::ComputeCallArgc(acc_.GetNumValueIn(gate),
1465                 EcmaOpcode::CALLARG1_IMM8_V8));
1466             break;
1467         }
1468         case EcmaOpcode::CALLARGS2_IMM8_V8_V8: {
1469             actualArgc = builder_.Int64(BytecodeCallArgc::ComputeCallArgc(acc_.GetNumValueIn(gate),
1470                 EcmaOpcode::CALLARGS2_IMM8_V8_V8));
1471             break;
1472         }
1473         case EcmaOpcode::CALLARGS3_IMM8_V8_V8_V8: {
1474             actualArgc = builder_.Int64(BytecodeCallArgc::ComputeCallArgc(acc_.GetNumValueIn(gate),
1475                 EcmaOpcode::CALLARGS3_IMM8_V8_V8_V8));
1476             break;
1477         }
1478         case EcmaOpcode::CALLRANGE_IMM8_IMM8_V8: {
1479             actualArgc = builder_.Int64(BytecodeCallArgc::ComputeCallArgc(acc_.GetNumValueIn(gate),
1480                 EcmaOpcode::CALLRANGE_IMM8_IMM8_V8));
1481             break;
1482         }
1483         default:
1484             UNREACHABLE();
1485     }
1486     if (!tacc.IsHotnessFunc()) {
1487         return;
1488     }
1489     uint32_t len = tacc.GetFunctionTypeLength();
1490     GateRef func = tacc.GetFunc();
1491     GateRef newTarget = builder_.Undefined();
1492     GateRef thisObj = builder_.Undefined();
1493     std::vector<GateRef> argsFastCall { glue_, func, thisObj};
1494     std::vector<GateRef> args { glue_, actualArgc, func, newTarget, thisObj };
1495     for (uint32_t i = 0; i < argc; i++) {
1496         GateRef value = acc_.GetValueIn(gate, i);
1497         argsFastCall.emplace_back(value);
1498         args.emplace_back(value);
1499     }
1500     for (uint32_t i = argc; i < len; i++) {
1501         argsFastCall.emplace_back(builder_.Undefined());
1502         args.emplace_back(builder_.Undefined());
1503     }
1504     CheckCallTargetAndLowerCall(tacc, args, argsFastCall);
1505 }
1506 
LowerTypedCallArg0(GateRef gate)1507 void TypedBytecodeLowering::LowerTypedCallArg0(GateRef gate)
1508 {
1509     CallArg0TypeInfoAccessor tacc(thread_, circuit_, gate);
1510     if (!tacc.IsFunctionTypeKind()) {
1511         return;
1512     }
1513     LowerTypedCall<EcmaOpcode::CALLARG0_IMM8>(tacc);
1514 }
1515 
LowerTypedCallArg1(GateRef gate)1516 void TypedBytecodeLowering::LowerTypedCallArg1(GateRef gate)
1517 {
1518     CallArg1TypeInfoAccessor tacc(thread_, circuit_, gate);
1519     GateRef func = tacc.GetFunc();
1520     GateRef a0Value = tacc.GetValue();
1521     GateType a0Type = tacc.GetValueGateType();
1522     BuiltinsStubCSigns::ID id = tacc.TryGetPGOBuiltinId();
1523     if ((IS_TYPED_BUILTINS_MATH_ID(id) && a0Type.IsNumberType())) {
1524         AddProfiling(gate);
1525         SpeculateCallBuiltin(gate, func, { a0Value }, id, false);
1526     } else if (IS_TYPED_BUILTINS_NUMBER_ID(id)) {
1527         AddProfiling(gate);
1528         SpeculateCallBuiltin(gate, func, { a0Value }, id, true);
1529     } else {
1530         if (!tacc.IsFunctionTypeKind()) {
1531             return;
1532         }
1533         LowerTypedCall<EcmaOpcode::CALLARG1_IMM8_V8>(tacc);
1534     }
1535 }
1536 
LowerTypedCallArg2(GateRef gate)1537 void TypedBytecodeLowering::LowerTypedCallArg2(GateRef gate)
1538 {
1539     CallArg2TypeInfoAccessor tacc(thread_, circuit_, gate);
1540     if (!tacc.IsFunctionTypeKind()) {
1541         return;
1542     }
1543     LowerTypedCall<EcmaOpcode::CALLARGS2_IMM8_V8_V8>(tacc);
1544 }
1545 
LowerTypedCallArg3(GateRef gate)1546 void TypedBytecodeLowering::LowerTypedCallArg3(GateRef gate)
1547 {
1548     CallArg3TypeInfoAccessor tacc(thread_, circuit_, gate);
1549     if (!tacc.IsFunctionTypeKind()) {
1550         return;
1551     }
1552     LowerTypedCall<EcmaOpcode::CALLARGS3_IMM8_V8_V8_V8>(tacc);
1553 }
1554 
LowerTypedCallrange(GateRef gate)1555 void TypedBytecodeLowering::LowerTypedCallrange(GateRef gate)
1556 {
1557     CallRangeTypeInfoAccessor tacc(thread_, circuit_, gate);
1558     if (!tacc.IsFunctionTypeKind()) {
1559         return;
1560     }
1561     LowerTypedCall<EcmaOpcode::CALLRANGE_IMM8_IMM8_V8>(tacc);
1562 }
1563 
IsLoadVtable(GateRef func)1564 bool TypedBytecodeLowering::IsLoadVtable(GateRef func)
1565 {
1566     auto op = acc_.GetOpCode(func);
1567     if (op != OpCode::LOAD_PROPERTY || !acc_.IsVtable(func)) {
1568         return false;
1569     }
1570     return true;
1571 }
1572 
1573 template<EcmaOpcode Op, class TypeAccessor>
LowerTypedThisCall(const TypeAccessor & tacc)1574 void TypedBytecodeLowering::LowerTypedThisCall(const TypeAccessor &tacc)
1575 {
1576     uint32_t argc = tacc.GetArgc();
1577     GateRef gate = tacc.GetGate();
1578     GateRef actualArgc = Circuit::NullGate();
1579     switch (Op) {
1580         case EcmaOpcode::CALLTHIS0_IMM8_V8: {
1581             actualArgc = builder_.Int64(BytecodeCallArgc::ComputeCallArgc(acc_.GetNumValueIn(gate),
1582                 EcmaOpcode::CALLTHIS0_IMM8_V8));
1583             break;
1584         }
1585         case EcmaOpcode::CALLTHIS1_IMM8_V8_V8: {
1586             actualArgc = builder_.Int64(BytecodeCallArgc::ComputeCallArgc(acc_.GetNumValueIn(gate),
1587                 EcmaOpcode::CALLTHIS1_IMM8_V8_V8));
1588             break;
1589         }
1590         case EcmaOpcode::CALLTHIS2_IMM8_V8_V8_V8: {
1591             actualArgc = builder_.Int64(BytecodeCallArgc::ComputeCallArgc(acc_.GetNumValueIn(gate),
1592                 EcmaOpcode::CALLTHIS2_IMM8_V8_V8_V8));
1593             break;
1594         }
1595         case EcmaOpcode::CALLTHIS3_IMM8_V8_V8_V8_V8: {
1596             actualArgc = builder_.Int64(BytecodeCallArgc::ComputeCallArgc(acc_.GetNumValueIn(gate),
1597                 EcmaOpcode::CALLTHIS3_IMM8_V8_V8_V8_V8));
1598             break;
1599         }
1600         case EcmaOpcode::CALLTHISRANGE_IMM8_IMM8_V8: {
1601             actualArgc = builder_.Int64(BytecodeCallArgc::ComputeCallArgc(acc_.GetNumValueIn(gate),
1602                 EcmaOpcode::CALLTHISRANGE_IMM8_IMM8_V8));
1603             break;
1604         }
1605         default:
1606             UNREACHABLE();
1607     }
1608 
1609     uint32_t len = tacc.GetFunctionTypeLength();
1610     GateRef func = tacc.GetFunc();
1611     GateRef newTarget = builder_.Undefined();
1612     GateRef thisObj = tacc.GetThisObj();
1613     std::vector<GateRef> argsFastCall { glue_, func, thisObj};
1614     std::vector<GateRef> args { glue_, actualArgc, func, newTarget, thisObj };
1615     for (uint32_t i = 0; i < argc; i++) {
1616         GateRef value = acc_.GetValueIn(gate, i + 1);
1617         argsFastCall.emplace_back(value);
1618         args.emplace_back(value);
1619     }
1620     for (uint32_t i = argc; i < len; i++) {
1621         argsFastCall.emplace_back(builder_.Undefined());
1622         args.emplace_back(builder_.Undefined());
1623     }
1624     CheckThisCallTargetAndLowerCall(tacc, args, argsFastCall);
1625 }
1626 
LowerTypedCallthis0(GateRef gate)1627 void TypedBytecodeLowering::LowerTypedCallthis0(GateRef gate)
1628 {
1629     CallThis0TypeInfoAccessor tacc(thread_, circuit_, gate);
1630     BuiltinsStubCSigns::ID id = tacc.TryGetBuiltinId(BuiltinTypeId::ARRAY);
1631     if (id == BuiltinsStubCSigns::ID::SORT) {
1632         AddProfiling(gate);
1633         SpeculateCallBuiltin(gate, tacc.GetFunc(), { tacc.GetThisObj() }, id, true);
1634         return;
1635     }
1636     BuiltinsStubCSigns::ID pgoFuncId = tacc.TryGetPGOBuiltinId();
1637     if (IS_TYPED_BUILTINS_ID_CALL_THIS0(pgoFuncId)) {
1638         AddProfiling(gate);
1639         SpeculateCallBuiltin(gate, tacc.GetFunc(), { tacc.GetThisObj() }, pgoFuncId, true);
1640         return;
1641     }
1642     if (!tacc.CanOptimizeAsFastCall()) {
1643         return;
1644     }
1645     LowerTypedThisCall<EcmaOpcode::CALLTHIS0_IMM8_V8>(tacc);
1646 }
1647 
LowerTypedCallthis1(GateRef gate)1648 void TypedBytecodeLowering::LowerTypedCallthis1(GateRef gate)
1649 {
1650     CallThis1TypeInfoAccessor tacc(thread_, circuit_, gate);
1651     BuiltinsStubCSigns::ID id = tacc.TryGetBuiltinId(BuiltinTypeId::MATH);
1652     if (id == BuiltinsStubCSigns::ID::NONE) {
1653         id = tacc.TryGetBuiltinId(BuiltinTypeId::JSON);
1654         if (id != BuiltinsStubCSigns::ID::NONE) {
1655             AddProfiling(gate);
1656             SpeculateCallBuiltin(gate, tacc.GetFunc(), { tacc.GetArg0() }, id, true);
1657             return;
1658         }
1659     } else if (tacc.Arg0IsNumberType()) {
1660             AddProfiling(gate);
1661             SpeculateCallBuiltin(gate, tacc.GetFunc(), { tacc.GetArg0() }, id, false);
1662             return;
1663     }
1664     if (!tacc.CanOptimizeAsFastCall()) {
1665         return;
1666     }
1667     LowerTypedThisCall<EcmaOpcode::CALLTHIS1_IMM8_V8_V8>(tacc);
1668 }
1669 
LowerTypedCallthis2(GateRef gate)1670 void TypedBytecodeLowering::LowerTypedCallthis2(GateRef gate)
1671 {
1672     CallThis2TypeInfoAccessor tacc(thread_, circuit_, gate);
1673     if (!tacc.CanOptimizeAsFastCall()) {
1674         return;
1675     }
1676     LowerTypedThisCall<EcmaOpcode::CALLTHIS2_IMM8_V8_V8_V8>(tacc);
1677 }
1678 
LowerTypedCallthis3(GateRef gate)1679 void TypedBytecodeLowering::LowerTypedCallthis3(GateRef gate)
1680 {
1681     CallThis3TypeInfoAccessor tacc(thread_, circuit_, gate);
1682     BuiltinsStubCSigns::ID id = tacc.TryGetBuiltinId(BuiltinTypeId::STRING);
1683     if (IS_TYPED_BUILTINS_ID_CALL_THIS3(id)) {
1684         AddProfiling(gate);
1685         SpeculateCallBuiltin(gate, tacc.GetFunc(), tacc.GetArgs(), id, true);
1686         return;
1687     }
1688     if (!tacc.CanOptimizeAsFastCall()) {
1689         return;
1690     }
1691     LowerTypedThisCall<EcmaOpcode::CALLTHIS3_IMM8_V8_V8_V8_V8>(tacc);
1692 }
1693 
LowerTypedCallthisrange(GateRef gate)1694 void TypedBytecodeLowering::LowerTypedCallthisrange(GateRef gate)
1695 {
1696     CallThisRangeTypeInfoAccessor tacc(thread_, circuit_, gate);
1697     if (!tacc.CanOptimizeAsFastCall()) {
1698         return;
1699     }
1700     LowerTypedThisCall<EcmaOpcode::CALLTHISRANGE_IMM8_IMM8_V8>(tacc);
1701 }
1702 
LowerTypedCallInit(GateRef gate)1703 void TypedBytecodeLowering::LowerTypedCallInit(GateRef gate)
1704 {
1705     // same as callthis0
1706     LowerTypedCallthis0(gate);
1707 }
1708 
AddProfiling(GateRef gate)1709 void TypedBytecodeLowering::AddProfiling(GateRef gate)
1710 {
1711     hitTypedOpCount_++;
1712     AddHitBytecodeCount();
1713     if (IsTraceBC()) {
1714         // see stateSplit as a part of JSByteCode if exists
1715         GateRef maybeStateSplit = acc_.GetDep(gate);
1716         GateRef current = Circuit::NullGate();
1717         if (acc_.GetOpCode(maybeStateSplit) == OpCode::STATE_SPLIT) {
1718             current = maybeStateSplit;
1719         } else {
1720             current = gate;
1721         }
1722 
1723         EcmaOpcode ecmaOpcode = acc_.GetByteCodeOpcode(gate);
1724         auto ecmaOpcodeGate = builder_.Int32(static_cast<uint32_t>(ecmaOpcode));
1725         GateRef constOpcode = builder_.Int32ToTaggedInt(ecmaOpcodeGate);
1726         GateRef typedPath = builder_.Int32ToTaggedInt(builder_.Int32(1));
1727         GateRef traceGate = builder_.CallRuntime(glue_, RTSTUB_ID(DebugAOTPrint), acc_.GetDep(current),
1728                                                  { constOpcode, typedPath }, gate);
1729         acc_.SetDep(current, traceGate);
1730         builder_.SetDepend(acc_.GetDep(gate));  // set gate depend: trace or STATE_SPLIT
1731     }
1732 
1733     if (IsProfiling()) {
1734         // see stateSplit as a part of JSByteCode if exists
1735         GateRef maybeStateSplit = acc_.GetDep(gate);
1736         GateRef current = Circuit::NullGate();
1737         if (acc_.GetOpCode(maybeStateSplit) == OpCode::STATE_SPLIT) {
1738             current = maybeStateSplit;
1739         } else {
1740             current = gate;
1741         }
1742 
1743         if (acc_.HasFrameState(gate)) {
1744             // func, pcoffset, opcode, mode
1745             GateRef func = argAcc_.GetFrameArgsIn(gate, FrameArgIdx::FUNC);
1746             GateRef bcIndex = builder_.Int32ToTaggedInt(builder_.Int32(acc_.TryGetBcIndex(gate)));
1747             EcmaOpcode ecmaOpcode = acc_.GetByteCodeOpcode(gate);
1748             auto ecmaOpcodeGate = builder_.Int32(static_cast<uint32_t>(ecmaOpcode));
1749             GateRef constOpcode = builder_.Int32ToTaggedInt(ecmaOpcodeGate);
1750             GateRef mode =
1751                 builder_.Int32ToTaggedInt(builder_.Int32(static_cast<int32_t>(OptCodeProfiler::Mode::TYPED_PATH)));
1752             GateRef profiling = builder_.CallRuntime(glue_, RTSTUB_ID(ProfileOptimizedCode), acc_.GetDep(current),
1753                 { func, bcIndex, constOpcode, mode }, gate);
1754             acc_.SetDep(current, profiling);
1755             builder_.SetDepend(acc_.GetDep(gate));  // set gate depend: profiling or STATE_SPLIT
1756         }
1757     }
1758 }
1759 
AddBytecodeCount(EcmaOpcode op)1760 void TypedBytecodeLowering::AddBytecodeCount(EcmaOpcode op)
1761 {
1762     currentOp_ = op;
1763     if (bytecodeMap_.find(op) != bytecodeMap_.end()) {
1764         bytecodeMap_[op]++;
1765     } else {
1766         bytecodeMap_[op] = 1;
1767     }
1768 }
1769 
DeleteBytecodeCount(EcmaOpcode op)1770 void TypedBytecodeLowering::DeleteBytecodeCount(EcmaOpcode op)
1771 {
1772     bytecodeMap_.erase(op);
1773 }
1774 
AddHitBytecodeCount()1775 void TypedBytecodeLowering::AddHitBytecodeCount()
1776 {
1777     if (bytecodeHitTimeMap_.find(currentOp_) != bytecodeHitTimeMap_.end()) {
1778         bytecodeHitTimeMap_[currentOp_]++;
1779     } else {
1780         bytecodeHitTimeMap_[currentOp_] = 1;
1781     }
1782 }
1783 
LowerTypedTypeOf(GateRef gate)1784 void TypedBytecodeLowering::LowerTypedTypeOf(GateRef gate)
1785 {
1786     // 1: number of value inputs
1787     TypeOfTypeInfoAccessor tacc(thread_, circuit_, gate);
1788     if (tacc.IsIllegalType()) {
1789         return;
1790     }
1791     AddProfiling(gate);
1792     if (!Uncheck()) {
1793         builder_.TypeOfCheck(tacc.GetValue(), tacc.GetValueGateType());
1794     }
1795     GateRef result = builder_.TypedTypeOf(tacc.GetValueGateType());
1796     acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), result);
1797 }
1798 
LowerGetIterator(GateRef gate)1799 void TypedBytecodeLowering::LowerGetIterator(GateRef gate)
1800 {
1801     GetIteratorTypeInfoAccessor tacc(thread_, circuit_, gate);
1802     BuiltinsStubCSigns::ID id = tacc.TryGetPGOBuiltinId();
1803     if (id == BuiltinsStubCSigns::ID::NONE) {
1804         return;
1805     }
1806     AddProfiling(gate);
1807     GateRef obj = tacc.GetCallee();
1808     SpeculateCallBuiltin(gate, obj, { obj }, id, true);
1809 }
1810 
LowerTypedTryLdGlobalByName(GateRef gate)1811 void TypedBytecodeLowering::LowerTypedTryLdGlobalByName(GateRef gate)
1812 {
1813     if (!enableLoweringBuiltin_) {
1814         return;
1815     }
1816     DISALLOW_GARBAGE_COLLECTION;
1817     LoadGlobalObjByNameTypeInfoAccessor tacc(thread_, circuit_, gate);
1818     JSTaggedValue key = tacc.GetKeyTaggedValue();
1819 
1820     BuiltinIndex& builtin = BuiltinIndex::GetInstance();
1821     auto index = builtin.GetBuiltinIndex(key);
1822     if (index == builtin.NOT_FOUND) {
1823         return;
1824     }
1825     AddProfiling(gate);
1826     GateRef result = builder_.LoadBuiltinObject(index);
1827     acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), result);
1828     DeleteConstDataIfNoUser(tacc.GetKey());
1829 }
1830 
LowerInstanceOf(GateRef gate)1831 void TypedBytecodeLowering::LowerInstanceOf(GateRef gate)
1832 {
1833     InstanceOfTypeInfoAccessor tacc(thread_, circuit_, gate, chunk_);
1834     if (tacc.TypesIsEmpty() || tacc.HasIllegalType()) {
1835         return;
1836     }
1837     AddProfiling(gate);
1838     size_t typeCount = tacc.GetTypeCount();
1839     std::vector<GateRef> expectedHCIndexes;
1840     for (size_t i = 0; i < typeCount; ++i) {
1841         GateRef temp = builder_.Int32(tacc.GetExpectedHClassIndex(i));
1842         expectedHCIndexes.emplace_back(temp);
1843     }
1844     DEFVALUE(result, (&builder_), VariableType::JS_ANY(), builder_.Hole());
1845     // RuntimeCheck -
1846     // 1. pgo.hclass == ctor.hclass
1847     // 2. ctor.hclass has a prototype chain up to Function.prototype
1848     GateRef obj = tacc.GetReceiver();
1849     GateRef target = tacc.GetTarget();
1850 
1851     builder_.ObjectTypeCheck(acc_.GetGateType(gate), true, target, expectedHCIndexes[0]);
1852     builder_.ProtoChangeMarkerCheck(target);
1853 
1854     result = builder_.OrdinaryHasInstance(obj, target);
1855     acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), *result);
1856 }
1857 
LowerCreateEmptyObject(GateRef gate)1858 void TypedBytecodeLowering::LowerCreateEmptyObject(GateRef gate)
1859 {
1860     AddProfiling(gate);
1861     GateRef globalEnv = builder_.GetGlobalEnv();
1862     GateRef hclass = builder_.GetGlobalEnvObjHClass(globalEnv, GlobalEnv::OBJECT_FUNCTION_INDEX);
1863 
1864     JSHandle<JSFunction> objectFunc(tsManager_->GetEcmaVM()->GetGlobalEnv()->GetObjectFunction());
1865     JSTaggedValue protoOrHClass = objectFunc->GetProtoOrHClass();
1866     JSHClass *objectHC = JSHClass::Cast(protoOrHClass.GetTaggedObject());
1867     size_t objectSize = objectHC->GetObjectSize();
1868 
1869     GateRef emptyArray = builder_.GetGlobalConstantValue(ConstantIndex::EMPTY_ARRAY_OBJECT_INDEX);
1870     GateRef size = builder_.IntPtr(objectHC->GetObjectSize());
1871 
1872     builder_.StartAllocate();
1873     GateRef object = builder_.HeapAlloc(size, GateType::TaggedValue(), RegionSpaceFlag::IN_YOUNG_SPACE);
1874 
1875     // initialization
1876     for (size_t offset = JSObject::SIZE; offset < objectSize; offset += JSTaggedValue::TaggedTypeSize()) {
1877         builder_.StoreConstOffset(VariableType::INT64(), object, offset, builder_.Undefined());
1878     }
1879     builder_.StoreConstOffset(VariableType::JS_POINTER(), object, JSObject::HCLASS_OFFSET, hclass);
1880     builder_.StoreConstOffset(VariableType::INT64(), object, JSObject::HASH_OFFSET,
1881                               builder_.Int64(JSTaggedValue(0).GetRawData()));
1882     builder_.StoreConstOffset(VariableType::JS_POINTER(), object, JSObject::PROPERTIES_OFFSET, emptyArray);
1883     builder_.StoreConstOffset(VariableType::JS_POINTER(), object, JSObject::ELEMENTS_OFFSET, emptyArray);
1884     builder_.FinishAllocate(object);
1885 
1886     acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), object);
1887 }
1888 
LowerTypedStOwnByValue(GateRef gate)1889 void TypedBytecodeLowering::LowerTypedStOwnByValue(GateRef gate)
1890 {
1891     // StOwnByValue is rarely used, so the callruntime solution is used
1892     AddProfiling(gate);
1893     return;
1894 }
1895 
LowerCreateObjectWithBuffer(GateRef gate)1896 void TypedBytecodeLowering::LowerCreateObjectWithBuffer(GateRef gate)
1897 {
1898     CreateObjWithBufferTypeInfoAccessor tacc(thread_, circuit_, gate, recordName_);
1899     if (!tacc.CanOptimize()) {
1900         return;
1901     }
1902     JSTaggedValue hclassVal = tacc.GetHClass();
1903     if (hclassVal.IsUndefined()) {
1904         return;
1905     }
1906     JSHandle<JSHClass> newClass(thread_, hclassVal);
1907     GateRef index = tacc.GetIndex();
1908     JSHandle<JSObject> objhandle = tacc.GetObjHandle();
1909     std::vector<uint64_t> inlinedProps;
1910     auto layout = LayoutInfo::Cast(newClass->GetLayout().GetTaggedObject());
1911     for (uint32_t i = 0; i < newClass->GetInlinedProperties(); i++) {
1912         auto attr = layout->GetAttr(i);
1913         JSTaggedValue value = objhandle->GetPropertyInlinedProps(i);
1914         if ((!attr.IsTaggedRep()) || value.IsUndefinedOrNull() ||
1915             value.IsNumber() || value.IsBoolean() || value.IsException()) {
1916             auto converted = JSObject::ConvertValueWithRep(attr, value);
1917             if (!converted.first) {
1918                 return;
1919             }
1920             inlinedProps.emplace_back(converted.second.GetRawData());
1921         } else {
1922             return;
1923         }
1924     }
1925 
1926     AddProfiling(gate);
1927     GateRef jsFunc = argAcc_.GetFrameArgsIn(gate, FrameArgIdx::FUNC);
1928     auto size = newClass->GetObjectSize();
1929     std::vector<GateRef> valueIn;
1930     valueIn.emplace_back(jsFunc);
1931     valueIn.emplace_back(builder_.IntPtr(size));
1932     valueIn.emplace_back(index);
1933     valueIn.emplace_back(builder_.Int64(newClass.GetTaggedValue().GetRawData()));
1934     valueIn.emplace_back(acc_.GetValueIn(gate, 1));
1935     for (uint32_t i = 0; i < newClass->GetInlinedProperties(); i++) {
1936         valueIn.emplace_back(builder_.Int64(inlinedProps.at(i)));
1937         valueIn.emplace_back(builder_.Int32(newClass->GetInlinedPropertiesOffset(i)));
1938     }
1939     GateRef ret = builder_.TypedCreateObjWithBuffer(valueIn);
1940     acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), ret);
1941 }
1942 }  // namespace panda::ecmascript
1943