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 
23 namespace panda::ecmascript::kungfu {
24 
25 class EscapeAnalysis;
26 class FieldLocation;
27 
28 class VirtualObject {
29 public:
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);
37 private:
38     ChunkVector<FieldLocation> fields_;
39     // Gates which use this virtual object
40     ChunkVector<GateRef> users_;
41     bool escaped_ {false};
42 };
43 
44 class FieldLocation {
45 public:
FieldLocation()46     FieldLocation() : id_(maxid++) {}
FieldLocation(size_t id)47     FieldLocation(size_t id) : id_(id) {}
operator ==(const FieldLocation &v) const48     bool operator == (const FieldLocation &v) const
49     {
50         return id_ == v.id_;
51     }
operator !=(const FieldLocation &v) const52     bool operator != (const FieldLocation &v) const
53     {
54         return id_ != v.id_;
55     }
operator <(const FieldLocation &v) const56     bool operator < (const FieldLocation &v) const
57     {
58         return id_ < v.id_;
59     }
60     static constexpr size_t invalid = -1;
Invalid()61     static FieldLocation Invalid()
62     {
63         return FieldLocation(invalid);
64     }
65 private:
66     static size_t maxid;
67     size_t id_;
68 };
69 
70 class State {
71 public:
State(Chunk* chunk)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;
begin() const76     auto begin() const { return map_.begin(); }
end() const77     auto end() const { return map_.end(); }
78 private:
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.
85 class GateInfo {
86 public:
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);
96 private:
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 
106 class EscapeAnalysis : public PassVisitor {
107 public:
EscapeAnalysis(Circuit* circuit, RPOVisitor* visitor, Chunk* chunk, bool isTraced)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);
126 private:
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