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