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