1/*
2 * Copyright (c) 2024 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_ESCAPE_ANALYSIS_H
17#define ECMASCRIPT_COMPILER_ESCAPE_ANALYSIS_H
18
19#include "ecmascript/compiler/combined_pass_visitor.h"
20#include "ecmascript/compiler/gate_accessor.h"
21#include "ecmascript/mem/chunk_containers.h"
22
23namespace panda::ecmascript::kungfu {
24
25class EscapeAnalysis;
26class FieldLocation;
27
28class VirtualObject {
29public:
30    VirtualObject(size_t numIn, Chunk* chunk);
31    void SetEscaped();
32    bool IsEscaped() const;
33    ChunkVector<GateRef>& GetUsers();
34    void ClearUsers();
35    void AddUser(GateRef gate);
36    FieldLocation GetField(size_t offset);
37private:
38    ChunkVector<FieldLocation> fields_;
39    // Gates which use this virtual object
40    ChunkVector<GateRef> users_;
41    bool escaped_ {false};
42};
43
44class FieldLocation {
45public:
46    FieldLocation() : id_(maxid++) {}
47    FieldLocation(size_t id) : id_(id) {}
48    bool operator == (const FieldLocation &v) const
49    {
50        return id_ == v.id_;
51    }
52    bool operator != (const FieldLocation &v) const
53    {
54        return id_ != v.id_;
55    }
56    bool operator < (const FieldLocation &v) const
57    {
58        return id_ < v.id_;
59    }
60    static constexpr size_t invalid = -1;
61    static FieldLocation Invalid()
62    {
63        return FieldLocation(invalid);
64    }
65private:
66    static size_t maxid;
67    size_t id_;
68};
69
70class State {
71public:
72    explicit State(Chunk* chunk) : map_(chunk) {}
73    void SetFieldValue(FieldLocation field, GateRef gate);
74    GateRef GetFieldValue(FieldLocation field) const;
75    bool IsMapEqual(const State &state) const;
76    auto begin() const { return map_.begin(); }
77    auto end() const { return map_.end(); }
78private:
79    ChunkMap<FieldLocation, GateRef> map_;
80};
81
82// When we visit a gate, we first create a GateInfo which maintains results and all information
83// that may be used in this visit. After finishing this visit, virtual object and replacement
84// of this gate must be reset.
85class GateInfo {
86public:
87    GateInfo(Circuit* circuit, GateRef curGate, EscapeAnalysis* escapeAnalysis, Chunk* chunk);
88    ~GateInfo();
89    GateRef GetCurrentGate() const;
90    GateRef GetFieldValue(FieldLocation field) const;
91    void SetFieldValue(FieldLocation field, GateRef value);
92    void SetEliminated();
93    void SetVirtualObject(VirtualObject* object);
94    State MergeState(GateRef gate);
95    void SetReplacement(GateRef replacement);
96private:
97    Circuit* circuit_;
98    GateAccessor acc_;
99    GateRef curGate_;
100    EscapeAnalysis* escapeAnalysis_;
101    State state_;
102    VirtualObject* object_ {nullptr};
103    GateRef replacement_ {Circuit::NullGate()};
104};
105
106class EscapeAnalysis : public PassVisitor {
107public:
108    EscapeAnalysis(Circuit* circuit, RPOVisitor* visitor, Chunk* chunk, bool isTraced)
109        : PassVisitor(circuit, chunk, visitor), circuit_(circuit), replacements_(chunk), gateToVirtualObject_(chunk),
110          gateToState_(chunk), chunk_(chunk), isTraced_(isTraced) {}
111
112    GateRef VisitGate(GateRef gate) override;
113    void SetEscaped(GateRef gate);
114    GateRef GetCurrentGate(GateRef gate) const;
115    void RevisitUser(VirtualObject* vObj);
116    GateRef TryGetReplacement(GateRef gate) const;
117    void SetReplacement(GateRef gate, GateRef replacement);
118    VirtualObject* TryGetVirtualObject(GateRef gate) const;
119    VirtualObject* TryGetVirtualObjectAndAddUser(GateRef gate, GateRef currentGate);
120    void SetVirtualObject(GateRef gate, VirtualObject* object);
121    VirtualObject* GetOrCreateVirtualObject(size_t numIn, GateInfo* info);
122    State& GetOrCreateState(GateRef gate);
123    void SetState(GateRef gate, State state);
124    void RevisitGate(GateRef gate);
125    void SetReplaceGate(GateRef gate);
126private:
127    GateRef VisitCreateObjectWithBuffer(GateRef gate, GateInfo* info);
128    GateRef VisitLoadProperty(GateRef gate, GateInfo* info);
129    GateRef VisitLoadConstOffset(GateRef gate, GateInfo* info);
130    GateRef VisitStoreProperty(GateRef gate, GateInfo* info);
131    GateRef VisitObjectTypeCheck(GateRef gate, GateInfo* info);
132
133    Circuit *circuit_ {nullptr};
134    ChunkMap<GateRef, GateRef> replacements_;
135    ChunkMap<GateRef, VirtualObject*> gateToVirtualObject_;
136    ChunkMap<GateRef, State> gateToState_;
137    GateRef replaceGate_ {Circuit::NullGate()};
138    Chunk* chunk_;
139    bool isTraced_;
140};
141
142};
143
144#endif