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 #ifndef ECMASCRIPT_COMPILER_TS_INLINE_LOWERING_H
17 #define ECMASCRIPT_COMPILER_TS_INLINE_LOWERING_H
18 
19 #include "ecmascript/compiler/argument_accessor.h"
20 #include "ecmascript/compiler/bytecode_circuit_builder.h"
21 #include "ecmascript/compiler/bytecode_info_collector.h"
22 #include "ecmascript/compiler/pass_manager.h"
23 #include "ecmascript/compiler/type_info_accessors.h"
24 
25 namespace panda::ecmascript::kungfu {
26 class CircuitRootScope {
27 public:
CircuitRootScope(Circuit *circuit)28     explicit CircuitRootScope(Circuit *circuit)
29         : circuit_(circuit), root_(circuit->GetRoot())
30     {
31     }
32 
~CircuitRootScope()33     ~CircuitRootScope()
34     {
35         circuit_->SetRoot(root_);
36     }
37 
38 private:
39     Circuit *circuit_ {nullptr};
40     GateRef root_ { 0 };
41 };
42 
43 class TSInlineLowering {
44 public:
45     static constexpr size_t MAX_INLINE_CALL_ALLOWED = 6;
TSInlineLowering(Circuit *circuit, PassContext *ctx, bool enableLog, const std::string &name, NativeAreaAllocator *nativeAreaAllocator, PassOptions *options, uint32_t methodOffset, CallMethodFlagMap *callMethodFlagMap)46     TSInlineLowering(Circuit *circuit, PassContext *ctx, bool enableLog, const std::string &name,
47                      NativeAreaAllocator *nativeAreaAllocator, PassOptions *options, uint32_t methodOffset,
48                      CallMethodFlagMap *callMethodFlagMap)
49         : circuit_(circuit),
50           compilationEnv_(ctx->GetCompilationEnv()),
51           acc_(circuit),
52           glue_(acc_.GetGlueFromArgList()),
53           builder_(circuit, ctx->GetCompilerConfig()),
54           ptManager_(ctx->GetPTManager()),
55           ctx_(ctx),
56           passOptions_(options),
57           enableLog_(enableLog),
58           methodName_(name),
59           enableTypeLowering_(ctx->GetCompilationEnv()->GetJSOptions().IsEnableTypeLowering()),
60           traceInline_(ctx->GetCompilationEnv()->GetJSOptions().GetTraceInline()),
61           maxInlineBytecodesCount_(ctx->GetCompilationEnv()->GetJSOptions().GetMaxInlineBytecodes()),
62           nativeAreaAllocator_(nativeAreaAllocator),
63           noCheck_(ctx->GetCompilationEnv()->GetJSOptions().IsCompilerNoCheck()),
64           chunk_(circuit->chunk()),
65           inlinedCallMap_(circuit->chunk()),
66           argAcc_(circuit),
67           initMethodOffset_(methodOffset),
68           callMethodFlagMap_(callMethodFlagMap) {}
69 
70     ~TSInlineLowering() = default;
71 
72     void RunTSInlineLowering();
73 
74 private:
IsLogEnabled() const75     bool IsLogEnabled() const
76     {
77         return enableLog_;
78     }
79 
GetMethodName() const80     const std::string& GetMethodName() const
81     {
82         return methodName_;
83     }
84 
IsSmallMethod(size_t bcSize) const85     bool IsSmallMethod(size_t bcSize) const
86     {
87         return bcSize <= maxInlineBytecodesCount_;
88     }
89 
IsInlineCountsOverflow(size_t inlineCount) const90     bool IsInlineCountsOverflow(size_t inlineCount) const
91     {
92         return inlineCount >= MAX_INLINE_CALL_ALLOWED;
93     }
94 
UpdateInlineCounts(GateRef frameArgs, size_t inlineCallCounts)95     void UpdateInlineCounts(GateRef frameArgs, size_t inlineCallCounts)
96     {
97         inlinedCallMap_[frameArgs] = ++inlineCallCounts;
98     }
99 
IsCallSetter(CallKind kind) const100     bool IsCallSetter(CallKind kind) const
101     {
102         return kind == CallKind::CALL_SETTER;
103     }
104 
105     void CollectInlineInfo();
106     void GetInlinedMethodId(GateRef gate);
107     void CandidateInlineCall(GateRef gate, ChunkQueue<InlineTypeInfoAccessor> &workList);
108     void TryInline(InlineTypeInfoAccessor &info, ChunkQueue<InlineTypeInfoAccessor> &workList);
109     bool FilterInlinedMethod(MethodLiteral* method, std::vector<const uint8_t*> pcOffsets);
110     bool FilterCallInTryCatch(GateRef gate);
111     void InlineCall(
112         MethodInfo &methodInfo, MethodPcInfo &methodPCInfo, MethodLiteral *method, InlineTypeInfoAccessor &info);
113     void ReplaceCallInput(InlineTypeInfoAccessor &info, GateRef glue, MethodLiteral *method);
114     void ReplaceEntryGate(GateRef callGate, GateRef callerFunc, GateRef inlineFunc, GateRef glue);
115     void ReplaceReturnGate(GateRef callGate);
116     void ReplaceHirAndDeleteState(GateRef gate, GateRef state, GateRef depend, GateRef value);
117     GateRef MergeAllReturn(const std::vector<GateRef> &returnVector, GateRef &state, GateRef &depend);
118     bool CheckParameter(GateRef gate, InlineTypeInfoAccessor &info, MethodLiteral* method);
119     void LowerToInlineCall(InlineTypeInfoAccessor &info, const std::vector<GateRef> &args, MethodLiteral* method);
120     void RemoveRoot();
121     void BuildFrameStateChain(InlineTypeInfoAccessor &info, BytecodeCircuitBuilder &builder);
122     GateRef TraceInlineFunction(GateRef glue, GateRef depend, std::vector<GateRef> &args, GateRef callGate);
123     void InlineFuncCheck(const InlineTypeInfoAccessor &info);
124     void SupplementType(GateRef callGate, GateRef targetGate);
125     void UpdateWorkList(ChunkQueue<InlineTypeInfoAccessor> &workList);
126     size_t GetOrInitialInlineCounts(GateRef frameArgs);
127     bool IsRecursiveFunc(InlineTypeInfoAccessor &info, size_t calleeMethodOffset);
128     void CandidateAccessor(GateRef gate, ChunkQueue<InlineTypeInfoAccessor> &workList, CallKind kind);
129     void CandidateNormalCall(GateRef gate, ChunkQueue<InlineTypeInfoAccessor> &workList, CallKind kind);
130     void InlineAccessorCheck(const InlineTypeInfoAccessor &info);
131     void InlineAccessorCheckInJIT(const InlineTypeInfoAccessor &info);
132     void InlineCheck(InlineTypeInfoAccessor &info);
133     GateRef GetAccessorReceiver(GateRef gate);
134     GateRef GetFrameArgs(InlineTypeInfoAccessor &info);
135     void ReplaceAccessorInput(InlineTypeInfoAccessor &info, GateRef glue, MethodLiteral *method);
136     void ReplaceInput(InlineTypeInfoAccessor &info, GateRef glue, MethodLiteral *method);
137     GateRef BuildAccessor(InlineTypeInfoAccessor &info);
138     GateRef GetCallSetterValue(GateRef gate);
139     GateRef GetFrameState(InlineTypeInfoAccessor &info);
140     void SetInitCallTargetAndConstPoolId(InlineTypeInfoAccessor &info);
141     uint32_t GetAccessorConstpoolId(InlineTypeInfoAccessor &info);
142     bool CalleePFIProcess(uint32_t methodOffset);
143     void UpdateCallMethodFlagMap(uint32_t methodOffset, const MethodLiteral *method);
144 
145     Circuit *circuit_ {nullptr};
146     CompilationEnv *compilationEnv_ {nullptr};
147     GateAccessor acc_;
148     GateRef glue_;
149     CircuitBuilder builder_;
150     PGOTypeManager *ptManager_ {nullptr};
151     PassContext *ctx_ {nullptr};
152     PassOptions *passOptions_ {nullptr};
153     bool enableLog_ {false};
154     std::string methodName_;
155     bool enableTypeLowering_ {false};
156     bool inlineSuccess_ {false};
157     bool traceInline_ {false};
158     size_t maxInlineBytecodesCount_ {0};
159     NativeAreaAllocator *nativeAreaAllocator_ {nullptr};
160     bool noCheck_ {false};
161     Chunk* chunk_ {nullptr};
162     ChunkMap<GateRef, size_t> inlinedCallMap_;
163     size_t lastCallId_ {0};
164     ArgumentAccessor argAcc_;
165     uint32_t initMethodOffset_ {0};
166     uint32_t initConstantPoolId_ {0};
167     GateRef initCallTarget_ {Circuit::NullGate()};
168     CallMethodFlagMap *callMethodFlagMap_;
169 };
170 }  // panda::ecmascript::kungfu
171 #endif  // ECMASCRIPT_COMPILER_TS_INLINE_LOWERING_H
172