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