• 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 #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/builtins/builtins_call_signature.h"
21 #include "ecmascript/compiler/bytecode_circuit_builder.h"
22 #include "ecmascript/compiler/bytecode_info_collector.h"
23 #include "ecmascript/compiler/circuit_builder-inl.h"
24 #include "ecmascript/compiler/pass_manager.h"
25 #include "ecmascript/jspandafile/js_pandafile.h"
26 
27 namespace panda::ecmascript::kungfu {
28 enum CallKind : uint8_t {
29     CALL,
30     CALL_THIS,
31     CALL_SETTER,
32     CALL_GETTER,
33     INVALID
34 };
35 class CircuitRootScope {
36 public:
CircuitRootScope(Circuit * circuit)37     explicit CircuitRootScope(Circuit *circuit)
38         : circuit_(circuit), root_(circuit->GetRoot())
39     {
40     }
41 
~CircuitRootScope()42     ~CircuitRootScope()
43     {
44         circuit_->SetRoot(root_);
45     }
46 
47 private:
48     Circuit *circuit_ {nullptr};
49     GateRef root_ { 0 };
50 };
51 
52 class CallGateInfo {
53 public:
CallGateInfo(GateRef call,CallKind kind,GlobalTSTypeRef gt,uint32_t type)54     explicit CallGateInfo(GateRef call, CallKind kind, GlobalTSTypeRef gt, uint32_t type)
55         : call_(call), kind_(kind), gt_(gt), type_(type)
56     {
57     }
58 
59     ~CallGateInfo() = default;
60 
GetCallGate()61     GateRef GetCallGate() const
62     {
63         return call_;
64     }
65 
IsCallThis()66     bool IsCallThis() const
67     {
68         return kind_ == CallKind::CALL_THIS;
69     }
70 
IsNormalCall()71     bool IsNormalCall() const
72     {
73         return kind_ == CallKind::CALL || kind_ == CallKind::CALL_THIS;
74     }
75 
IsCallAccessor()76     bool IsCallAccessor() const
77     {
78         return kind_ == CallKind::CALL_SETTER || kind_ == CallKind::CALL_GETTER;
79     }
80 
IsCallGetter()81     bool IsCallGetter() const
82     {
83         return kind_ == CallKind::CALL_GETTER;
84     }
85 
IsCallSetter()86     bool IsCallSetter() const
87     {
88         return kind_ == CallKind::CALL_SETTER;
89     }
90 
GetFuncGT()91     GlobalTSTypeRef GetFuncGT() const
92     {
93         return gt_;
94     }
95 
GetType()96     uint32_t GetType() const
97     {
98         return type_;
99     }
100 
101 private:
102     GateRef call_ {Circuit::NullGate()};
103     CallKind kind_ {CallKind::INVALID};
104     GlobalTSTypeRef gt_;
105     uint32_t type_;
106 };
107 
108 class TSInlineLowering {
109 public:
110     static constexpr size_t MAX_INLINE_CALL_ALLOWED = 5;
TSInlineLowering(Circuit * circuit,PassContext * ctx,bool enableLog,const std::string & name,NativeAreaAllocator * nativeAreaAllocator,PassOptions * options,uint32_t methodOffset)111     TSInlineLowering(Circuit *circuit, PassContext *ctx, bool enableLog, const std::string& name,
112                      NativeAreaAllocator* nativeAreaAllocator, PassOptions *options, uint32_t methodOffset)
113         : circuit_(circuit),
114           acc_(circuit),
115           builder_(circuit, ctx->GetCompilerConfig()),
116           tsManager_(ctx->GetTSManager()),
117           ctx_(ctx),
118           passOptions_(options),
119           enableLog_(enableLog),
120           methodName_(name),
121           enableTypeLowering_(ctx->GetEcmaVM()->GetJSOptions().IsEnableTypeLowering()),
122           traceInline_(ctx->GetEcmaVM()->GetJSOptions().GetTraceInline()),
123           maxInlineBytecodesCount_(ctx->GetEcmaVM()->GetJSOptions().GetMaxInlineBytecodes()),
124           nativeAreaAllocator_(nativeAreaAllocator),
125           noCheck_(ctx->GetEcmaVM()->GetJSOptions().IsCompilerNoCheck()),
126           chunk_(circuit->chunk()),
127           inlinedCallMap_(circuit->chunk()),
128           argAcc_(circuit),
129           initMethodOffset_(methodOffset) {}
130 
131     ~TSInlineLowering() = default;
132 
133     void RunTSInlineLowering();
134 
135 private:
IsLogEnabled()136     bool IsLogEnabled() const
137     {
138         return enableLog_;
139     }
140 
GetMethodName()141     const std::string& GetMethodName() const
142     {
143         return methodName_;
144     }
145 
IsSmallMethod(size_t bcSize)146     bool IsSmallMethod(size_t bcSize) const
147     {
148         return bcSize <= maxInlineBytecodesCount_;
149     }
150 
IsInlineCountsOverflow(size_t inlineCount)151     bool IsInlineCountsOverflow(size_t inlineCount) const
152     {
153         return inlineCount >= MAX_INLINE_CALL_ALLOWED;
154     }
155 
UpdateInlineCounts(GateRef frameArgs,size_t inlineCallCounts)156     void UpdateInlineCounts(GateRef frameArgs, size_t inlineCallCounts)
157     {
158         inlinedCallMap_[frameArgs] = ++inlineCallCounts;
159     }
160 
EnableFastAccessor()161     bool EnableFastAccessor() const
162     {
163         return isFastAccessor_ && !traceInline_;
164     }
165 
166     void CandidateInlineCall(GateRef gate, ChunkQueue<CallGateInfo> &workList);
167     void TryInline(CallGateInfo &info, ChunkQueue<CallGateInfo> &workList);
168     bool FilterInlinedMethod(MethodLiteral* method, std::vector<const uint8_t*> pcOffsets);
169     bool FilterCallInTryCatch(GateRef gate);
170     void InlineCall(MethodInfo &methodInfo, MethodPcInfo &methodPCInfo, MethodLiteral* method, CallGateInfo &info);
171     void ReplaceCallInput(CallGateInfo &info, GateRef glue, MethodLiteral *method);
172     void ReplaceEntryGate(GateRef callGate, GateRef callerFunc, GateRef inlineFunc, GateRef glue);
173     void ReplaceReturnGate(GateRef callGate);
174     void ReplaceHirAndDeleteState(GateRef gate, GateRef state, GateRef depend, GateRef value);
175     GateRef MergeAllReturn(const std::vector<GateRef> &returnVector, GateRef &state, GateRef &depend);
176     bool CheckParameter(GateRef gate, CallGateInfo &info, MethodLiteral* method);
177     void LowerToInlineCall(CallGateInfo &info, const std::vector<GateRef> &args, MethodLiteral* method);
178     void RemoveRoot();
179     void BuildFrameStateChain(CallGateInfo &info, BytecodeCircuitBuilder &builder);
180     GateRef TraceInlineFunction(GateRef glue, GateRef depend, std::vector<GateRef> &args, GateRef callGate);
181     void InlineFuncCheck(const CallGateInfo &info);
182     void SupplementType(GateRef callGate, GateRef targetGate);
183     void UpdateWorkList(ChunkQueue<CallGateInfo> &workList);
184     size_t GetOrInitialInlineCounts(GateRef frameArgs);
185     bool IsRecursiveFunc(CallGateInfo &info, size_t calleeMethodOffset);
186     bool IsAccessor(GateRef receiver, GateRef constData);
187     GlobalTSTypeRef GetAccessorFuncType(GateRef receiver, GateRef constData);
188     void CandidateAccessor(GateRef gate, ChunkQueue<CallGateInfo> &workList, CallKind kind);
189     void CandidateNormalCall(GateRef gate, ChunkQueue<CallGateInfo> &workList, CallKind kind);
190     void InlineAccessorCheck(GateRef gate, GateRef receiver);
191     void InlineCheck(CallGateInfo &info);
192     GateRef GetAccessorReceiver(GateRef gate);
193     GateRef GetFrameArgs(CallGateInfo &info);
194     void ReplaceAccessorInput(CallGateInfo &info, GateRef glue, MethodLiteral *method);
195     void ReplaceInput(CallGateInfo &info, GateRef glue, MethodLiteral *method);
196     GateRef BuildAccessor(CallGateInfo &info);
197     uint32_t GetPlrData(GateRef receiver, GateRef constData);
198     GateRef GetCallSetterValue(GateRef gate);
199     GlobalTSTypeRef GetAccessorFuncGT(GateRef receiver, GateRef constData);
200     GateRef GetFrameState(CallGateInfo &info);
201     void SetInitCallTargetAndConstPoolId(CallGateInfo &info);
202     void AnalyseFastAccessor(CallGateInfo &info, std::vector<const uint8_t*> pcOffsets, uint32_t inlineMethodOffset);
203 
204     Circuit *circuit_ {nullptr};
205     GateAccessor acc_;
206     CircuitBuilder builder_;
207     TSManager *tsManager_ {nullptr};
208     PassContext *ctx_ {nullptr};
209     PassOptions *passOptions_ {nullptr};
210     bool enableLog_ {false};
211     std::string methodName_;
212     bool enableTypeLowering_ {false};
213     bool inlineSuccess_ {false};
214     bool traceInline_ {false};
215     size_t maxInlineBytecodesCount_ {0};
216     NativeAreaAllocator *nativeAreaAllocator_ {nullptr};
217     bool noCheck_ {false};
218     Chunk* chunk_ {nullptr};
219     ChunkMap<GateRef, size_t> inlinedCallMap_;
220     size_t lastCallId_ {0};
221     ArgumentAccessor argAcc_;
222     uint32_t initMethodOffset_ {0};
223     int32_t initConstantPoolId_ {0};
224     GateRef initCallTarget_ {Circuit::NullGate()};
225     bool isFastAccessor_ {false};
226 };
227 }  // panda::ecmascript::kungfu
228 #endif  // ECMASCRIPT_COMPILER_TS_INLINE_LOWERING_H
229