• 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 #include "ecmascript/compiler/bytecode_circuit_builder.h"
16 #include "ecmascript/compiler/bytecodes.h"
17 #include "ecmascript/compiler/compiler_log.h"
18 #include "ecmascript/compiler/pass.h"
19 #include "ecmascript/compiler/ts_inline_lowering.h"
20 #include "ecmascript/ts_types/ts_manager.h"
21 #include "ecmascript/ts_types/ts_type.h"
22 #include "libpandabase/utils/utf.h"
23 #include "libpandafile/class_data_accessor-inl.h"
24 #include "ecmascript/ts_types/ts_type_accessor.h"
25 
26 namespace panda::ecmascript::kungfu {
RunTSInlineLowering()27 void TSInlineLowering::RunTSInlineLowering()
28 {
29     circuit_->AdvanceTime();
30     ChunkQueue<CallGateInfo> workList(chunk_);
31     UpdateWorkList(workList);
32 
33     while (!workList.empty()) {
34         CallGateInfo info = workList.front();
35         workList.pop();
36         TryInline(info, workList);
37     }
38 }
39 
CandidateInlineCall(GateRef gate,ChunkQueue<CallGateInfo> & workList)40 void TSInlineLowering::CandidateInlineCall(GateRef gate, ChunkQueue<CallGateInfo> &workList)
41 {
42     EcmaOpcode ecmaOpcode = acc_.GetByteCodeOpcode(gate);
43     switch (ecmaOpcode) {
44         case EcmaOpcode::LDOBJBYNAME_IMM8_ID16:
45         case EcmaOpcode::LDOBJBYNAME_IMM16_ID16:
46         case EcmaOpcode::LDTHISBYNAME_IMM8_ID16:
47         case EcmaOpcode::LDTHISBYNAME_IMM16_ID16:
48             CandidateAccessor(gate, workList, CallKind::CALL_GETTER);
49             break;
50         case EcmaOpcode::STOBJBYNAME_IMM8_ID16_V8:
51         case EcmaOpcode::STOBJBYNAME_IMM16_ID16_V8:
52         case EcmaOpcode::STTHISBYNAME_IMM8_ID16:
53         case EcmaOpcode::STTHISBYNAME_IMM16_ID16:
54             CandidateAccessor(gate, workList, CallKind::CALL_SETTER);
55             break;
56         case EcmaOpcode::CALLTHIS0_IMM8_V8:
57         case EcmaOpcode::CALLTHIS1_IMM8_V8_V8:
58         case EcmaOpcode::CALLTHIS2_IMM8_V8_V8_V8:
59         case EcmaOpcode::CALLTHIS3_IMM8_V8_V8_V8_V8:
60         case EcmaOpcode::CALLTHISRANGE_IMM8_IMM8_V8:
61         case EcmaOpcode::WIDE_CALLTHISRANGE_PREF_IMM16_V8:
62             CandidateNormalCall(gate, workList, CallKind::CALL_THIS);
63             break;
64         case EcmaOpcode::CALLARG0_IMM8:
65         case EcmaOpcode::CALLARG1_IMM8_V8:
66         case EcmaOpcode::CALLARGS2_IMM8_V8_V8:
67         case EcmaOpcode::CALLARGS3_IMM8_V8_V8_V8:
68         case EcmaOpcode::CALLRANGE_IMM8_IMM8_V8:
69         case EcmaOpcode::WIDE_CALLRANGE_PREF_IMM16_V8:
70             CandidateNormalCall(gate, workList, CallKind::CALL);
71             break;
72         default:
73             break;
74     }
75 }
76 
TryInline(CallGateInfo & info,ChunkQueue<CallGateInfo> & workList)77 void TSInlineLowering::TryInline(CallGateInfo &info, ChunkQueue<CallGateInfo> &workList)
78 {
79     GateRef gate = info.GetCallGate();
80     // inline doesn't support try-catch
81     bool inTryCatch = FilterCallInTryCatch(gate);
82     if (inTryCatch) {
83         return;
84     }
85 
86     MethodLiteral* inlinedMethod = nullptr;
87     GlobalTSTypeRef gt = info.GetFuncGT();
88     auto methodOffset = tsManager_->GetFuncMethodOffset(gt);
89     if (methodOffset == 0 || ctx_->IsSkippedMethod(methodOffset)) {
90         return;
91     }
92     if (IsRecursiveFunc(info, methodOffset)) {
93         return;
94     }
95     inlinedMethod = ctx_->GetJSPandaFile()->FindMethodLiteral(methodOffset);
96     if (!CheckParameter(gate, info, inlinedMethod)) {
97         return;
98     }
99     auto &bytecodeInfo = ctx_->GetBytecodeInfo();
100     auto &methodInfo = bytecodeInfo.GetMethodList().at(methodOffset);
101     auto &methodPcInfos = bytecodeInfo.GetMethodPcInfos();
102     auto &methodPcInfo = methodPcInfos[methodInfo.GetMethodPcInfoIndex()];
103     GateRef frameState = GetFrameState(info);
104     GateRef frameArgs = acc_.GetValueIn(frameState);
105     size_t inlineCallCounts = GetOrInitialInlineCounts(frameArgs);
106     if (IsSmallMethod(methodPcInfo.pcOffsets.size()) && !IsInlineCountsOverflow(inlineCallCounts)) {
107         inlineSuccess_ = FilterInlinedMethod(inlinedMethod, methodPcInfo.pcOffsets);
108         if (inlineSuccess_) {
109             GateRef glue = acc_.GetGlueFromArgList();
110             SetInitCallTargetAndConstPoolId(info);
111             CircuitRootScope scope(circuit_);
112             AnalyseFastAccessor(info, methodPcInfo.pcOffsets, methodOffset);
113             if (!noCheck_) {
114                 InlineCheck(info);
115             }
116             InlineCall(methodInfo, methodPcInfo, inlinedMethod, info);
117             ReplaceInput(info, glue, inlinedMethod);
118             UpdateInlineCounts(frameArgs, inlineCallCounts);
119             if (info.IsNormalCall()) {
120                 UpdateWorkList(workList);
121             } else {
122                 lastCallId_ = circuit_->GetGateCount() - 1;
123             }
124         }
125     }
126 
127     if ((inlinedMethod != nullptr) && IsLogEnabled() && inlineSuccess_) {
128         inlineSuccess_ = false;
129         auto jsPandaFile = ctx_->GetJSPandaFile();
130         const std::string methodName(
131             MethodLiteral::GetMethodName(jsPandaFile, inlinedMethod->GetMethodId()));
132         std::string fileName = jsPandaFile->GetFileName();
133         const std::string recordName(MethodLiteral::GetRecordName(jsPandaFile, inlinedMethod->GetMethodId()));
134         std::string fullName = methodName + "@" + recordName + "@" + fileName;
135         LOG_COMPILER(INFO) << "";
136         LOG_COMPILER(INFO) << "\033[34m"
137                            << "===================="
138                            << " After inlining "
139                            << "[" << fullName << "]"
140                            << " Caller method "
141                            << "[" << methodName_ << "]"
142                            << "===================="
143                            << "\033[0m";
144         circuit_->PrintAllGatesWithBytecode();
145         LOG_COMPILER(INFO) << "\033[34m" << "========================= End ==========================" << "\033[0m";
146     }
147 }
148 
FilterInlinedMethod(MethodLiteral * method,std::vector<const uint8_t * > pcOffsets)149 bool TSInlineLowering::FilterInlinedMethod(MethodLiteral* method, std::vector<const uint8_t*> pcOffsets)
150 {
151     const JSPandaFile *jsPandaFile = ctx_->GetJSPandaFile();
152     const panda_file::File *pf = jsPandaFile->GetPandaFile();
153     panda_file::MethodDataAccessor mda(*pf, method->GetMethodId());
154     panda_file::CodeDataAccessor cda(*pf, mda.GetCodeId().value());
155     if (cda.GetTriesSize() != 0) {
156         return false;
157     }
158     for (size_t i = 0; i < pcOffsets.size(); i++) {
159         auto pc = pcOffsets[i];
160         auto ecmaOpcode = ctx_->GetByteCodes()->GetOpcode(pc);
161         switch (ecmaOpcode) {
162             case EcmaOpcode::GETUNMAPPEDARGS:
163             case EcmaOpcode::SUSPENDGENERATOR_V8:
164             case EcmaOpcode::RESUMEGENERATOR:
165             case EcmaOpcode::COPYRESTARGS_IMM8:
166             case EcmaOpcode::WIDE_COPYRESTARGS_PREF_IMM16:
167             case EcmaOpcode::CREATEASYNCGENERATOROBJ_V8:
168                 return false;
169             default:
170                 break;
171         }
172     }
173     return true;
174 }
175 
InlineCall(MethodInfo & methodInfo,MethodPcInfo & methodPCInfo,MethodLiteral * method,CallGateInfo & info)176 void TSInlineLowering::InlineCall(MethodInfo &methodInfo, MethodPcInfo &methodPCInfo, MethodLiteral* method,
177                                   CallGateInfo &info)
178 {
179     const JSPandaFile *jsPandaFile = ctx_->GetJSPandaFile();
180     TSManager *tsManager = ctx_->GetTSManager();
181     CompilerLog *log = ctx_->GetCompilerLog();
182     CString recordName = MethodLiteral::GetRecordName(jsPandaFile, method->GetMethodId());
183     bool hasTyps = jsPandaFile->HasTSTypes(recordName);
184     if (!hasTyps) {
185         return;
186     }
187     const std::string methodName(MethodLiteral::GetMethodName(jsPandaFile, method->GetMethodId()));
188     std::string fileName = jsPandaFile->GetFileName();
189     std::string fullName = methodName + "@" + std::string(recordName) + "@" + fileName;
190 
191     circuit_->InitRoot();
192     BytecodeCircuitBuilder builder(jsPandaFile, method, methodPCInfo,
193                                    tsManager, circuit_,
194                                    ctx_->GetByteCodes(), true, IsLogEnabled(),
195                                    enableTypeLowering_, fullName, recordName, ctx_->GetPfDecoder(), true,
196                                    passOptions_->EnableOptTrackField());
197     {
198         if (enableTypeLowering_) {
199             BuildFrameStateChain(info, builder);
200         }
201         TimeScope timeScope("BytecodeToCircuit", methodName, method->GetMethodId().GetOffset(), log);
202         builder.BytecodeToCircuit();
203     }
204 
205     PassData data(&builder, circuit_, ctx_, log, fullName,
206                   &methodInfo, hasTyps, recordName,
207                   method, method->GetMethodId().GetOffset(), nativeAreaAllocator_, ctx_->GetPfDecoder(), passOptions_);
208     PassRunner<PassData> pipeline(&data);
209     if (builder.EnableLoopOptimization()) {
210         pipeline.RunPass<LoopOptimizationPass>();
211     }
212     pipeline.RunPass<TypeInferPass>();
213     pipeline.RunPass<PGOTypeInferPass>();
214 }
215 
CheckParameter(GateRef gate,CallGateInfo & info,MethodLiteral * method)216 bool TSInlineLowering::CheckParameter(GateRef gate, CallGateInfo &info, MethodLiteral* method)
217 {
218     if (info.IsCallAccessor()) {
219         return true;
220     }
221     size_t numIns = acc_.GetNumValueIn(gate);
222     size_t fixedInputsNum = info.IsCallThis() ? 2 : 1; // 2: calltarget and this
223 
224     uint32_t declaredNumArgs = method->GetNumArgsWithCallField();
225     return declaredNumArgs == (numIns - fixedInputsNum);
226 }
227 
ReplaceCallInput(CallGateInfo & info,GateRef glue,MethodLiteral * method)228 void TSInlineLowering::ReplaceCallInput(CallGateInfo &info, GateRef glue, MethodLiteral *method)
229 {
230     GateRef gate = info.GetCallGate();
231     bool isCallThis = info.IsCallThis();
232     std::vector<GateRef> vec;
233     size_t numIns = acc_.GetNumValueIn(gate);
234     // 1: last one elem is function
235     GateRef callTarget = acc_.GetValueIn(gate, numIns - 1);
236     GateRef thisObj = Circuit::NullGate();
237     size_t fixedInputsNum = 0;
238     if (isCallThis) {
239         fixedInputsNum = 2; // 2: call target and this
240         thisObj = acc_.GetValueIn(gate, 0);
241     } else {
242         fixedInputsNum = 1; // 1: call target
243         thisObj = builder_.Undefined();
244     }
245     // -1: callTarget
246     size_t actualArgc = numIns + NUM_MANDATORY_JSFUNC_ARGS - fixedInputsNum;
247     vec.emplace_back(glue); // glue
248     if (!method->IsFastCall()) {
249         vec.emplace_back(builder_.Int64(actualArgc)); // argc
250     }
251     vec.emplace_back(callTarget);
252     if (!method->IsFastCall()) {
253         vec.emplace_back(builder_.Undefined()); // newTarget
254     }
255     vec.emplace_back(thisObj);
256     // -1: call Target
257     for (size_t i = fixedInputsNum - 1; i < numIns - 1; i++) {
258         vec.emplace_back(acc_.GetValueIn(gate, i));
259     }
260     LowerToInlineCall(info, vec, method);
261 }
262 
ReplaceAccessorInput(CallGateInfo & info,GateRef glue,MethodLiteral * method)263 void TSInlineLowering::ReplaceAccessorInput(CallGateInfo &info, GateRef glue, MethodLiteral *method)
264 {
265     GateRef gate = info.GetCallGate();
266     std::vector<GateRef> vec;
267     GateRef thisObj = GetAccessorReceiver(gate);
268     GateRef callTarget = Circuit::NullGate();
269     // Fast accessor will not load getter or setter func
270     if (EnableFastAccessor()) {
271         callTarget = initCallTarget_;
272     } else {
273         callTarget = BuildAccessor(info);
274     }
275     size_t actualArgc = 0;
276     if (info.IsCallGetter()) {
277         actualArgc = NUM_MANDATORY_JSFUNC_ARGS;
278     } else if (info.IsCallSetter()) {
279         actualArgc = NUM_MANDATORY_JSFUNC_ARGS + 1;
280     } else {
281         UNREACHABLE();
282     }
283 
284     vec.emplace_back(glue); // glue
285     if (!method->IsFastCall()) {
286         vec.emplace_back(builder_.Int64(actualArgc)); // argc
287     }
288     vec.emplace_back(callTarget);
289     if (!method->IsFastCall()) {
290         vec.emplace_back(builder_.Undefined()); // newTarget
291     }
292     vec.emplace_back(thisObj);
293 
294     if (info.IsCallSetter()) {
295         vec.emplace_back(GetCallSetterValue(gate));
296     }
297     LowerToInlineCall(info, vec, method);
298 }
299 
BuildAccessor(CallGateInfo & info)300 GateRef TSInlineLowering::BuildAccessor(CallGateInfo &info)
301 {
302     GateRef gate = info.GetCallGate();
303     GateRef depend = acc_.GetDep(gate);
304     GateRef receiver = GetAccessorReceiver(gate);
305     GateRef accessor = Circuit::NullGate();
306     uint32_t plrData = GetPlrData(receiver, acc_.GetValueIn(gate, 1));
307     if (info.IsCallGetter()) {
308         accessor = circuit_->NewGate(circuit_->LoadGetter(), MachineType::I64,
309                                      {depend, receiver, builder_.Int32(plrData)}, GateType::AnyType());
310     } else {
311         accessor = circuit_->NewGate(circuit_->LoadSetter(), MachineType::I64,
312                                      {depend, receiver, builder_.Int32(plrData)}, GateType::AnyType());
313     }
314     acc_.ReplaceDependIn(gate, accessor);
315     return accessor;
316 }
317 
GetPlrData(GateRef receiver,GateRef constData)318 uint32_t TSInlineLowering::GetPlrData(GateRef receiver, GateRef constData)
319 {
320     uint16_t propIndex = acc_.GetConstantValue(constData);
321     auto prop = tsManager_->GetStringFromConstantPool(propIndex);
322     GateType receiverType = acc_.GetGateType(receiver);
323     receiverType = tsManager_->TryNarrowUnionType(receiverType);
324     int hclassIndex = tsManager_->GetHClassIndexByInstanceGateType(receiverType);
325     JSHClass *hclass = JSHClass::Cast(tsManager_->GetValueFromCache(hclassIndex).GetTaggedObject());
326     PropertyLookupResult plr = JSHClass::LookupPropertyInAotHClass(tsManager_->GetThread(), hclass, prop);
327     return plr.GetData();
328 }
329 
ReplaceInput(CallGateInfo & info,GateRef glue,MethodLiteral * method)330 void TSInlineLowering::ReplaceInput(CallGateInfo &info, GateRef glue, MethodLiteral *method)
331 {
332     if (info.IsNormalCall()) {
333         ReplaceCallInput(info, glue, method);
334     } else {
335         ASSERT(info.IsCallAccessor());
336         ReplaceAccessorInput(info, glue, method);
337     }
338 }
339 
MergeAllReturn(const std::vector<GateRef> & returnVector,GateRef & state,GateRef & depend)340 GateRef TSInlineLowering::MergeAllReturn(const std::vector<GateRef> &returnVector, GateRef &state, GateRef &depend)
341 {
342     size_t numOfIns = returnVector.size();
343     auto stateList = std::vector<GateRef>(numOfIns, Circuit::NullGate());
344     auto dependList = std::vector<GateRef>(numOfIns + 1, Circuit::NullGate());
345     auto vaueList = std::vector<GateRef>(numOfIns + 1, Circuit::NullGate());
346 
347     for (size_t i = 0; i < returnVector.size(); i++) {
348         GateRef returnGate = returnVector.at(i);
349         ASSERT(acc_.GetOpCode(acc_.GetState(returnGate)) != OpCode::IF_EXCEPTION);
350         stateList[i] = acc_.GetState(returnGate);
351         dependList[i + 1] = acc_.GetDep(returnGate);
352         vaueList[i + 1] = acc_.GetValueIn(returnGate, 0);
353         acc_.DeleteGate(returnGate);
354     }
355 
356     state = circuit_->NewGate(circuit_->Merge(numOfIns), stateList);
357     dependList[0] = state;
358     vaueList[0] = state;
359     depend = circuit_->NewGate(circuit_->DependSelector(numOfIns), dependList);
360     return circuit_->NewGate(circuit_->ValueSelector(numOfIns), MachineType::I64, numOfIns + 1,
361                              vaueList.data(), GateType::AnyType());
362 }
363 
ReplaceEntryGate(GateRef callGate,GateRef callerFunc,GateRef inlineFunc,GateRef glue)364 void TSInlineLowering::ReplaceEntryGate(GateRef callGate, GateRef callerFunc, GateRef inlineFunc, GateRef glue)
365 {
366     auto stateEntry = acc_.GetStateRoot();
367     auto dependEntry = acc_.GetDependRoot();
368 
369     GateRef callState = acc_.GetState(callGate);
370     GateRef callDepend = acc_.GetDep(callGate);
371     auto stateUse = acc_.Uses(stateEntry);
372 
373     // support inline trace
374     GateRef newDep = Circuit::NullGate();
375     if (traceInline_) {
376         std::vector<GateRef> args{callerFunc, inlineFunc};
377         newDep = TraceInlineFunction(glue, callDepend, args, callGate);
378     } else {
379         newDep = callDepend;
380     }
381 
382     for (auto stateUseIt = stateUse.begin(); stateUseIt != stateUse.end();) {
383         stateUseIt = acc_.ReplaceIn(stateUseIt, callState);
384     }
385 
386     auto dependUse = acc_.Uses(dependEntry);
387     for (auto dependUseIt = dependUse.begin(); dependUseIt != dependUse.end();) {
388         dependUseIt = acc_.ReplaceIn(dependUseIt, newDep);
389     }
390 }
391 
TraceInlineFunction(GateRef glue,GateRef depend,std::vector<GateRef> & args,GateRef callGate)392 GateRef TSInlineLowering::TraceInlineFunction(GateRef glue, GateRef depend, std::vector<GateRef> &args,
393                                               GateRef callGate)
394 {
395     size_t index = RTSTUB_ID(AotInlineTrace);
396     GateRef result = builder_.NoLabelCallRuntime(glue, depend, index, args, callGate);
397     return result;
398 }
399 
ReplaceReturnGate(GateRef callGate)400 void TSInlineLowering::ReplaceReturnGate(GateRef callGate)
401 {
402     std::vector<GateRef> returnVector;
403     acc_.GetReturnOuts(returnVector);
404 
405     GateRef value = Circuit::NullGate();
406     GateRef state = Circuit::NullGate();
407     GateRef depend = Circuit::NullGate();
408 
409     if (returnVector.size() == 1) {
410         GateRef returnGate = returnVector.at(0);
411         GateRef returnState = acc_.GetState(returnGate);
412         depend = acc_.GetDep(returnGate);
413         state = returnState;
414         value = acc_.GetValueIn(returnGate, 0);
415         acc_.DeleteGate(returnGate);
416     } else {
417         value = MergeAllReturn(returnVector, state, depend);
418     }
419     SupplementType(callGate, value);
420     ReplaceHirAndDeleteState(callGate, state, depend, value);
421 }
422 
ReplaceHirAndDeleteState(GateRef gate,GateRef state,GateRef depend,GateRef value)423 void TSInlineLowering::ReplaceHirAndDeleteState(GateRef gate, GateRef state, GateRef depend, GateRef value)
424 {
425     auto uses = acc_.Uses(gate);
426     for (auto useIt = uses.begin(); useIt != uses.end();) {
427         if (acc_.IsStateIn(useIt)) {
428             useIt = acc_.ReplaceIn(useIt, state);
429         } else if (acc_.IsDependIn(useIt)) {
430             useIt = acc_.ReplaceIn(useIt, depend);
431         } else if (acc_.IsValueIn(useIt)) {
432             useIt = acc_.ReplaceIn(useIt, value);
433         } else {
434             LOG_ECMA(FATAL) << "this branch is unreachable";
435             UNREACHABLE();
436         }
437     }
438     acc_.DeleteGate(gate);
439 }
440 
LowerToInlineCall(CallGateInfo & info,const std::vector<GateRef> & args,MethodLiteral * method)441 void TSInlineLowering::LowerToInlineCall(CallGateInfo &info, const std::vector<GateRef> &args, MethodLiteral* method)
442 {
443     GateRef callGate = info.GetCallGate();
444     // replace in value/args
445     ArgumentAccessor argAcc(circuit_);
446     ASSERT(argAcc.ArgsCount() == args.size());
447     for (size_t i = 0; i < argAcc.ArgsCount(); i++) {
448         GateRef arg = argAcc.ArgsAt(i);
449         acc_.UpdateAllUses(arg, args.at(i));
450         acc_.SetGateType(args.at(i), acc_.GetGateType(arg));
451         acc_.DeleteGate(arg);
452     }
453     // replace in depend and state
454     GateRef glue = args.at(static_cast<size_t>(CommonArgIdx::GLUE));
455     GateRef inlineFunc;
456     if (method->IsFastCall()) {
457         inlineFunc = args.at(static_cast<size_t>(FastCallArgIdx::FUNC));
458     } else {
459         inlineFunc = args.at(static_cast<size_t>(CommonArgIdx::FUNC));
460     }
461     GateRef frameArgs = GetFrameArgs(info);
462     GateRef callerFunc = acc_.GetValueIn(frameArgs, 0);
463     ReplaceEntryGate(callGate, callerFunc, inlineFunc, glue);
464     // replace use gate
465     ReplaceReturnGate(callGate);
466     // remove Useless root gates
467     RemoveRoot();
468 }
469 
InlineFuncCheck(const CallGateInfo & info)470 void TSInlineLowering::InlineFuncCheck(const CallGateInfo &info)
471 {
472     GateRef gate = info.GetCallGate();
473     GateRef callState = acc_.GetState(gate);
474     GateRef callDepend = acc_.GetDep(gate);
475     ASSERT(acc_.HasFrameState(gate));
476     GateRef frameState = acc_.GetFrameState(gate);
477     size_t funcIndex = acc_.GetNumValueIn(gate) - 1;
478     GateRef inlineFunc =  acc_.GetValueIn(gate, funcIndex);
479     // Do not load from inlineFunc beacause type in inlineFunc could be modified by others
480     GlobalTSTypeRef funcGt = info.GetFuncGT();
481     auto methodOffset = tsManager_->GetFuncMethodOffset(funcGt);
482     GateRef ret = circuit_->NewGate(circuit_->JSInlineTargetTypeCheck(info.GetType()),
483         MachineType::I1, {callState, callDepend, inlineFunc, builder_.IntPtr(methodOffset), frameState},
484         GateType::NJSValue());
485     acc_.ReplaceStateIn(gate, ret);
486     acc_.ReplaceDependIn(gate, ret);
487 }
488 
InlineAccessorCheck(GateRef gate,GateRef receiver)489 void TSInlineLowering::InlineAccessorCheck(GateRef gate, GateRef receiver)
490 {
491     GateRef callState = acc_.GetState(gate);
492     GateRef callDepend = acc_.GetDep(gate);
493     GateType receiverType = acc_.GetGateType(receiver);
494     receiverType = tsManager_->TryNarrowUnionType(receiverType);
495     int hclassIndex = tsManager_->GetHClassIndexByInstanceGateType(receiverType);
496     GateRef hclassIndexGate = builder_.IntPtr(hclassIndex);
497     auto frameState = acc_.FindNearestFrameState(callDepend);
498     GateRef ret = circuit_->NewGate(circuit_->InlineAccessorCheck(static_cast<size_t>(receiverType.Value())),
499         MachineType::I1, {callState, callDepend, receiver, hclassIndexGate, frameState}, GateType::NJSValue());
500     acc_.ReplaceStateIn(gate, ret);
501     acc_.ReplaceDependIn(gate, ret);
502 }
503 
InlineCheck(CallGateInfo & info)504 void TSInlineLowering::InlineCheck(CallGateInfo &info)
505 {
506     if (info.IsNormalCall()) {
507         InlineFuncCheck(info);
508     } else {
509         ASSERT(info.IsCallAccessor());
510         GateRef gate = info.GetCallGate();
511         GateRef receiver = GetAccessorReceiver(gate);
512         InlineAccessorCheck(gate, receiver);
513     }
514 }
515 
RemoveRoot()516 void TSInlineLowering::RemoveRoot()
517 {
518     GateRef circuitRoot = acc_.GetCircuitRoot();
519     auto uses = acc_.Uses(circuitRoot);
520     for (auto it = uses.begin(); it != uses.end();) {
521         it = acc_.DeleteGate(it);
522     }
523 
524     acc_.DeleteGate(circuitRoot);
525 }
526 
BuildFrameStateChain(CallGateInfo & info,BytecodeCircuitBuilder & builder)527 void TSInlineLowering::BuildFrameStateChain(CallGateInfo &info, BytecodeCircuitBuilder &builder)
528 {
529     GateRef preFrameState = GetFrameState(info);
530     ASSERT(acc_.GetOpCode(preFrameState) == OpCode::FRAME_STATE);
531     builder.SetPreFrameState(preFrameState);
532 }
533 
FilterCallInTryCatch(GateRef gate)534 bool TSInlineLowering::FilterCallInTryCatch(GateRef gate)
535 {
536     auto uses = acc_.Uses(gate);
537     for (auto it = uses.begin(); it != uses.end(); ++it) {
538         if (acc_.GetOpCode(*it) == OpCode::IF_SUCCESS || acc_.GetOpCode(*it) == OpCode::IF_EXCEPTION) {
539             return true;
540         }
541     }
542     return false;
543 }
544 
SupplementType(GateRef callGate,GateRef targetGate)545 void TSInlineLowering::SupplementType(GateRef callGate, GateRef targetGate)
546 {
547     GateType callGateType = acc_.GetGateType(callGate);
548     GateType targetGateType = acc_.GetGateType(targetGate);
549     if (!callGateType.IsAnyType() && targetGateType.IsAnyType()) {
550         acc_.SetGateType(targetGate, callGateType);
551     }
552 }
553 
UpdateWorkList(ChunkQueue<CallGateInfo> & workList)554 void TSInlineLowering::UpdateWorkList(ChunkQueue<CallGateInfo> &workList)
555 {
556     std::vector<GateRef> gateList;
557     circuit_->GetAllGates(gateList);
558     for (const auto &gate : gateList) {
559         if (acc_.GetId(gate) <= lastCallId_) {
560             continue;
561         }
562         auto op = acc_.GetOpCode(gate);
563         if (op == OpCode::JS_BYTECODE) {
564             CandidateInlineCall(gate, workList);
565         }
566     }
567 }
568 
GetOrInitialInlineCounts(GateRef frameArgs)569 size_t TSInlineLowering::GetOrInitialInlineCounts(GateRef frameArgs)
570 {
571     auto it = inlinedCallMap_.find(frameArgs);
572     if (it == inlinedCallMap_.end()) {
573         inlinedCallMap_[frameArgs] = 0;
574     }
575     return inlinedCallMap_[frameArgs];
576 }
577 
578 
IsRecursiveFunc(CallGateInfo & info,size_t calleeMethodOffset)579 bool TSInlineLowering::IsRecursiveFunc(CallGateInfo &info, size_t calleeMethodOffset)
580 {
581     GateRef frameArgs = GetFrameArgs(info);
582     GateRef caller = acc_.GetValueIn(frameArgs);
583     auto funcType = acc_.GetGateType(caller);
584     GlobalTSTypeRef gt = funcType.GetGTRef();
585     if (!tsManager_->IsFunctionTypeKind(gt)) {
586         return false;
587     }
588     auto callerMethodOffset = tsManager_->GetFuncMethodOffset(gt);
589     return callerMethodOffset == calleeMethodOffset;
590 }
591 
IsAccessor(GateRef receiver,GateRef constData)592 bool TSInlineLowering::IsAccessor(GateRef receiver, GateRef constData)
593 {
594     uint16_t propIndex = acc_.GetConstantValue(constData);
595     auto prop = tsManager_->GetStringFromConstantPool(propIndex);
596     GateType receiverType = acc_.GetGateType(receiver);
597     receiverType = tsManager_->TryNarrowUnionType(receiverType);
598     if (tsManager_->IsClassInstanceTypeKind(receiverType)) {
599         int hclassIndex = tsManager_->GetHClassIndexByInstanceGateType(receiverType);
600         if (hclassIndex == -1) {
601             return false;
602         }
603         JSHClass *hclass = JSHClass::Cast(tsManager_->GetValueFromCache(hclassIndex).GetTaggedObject());
604         if (!hclass->HasTSSubtyping()) {
605             return false;
606         }
607         PropertyLookupResult plr = JSHClass::LookupPropertyInAotHClass(tsManager_->GetThread(), hclass, prop);
608         if (!plr.IsFound()) {
609             return false;
610         }
611 
612         return plr.IsAccessor();
613     }
614     return false;
615 }
616 
GetAccessorFuncGT(GateRef receiver,GateRef constData)617 GlobalTSTypeRef TSInlineLowering::GetAccessorFuncGT(GateRef receiver, GateRef constData)
618 {
619     GateType receiverType = acc_.GetGateType(receiver);
620     receiverType = tsManager_->TryNarrowUnionType(receiverType);
621     GlobalTSTypeRef classInstanceGT = receiverType.GetGTRef();
622     GlobalTSTypeRef classGT = tsManager_->GetClassType(classInstanceGT);
623     TSTypeAccessor tsTypeAcc(tsManager_, classGT);
624     uint16_t propIndex = acc_.GetConstantValue(constData);
625     auto prop = tsManager_->GetStringFromConstantPool(propIndex);
626     GlobalTSTypeRef funcGT = tsTypeAcc.GetPrototypePropGT(prop);
627     return funcGT;
628 }
629 
CandidateAccessor(GateRef gate,ChunkQueue<CallGateInfo> & workList,CallKind kind)630 void TSInlineLowering::CandidateAccessor(GateRef gate, ChunkQueue<CallGateInfo> &workList, CallKind kind)
631 {
632     GateRef receiver = GetAccessorReceiver(gate);
633     GateRef constData = acc_.GetValueIn(gate, 1);
634     if (IsAccessor(receiver, constData)) {
635         GlobalTSTypeRef gt = GetAccessorFuncGT(receiver, constData);
636         if (!gt.IsDefault()) {
637             workList.push(CallGateInfo(gate, kind, gt, 0));
638             lastCallId_ = acc_.GetId(gate);
639         }
640     }
641 }
642 
CandidateNormalCall(GateRef gate,ChunkQueue<CallGateInfo> & workList,CallKind kind)643 void TSInlineLowering::CandidateNormalCall(GateRef gate, ChunkQueue<CallGateInfo> &workList, CallKind kind)
644 {
645     size_t funcIndex = acc_.GetNumValueIn(gate) - 1;
646     auto funcType = acc_.GetGateType(acc_.GetValueIn(gate, funcIndex));
647     if (tsManager_->IsFunctionTypeKind(funcType)) {
648         GlobalTSTypeRef gt = funcType.GetGTRef();
649         workList.push(CallGateInfo(gate, kind, gt, funcType.Value()));
650         lastCallId_ = acc_.GetId(gate);
651     }
652 }
653 
GetAccessorReceiver(GateRef gate)654 GateRef TSInlineLowering::GetAccessorReceiver(GateRef gate)
655 {
656     EcmaOpcode ecmaOpcode = acc_.GetByteCodeOpcode(gate);
657     if (UNLIKELY(ecmaOpcode == EcmaOpcode::STTHISBYNAME_IMM8_ID16 ||
658                  ecmaOpcode == EcmaOpcode::STTHISBYNAME_IMM16_ID16)) {
659         return argAcc_.GetFrameArgsIn(gate, FrameArgIdx::THIS_OBJECT);
660     }
661     return acc_.GetValueIn(gate, 2); // 2: receiver
662 }
663 
GetCallSetterValue(GateRef gate)664 GateRef TSInlineLowering::GetCallSetterValue(GateRef gate)
665 {
666     EcmaOpcode ecmaOpcode = acc_.GetByteCodeOpcode(gate);
667     if (ecmaOpcode == EcmaOpcode::STTHISBYNAME_IMM8_ID16 ||
668         ecmaOpcode == EcmaOpcode::STTHISBYNAME_IMM16_ID16) {
669         return acc_.GetValueIn(gate, 2); // 2: value
670     }
671     return acc_.GetValueIn(gate, 3); // 3: value
672 }
673 
GetFrameState(CallGateInfo & info)674 GateRef TSInlineLowering::GetFrameState(CallGateInfo &info)
675 {
676     GateRef gate = info.GetCallGate();
677     if (info.IsNormalCall()) {
678         return acc_.GetFrameState(gate);
679     }
680     ASSERT(info.IsCallAccessor());
681     GateRef frameState = acc_.FindNearestFrameState(gate);
682     return frameState;
683 }
684 
GetFrameArgs(CallGateInfo & info)685 GateRef TSInlineLowering::GetFrameArgs(CallGateInfo &info)
686 {
687     GateRef frameState = GetFrameState(info);
688     return acc_.GetValueIn(frameState);
689 }
690 
SetInitCallTargetAndConstPoolId(CallGateInfo & info)691 void TSInlineLowering::SetInitCallTargetAndConstPoolId(CallGateInfo &info)
692 {
693     if (initCallTarget_ == Circuit::NullGate()) {
694         GateRef frameArgs = GetFrameArgs(info);
695         initCallTarget_ = acc_.GetValueIn(frameArgs, 0);
696         const JSPandaFile *pf = ctx_->GetJSPandaFile();
697         initConstantPoolId_ = tsManager_->GetConstantPoolIDByMethodOffset(pf, initMethodOffset_);
698     }
699 }
700 
AnalyseFastAccessor(CallGateInfo & info,std::vector<const uint8_t * > pcOffsets,uint32_t inlineMethodOffset)701 void TSInlineLowering::AnalyseFastAccessor(CallGateInfo &info, std::vector<const uint8_t*> pcOffsets,
702                                            uint32_t inlineMethodOffset)
703 {
704     isFastAccessor_ = false;
705     if (!info.IsCallAccessor()) {
706         return;
707     }
708     const JSPandaFile *pf = ctx_->GetJSPandaFile();
709     int32_t constantpoolId = tsManager_->GetConstantPoolIDByMethodOffset(pf, inlineMethodOffset);
710     if (constantpoolId == initConstantPoolId_) {
711         for (size_t i = 0; i < pcOffsets.size(); i++) {
712             auto pc = pcOffsets[i];
713             auto ecmaOpcode = ctx_->GetByteCodes()->GetOpcode(pc);
714             // These bytecodes require calltarget during the lowering process, so the acquisition of the accessor
715             // function cannot be omitted.
716             switch (ecmaOpcode) {
717                 case EcmaOpcode::CREATEARRAYWITHBUFFER_IMM8_ID16:
718                 case EcmaOpcode::CREATEARRAYWITHBUFFER_IMM16_ID16:
719                 case EcmaOpcode::STMODULEVAR_IMM8:
720                 case EcmaOpcode::WIDE_STMODULEVAR_PREF_IMM16:
721                 case EcmaOpcode::DYNAMICIMPORT:
722                 case EcmaOpcode::LDLOCALMODULEVAR_IMM8:
723                 case EcmaOpcode::WIDE_LDLOCALMODULEVAR_PREF_IMM16:
724                 case EcmaOpcode::LDEXTERNALMODULEVAR_IMM8:
725                 case EcmaOpcode::WIDE_LDEXTERNALMODULEVAR_PREF_IMM16:
726                 case EcmaOpcode::GETMODULENAMESPACE_IMM8:
727                 case EcmaOpcode::WIDE_GETMODULENAMESPACE_PREF_IMM16:
728                 case EcmaOpcode::SUPERCALLSPREAD_IMM8_V8:
729                 case EcmaOpcode::NEWLEXENVWITHNAME_IMM8_ID16:
730                 case EcmaOpcode::WIDE_NEWLEXENVWITHNAME_PREF_IMM16_ID16:
731                 case EcmaOpcode::LDSUPERBYVALUE_IMM8_V8:
732                 case EcmaOpcode::LDSUPERBYVALUE_IMM16_V8:
733                 case EcmaOpcode::STSUPERBYVALUE_IMM16_V8_V8:
734                 case EcmaOpcode::STSUPERBYVALUE_IMM8_V8_V8:
735                 case EcmaOpcode::LDSUPERBYNAME_IMM8_ID16:
736                 case EcmaOpcode::LDSUPERBYNAME_IMM16_ID16:
737                 case EcmaOpcode::STSUPERBYNAME_IMM8_ID16_V8:
738                 case EcmaOpcode::STSUPERBYNAME_IMM16_ID16_V8:
739                 case EcmaOpcode::DEFINECLASSWITHBUFFER_IMM8_ID16_ID16_IMM16_V8:
740                 case EcmaOpcode::DEFINECLASSWITHBUFFER_IMM16_ID16_ID16_IMM16_V8:
741                 case EcmaOpcode::DEFINEFUNC_IMM8_ID16_IMM8:
742                 case EcmaOpcode::DEFINEFUNC_IMM16_ID16_IMM8:
743                 case EcmaOpcode::DEFINEMETHOD_IMM8_ID16_IMM8:
744                 case EcmaOpcode::DEFINEMETHOD_IMM16_ID16_IMM8:
745                     return;
746                 default:
747                     break;
748             }
749         }
750         isFastAccessor_ = true;
751     }
752 }
753 }  // namespace panda::ecmascript
754