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
25namespace panda::ecmascript::kungfu {
26class CircuitRootScope {
27public:
28    explicit CircuitRootScope(Circuit *circuit)
29        : circuit_(circuit), root_(circuit->GetRoot())
30    {
31    }
32
33    ~CircuitRootScope()
34    {
35        circuit_->SetRoot(root_);
36    }
37
38private:
39    Circuit *circuit_ {nullptr};
40    GateRef root_ { 0 };
41};
42
43class TSInlineLowering {
44public:
45    static constexpr size_t MAX_INLINE_CALL_ALLOWED = 6;
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
74private:
75    bool IsLogEnabled() const
76    {
77        return enableLog_;
78    }
79
80    const std::string& GetMethodName() const
81    {
82        return methodName_;
83    }
84
85    bool IsSmallMethod(size_t bcSize) const
86    {
87        return bcSize <= maxInlineBytecodesCount_;
88    }
89
90    bool IsInlineCountsOverflow(size_t inlineCount) const
91    {
92        return inlineCount >= MAX_INLINE_CALL_ALLOWED;
93    }
94
95    void UpdateInlineCounts(GateRef frameArgs, size_t inlineCallCounts)
96    {
97        inlinedCallMap_[frameArgs] = ++inlineCallCounts;
98    }
99
100    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