1/*
2 * Copyright (c) 2021 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_GATE_H
17#define ECMASCRIPT_COMPILER_GATE_H
18
19#include <array>
20#include <iostream>
21#include <map>
22#include <optional>
23#include <set>
24#include <sstream>
25#include <string>
26#include <type_traits>
27#include <vector>
28
29#include "ecmascript/compiler/share_gate_meta_data.h"
30#include "ecmascript/compiler/hcr_gate_meta_data.h"
31#include "ecmascript/compiler/mcr_gate_meta_data.h"
32#include "ecmascript/compiler/lcr_gate_meta_data.h"
33#include "ecmascript/compiler/type.h"
34
35#include "libpandabase/macros.h"
36
37namespace panda::ecmascript::kungfu {
38using BitField = uint64_t;
39using GateRef = int32_t; // for external users
40using GateId = uint32_t;
41using GateOp = uint8_t;
42using GateMark = uint8_t;
43using TimeStamp = uint8_t;
44using SecondaryOp = uint8_t;
45using OutIdx = uint32_t;
46class Gate;
47class BytecodeCircuitBuilder;
48
49enum MarkCode : GateMark {
50    NO_MARK = 0,
51    PREVISIT,
52    VISITED,
53    FINISHED,
54};
55
56class Out {
57public:
58    Out() = default;
59    void SetNextOut(const Out *ptr);
60    [[nodiscard]] Out *GetNextOut();
61    [[nodiscard]] const Out *GetNextOutConst() const;
62    void SetPrevOut(const Out *ptr);
63    [[nodiscard]] Out *GetPrevOut();
64    [[nodiscard]] const Out *GetPrevOutConst() const;
65    void SetIndex(OutIdx idx);
66    [[nodiscard]] OutIdx GetIndex() const;
67    [[nodiscard]] Gate *GetGate();
68    [[nodiscard]] const Gate *GetGateConst() const;
69    void SetPrevOutNull();
70    [[nodiscard]] bool IsPrevOutNull() const;
71    void SetNextOutNull();
72    [[nodiscard]] bool IsNextOutNull() const;
73    [[nodiscard]] bool IsStateEdge() const;
74    ~Out() = default;
75
76private:
77    GateRef nextOut_;
78    GateRef prevOut_;
79    OutIdx idx_;
80};
81
82class In {
83public:
84    In() = default;
85    void SetGate(const Gate *ptr);
86    [[nodiscard]] Gate *GetGate();
87    [[nodiscard]] const Gate *GetGateConst() const;
88    void SetGateNull();
89    [[nodiscard]] bool IsGateNull() const;
90    ~In() = default;
91
92private:
93    GateRef gatePtr_;
94};
95
96// Gate structure
97// for example:
98// ```
99// g0 = op0(...)
100// g1 = op1(...)
101// g2 = op2(g0, g1)
102// g3 = op3(g2)
103// g4 = op4(g2, g0, g1)
104// g5 = op5(g3, g4)
105
106// +---- out[1] ----+---- out[0] ----+-------- g2 --------+-- in[0] --+-- in[1] --+
107// |                |                |                    |           |           |
108// | next=null      | next=null      | ...                |           |           |
109// | idx=1          | idx=0          |                    |    g0     |    g1     |
110// | prev=g4.out[2] | prev=g4.out[1] | firstOut=g4.out[0] |           |           |
111// |                |                |                    |           |           |
112// +----------------+----------------+--------------------+-----------+-----------+
113//       ^               ^
114//       |               |
115//       |               |
116//       |               |          +---- out[0] ----+-------- g3 --------+-- in[0] --+
117//       |               |          |                |                    |           |
118//       |               |          | next=null      | ...                |           |
119//       |               |          | idx=0          |                    |    g2     |
120//       |               |          | prev=g4.out[0] | firstOut=g5.out[0] |           |
121//       |               |          |                |                    |           |
122//       |               |          +----------------+--------------------+-----------+
123//       |               |               ^
124//       |               |               |
125//       |               |               |
126//       V               V               V
127// +---- out[2] ----+---- out[1] ----+---- out[0] ----+-------- g4 --------+-- in[0] --+-- in[1] --+-- in[2] --+
128// |                |                |                |                    |           |           |           |
129// | next=g2.out[1] | next=g2.out[0] | next=g3.out[0] | ...                |           |           |           |
130// | idx=2          | idx=1          | idx=0          |                    |    g2     |    g0     |    g1     |
131// | prev=null      | prev=null      | prev=null      | firstOut=g5.out[1] |           |           |           |
132// |                |                |                |                    |           |           |           |
133// +----------------+----------------+----------------+--------------------+-----------+-----------+-----------+
134// ```
135
136class Gate {
137public:
138    // NOLINTNEXTLINE(modernize-avoid-c-arrays)
139    Gate(const GateMetaData* meta, GateId id, Gate *inList[], MachineType machineType, GateType type);
140    static size_t GetGateSize(size_t numIns)
141    {
142        numIns = (numIns == 0) ? 1 : numIns;
143        return numIns * (sizeof(In) + sizeof(Out)) + sizeof(Gate);
144    }
145    static size_t GetOutListSize(size_t numIns)
146    {
147        numIns = (numIns == 0) ? 1 : numIns;
148        return numIns * sizeof(Out);
149    }
150    void NewIn(size_t idx, Gate *in);
151    void ModifyIn(size_t idx, Gate *in);
152    void DeleteIn(size_t idx);
153    void DeleteGate();
154    static constexpr GateRef InvalidGateRef = -1;
155    [[nodiscard]] Out *GetOut(size_t idx);
156    [[nodiscard]] Out *GetFirstOut();
157    [[nodiscard]] const Out *GetOutConst(size_t idx) const;
158    [[nodiscard]] const Out *GetFirstOutConst() const;
159    // note: GetFirstOut() is not equal to GetOut(0)
160    // note: behavior of GetFirstOut() is undefined when there are no Outs
161    // note: use IsFirstOutNull() to check first if there may be no Outs
162    void SetFirstOut(const Out *firstOut);
163    void SetFirstOutNull();
164    [[nodiscard]] bool IsFirstOutNull() const;
165    [[nodiscard]] In *GetIn(size_t idx);
166    [[nodiscard]] const In *GetInConst(size_t idx) const;
167    [[nodiscard]] Gate *GetInGate(size_t idx);
168    [[nodiscard]] const Gate *GetInGateConst(size_t idx) const;
169    // note: behavior of GetInGate(idx) is undefined when Ins[idx] is deleted or not assigned
170    // note: use IsInGateNull(idx) to check first if Ins[idx] may be deleted or not assigned
171    [[nodiscard]] bool IsInGateNull(size_t idx) const;
172    [[nodiscard]] OpCode GetOpCode() const;
173    [[nodiscard]] GateId GetId() const;
174    [[nodiscard]] size_t GetNumIns() const;
175    [[nodiscard]] size_t GetStateCount() const;
176    [[nodiscard]] size_t GetDependCount() const;
177    [[nodiscard]] size_t GetInValueCount() const;
178    [[nodiscard]] size_t GetInFrameStateCount() const;
179    [[nodiscard]] size_t GetInValueStarts() const;
180    [[nodiscard]] size_t GetRootCount() const;
181    [[nodiscard]] size_t GetInFrameStateStarts() const;
182    void Print(std::string bytecode = "", bool inListPreview = false, size_t highlightIdx = -1,
183        std::string_view comment = "") const;
184    std::string ToString(std::string bytecode = "", bool inListPreview = false, size_t highlightIdx = -1,
185        std::string_view comment = "") const;
186    void ShortPrint(std::string bytecode = "", bool inListPreview = false, size_t highlightIdx = -1) const;
187    size_t PrintInGate(size_t numIns, size_t idx, size_t size, bool inListPreview, size_t highlightIdx,
188                       std::ostringstream &log, bool isEnd = false) const;
189    void PrintGateWithAdditionOp(std::string additionOp, std::string_view comment) const;
190    void PrintWithBytecode(std::string_view comment) const;
191    void CheckNullInput() const;
192    void CheckStateInput() const;
193    void CheckValueInput(bool isArch64) const;
194    void CheckDependInput() const;
195    void CheckRootInput() const;
196    void CheckFrameStateInput() const;
197    void CheckStateOutput(const std::string& methodName) const;
198    std::string GetValueInAndOut(bool inListPreview = false, size_t highlightIdx = -1) const;
199    void CheckBranchOutput() const;
200    void CheckNOP() const;
201    void CheckSelector() const;
202    void CheckRelay() const;
203    void Verify(bool isArch64, const std::string& methodName) const;
204    [[nodiscard]] MarkCode GetMark(TimeStamp stamp) const;
205    void SetMark(MarkCode mark, TimeStamp stamp);
206    MachineType GetMachineType() const
207    {
208        return machineType_;
209    }
210    void SetMachineType(MachineType machineType)
211    {
212        machineType_ = machineType;
213    }
214    GateType GetGateType() const
215    {
216        return type_;
217    }
218    void SetGateType(GateType type)
219    {
220        type_ = type;
221    }
222    const GateMetaData* GetMetaData() const
223    {
224        return meta_;
225    }
226
227    const OneParameterMetaData* GetOneParameterMetaData() const
228    {
229        return OneParameterMetaData::Cast(meta_);
230    }
231
232    const StringMetaData* GetStringMetaData() const
233    {
234        ASSERT(meta_->IsStringType());
235        return static_cast<const StringMetaData*>(meta_);
236    }
237
238    const JSBytecodeMetaData* GetJSBytecodeMetaData() const
239    {
240        return JSBytecodeMetaData::Cast(meta_);
241    }
242
243    const BoolMetaData* GetBoolMetaData() const
244    {
245        return BoolMetaData::Cast(meta_);
246    }
247
248    const TypedCallMetaData* GetTypedCallMetaData() const
249    {
250        return TypedCallMetaData::Cast(meta_);
251    }
252
253    const NewConstructMetaData* GetNewConstructMetaData() const
254    {
255        return NewConstructMetaData::Cast(meta_);
256    }
257
258    std::string MachineTypeStr(MachineType machineType) const;
259    std::string GateTypeStr(GateType gateType) const;
260    ~Gate() = default;
261
262private:
263    friend class Circuit;
264    friend class GateAccessor;
265    void CheckInputOpcode(size_t idx, OpCode expected) const;
266    void CheckInputMachineType(size_t idx, MachineType expected, bool isArch64) const;
267    void CheckNotInputMachineType(size_t idx, MachineType notExpected) const;
268    void CheckState(size_t idx) const;
269    void CheckGeneralState(size_t idx) const;
270    void CheckFailed(std::string errorString, size_t highlightIdx) const;
271    void SetMetaData(const GateMetaData* meta)
272    {
273        meta_ = meta;
274    }
275    uint64_t TryGetValue() const
276    {
277        if (meta_->IsOneParameterKind()) {
278            return GetOneParameterMetaData()->GetValue();
279        }
280        return 0;
281    }
282    void DumpHeader(std::ostringstream &oss, const std::string& additionOp) const;
283
284    void DumpInputs(std::ostringstream &oss, bool inListPreview, size_t highlightIdx) const;
285
286    void DumpOutputs(std::ostringstream &oss, bool inListPreview) const;
287    std::string GetBytecodeStr() const;
288
289    // ...
290    // out(2)
291    // out(1)
292    // out(0)
293    const GateMetaData *meta_ { nullptr }; // uintptr_t
294    GateId id_ { 0 }; // uint32_t
295    GateType type_ { GateType::Empty() }; // uint32_t
296    MachineType machineType_ { MachineType::NOVALUE }; // uint8_t
297    TimeStamp stamp_ { 0 }; // uint8_t
298    MarkCode mark_ { MarkCode::NO_MARK }; // uint8_t
299    uint8_t bitField_ { 0 };
300    GateRef firstOut_ { 0 }; // int32_t
301    // in(0)
302    // in(1)
303    // in(2)
304    // ...
305};
306} // namespace panda::ecmascript::kungfu
307
308#endif  // ECMASCRIPT_COMPILER_GATE_H
309