1 /*
2  * Copyright (c) 2023 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 #include "ecmascript/compiler/gate.h"
17 #include "ecmascript/compiler/share_gate_meta_data.h"
18 #include "ecmascript/compiler/gate_meta_data_builder.h"
19 
20 namespace panda::ecmascript::kungfu {
21 
Str(OpCode opcode)22 std::string GateMetaData::Str(OpCode opcode)
23 {
24     const std::map<OpCode, const char *> strMap = {
25 #define GATE_NAME_MAP(NAME, OP, R, S, D, V) { OpCode::OP, #OP },
26     IMMUTABLE_META_DATA_CACHE_LIST(GATE_NAME_MAP)
27     GATE_META_DATA_LIST_WITH_BOOL(GATE_NAME_MAP)
28     GATE_META_DATA_LIST_WITH_BOOL_VALUE_IN(GATE_NAME_MAP)
29     GATE_META_DATA_LIST_WITH_SIZE(GATE_NAME_MAP)
30     GATE_META_DATA_LIST_WITH_ONE_PARAMETER(GATE_NAME_MAP)
31     GATE_META_DATA_LIST_WITH_PC_OFFSET(GATE_NAME_MAP)
32     GATE_META_DATA_LIST_FOR_CALL(GATE_NAME_MAP)
33     GATE_META_DATA_LIST_FOR_NEW(GATE_NAME_MAP)
34     GATE_META_DATA_LIST_WITH_PC_OFFSET_FIXED_VALUE(GATE_NAME_MAP)
35 #undef GATE_NAME_MAP
36 #define GATE_NAME_MAP(OP) { OpCode::OP, #OP },
37         GATE_OPCODE_LIST(GATE_NAME_MAP)
38 #undef GATE_NAME_MAP
39     };
40     if (strMap.count(opcode) > 0) {
41         return strMap.at(opcode);
42     }
43     return "OP-" + std::to_string(static_cast<uint8_t>(opcode));
44 }
45 
IsRoot() const46 bool GateMetaData::IsRoot() const
47 {
48     switch (opcode_) {
49         case OpCode::CIRCUIT_ROOT:
50         case OpCode::DEPEND_ENTRY:
51         case OpCode::ARG_LIST:
52         case OpCode::STATE_ENTRY:
53         case OpCode::RETURN_LIST:
54             return true;
55         default:
56             return false;
57     }
58 }
59 
IsProlog() const60 bool GateMetaData::IsProlog() const
61 {
62     return (opcode_ == OpCode::ARG || opcode_ == OpCode::INITVREG);
63 }
64 
IsFixed() const65 bool GateMetaData::IsFixed() const
66 {
67     switch (opcode_) {
68         case OpCode::VALUE_SELECTOR:
69         case OpCode::DEPEND_SELECTOR:
70         case OpCode::DEPEND_RELAY:
71         case OpCode::LOOP_EXIT_DEPEND:
72         case OpCode::LOOP_EXIT_VALUE:
73             return true;
74         default:
75             return false;
76     }
77 }
78 
IsSchedulable() const79 bool GateMetaData::IsSchedulable() const
80 {
81     ASSERT(!IsNop());
82 #ifndef NDEBUG
83     if (GetStateCount() == 0) {
84         ASSERT(!IsFixed());
85     }
86 #endif
87     return (!IsProlog()) && (!IsRoot()) && (GetStateCount() == 0);
88 }
89 
IsState() const90 bool GateMetaData::IsState() const
91 {
92     ASSERT(!IsNop());
93 #ifndef NDEBUG
94     if (GetStateCount() > 0) {
95         ASSERT(!IsProlog());
96         ASSERT(!IsRoot());
97     }
98 #endif
99     return (!IsVirtualState()) && (!IsFixed()) && (GetStateCount() > 0);
100 }
101 
IsGeneralState() const102 bool GateMetaData::IsGeneralState() const
103 {
104     switch (opcode_) {
105         case OpCode::IF_BRANCH:
106         case OpCode::SWITCH_BRANCH:
107         case OpCode::IF_TRUE:
108         case OpCode::IF_FALSE:
109         case OpCode::IF_SUCCESS:
110         case OpCode::IF_EXCEPTION:
111         case OpCode::SWITCH_CASE:
112         case OpCode::DEFAULT_CASE:
113         case OpCode::MERGE:
114         case OpCode::LOOP_BEGIN:
115         case OpCode::LOOP_BACK:
116         case OpCode::LOOP_EXIT:
117         case OpCode::ORDINARY_BLOCK:
118         case OpCode::STATE_ENTRY:
119         case OpCode::DEOPT_CHECK:
120         case OpCode::RETURN:
121         case OpCode::RETURN_VOID:
122             return true;
123         default:
124             return false;
125     }
126 }
127 
IsTerminalState() const128 bool GateMetaData::IsTerminalState() const
129 {
130     switch (opcode_) {
131         case OpCode::RETURN:
132         case OpCode::THROW:
133         case OpCode::RETURN_VOID:
134         case OpCode::GET_EXCEPTION:
135         case OpCode::STATE_SPLIT:
136             return true;
137         default:
138             return false;
139     }
140 }
141 
IsVirtualState() const142 bool GateMetaData::IsVirtualState() const
143 {
144     switch (opcode_) {
145         case OpCode::GET_EXCEPTION:
146         case OpCode::STATE_SPLIT:
147             return true;
148         default:
149             return false;
150     }
151 }
152 
IsCFGMerge() const153 bool GateMetaData::IsCFGMerge() const
154 {
155     return (opcode_ == OpCode::MERGE) || (opcode_ == OpCode::LOOP_BEGIN);
156 }
157 
IsControlCase() const158 bool GateMetaData::IsControlCase() const
159 {
160     ASSERT(HasFlag(GateFlags::CONTROL));
161     // should add relay
162     switch (opcode_) {
163         case OpCode::IF_BRANCH:
164         case OpCode::SWITCH_BRANCH:
165         case OpCode::IF_TRUE:
166         case OpCode::IF_FALSE:
167         case OpCode::SWITCH_CASE:
168         case OpCode::DEFAULT_CASE:
169             return true;
170         default:
171             return false;
172     }
173 }
174 
IsIfOrSwitchRelated() const175 bool GateMetaData::IsIfOrSwitchRelated() const
176 {
177     switch (opcode_) {
178         case OpCode::IF_TRUE:
179         case OpCode::IF_FALSE:
180         case OpCode::SWITCH_CASE:
181         case OpCode::DEFAULT_CASE:
182         case OpCode::IF_SUCCESS:
183         case OpCode::IF_EXCEPTION:
184             return true;
185         default:
186             return false;
187     }
188 }
189 
IsLoopHead() const190 bool GateMetaData::IsLoopHead() const
191 {
192     return (opcode_ == OpCode::LOOP_BEGIN);
193 }
194 
IsNop() const195 bool GateMetaData::IsNop() const
196 {
197     return (opcode_ == OpCode::NOP || opcode_ == OpCode::DEAD);
198 }
199 
IsDead() const200 bool GateMetaData::IsDead() const
201 {
202     return opcode_ == OpCode::DEAD;
203 }
204 
IsConstant() const205 bool GateMetaData::IsConstant() const
206 {
207     return (opcode_ == OpCode::CONSTANT);
208 }
209 
IsDependSelector() const210 bool GateMetaData::IsDependSelector() const
211 {
212     return (opcode_ == OpCode::DEPEND_SELECTOR);
213 }
214 
GateMetaBuilder(Chunk* chunk)215 GateMetaBuilder::GateMetaBuilder(Chunk* chunk)
216     : cache_(), chunk_(chunk) {}
217 
218 #define DECLARE_GATE_META(NAME, OP, R, S, D, V) \
219 const GateMetaData* GateMetaBuilder::NAME()     \
220 {                                               \
221     return &cache_.cached##NAME##_;             \
222 }
223 IMMUTABLE_META_DATA_CACHE_LIST(DECLARE_GATE_META)
224 #undef DECLARE_GATE_META
225 
226 #define DECLARE_GATE_META(NAME, OP, R, S, D, V)                           \
227 const GateMetaData* GateMetaBuilder::NAME(bool value)                     \
228 {                                                                         \
229     auto meta = new (chunk_) BoolMetaData(OpCode::OP, R, S, D, V, value); \
230     return meta;                                                          \
231 }
232 GATE_META_DATA_LIST_WITH_BOOL(DECLARE_GATE_META)
233 #undef DECLARE_GATE_META
234 
235 #define DECLARE_GATE_META_WITH_BOOL_VALUE_IN(NAME, OP, R, S, D, V)        \
236 const GateMetaData* GateMetaBuilder::NAME(size_t value, bool flag)        \
237 {                                                                         \
238     auto meta = new (chunk_) BoolMetaData(OpCode::OP, R, S, D, V, flag);  \
239     return meta;                                                          \
240 }
241 GATE_META_DATA_LIST_WITH_BOOL_VALUE_IN(DECLARE_GATE_META_WITH_BOOL_VALUE_IN)
242 #undef DECLARE_GATE_META_WITH_BOOL_VALUE_IN
243 
244 #define DECLARE_GATE_META(NAME, OP, R, S, D, V)                    \
245 const GateMetaData* GateMetaBuilder::NAME(size_t value)            \
246 {                                                                  \
247     switch (value) {                                               \
248         case GateMetaDataChache::ONE_VALUE:                        \
249             return &cache_.cached##NAME##1_;                       \
250         case GateMetaDataChache::TWO_VALUE:                        \
251             return &cache_.cached##NAME##2_;                       \
252         case GateMetaDataChache::THREE_VALUE:                      \
253             return &cache_.cached##NAME##3_;                       \
254         case GateMetaDataChache::FOUR_VALUE:                       \
255             return &cache_.cached##NAME##4_;                       \
256         case GateMetaDataChache::FIVE_VALUE:                       \
257             return &cache_.cached##NAME##5_;                       \
258         default:                                                   \
259             break;                                                 \
260     }                                                              \
261     auto meta = new (chunk_) GateMetaData(OpCode::OP, R, S, D, V); \
262     meta->SetKind(GateMetaData::Kind::MUTABLE_WITH_SIZE);          \
263     return meta;                                                   \
264 }
265 GATE_META_DATA_LIST_WITH_SIZE(DECLARE_GATE_META)
266 #undef DECLARE_GATE_META
267 
268 #define DECLARE_GATE_META(NAME, OP, R, S, D, V)                                   \
269 const GateMetaData* GateMetaBuilder::NAME(uint64_t value)                         \
270 {                                                                                 \
271     switch (value) {                                                              \
272         case GateMetaDataChache::ONE_VALUE:                                       \
273             return &cache_.cached##NAME##1_;                                      \
274         case GateMetaDataChache::TWO_VALUE:                                       \
275             return &cache_.cached##NAME##2_;                                      \
276         case GateMetaDataChache::THREE_VALUE:                                     \
277             return &cache_.cached##NAME##3_;                                      \
278         case GateMetaDataChache::FOUR_VALUE:                                      \
279             return &cache_.cached##NAME##4_;                                      \
280         case GateMetaDataChache::FIVE_VALUE:                                      \
281             return &cache_.cached##NAME##5_;                                      \
282         default:                                                                  \
283             break;                                                                \
284     }                                                                             \
285     auto meta = new (chunk_) OneParameterMetaData(OpCode::OP, R, S, D, V, value); \
286     meta->SetKind(GateMetaData::Kind::MUTABLE_ONE_PARAMETER);                     \
287     return meta;                                                                  \
288 }
289 GATE_META_DATA_LIST_WITH_VALUE(DECLARE_GATE_META)
290 #undef DECLARE_GATE_META
291 
292 #define DECLARE_GATE_META(NAME, OP, R, S, D, V)                                   \
293 const GateMetaData* GateMetaBuilder::NAME(uint64_t value)                         \
294 {                                                                                 \
295     auto meta = new (chunk_) OneParameterMetaData(OpCode::OP, R, S, D, V, value); \
296     meta->SetKind(GateMetaData::Kind::MUTABLE_ONE_PARAMETER);                     \
297     return meta;                                                                  \
298 }
299 GATE_META_DATA_LIST_WITH_GATE_TYPE(DECLARE_GATE_META)
300 #undef DECLARE_GATE_META
301 
302 #define DECLARE_GATE_META(NAME, OP, R, S, D, V)                                          \
303 const GateMetaData* GateMetaBuilder::NAME(uint64_t value, uint64_t pcOffset)             \
304 {                                                                                        \
305     auto meta = new (chunk_) OneParameterMetaData(OpCode::OP, R, S, D, value, pcOffset); \
306     meta->SetKind(GateMetaData::Kind::MUTABLE_ONE_PARAMETER);                            \
307     return meta;                                                                         \
308 }
309 GATE_META_DATA_LIST_WITH_PC_OFFSET(DECLARE_GATE_META)
310 #undef DECLARE_GATE_META
311 
312 #define DECLARE_GATE_META_FOR_CALL(NAME, OP, R, S, D, V)                                        \
313 const GateMetaData* GateMetaBuilder::NAME(uint64_t value, uint64_t pcOffset, bool noGC)         \
314 {                                                                                               \
315     auto meta = new (chunk_) TypedCallMetaData(OpCode::OP, R, S, D, value, pcOffset, noGC);     \
316     meta->SetKind(GateMetaData::Kind::TYPED_CALL);                                              \
317     return meta;                                                                                \
318 }
319 GATE_META_DATA_LIST_FOR_CALL(DECLARE_GATE_META_FOR_CALL)
320 #undef DECLARE_GATE_META_FOR_CALL
321 
322 #define DECLARE_GATE_META_FOR_NEW(NAME, OP, R, S, D, V)                                         \
323 const GateMetaData* GateMetaBuilder::NAME(uint64_t value, uint64_t pcOffset,                    \
324                                           bool isFastCall)                                      \
325 {                                                                                               \
326     auto meta = new (chunk_) NewConstructMetaData(OpCode::OP, R, S, D, value,                   \
327                                                   pcOffset, isFastCall);                        \
328     meta->SetKind(GateMetaData::Kind::CALL_NEW);                                                \
329     return meta;                                                                                \
330 }
331 GATE_META_DATA_LIST_FOR_NEW(DECLARE_GATE_META_FOR_NEW)
332 #undef DECLARE_GATE_META_FOR_NEW
333 
334 #define DECLARE_GATE_META(NAME, OP, R, S, D, V)                                          \
335 const GateMetaData* GateMetaBuilder::NAME(uint64_t pcOffset) const                       \
336 {                                                                                        \
337     auto meta = new (chunk_) OneParameterMetaData(OpCode::OP, R, S, D, V, pcOffset);     \
338     meta->SetKind(GateMetaData::Kind::MUTABLE_ONE_PARAMETER);                            \
339     return meta;                                                                         \
340 }
341 GATE_META_DATA_LIST_WITH_PC_OFFSET_FIXED_VALUE(DECLARE_GATE_META)
342 #undef DECLARE_GATE_META
343 
Arg(uint64_t value)344 const GateMetaData* GateMetaBuilder::Arg(uint64_t value)
345 {
346     switch (value) {
347 #define DECLARE_CACHED_VALUE_CASE(VALUE)                 \
348         case VALUE: {                                    \
349             return &cache_.cachedArg##VALUE##_;          \
350         }
351 CACHED_ARG_LIST(DECLARE_CACHED_VALUE_CASE)
352 #undef DECLARE_CACHED_VALUE_CASE
353         default:
354             break;
355     }
356 
357     auto meta = new (chunk_) OneParameterMetaData(OpCode::ARG, GateFlags::HAS_ROOT, 0, 0, 0, value);
358     meta->SetKind(GateMetaData::Kind::MUTABLE_ONE_PARAMETER);
359     return meta;
360 }
361 
InitVreg(uint64_t value)362 const GateMetaData* GateMetaBuilder::InitVreg(uint64_t value)
363 {
364     auto meta = new (chunk_) OneParameterMetaData(OpCode::INITVREG, GateFlags::HAS_ROOT, 0, 0, 0, value);
365     meta->SetKind(GateMetaData::Kind::MUTABLE_ONE_PARAMETER);
366     return meta;
367 }
368 }  // namespace panda::ecmascript::kungfu
369