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