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
20namespace panda::ecmascript::kungfu {
21
22std::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
46bool 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
60bool GateMetaData::IsProlog() const
61{
62    return (opcode_ == OpCode::ARG || opcode_ == OpCode::INITVREG);
63}
64
65bool 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
79bool 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
90bool 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
102bool 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
128bool 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
142bool 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
153bool GateMetaData::IsCFGMerge() const
154{
155    return (opcode_ == OpCode::MERGE) || (opcode_ == OpCode::LOOP_BEGIN);
156}
157
158bool 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
175bool 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
190bool GateMetaData::IsLoopHead() const
191{
192    return (opcode_ == OpCode::LOOP_BEGIN);
193}
194
195bool GateMetaData::IsNop() const
196{
197    return (opcode_ == OpCode::NOP || opcode_ == OpCode::DEAD);
198}
199
200bool GateMetaData::IsDead() const
201{
202    return opcode_ == OpCode::DEAD;
203}
204
205bool GateMetaData::IsConstant() const
206{
207    return (opcode_ == OpCode::CONSTANT);
208}
209
210bool GateMetaData::IsDependSelector() const
211{
212    return (opcode_ == OpCode::DEPEND_SELECTOR);
213}
214
215GateMetaBuilder::GateMetaBuilder(Chunk* chunk)
216    : cache_(), chunk_(chunk) {}
217
218#define DECLARE_GATE_META(NAME, OP, R, S, D, V) \
219const GateMetaData* GateMetaBuilder::NAME()     \
220{                                               \
221    return &cache_.cached##NAME##_;             \
222}
223IMMUTABLE_META_DATA_CACHE_LIST(DECLARE_GATE_META)
224#undef DECLARE_GATE_META
225
226#define DECLARE_GATE_META(NAME, OP, R, S, D, V)                           \
227const GateMetaData* GateMetaBuilder::NAME(bool value)                     \
228{                                                                         \
229    auto meta = new (chunk_) BoolMetaData(OpCode::OP, R, S, D, V, value); \
230    return meta;                                                          \
231}
232GATE_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)        \
236const 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}
241GATE_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)                    \
245const 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}
265GATE_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)                                   \
269const 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}
289GATE_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)                                   \
293const 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}
299GATE_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)                                          \
303const 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}
309GATE_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)                                        \
313const 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}
319GATE_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)                                         \
323const 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}
331GATE_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)                                          \
335const 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}
341GATE_META_DATA_LIST_WITH_PC_OFFSET_FIXED_VALUE(DECLARE_GATE_META)
342#undef DECLARE_GATE_META
343
344const 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        }
351CACHED_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
362const 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