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