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