• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 #include "ecmascript/compiler/bytecode_circuit_builder.h"
16 #include "ecmascript/compiler/bytecodes.h"
17 #include "ecmascript/compiler/compiler_log.h"
18 #include "ecmascript/compiler/pass.h"
19 #include "ecmascript/compiler/ts_inline_lowering.h"
20 #include "ecmascript/compiler/type_info_accessors.h"
21 #include "ecmascript/ts_types/ts_manager.h"
22 #include "ecmascript/ts_types/ts_type.h"
23 #include "libpandabase/utils/utf.h"
24 #include "libpandafile/class_data_accessor-inl.h"
25 #include "ecmascript/ts_types/ts_type_accessor.h"
26 
27 namespace panda::ecmascript::kungfu {
RunTSInlineLowering()28 void TSInlineLowering::RunTSInlineLowering()
29 {
30     circuit_->AdvanceTime();
31     ChunkQueue<InlineTypeInfoAccessor> workList(chunk_);
32     UpdateWorkList(workList);
33 
34     while (!workList.empty()) {
35         InlineTypeInfoAccessor &info = workList.front();
36         workList.pop();
37         TryInline(info, workList);
38     }
39     CollectInlineInfo();
40 }
41 
CollectInlineInfo()42 void TSInlineLowering::CollectInlineInfo()
43 {
44     std::vector<GateRef> gateList;
45     circuit_->GetAllGates(gateList);
46     for (const auto &gate : gateList) {
47         auto op = acc_.GetOpCode(gate);
48         if (op == OpCode::FRAME_ARGS) {
49             GetInlinedMethodId(gate);
50         }
51     }
52 }
53 
GetInlinedMethodId(GateRef gate)54 void TSInlineLowering::GetInlinedMethodId(GateRef gate)
55 {
56     ASSERT(acc_.GetOpCode(gate) == OpCode::FRAME_ARGS);
57     GateRef func = acc_.GetValueIn(gate, static_cast<size_t>(FrameArgIdx::FUNC));
58     uint32_t methodOffset = 0;
59     auto funcType = acc_.GetGateType(func);
60     if (tsManager_->IsFunctionTypeKind(funcType)) {
61         GlobalTSTypeRef gt = funcType.GetGTRef();
62         methodOffset = tsManager_->GetFuncMethodOffset(gt);
63     }
64     if (methodOffset == 0) {
65         auto pgoType = acc_.TryGetPGOType(gate);
66         if (pgoType.IsValidCallMethodId()) {
67             methodOffset = pgoType.GetCallMethodId();
68         }
69     }
70     acc_.UpdateMethodOffset(gate, methodOffset);
71 }
72 
CandidateInlineCall(GateRef gate,ChunkQueue<InlineTypeInfoAccessor> & workList)73 void TSInlineLowering::CandidateInlineCall(GateRef gate, ChunkQueue<InlineTypeInfoAccessor> &workList)
74 {
75     EcmaOpcode ecmaOpcode = acc_.GetByteCodeOpcode(gate);
76     switch (ecmaOpcode) {
77         case EcmaOpcode::LDOBJBYNAME_IMM8_ID16:
78         case EcmaOpcode::LDOBJBYNAME_IMM16_ID16:
79         case EcmaOpcode::LDTHISBYNAME_IMM8_ID16:
80         case EcmaOpcode::LDTHISBYNAME_IMM16_ID16:
81             CandidateAccessor(gate, workList, CallKind::CALL_GETTER);
82             break;
83         case EcmaOpcode::STOBJBYNAME_IMM8_ID16_V8:
84         case EcmaOpcode::STOBJBYNAME_IMM16_ID16_V8:
85         case EcmaOpcode::STTHISBYNAME_IMM8_ID16:
86         case EcmaOpcode::STTHISBYNAME_IMM16_ID16:
87             CandidateAccessor(gate, workList, CallKind::CALL_SETTER);
88             break;
89         case EcmaOpcode::CALLTHIS0_IMM8_V8:
90         case EcmaOpcode::CALLTHIS1_IMM8_V8_V8:
91         case EcmaOpcode::CALLTHIS2_IMM8_V8_V8_V8:
92         case EcmaOpcode::CALLTHIS3_IMM8_V8_V8_V8_V8:
93         case EcmaOpcode::CALLTHISRANGE_IMM8_IMM8_V8:
94         case EcmaOpcode::WIDE_CALLTHISRANGE_PREF_IMM16_V8:
95             CandidateNormalCall(gate, workList, CallKind::CALL_THIS);
96             break;
97         case EcmaOpcode::CALLRUNTIME_CALLINIT_PREF_IMM8_V8:
98             CandidateNormalCall(gate, workList, CallKind::CALL_INIT);
99             break;
100         case EcmaOpcode::CALLARG0_IMM8:
101         case EcmaOpcode::CALLARG1_IMM8_V8:
102         case EcmaOpcode::CALLARGS2_IMM8_V8_V8:
103         case EcmaOpcode::CALLARGS3_IMM8_V8_V8_V8:
104         case EcmaOpcode::CALLRANGE_IMM8_IMM8_V8:
105         case EcmaOpcode::WIDE_CALLRANGE_PREF_IMM16_V8:
106             CandidateNormalCall(gate, workList, CallKind::CALL);
107             break;
108         default:
109             break;
110     }
111 }
112 
TryInline(InlineTypeInfoAccessor & info,ChunkQueue<InlineTypeInfoAccessor> & workList)113 void TSInlineLowering::TryInline(InlineTypeInfoAccessor &info, ChunkQueue<InlineTypeInfoAccessor> &workList)
114 {
115     GateRef gate = info.GetCallGate();
116     // inline doesn't support try-catch
117     bool inTryCatch = FilterCallInTryCatch(gate);
118     if (inTryCatch) {
119         return;
120     }
121 
122     MethodLiteral* inlinedMethod = nullptr;
123     uint32_t methodOffset = info.GetCallMethodId();
124     if (methodOffset == 0 || ctx_->IsSkippedMethod(methodOffset)) {
125         return;
126     }
127     if (IsRecursiveFunc(info, methodOffset)) {
128         return;
129     }
130     inlinedMethod = ctx_->GetJSPandaFile()->FindMethodLiteral(methodOffset);
131     if (!CheckParameter(gate, info, inlinedMethod)) {
132         return;
133     }
134     auto &bytecodeInfo = ctx_->GetBytecodeInfo();
135     auto &methodInfo = bytecodeInfo.GetMethodList().at(methodOffset);
136     auto &methodPcInfos = bytecodeInfo.GetMethodPcInfos();
137     auto &methodPcInfo = methodPcInfos[methodInfo.GetMethodPcInfoIndex()];
138     if (ctx_->FilterMethod(inlinedMethod, methodPcInfo)) {
139         return;
140     }
141     GateRef frameState = GetFrameState(info);
142     GateRef frameArgs = acc_.GetValueIn(frameState);
143     size_t inlineCallCounts = GetOrInitialInlineCounts(frameArgs);
144     if (IsSmallMethod(methodPcInfo.pcOffsets.size()) && !IsInlineCountsOverflow(inlineCallCounts)) {
145         inlineSuccess_ = FilterInlinedMethod(inlinedMethod, methodPcInfo.pcOffsets);
146         if (inlineSuccess_) {
147             SetInitCallTargetAndConstPoolId(info);
148             CircuitRootScope scope(circuit_);
149             if (!noCheck_ && !info.IsCallInit()) {
150                 InlineCheck(info);
151             }
152             InlineCall(methodInfo, methodPcInfo, inlinedMethod, info);
153             UpdateInlineCounts(frameArgs, inlineCallCounts);
154             if (info.IsNormalCall()) {
155                 UpdateWorkList(workList);
156             } else {
157                 lastCallId_ = circuit_->GetGateCount() - 1;
158             }
159         }
160     }
161 
162     if ((inlinedMethod != nullptr) && IsLogEnabled() && inlineSuccess_) {
163         inlineSuccess_ = false;
164         auto jsPandaFile = ctx_->GetJSPandaFile();
165         const std::string methodName(
166             MethodLiteral::GetMethodName(jsPandaFile, inlinedMethod->GetMethodId()));
167         std::string fileName = jsPandaFile->GetFileName();
168         const std::string recordName(MethodLiteral::GetRecordName(jsPandaFile, inlinedMethod->GetMethodId()));
169         std::string fullName = methodName + "@" + recordName + "@" + fileName;
170         LOG_COMPILER(INFO) << "";
171         LOG_COMPILER(INFO) << "\033[34m"
172                            << "===================="
173                            << " After inlining "
174                            << "[" << fullName << "]"
175                            << " Caller method "
176                            << "[" << methodName_ << "]"
177                            << "===================="
178                            << "\033[0m";
179         circuit_->PrintAllGatesWithBytecode();
180         LOG_COMPILER(INFO) << "\033[34m" << "========================= End ==========================" << "\033[0m";
181     }
182 }
183 
FilterInlinedMethod(MethodLiteral * method,std::vector<const uint8_t * > pcOffsets)184 bool TSInlineLowering::FilterInlinedMethod(MethodLiteral* method, std::vector<const uint8_t*> pcOffsets)
185 {
186     const JSPandaFile *jsPandaFile = ctx_->GetJSPandaFile();
187     const panda_file::File *pf = jsPandaFile->GetPandaFile();
188     panda_file::MethodDataAccessor mda(*pf, method->GetMethodId());
189     panda_file::CodeDataAccessor cda(*pf, mda.GetCodeId().value());
190     if (cda.GetTriesSize() != 0) {
191         return false;
192     }
193     for (size_t i = 0; i < pcOffsets.size(); i++) {
194         auto pc = pcOffsets[i];
195         auto ecmaOpcode = ctx_->GetByteCodes()->GetOpcode(pc);
196         switch (ecmaOpcode) {
197             case EcmaOpcode::GETUNMAPPEDARGS:
198             case EcmaOpcode::SUSPENDGENERATOR_V8:
199             case EcmaOpcode::RESUMEGENERATOR:
200             case EcmaOpcode::COPYRESTARGS_IMM8:
201             case EcmaOpcode::WIDE_COPYRESTARGS_PREF_IMM16:
202             case EcmaOpcode::CREATEASYNCGENERATOROBJ_V8:
203                 return false;
204             default:
205                 break;
206         }
207     }
208     return true;
209 }
210 
InlineCall(MethodInfo & methodInfo,MethodPcInfo & methodPCInfo,MethodLiteral * method,InlineTypeInfoAccessor & info)211 void TSInlineLowering::InlineCall(MethodInfo &methodInfo, MethodPcInfo &methodPCInfo, MethodLiteral* method,
212                                   InlineTypeInfoAccessor &info)
213 {
214     const JSPandaFile *jsPandaFile = ctx_->GetJSPandaFile();
215     TSManager *tsManager = ctx_->GetTSManager();
216     CompilerLog *log = ctx_->GetCompilerLog();
217     CString recordName = MethodLiteral::GetRecordName(jsPandaFile, method->GetMethodId());
218     bool hasTyps = jsPandaFile->HasTSTypes(recordName);
219     const std::string methodName(MethodLiteral::GetMethodName(jsPandaFile, method->GetMethodId()));
220     std::string fileName = jsPandaFile->GetFileName();
221     std::string fullName = methodName + "@" + std::string(recordName) + "@" + fileName;
222 
223     circuit_->InitRoot();
224     BytecodeCircuitBuilder builder(jsPandaFile, method, methodPCInfo,
225                                    tsManager, circuit_,
226                                    ctx_->GetByteCodes(), true, IsLogEnabled(),
227                                    enableTypeLowering_, fullName, recordName, ctx_->GetPfDecoder(), true,
228                                    passOptions_->EnableOptTrackField());
229     {
230         if (enableTypeLowering_) {
231             BuildFrameStateChain(info, builder);
232         }
233         TimeScope timeScope("BytecodeToCircuit", methodName, method->GetMethodId().GetOffset(), log);
234         builder.BytecodeToCircuit();
235     }
236 
237     ReplaceInput(info, glue_, method);
238 
239     PassData data(&builder, circuit_, ctx_, log, fullName,
240                   &methodInfo, hasTyps, recordName,
241                   method, method->GetMethodId().GetOffset(), nativeAreaAllocator_, ctx_->GetPfDecoder(), passOptions_);
242     PassRunner<PassData> pipeline(&data);
243     pipeline.RunPass<RedundantPhiEliminationPass>();
244     if (builder.EnableLoopOptimization()) {
245         pipeline.RunPass<LoopOptimizationPass>();
246         pipeline.RunPass<RedundantPhiEliminationPass>();
247     }
248     pipeline.RunPass<TypeInferPass>();
249     pipeline.RunPass<PGOTypeInferPass>();
250 }
251 
CheckParameter(GateRef gate,InlineTypeInfoAccessor & info,MethodLiteral * method)252 bool TSInlineLowering::CheckParameter(GateRef gate, InlineTypeInfoAccessor &info, MethodLiteral* method)
253 {
254     if (method == nullptr) {
255         return false;
256     }
257     if (info.IsCallAccessor()) {
258         return true;
259     }
260     size_t numIns = acc_.GetNumValueIn(gate);
261     size_t fixedInputsNum = info.IsCallThis() ? 2 : 1; // 2: calltarget and this
262 
263     uint32_t declaredNumArgs = method->GetNumArgsWithCallField();
264     return declaredNumArgs == (numIns - fixedInputsNum);
265 }
266 
ReplaceCallInput(InlineTypeInfoAccessor & info,GateRef glue,MethodLiteral * method)267 void TSInlineLowering::ReplaceCallInput(InlineTypeInfoAccessor &info, GateRef glue, MethodLiteral *method)
268 {
269     GateRef gate = info.GetCallGate();
270     bool isCallThis = info.IsCallThis();
271     std::vector<GateRef> vec;
272     size_t numIns = acc_.GetNumValueIn(gate);
273     // 1: last one elem is function
274     GateRef callTarget = acc_.GetValueIn(gate, numIns - 1);
275     GateRef thisObj = Circuit::NullGate();
276     size_t fixedInputsNum = 0;
277     if (isCallThis) {
278         fixedInputsNum = 2; // 2: call target and this
279         thisObj = acc_.GetValueIn(gate, 0);
280     } else {
281         fixedInputsNum = 1; // 1: call target
282         thisObj = builder_.Undefined();
283     }
284     // -1: callTarget
285     size_t actualArgc = numIns + NUM_MANDATORY_JSFUNC_ARGS - fixedInputsNum;
286     vec.emplace_back(glue); // glue
287     if (!method->IsFastCall()) {
288         vec.emplace_back(builder_.Int64(actualArgc)); // argc
289     }
290     vec.emplace_back(callTarget);
291     if (!method->IsFastCall()) {
292         vec.emplace_back(builder_.Undefined()); // newTarget
293     }
294     vec.emplace_back(thisObj);
295     // -1: call Target
296     for (size_t i = fixedInputsNum - 1; i < numIns - 1; i++) {
297         vec.emplace_back(acc_.GetValueIn(gate, i));
298     }
299     LowerToInlineCall(info, vec, method);
300 }
301 
ReplaceAccessorInput(InlineTypeInfoAccessor & info,GateRef glue,MethodLiteral * method)302 void TSInlineLowering::ReplaceAccessorInput(InlineTypeInfoAccessor &info, GateRef glue, MethodLiteral *method)
303 {
304     GateRef gate = info.GetCallGate();
305     std::vector<GateRef> vec;
306     GateRef thisObj = GetAccessorReceiver(gate);
307     GateRef callTarget = Circuit::NullGate();
308     callTarget = BuildAccessor(info);
309     size_t actualArgc = 0;
310     if (info.IsCallGetter()) {
311         actualArgc = NUM_MANDATORY_JSFUNC_ARGS;
312     } else if (info.IsCallSetter()) {
313         actualArgc = NUM_MANDATORY_JSFUNC_ARGS + 1;
314     } else {
315         UNREACHABLE();
316     }
317 
318     vec.emplace_back(glue); // glue
319     if (!method->IsFastCall()) {
320         vec.emplace_back(builder_.Int64(actualArgc)); // argc
321     }
322     vec.emplace_back(callTarget);
323     if (!method->IsFastCall()) {
324         vec.emplace_back(builder_.Undefined()); // newTarget
325     }
326     vec.emplace_back(thisObj);
327 
328     if (info.IsCallSetter()) {
329         vec.emplace_back(GetCallSetterValue(gate));
330     }
331     LowerToInlineCall(info, vec, method);
332 }
333 
BuildAccessor(InlineTypeInfoAccessor & info)334 GateRef TSInlineLowering::BuildAccessor(InlineTypeInfoAccessor &info)
335 {
336     GateRef gate = info.GetCallGate();
337     Environment env(gate, circuit_, &builder_);
338     GateRef receiver = GetAccessorReceiver(gate);
339     GateRef accessor = Circuit::NullGate();
340     uint32_t plrData = info.GetPlr().GetData();
341 
342     const PGORWOpType *pgoTypes = acc_.TryGetPGOType(gate).GetPGORWOpType();
343     ASSERT(pgoTypes->GetCount() == 1);
344     auto pgoType = pgoTypes->GetObjectInfo(0);
345     ProfileTyper holderType = std::make_pair(pgoType.GetHoldRootType(), pgoType.GetHoldType());
346     PGOTypeManager *ptManager = thread_->GetCurrentEcmaContext()->GetPTManager();
347     int holderHCIndex = static_cast<int>(ptManager->GetHClassIndexByProfileType(holderType));
348     ASSERT(ptManager->QueryHClass(holderType.first, holderType.second).IsJSHClass());
349     ArgumentAccessor argAcc(circuit_);
350     GateRef jsFunc = argAcc.GetFrameArgsIn(gate, FrameArgIdx::FUNC);
351 
352     auto currentLabel = env.GetCurrentLabel();
353     auto state = currentLabel->GetControl();
354     auto depend = currentLabel->GetDepend();
355     GateRef holder = circuit_->NewGate(circuit_->LookUpHolder(), MachineType::I64,
356                                        { state, depend, receiver, builder_.Int32(holderHCIndex), jsFunc},
357                                        GateType::AnyType());
358 
359     GateRef frameState = acc_.GetFrameState(gate);
360     // Check whether constpool ids of caller functions and callee functions are consistent. If they are consistent,
361     // the caller function is used in get constpool. It avoids a depend dependence on the accessor function, and thus a
362     // load accessor.
363     // Example:
364     // function A inline Accessor B, if A.constpoolId == B.constpoolId, Use A.GetConstpool to replace B.GetConstpool
365     if (initConstantPoolId_ == GetAccessorConstpoolId(info)) {
366         frameState = initCallTarget_;
367     }
368     if (info.IsCallGetter()) {
369         accessor = circuit_->NewGate(circuit_->LoadGetter(), MachineType::I64,
370                                      { holder, holder, builder_.Int32(plrData), frameState },
371                                      GateType::AnyType());
372     } else {
373         accessor = circuit_->NewGate(circuit_->LoadSetter(), MachineType::I64,
374                                      { holder, holder, builder_.Int32(plrData), frameState },
375                                      GateType::AnyType());
376     }
377     acc_.ReplaceDependIn(gate, holder);
378     acc_.ReplaceStateIn(gate, holder);
379     return accessor;
380 }
381 
ReplaceInput(InlineTypeInfoAccessor & info,GateRef glue,MethodLiteral * method)382 void TSInlineLowering::ReplaceInput(InlineTypeInfoAccessor &info, GateRef glue, MethodLiteral *method)
383 {
384     if (info.IsNormalCall()) {
385         ReplaceCallInput(info, glue, method);
386     } else {
387         ASSERT(info.IsCallAccessor());
388         ReplaceAccessorInput(info, glue, method);
389     }
390 }
391 
MergeAllReturn(const std::vector<GateRef> & returnVector,GateRef & state,GateRef & depend)392 GateRef TSInlineLowering::MergeAllReturn(const std::vector<GateRef> &returnVector, GateRef &state, GateRef &depend)
393 {
394     size_t numOfIns = returnVector.size();
395     auto stateList = std::vector<GateRef>(numOfIns, Circuit::NullGate());
396     auto dependList = std::vector<GateRef>(numOfIns + 1, Circuit::NullGate());
397     auto vaueList = std::vector<GateRef>(numOfIns + 1, Circuit::NullGate());
398 
399     for (size_t i = 0; i < returnVector.size(); i++) {
400         GateRef returnGate = returnVector.at(i);
401         ASSERT(acc_.GetOpCode(acc_.GetState(returnGate)) != OpCode::IF_EXCEPTION);
402         stateList[i] = acc_.GetState(returnGate);
403         dependList[i + 1] = acc_.GetDep(returnGate);
404         vaueList[i + 1] = acc_.GetValueIn(returnGate, 0);
405         acc_.DeleteGate(returnGate);
406     }
407 
408     state = circuit_->NewGate(circuit_->Merge(numOfIns), stateList);
409     dependList[0] = state;
410     vaueList[0] = state;
411     depend = circuit_->NewGate(circuit_->DependSelector(numOfIns), dependList);
412     return circuit_->NewGate(circuit_->ValueSelector(numOfIns), MachineType::I64, numOfIns + 1,
413                              vaueList.data(), GateType::AnyType());
414 }
415 
ReplaceEntryGate(GateRef callGate,GateRef callerFunc,GateRef inlineFunc,GateRef glue)416 void TSInlineLowering::ReplaceEntryGate(GateRef callGate, GateRef callerFunc, GateRef inlineFunc, GateRef glue)
417 {
418     auto stateEntry = acc_.GetStateRoot();
419     auto dependEntry = acc_.GetDependRoot();
420 
421     GateRef callState = acc_.GetState(callGate);
422     GateRef callDepend = acc_.GetDep(callGate);
423     auto stateUse = acc_.Uses(stateEntry);
424 
425     // support inline trace
426     GateRef newDep = Circuit::NullGate();
427     if (traceInline_) {
428         std::vector<GateRef> args{callerFunc, inlineFunc};
429         newDep = TraceInlineFunction(glue, callDepend, args, callGate);
430     } else {
431         newDep = callDepend;
432     }
433 
434     for (auto stateUseIt = stateUse.begin(); stateUseIt != stateUse.end();) {
435         stateUseIt = acc_.ReplaceIn(stateUseIt, callState);
436     }
437 
438     auto dependUse = acc_.Uses(dependEntry);
439     for (auto dependUseIt = dependUse.begin(); dependUseIt != dependUse.end();) {
440         dependUseIt = acc_.ReplaceIn(dependUseIt, newDep);
441     }
442 }
443 
TraceInlineFunction(GateRef glue,GateRef depend,std::vector<GateRef> & args,GateRef callGate)444 GateRef TSInlineLowering::TraceInlineFunction(GateRef glue, GateRef depend, std::vector<GateRef> &args,
445                                               GateRef callGate)
446 {
447     size_t index = RTSTUB_ID(AotInlineTrace);
448     GateRef result = builder_.NoLabelCallRuntime(glue, depend, index, args, callGate);
449     return result;
450 }
451 
ReplaceReturnGate(GateRef callGate)452 void TSInlineLowering::ReplaceReturnGate(GateRef callGate)
453 {
454     std::vector<GateRef> returnVector;
455     acc_.GetReturnOuts(returnVector);
456 
457     GateRef value = Circuit::NullGate();
458     GateRef state = Circuit::NullGate();
459     GateRef depend = Circuit::NullGate();
460 
461     if (returnVector.size() == 1) {
462         GateRef returnGate = returnVector.at(0);
463         GateRef returnState = acc_.GetState(returnGate);
464         depend = acc_.GetDep(returnGate);
465         state = returnState;
466         value = acc_.GetValueIn(returnGate, 0);
467         acc_.DeleteGate(returnGate);
468     } else {
469         value = MergeAllReturn(returnVector, state, depend);
470     }
471     SupplementType(callGate, value);
472     ReplaceHirAndDeleteState(callGate, state, depend, value);
473 }
474 
ReplaceHirAndDeleteState(GateRef gate,GateRef state,GateRef depend,GateRef value)475 void TSInlineLowering::ReplaceHirAndDeleteState(GateRef gate, GateRef state, GateRef depend, GateRef value)
476 {
477     auto uses = acc_.Uses(gate);
478     for (auto useIt = uses.begin(); useIt != uses.end();) {
479         if (acc_.IsStateIn(useIt)) {
480             useIt = acc_.ReplaceIn(useIt, state);
481         } else if (acc_.IsDependIn(useIt)) {
482             useIt = acc_.ReplaceIn(useIt, depend);
483         } else if (acc_.IsValueIn(useIt)) {
484             useIt = acc_.ReplaceIn(useIt, value);
485         } else {
486             LOG_ECMA(FATAL) << "this branch is unreachable";
487             UNREACHABLE();
488         }
489     }
490     acc_.DeleteGate(gate);
491 }
492 
LowerToInlineCall(InlineTypeInfoAccessor & info,const std::vector<GateRef> & args,MethodLiteral * method)493 void TSInlineLowering::LowerToInlineCall(
494     InlineTypeInfoAccessor &info, const std::vector<GateRef> &args, MethodLiteral *method)
495 {
496     GateRef callGate = info.GetCallGate();
497     // replace in value/args
498     ArgumentAccessor argAcc(circuit_);
499     ASSERT(argAcc.ArgsCount() == args.size());
500     for (size_t i = 0; i < argAcc.ArgsCount(); i++) {
501         GateRef arg = argAcc.ArgsAt(i);
502         acc_.UpdateAllUses(arg, args.at(i));
503         if (acc_.GetGateType(args.at(i)).IsAnyType()) {
504             acc_.SetGateType(args.at(i), acc_.GetGateType(arg));
505         }
506         acc_.DeleteGate(arg);
507     }
508     // replace in depend and state
509     GateRef glue = args.at(static_cast<size_t>(CommonArgIdx::GLUE));
510     GateRef inlineFunc;
511     if (method->IsFastCall()) {
512         inlineFunc = args.at(static_cast<size_t>(FastCallArgIdx::FUNC));
513     } else {
514         inlineFunc = args.at(static_cast<size_t>(CommonArgIdx::FUNC));
515     }
516     GateRef frameArgs = GetFrameArgs(info);
517     GateRef callerFunc = acc_.GetValueIn(frameArgs, 0);
518     ReplaceEntryGate(callGate, callerFunc, inlineFunc, glue);
519     // replace use gate
520     ReplaceReturnGate(callGate);
521     // remove Useless root gates
522     RemoveRoot();
523 }
524 
InlineFuncCheck(const InlineTypeInfoAccessor & info)525 void TSInlineLowering::InlineFuncCheck(const InlineTypeInfoAccessor &info)
526 {
527     GateRef gate = info.GetCallGate();
528     GateRef callState = acc_.GetState(gate);
529     GateRef callDepend = acc_.GetDep(gate);
530     ASSERT(acc_.HasFrameState(gate));
531     GateRef frameState = acc_.GetFrameState(gate);
532     size_t funcIndex = acc_.GetNumValueIn(gate) - 1;
533     GateRef inlineFunc =  acc_.GetValueIn(gate, funcIndex);
534     // Do not load from inlineFunc beacause type in inlineFunc could be modified by others
535     uint32_t methodOffset = info.GetCallMethodId();
536     GateRef ret = circuit_->NewGate(circuit_->JSInlineTargetTypeCheck(info.GetType()),
537         MachineType::I1, {callState, callDepend, inlineFunc, builder_.IntPtr(methodOffset), frameState},
538         GateType::NJSValue());
539     acc_.ReplaceStateIn(gate, ret);
540     acc_.ReplaceDependIn(gate, ret);
541 }
542 
InlineAccessorCheck(const InlineTypeInfoAccessor & info)543 void TSInlineLowering::InlineAccessorCheck(const InlineTypeInfoAccessor &info)
544 {
545     ASSERT(info.IsCallAccessor());
546     GateRef gate = info.GetCallGate();
547     GateRef receiver = GetAccessorReceiver(gate);
548     Environment env(gate, circuit_, &builder_);
549 
550     const PGORWOpType *pgoTypes = acc_.TryGetPGOType(gate).GetPGORWOpType();
551     ASSERT(pgoTypes->GetCount() == 1);
552     auto pgoType = pgoTypes->GetObjectInfo(0);
553     ProfileTyper receiverType = std::make_pair(pgoType.GetReceiverRootType(), pgoType.GetReceiverType());
554     PGOTypeManager *ptManager = thread_->GetCurrentEcmaContext()->GetPTManager();
555     int receiverHCIndex = static_cast<int>(ptManager->GetHClassIndexByProfileType(receiverType));
556     ASSERT(ptManager->QueryHClass(receiverType.first, receiverType.second).IsJSHClass());
557 
558     bool noNeedCheckHeapObject = acc_.IsHeapObjectFromElementsKind(receiver);
559     builder_.ObjectTypeCheck(acc_.GetGateType(gate), noNeedCheckHeapObject, receiver, builder_.Int32(receiverHCIndex),
560                              acc_.GetFrameState(gate));
561     auto currentLabel = env.GetCurrentLabel();
562     auto callState = currentLabel->GetControl();
563     auto callDepend = currentLabel->GetDepend();
564     auto frameState = acc_.GetFrameState(gate);
565     ArgumentAccessor argAcc(circuit_);
566     GateRef jsFunc = argAcc.GetFrameArgsIn(gate, FrameArgIdx::FUNC);
567     GateRef ret = circuit_->NewGate(circuit_->PrototypeCheck(receiverHCIndex), MachineType::I1,
568         {callState, callDepend, jsFunc, frameState}, GateType::NJSValue());
569     acc_.ReplaceStateIn(gate, ret);
570     acc_.ReplaceDependIn(gate, ret);
571 }
572 
InlineCheck(InlineTypeInfoAccessor & info)573 void TSInlineLowering::InlineCheck(InlineTypeInfoAccessor &info)
574 {
575     if (info.IsNormalCall()) {
576         InlineFuncCheck(info);
577     } else {
578         InlineAccessorCheck(info);
579     }
580 }
581 
RemoveRoot()582 void TSInlineLowering::RemoveRoot()
583 {
584     GateRef circuitRoot = acc_.GetCircuitRoot();
585     auto uses = acc_.Uses(circuitRoot);
586     for (auto it = uses.begin(); it != uses.end();) {
587         it = acc_.DeleteGate(it);
588     }
589 
590     acc_.DeleteGate(circuitRoot);
591 }
592 
BuildFrameStateChain(InlineTypeInfoAccessor & info,BytecodeCircuitBuilder & builder)593 void TSInlineLowering::BuildFrameStateChain(InlineTypeInfoAccessor &info, BytecodeCircuitBuilder &builder)
594 {
595     GateRef preFrameState = GetFrameState(info);
596     ASSERT(acc_.GetOpCode(preFrameState) == OpCode::FRAME_STATE);
597     builder.SetPreFrameState(preFrameState);
598     GateRef frameArgs = acc_.GetFrameArgs(preFrameState);
599     builder.SetPreFrameArgs(frameArgs);
600 }
601 
FilterCallInTryCatch(GateRef gate)602 bool TSInlineLowering::FilterCallInTryCatch(GateRef gate)
603 {
604     auto uses = acc_.Uses(gate);
605     for (auto it = uses.begin(); it != uses.end(); ++it) {
606         if (acc_.GetOpCode(*it) == OpCode::IF_SUCCESS || acc_.GetOpCode(*it) == OpCode::IF_EXCEPTION) {
607             return true;
608         }
609     }
610     return false;
611 }
612 
SupplementType(GateRef callGate,GateRef targetGate)613 void TSInlineLowering::SupplementType(GateRef callGate, GateRef targetGate)
614 {
615     GateType callGateType = acc_.GetGateType(callGate);
616     GateType targetGateType = acc_.GetGateType(targetGate);
617     if (!callGateType.IsAnyType() && targetGateType.IsAnyType()) {
618         acc_.SetGateType(targetGate, callGateType);
619     }
620 }
621 
UpdateWorkList(ChunkQueue<InlineTypeInfoAccessor> & workList)622 void TSInlineLowering::UpdateWorkList(ChunkQueue<InlineTypeInfoAccessor> &workList)
623 {
624     std::vector<GateRef> gateList;
625     circuit_->GetAllGates(gateList);
626     for (const auto &gate : gateList) {
627         if (acc_.GetId(gate) <= lastCallId_) {
628             continue;
629         }
630         auto op = acc_.GetOpCode(gate);
631         if (op == OpCode::JS_BYTECODE) {
632             CandidateInlineCall(gate, workList);
633         }
634     }
635 }
636 
GetOrInitialInlineCounts(GateRef frameArgs)637 size_t TSInlineLowering::GetOrInitialInlineCounts(GateRef frameArgs)
638 {
639     auto it = inlinedCallMap_.find(frameArgs);
640     if (it == inlinedCallMap_.end()) {
641         inlinedCallMap_[frameArgs] = 0;
642     }
643     return inlinedCallMap_[frameArgs];
644 }
645 
IsRecursiveFunc(InlineTypeInfoAccessor & info,size_t calleeMethodOffset)646 bool TSInlineLowering::IsRecursiveFunc(InlineTypeInfoAccessor &info, size_t calleeMethodOffset)
647 {
648     GateRef caller = info.GetCallGate();
649     GateRef frameArgs = GetFrameArgs(info);
650     while (acc_.GetOpCode(caller) == OpCode::JS_BYTECODE) {
651         auto callerMethodOffset = acc_.TryGetMethodOffset(caller);
652         if (callerMethodOffset == calleeMethodOffset) {
653             return true;
654         }
655         frameArgs = acc_.GetFrameArgs(frameArgs);
656         if (frameArgs == Circuit::NullGate()) {
657             break;
658         }
659         caller = acc_.GetValueIn(frameArgs);
660     }
661     return false;
662 }
663 
CandidateAccessor(GateRef gate,ChunkQueue<InlineTypeInfoAccessor> & workList,CallKind kind)664 void TSInlineLowering::CandidateAccessor(GateRef gate, ChunkQueue<InlineTypeInfoAccessor> &workList, CallKind kind)
665 {
666     GateRef receiver = GetAccessorReceiver(gate);
667     InlineTypeInfoAccessor tacc(thread_, circuit_, gate, receiver, kind);
668     if (tacc.IsEnableAccessorInline()) {
669         workList.emplace(thread_, circuit_, gate, receiver, kind);
670         lastCallId_ = acc_.GetId(gate);
671     }
672 }
673 
CandidateNormalCall(GateRef gate,ChunkQueue<InlineTypeInfoAccessor> & workList,CallKind kind)674 void TSInlineLowering::CandidateNormalCall(GateRef gate, ChunkQueue<InlineTypeInfoAccessor> &workList, CallKind kind)
675 {
676     size_t funcIndex = acc_.GetNumValueIn(gate) - 1;
677     auto func = acc_.GetValueIn(gate, funcIndex);
678     InlineTypeInfoAccessor tacc(thread_, 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         const JSPandaFile *pf = ctx_->GetJSPandaFile();
724         initConstantPoolId_ = tsManager_->GetConstantPoolIDByMethodOffset(pf, initMethodOffset_);
725     }
726 }
727 
GetAccessorConstpoolId(InlineTypeInfoAccessor & info)728 int32_t TSInlineLowering::GetAccessorConstpoolId(InlineTypeInfoAccessor &info)
729 {
730     ASSERT(info.IsCallAccessor());
731     uint32_t inlineMethodOffset = info.GetCallMethodId();
732     const JSPandaFile *pf = ctx_->GetJSPandaFile();
733     return tsManager_->GetConstantPoolIDByMethodOffset(pf, inlineMethodOffset);
734 }
735 }  // namespace panda::ecmascript
736