• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 2021-2022 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 PANDA_PLUGINS_ETS_RUNTIME_TS2ETS_ETS_TYPE_VISITOR_H
17 #define PANDA_PLUGINS_ETS_RUNTIME_TS2ETS_ETS_TYPE_VISITOR_H
18 
19 #include "libpandabase/macros.h"
20 #include "runtime/include/runtime.h"
21 #include "runtime/mem/heap_manager.h"
22 
23 namespace panda::ets::interop::js {
24 
25 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
26 #define TYPEVIS_PRIM_TYPES_LIST(V) \
27     V(U1)                          \
28     V(I8)                          \
29     V(U16)                         \
30     V(I16)                         \
31     V(I32)                         \
32     V(I64)                         \
33     V(F32)                         \
34     V(F64)
35 
36 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
37 #define TYPEVIS_RAISE_ERROR(val) \
38     do {                         \
39         Error() = (val);         \
40         return;                  \
41     } while (0)
42 
43 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
44 #define TYPEVIS_ABRUPT_ON_ERROR() \
45     do {                          \
46         if (UNLIKELY(!!Error()))  \
47             return;               \
48     } while (0)
49 
50 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
51 #define TYPEVIS_CHECK_ERROR(expr, val) \
52     do {                               \
53         if (UNLIKELY(!(expr)))         \
54             TYPEVIS_RAISE_ERROR(val);  \
55     } while (0)
56 
57 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
58 #define TYPEVIS_CHECK_FORWARD_ERROR(err)         \
59     do {                                         \
60         auto &_e = (err);                        \
61         TYPEVIS_CHECK_ERROR(!_e, std::move(_e)); \
62     } while (0)
63 
64 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
65 #define TYPEVIS_NAPI_CHECK(expr) TYPEVIS_CHECK_ERROR((expr) == napi_ok, #expr)
66 
67 class EtsTypeVisitor {
68 public:
69 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
70 #define DEF_VIS(name) virtual void Visit##name() = 0;
TYPEVIS_PRIM_TYPES_LIST(DEF_VIS)71     TYPEVIS_PRIM_TYPES_LIST(DEF_VIS)
72 #undef DEF_VIS
73 
74     virtual void VisitPrimitive(const panda::panda_file::Type type)
75     {
76         switch (type.GetId()) {
77 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
78 #define DELEGATE(name)                            \
79     case panda::panda_file::Type::TypeId::name: { \
80         return Visit##name();                     \
81     }
82             TYPEVIS_PRIM_TYPES_LIST(DELEGATE)
83 #undef DELEGATE
84 
85             default:
86                 TYPEVIS_RAISE_ERROR("bad primitive type");
87         }
88     }
89 
90     virtual void VisitString(panda::Class *klass) = 0;
91     virtual void VisitArray(panda::Class *klass) = 0;
92 
93     virtual void VisitFieldPrimitive(panda::Field const *field, panda::panda_file::Type type) = 0;
94     virtual void VisitFieldReference(panda::Field const *field, panda::Class *klass) = 0;
95 
VisitField(panda::Field const * field)96     virtual void VisitField(panda::Field const *field)
97     {
98         auto type = field->GetType();
99         if (type.IsPrimitive()) {
100             return VisitFieldPrimitive(field, type);
101         }
102         return VisitFieldReference(field, field->ResolveTypeClass());
103     }
104 
VisitObject(panda::Class * klass)105     virtual void VisitObject(panda::Class *klass)
106     {
107         auto fields = klass->GetInstanceFields();
108         for (auto const &f : fields) {
109             VisitField(&f);
110         }
111         InStatic() = true;
112         auto sfields = klass->GetStaticFields();
113         for (auto const &f : sfields) {
114             VisitField(&f);
115         }
116         InStatic() = false;
117         TYPEVIS_ABRUPT_ON_ERROR();
118     }
119 
VisitReference(panda::Class * klass)120     virtual void VisitReference(panda::Class *klass)
121     {
122         if (klass->IsStringClass()) {
123             return VisitString(klass);
124         }
125         if (klass->IsArrayClass()) {
126             return VisitArray(klass);
127         }
128         return VisitObject(klass);
129     }
130 
VisitClass(panda::Class * klass)131     virtual void VisitClass(panda::Class *klass)
132     {
133         if (klass->IsPrimitive()) {
134             return VisitPrimitive(klass->GetType());
135         }
136         return VisitReference(klass);
137     }
138 
Error()139     std::optional<std::string> &Error()
140     {
141         return error_;
142     }
143 
InStatic()144     bool &InStatic()
145     {
146         return inStatic_;
147     }
148 
149 private:
150     std::optional<std::string> error_;
151     bool inStatic_ = false;
152 };
153 
154 class EtsMethodVisitor {
155 public:
EtsMethodVisitor(panda::Method * method)156     explicit EtsMethodVisitor(panda::Method *method) : method_(method) {}
157 
VisitMethod()158     virtual void VisitMethod()
159     {
160         refArgIdx_ = 0;
161         auto excludeThis = static_cast<uint32_t>(!method_->IsStatic());
162         auto numArgs = method_->GetNumArgs() - excludeThis;
163         VisitReturn();
164         TYPEVIS_ABRUPT_ON_ERROR();
165         for (uint32_t i = 0; i < numArgs; ++i) {
166             VisitArgument(i);
167             TYPEVIS_ABRUPT_ON_ERROR();
168         }
169     }
170 
VisitArgs()171     virtual void VisitArgs()
172     {
173         refArgIdx_ = 0;
174         auto excludeThis = static_cast<uint32_t>(!method_->IsStatic());
175         auto numArgs = method_->GetNumArgs() - excludeThis;
176         if (!method_->GetReturnType().IsPrimitive()) {
177             refArgIdx_++;
178         }
179         for (uint32_t i = 0; i < numArgs; ++i) {
180             VisitArgument(i);
181             TYPEVIS_ABRUPT_ON_ERROR();
182         }
183     }
184 
VisitReturn()185     virtual void VisitReturn()
186     {
187         refArgIdx_ = 0;
188         VisitReturnImpl();
189     }
190 
Error()191     std::optional<std::string> &Error()
192     {
193         return error_;
194     }
195 
GetMethod()196     auto GetMethod() const
197     {
198         return method_;
199     }
200 
201 protected:
202     virtual void VisitReturn(panda::panda_file::Type type) = 0;
203     virtual void VisitReturn(panda::Class *klass) = 0;
204     virtual void VisitArgument(uint32_t idx, panda::panda_file::Type type) = 0;
205     virtual void VisitArgument(uint32_t idx, panda::Class *klass) = 0;
206 
207 private:
VisitReturnImpl()208     void VisitReturnImpl()
209     {
210         panda_file::Type type = method_->GetReturnType();
211         if (type.IsPrimitive()) {
212             return VisitReturn(type);
213         }
214         return VisitReturn(ResolveRefClass());
215     }
216 
VisitArgument(uint32_t argIdx)217     void VisitArgument(uint32_t argIdx)
218     {
219         auto excludeThis = static_cast<uint32_t>(!method_->IsStatic());
220         panda_file::Type type = method_->GetArgType(argIdx + excludeThis);
221         if (type.IsPrimitive()) {
222             return VisitArgument(argIdx, type);
223         }
224         return VisitArgument(argIdx, ResolveRefClass());
225     }
226 
ResolveRefClass()227     panda::Class *ResolveRefClass()
228     {
229         auto pf = method_->GetPandaFile();
230         panda_file::MethodDataAccessor mda(*pf, method_->GetFileId());
231         panda_file::ProtoDataAccessor pda(*pf, mda.GetProtoId());
232         auto classLinker = panda::Runtime::GetCurrent()->GetClassLinker();
233         auto ctx = method_->GetClass()->GetLoadContext();
234 
235         auto klassId = pda.GetReferenceType(refArgIdx_++);
236         auto klass = classLinker->GetClass(*pf, klassId, ctx);
237         return klass;
238     }
239 
240     panda::Method *method_ {};
241     uint32_t refArgIdx_ {};
242     std::optional<std::string> error_;
243 };
244 
245 class EtsConvertorRef {
246 public:
247     using ObjRoot = panda::ObjectHeader **;
248     using ValVariant = std::variant<panda::Value, ObjRoot>;
249 
250     EtsConvertorRef() = default;
EtsConvertorRef(ValVariant * dataPtr)251     explicit EtsConvertorRef(ValVariant *dataPtr)
252     {
253         u_.dataPtr = dataPtr;  // NOLINT(cppcoreguidelines-pro-type-union-access)
254     }
EtsConvertorRef(ObjRoot obj,size_t offs)255     EtsConvertorRef(ObjRoot obj, size_t offs) : isField_(true)
256     {
257         u_.field.obj = obj;    // NOLINT(cppcoreguidelines-pro-type-union-access)
258         u_.field.offs = offs;  // NOLINT(cppcoreguidelines-pro-type-union-access)
259     }
260 
261     template <typename T>
LoadPrimitive()262     T LoadPrimitive() const
263     {
264         if (isField_) {
265             // NOLINTNEXTLINE(cppcoreguidelines-pro-type-union-access)
266             return (*u_.field.obj)->GetFieldPrimitive<T>(u_.field.offs);
267         }
268         return std::get<panda::Value>(*u_.dataPtr).GetAs<T>();  // NOLINT(cppcoreguidelines-pro-type-union-access)
269     }
270 
LoadReference()271     panda::ObjectHeader *LoadReference() const
272     {
273         if (isField_) {
274             return (*u_.field.obj)->GetFieldObject(u_.field.offs);  // NOLINT(cppcoreguidelines-pro-type-union-access)
275         }
276         return *std::get<ObjRoot>(*u_.dataPtr);  // NOLINT(cppcoreguidelines-pro-type-union-access)
277     }
278 
279     template <typename T>
StorePrimitive(T val)280     void StorePrimitive(T val)
281     {
282         if (isField_) {
283             // NOLINTNEXTLINE(cppcoreguidelines-pro-type-union-access)
284             (*u_.field.obj)->SetFieldPrimitive<T>(u_.field.offs, val);
285         } else {
286             *u_.dataPtr = panda::Value(val);  // NOLINT(cppcoreguidelines-pro-type-union-access)
287         }
288     }
289 
StoreReference(ObjRoot val)290     void StoreReference(ObjRoot val)
291     {
292         if (isField_) {
293             (*u_.field.obj)->SetFieldObject(u_.field.offs, *val);  // NOLINT(cppcoreguidelines-pro-type-union-access)
294         } else {
295             *u_.dataPtr = val;  // NOLINT(cppcoreguidelines-pro-type-union-access)
296         }
297     }
298 
299 private:
300     union USlot {
301         struct FieldSlot {  // field slot
302             ObjRoot obj = nullptr;
303             size_t offs = 0;
304         };
305 
306         FieldSlot field;
307         ValVariant *dataPtr = nullptr;  // handle or primitive slot
308 
USlot()309         USlot() {}  // NOLINT(modernize-use-equals-default)
310     };
311 
312     USlot u_ {};
313     bool isField_ = false;
314 };
315 
316 }  // namespace panda::ets::interop::js
317 
318 #endif  // !PANDA_PLUGINS_ETS_RUNTIME_TS2ETS_ETS_TYPE_VISITOR_H
319