• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 2021-2025 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 "plugins/ets/runtime/ets_class_linker_extension.h"
17 #include "plugins/ets/runtime/interop_js/interop_context.h"
18 #include "plugins/ets/runtime/interop_js/interop_common.h"
19 #include "plugins/ets/runtime/interop_js/js_refconvert.h"
20 #include "plugins/ets/runtime/interop_js/js_convert.h"
21 #include "runtime/mem/local_object_handle.h"
22 
23 #include "plugins/ets/runtime/interop_js/js_refconvert_array.h"
24 
25 // NOLINTBEGIN(readability-identifier-naming)
26 // CC-OFF(G.FMT.07) project code style
27 napi_status __attribute__((weak)) napi_is_map(napi_env env, napi_value value, bool *result);
28 // CC-OFF(G.FMT.07) project code style
29 napi_status __attribute__((weak)) napi_is_set(napi_env env, napi_value value, bool *result);
30 // NOLINTEND(readability-identifier-naming)
31 
32 namespace ark::ets::interop::js {
33 
34 // JSRefConvert adapter for builtin reference types
35 template <typename Conv>
36 class JSRefConvertBuiltin : public JSRefConvert {
37 public:
JSRefConvertBuiltin()38     JSRefConvertBuiltin() : JSRefConvert(this) {}
39 
WrapImpl(InteropCtx * ctx,EtsObject * obj)40     napi_value WrapImpl(InteropCtx *ctx, EtsObject *obj)
41     {
42         using ObjType = std::remove_pointer_t<typename Conv::cpptype>;
43         return Conv::Wrap(ctx->GetJSEnv(), FromEtsObject<ObjType>(obj));
44     }
45 
UnwrapImpl(InteropCtx * ctx,napi_value jsValue)46     EtsObject *UnwrapImpl(InteropCtx *ctx, napi_value jsValue)
47     {
48         auto res = Conv::Unwrap(ctx, ctx->GetJSEnv(), jsValue);
49         if (!res) {
50             return nullptr;
51         }
52         return AsEtsObject(res.value());
53     }
54 };
55 
56 template <typename Conv>
RegisterBuiltinRefConvertor(JSRefConvertCache * cache,Class * klass)57 static inline void RegisterBuiltinRefConvertor(JSRefConvertCache *cache, Class *klass)
58 {
59     [[maybe_unused]] bool res = CheckClassInitialized<true>(klass);
60     ASSERT(res);
61     cache->Insert(klass, std::make_unique<JSRefConvertBuiltin<Conv>>());
62 }
63 
RegisterEtsProxyForStdClass(InteropCtx * ctx,std::string_view descriptor,char const * jsBuiltinName=nullptr,const ets_proxy::EtsClassWrapper::OverloadsMap * overloads=nullptr)64 static ets_proxy::EtsClassWrapper *RegisterEtsProxyForStdClass(
65     InteropCtx *ctx, std::string_view descriptor, char const *jsBuiltinName = nullptr,
66     const ets_proxy::EtsClassWrapper::OverloadsMap *overloads = nullptr)
67 {
68     auto coro = EtsCoroutine::GetCurrent();
69     ASSERT(coro != nullptr);
70     PandaEtsVM *vm = coro->GetPandaVM();
71     EtsClassLinker *etsClassLinker = vm->GetClassLinker();
72     auto etsClass = etsClassLinker->GetClass(descriptor.data());
73     if (UNLIKELY(etsClass == nullptr)) {
74         ctx->Fatal(std::string("nonexisting class ") + descriptor.data());
75     }
76 
77     // create ets_proxy bound to js builtin-constructor
78     ets_proxy::EtsClassWrappersCache *cache = ctx->GetEtsClassWrappersCache();
79     std::unique_ptr<ets_proxy::EtsClassWrapper> wrapper =
80         ets_proxy::EtsClassWrapper::Create(ctx, etsClass, jsBuiltinName, overloads);
81     if (UNLIKELY(wrapper == nullptr)) {
82         ctx->Fatal(std::string("ets_proxy creation failed for ") + etsClass->GetDescriptor());
83     }
84     return cache->Insert(etsClass, std::move(wrapper));
85 }
86 
87 namespace {
88 
89 namespace descriptors = panda_file_items::class_descriptors;
90 
91 [[maybe_unused]] constexpr const ets_proxy::EtsClassWrapper::OverloadsMap *NO_OVERLOADS = nullptr;
92 constexpr const char *NO_MIRROR = nullptr;
93 
94 class CompatConvertorsRegisterer {
95 private:
NotImplemented(char const * name)96     [[noreturn]] void NotImplemented(char const *name) __attribute__((noinline))
97     {
98         InteropCtx::Fatal(std::string("compat.") + name + " box is not implemented");
99     }
100 
NotAssignable(char const * name)101     EtsObject *NotAssignable(char const *name) __attribute__((noinline))
102     {
103         JSConvertTypeCheckFailed(name);
104         return nullptr;
105     };
106 
StdCtorRef(InteropCtx * ctxx,char const * name)107     napi_ref StdCtorRef(InteropCtx *ctxx, char const *name)
108     {
109         napi_env env = ctxx->GetJSEnv();
110         napi_value val;
111         NAPI_CHECK_FATAL(napi_get_named_property(env, GetGlobal(env), name, &val));
112         INTEROP_FATAL_IF(IsNull(env, val));
113         napi_ref ref;
114         NAPI_CHECK_FATAL(napi_create_reference(env, val, 1, &ref));
115         return ref;
116     }
117 
CheckInstanceof(napi_env env,napi_value val,napi_ref ctorRef)118     bool CheckInstanceof(napi_env env, napi_value val, napi_ref ctorRef)
119     {
120         bool result;
121         NAPI_CHECK_FATAL(napi_instanceof(env, val, GetReferenceValue(env, ctorRef), &result));
122         return result;
123     }
124 
125     template <typename ConvTag>
BuiltinConvert(InteropCtx * inCtx,napi_env env,napi_value jsValue)126     EtsObject *BuiltinConvert(InteropCtx *inCtx, napi_env env, napi_value jsValue)
127     {
128         auto res = ConvTag::UnwrapImpl(inCtx, env, jsValue);
129         if (UNLIKELY(!res.has_value())) {
130             return nullptr;
131         }
132         return AsEtsObject(res.value());
133     }
134 
RegisterExceptions()135     void RegisterExceptions()
136     {
137         static const ets_proxy::EtsClassWrapper::OverloadsMap W_ERROR_OVERLOADS {
138             {utf::CStringAsMutf8("<ctor>"), std::make_pair("Lstd/core/String;Lescompat/ErrorOptions;:V", 2)}};
139         static const ets_proxy::EtsClassWrapper::OverloadsMap W_EXCEPTION_OVERLOADS {
140             {utf::CStringAsMutf8("<ctor>"), std::make_pair("Lstd/core/String;:V", 1)}};
141         wError_ = RegisterClass(descriptors::ERROR, "Error", &W_ERROR_OVERLOADS);
142         RegisterClass(descriptors::EXCEPTION, nullptr, &W_EXCEPTION_OVERLOADS);
143 
144         static const std::array STD_EXCEPTIONS_LIST = {
145             // Errors
146             std::make_tuple("Lstd/core/AssertionError;", NO_MIRROR, &W_ERROR_OVERLOADS),
147             std::make_tuple("Lstd/core/DivideByZeroError;", NO_MIRROR, &W_ERROR_OVERLOADS),
148             std::make_tuple("Lstd/core/NullPointerError;", NO_MIRROR, &W_ERROR_OVERLOADS),
149             std::make_tuple("Lstd/core/UncaughtExceptionError;", NO_MIRROR, &W_ERROR_OVERLOADS),
150             std::make_tuple("Lstd/core/ArithmeticError;", NO_MIRROR, &W_ERROR_OVERLOADS),
151             std::make_tuple("Lstd/core/ClassCastError;", NO_MIRROR, &W_ERROR_OVERLOADS),
152             std::make_tuple("Lstd/core/IndexOutOfBoundsError;", NO_MIRROR, &W_ERROR_OVERLOADS),
153             std::make_tuple("Lstd/core/ArrayStoreError;", NO_MIRROR, &W_ERROR_OVERLOADS),
154             std::make_tuple("Lstd/core/NegativeArraySizeError;", NO_MIRROR, &W_ERROR_OVERLOADS),
155             std::make_tuple("Lstd/core/LinkerError;", NO_MIRROR, &W_ERROR_OVERLOADS),
156             std::make_tuple("Lstd/core/LinkerClassNotFoundError;", NO_MIRROR, &W_ERROR_OVERLOADS),
157             // Exceptions
158             std::make_tuple("Lstd/core/NoDataException;", NO_MIRROR, &W_EXCEPTION_OVERLOADS),
159             std::make_tuple("Lstd/core/ArgumentOutOfRangeException;", NO_MIRROR, &W_EXCEPTION_OVERLOADS),
160             std::make_tuple("Lstd/core/IllegalStateException;", NO_MIRROR, &W_EXCEPTION_OVERLOADS),
161             std::make_tuple("Lstd/core/UnsupportedOperationException;", NO_MIRROR, &W_EXCEPTION_OVERLOADS),
162             std::make_tuple("Lstd/core/IllegalMonitorStateError;", NO_MIRROR, &W_EXCEPTION_OVERLOADS),
163             std::make_tuple("Lstd/core/IllegalArgumentException;", NO_MIRROR, &W_EXCEPTION_OVERLOADS),
164             std::make_tuple("Lstd/core/RuntimeException;", NO_MIRROR, &W_EXCEPTION_OVERLOADS),
165         };
166         for (const auto &[descr, mirror, ovl] : STD_EXCEPTIONS_LIST) {
167             RegisterClass(descr, mirror, ovl);
168         }
169     }
170 
RegisterClass(std::string_view descriptor,char const * jsBuiltinName=nullptr,const ets_proxy::EtsClassWrapper::OverloadsMap * overloads=nullptr)171     ets_proxy::EtsClassWrapper *RegisterClass(std::string_view descriptor, char const *jsBuiltinName = nullptr,
172                                               const ets_proxy::EtsClassWrapper::OverloadsMap *overloads = nullptr)
173     {
174         ets_proxy::EtsClassWrapper *wclass = RegisterEtsProxyForStdClass(ctx_, descriptor, jsBuiltinName, overloads);
175         auto env = ctx_->GetJSEnv();
176         auto name = wclass->GetEtsClass()->GetRuntimeClass()->GetName();
177         auto jsCtor = wclass->GetJsCtor(env);
178         NAPI_CHECK_FATAL(napi_set_named_property(env, jsGlobalEts_, name.c_str(), jsCtor));
179         if (jsBuiltinName != nullptr) {
180             NAPI_CHECK_FATAL(napi_set_named_property(env, jsGlobalEts_, jsBuiltinName, jsCtor));
181         }
182         return wclass;
183     }
184 
RegisterClassWithLeafMatcher(std::string_view descriptor,char const * jsBuiltinName=nullptr,const ets_proxy::EtsClassWrapper::OverloadsMap * overloads=nullptr)185     ets_proxy::EtsClassWrapper *RegisterClassWithLeafMatcher(
186         std::string_view descriptor, char const *jsBuiltinName = nullptr,
187         const ets_proxy::EtsClassWrapper::OverloadsMap *overloads = nullptr)
188     {
189         ets_proxy::EtsClassWrapper *wclass = RegisterClass(descriptor, jsBuiltinName, overloads);
190         wclass->SetJSBuiltinMatcher(
191             [self = *this, wclass, descriptor](InteropCtx *ctxx, napi_value jsValue, bool verified = true) mutable {
192                 (void)verified;
193                 auto env = ctxx->GetJSEnv();
194                 napi_value constructor;
195                 bool match = false;
196                 NAPI_CHECK_FATAL(napi_get_named_property(env, jsValue, "constructor", &constructor));
197                 NAPI_CHECK_FATAL(napi_strict_equals(env, constructor, wclass->GetBuiltin(env), &match));
198                 if (match) {
199                     return wclass->CreateJSBuiltinProxy(ctxx, jsValue);
200                 }
201                 return self.NotAssignable(descriptor.data());
202             });
203         return wclass;
204     }
205 
RegisterArray()206     void RegisterArray()
207     {
208         static const ets_proxy::EtsClassWrapper::OverloadsMap W_ARRAY_OVERLOADS = {
209             {utf::CStringAsMutf8("<ctor>"), std::make_pair(":V", 1)},
210             {utf::CStringAsMutf8("$_get"), std::make_pair("I:Lstd/core/Object;", 2)},
211             {utf::CStringAsMutf8("$_set"), std::make_pair("ILstd/core/Object;:V", 3)},
212             {utf::CStringAsMutf8("at"), std::make_pair("I:Lstd/core/Object;", 2)},
213             {utf::CStringAsMutf8("copyWithin"), std::make_pair("III:Lescompat/Array;", 4)},
214             {utf::CStringAsMutf8("fill"),
215              std::make_pair("Lstd/core/Object;Lstd/core/Double;Lstd/core/Double;:Lescompat/Array;", 4)},
216             {utf::CStringAsMutf8("indexOf"), std::make_pair("Lstd/core/Object;Lstd/core/Double;:D", 3)},
217             {utf::CStringAsMutf8("lastIndexOf"), std::make_pair("Lstd/core/Object;I:I", 3)},
218             {utf::CStringAsMutf8("slice"), std::make_pair("II:Lescompat/Array;", 3)},
219             {utf::CStringAsMutf8("splice"), std::make_pair("I:Lescompat/Array;", 2)},
220             {utf::CStringAsMutf8("splice"), std::make_pair("IILescompat/Array;:Lescompat/Array;", 3)},
221             {utf::CStringAsMutf8("toSpliced"), std::make_pair("II[Lstd/core/Object;:Lescompat/Array;", 3)},
222             {utf::CStringAsMutf8("with"), std::make_pair("DLstd/core/Object;:Lescompat/Array;", 3)},
223         };
224         wArray_ = RegisterClass(descriptors::ARRAY, "Array", &W_ARRAY_OVERLOADS);
225         NAPI_CHECK_FATAL(napi_object_seal(ctx_->GetJSEnv(), jsGlobalEts_));
226     }
227 
RegisterError()228     void RegisterError()
229     {
230         wRangeError_ = RegisterClassWithLeafMatcher(descriptors::RANGE_ERROR, "RangeError");
231         wReferenceError_ = RegisterClassWithLeafMatcher(descriptors::REFERENCE_ERROR, "ReferenceError");
232         wSyntaxError_ = RegisterClassWithLeafMatcher(descriptors::SYNTAX_ERROR, "SyntaxError");
233         wURIError_ = RegisterClassWithLeafMatcher(descriptors::URI_ERROR, "URIError");
234         wTypeError_ = RegisterClassWithLeafMatcher(descriptors::TYPE_ERROR, "TypeError");
235         ASSERT(wRangeError_ != nullptr);
236         ASSERT(wReferenceError_ != nullptr);
237         ASSERT(wSyntaxError_ != nullptr);
238         ASSERT(wURIError_ != nullptr);
239         ASSERT(wTypeError_ != nullptr);
240 
241         ctorRangeError_ = StdCtorRef(ctx_, "RangeError");
242         ctorReferenceError_ = StdCtorRef(ctx_, "ReferenceError");
243         ctorSyntaxError_ = StdCtorRef(ctx_, "SyntaxError");
244         ctorURIError_ = StdCtorRef(ctx_, "URIError");
245         ctorTypeError_ = StdCtorRef(ctx_, "TypeError");
246         ASSERT(ctorRangeError_ != nullptr);
247         ASSERT(ctorReferenceError_ != nullptr);
248         ASSERT(ctorSyntaxError_ != nullptr);
249         ASSERT(ctorURIError_ != nullptr);
250         ASSERT(ctorTypeError_ != nullptr);
251     }
252 
RegisterMap()253     void RegisterMap()
254     {
255         static const ets_proxy::EtsClassWrapper::OverloadsMap W_MAP_OVERLOADS = {
256             {utf::CStringAsMutf8("<ctor>"), std::make_pair("Lstd/core/Object;:V", 2)}};
257         wMap_ = RegisterClassWithLeafMatcher(descriptors::MAP, "Map", &W_MAP_OVERLOADS);
258     }
259 
RegisterSet()260     void RegisterSet()
261     {
262         static const ets_proxy::EtsClassWrapper::OverloadsMap W_SET_OVERLOADS = {
263             {utf::CStringAsMutf8("<ctor>"), std::make_pair("Lstd/core/Object;:V", 2)}};
264         wSet_ = RegisterClassWithLeafMatcher(descriptors::SET, "Set", &W_SET_OVERLOADS);
265     }
266 
RegisterDate()267     void RegisterDate()
268     {
269         static const ets_proxy::EtsClassWrapper::OverloadsMap W_DATE_OVERLOADS {
270             {utf::CStringAsMutf8("setDate"), std::make_pair("D:D", 2)},
271             {utf::CStringAsMutf8("setUTCDate"), std::make_pair("D:D", 2)},
272             {utf::CStringAsMutf8("setMilliseconds"), std::make_pair("D:D", 2)},
273             {utf::CStringAsMutf8("setUTCMilliseconds"), std::make_pair("D:D", 2)},
274             {utf::CStringAsMutf8("setTime"), std::make_pair("J:V", 2)},
275         };
276         wDate_ = RegisterClassWithLeafMatcher(descriptors::DATE, "Date", &W_DATE_OVERLOADS);
277     }
278 
MArray(InteropCtx * ctxx,napi_value jsValue,bool verified=true)279     EtsObject *MArray(InteropCtx *ctxx, napi_value jsValue, bool verified = true)
280     {
281         napi_env env = ctxx->GetJSEnv();
282         bool isInstanceof;
283         if (!verified) {
284             NAPI_CHECK_FATAL(napi_is_array(env, jsValue, &isInstanceof));
285             if (!isInstanceof) {
286                 return NotAssignable("Array");
287             }
288         }
289         return wArray_->CreateJSBuiltinProxy(ctxx, jsValue);
290     }
291 
MMap(InteropCtx * ctxx,napi_value jsValue,bool verified=true)292     EtsObject *MMap(InteropCtx *ctxx, napi_value jsValue, bool verified = true)
293     {
294         napi_env env = ctxx->GetJSEnv();
295         bool isInstanceof;
296         if (!verified) {
297             NAPI_CHECK_FATAL(napi_is_map(env, jsValue, &isInstanceof));
298             if (!isInstanceof) {
299                 return NotAssignable("Map");
300             }
301         }
302         return wMap_->CreateJSBuiltinProxy(ctxx, jsValue);
303     }
304 
MSet(InteropCtx * ctxx,napi_value jsValue,bool verified=true)305     EtsObject *MSet(InteropCtx *ctxx, napi_value jsValue, bool verified = true)
306     {
307         napi_env env = ctxx->GetJSEnv();
308         bool isInstanceof;
309         if (!verified) {
310             NAPI_CHECK_FATAL(napi_is_set(env, jsValue, &isInstanceof));
311             if (!isInstanceof) {
312                 return NotAssignable("Set");
313             }
314         }
315         return wSet_->CreateJSBuiltinProxy(ctxx, jsValue);
316     }
317 
MDate(InteropCtx * ctxx,napi_value jsValue,bool verified=true)318     EtsObject *MDate(InteropCtx *ctxx, napi_value jsValue, bool verified = true)
319     {
320         napi_env env = ctxx->GetJSEnv();
321         bool isInstanceof;
322         if (!verified) {
323             NAPI_CHECK_FATAL(napi_is_date(env, jsValue, &isInstanceof));
324             if (!isInstanceof) {
325                 return NotAssignable("Date");
326             }
327         }
328         ASSERT(wDate_ != nullptr);
329         return wDate_->CreateJSBuiltinProxy(ctxx, jsValue);
330     }
331 
RegisterObject()332     void RegisterObject()
333     {
334         wObject_ = RegisterClass(descriptors::OBJECT, "Object");
335     }
336 
MError(InteropCtx * ctxx,napi_value jsValue,bool verified=true)337     EtsObject *MError(InteropCtx *ctxx, napi_value jsValue, bool verified = true)
338     {
339         napi_env env = ctxx->GetJSEnv();
340         bool isInstanceof;
341         if (!verified) {
342             NAPI_CHECK_FATAL(napi_is_error(env, jsValue, &isInstanceof));
343             if (!isInstanceof) {
344                 return NotAssignable("Error");
345             }
346         }
347 
348         if (CheckInstanceof(env, jsValue, ctorRangeError_)) {
349             return wRangeError_->CreateJSBuiltinProxy(ctxx, jsValue);
350         }
351         if (CheckInstanceof(env, jsValue, ctorReferenceError_)) {
352             return wReferenceError_->CreateJSBuiltinProxy(ctxx, jsValue);
353         }
354         if (CheckInstanceof(env, jsValue, ctorSyntaxError_)) {
355             return wSyntaxError_->CreateJSBuiltinProxy(ctxx, jsValue);
356         }
357         if (CheckInstanceof(env, jsValue, ctorURIError_)) {
358             return wURIError_->CreateJSBuiltinProxy(ctxx, jsValue);
359         }
360         if (CheckInstanceof(env, jsValue, ctorTypeError_)) {
361             return wTypeError_->CreateJSBuiltinProxy(ctxx, jsValue);
362         }
363 
364         // NOTE(vpukhov): compat: remove when compat/Error is implemented
365         return BuiltinConvert<JSConvertESError>(ctxx, env, jsValue);
366     }
367 
MObjectObject(InteropCtx * ctxx,napi_value jsValue)368     EtsObject *MObjectObject(InteropCtx *ctxx, napi_value jsValue)
369     {
370         napi_env env = ctxx->GetJSEnv();
371         bool isInstanceof;
372         NAPI_CHECK_FATAL(napi_is_array(env, jsValue, &isInstanceof));
373         if (isInstanceof) {
374             return MArray(ctxx, jsValue);
375         }
376         NAPI_CHECK_FATAL(napi_is_map(env, jsValue, &isInstanceof));
377         if (isInstanceof) {
378             return MMap(ctxx, jsValue);
379         }
380         NAPI_CHECK_FATAL(napi_is_set(env, jsValue, &isInstanceof));
381         if (isInstanceof) {
382             return MSet(ctxx, jsValue);
383         }
384         NAPI_CHECK_FATAL(napi_is_promise(env, jsValue, &isInstanceof));
385         if (isInstanceof) {
386             return BuiltinConvert<JSConvertPromise>(ctxx, env, jsValue);
387         }
388         NAPI_CHECK_FATAL(napi_is_error(env, jsValue, &isInstanceof));
389         if (isInstanceof) {
390             return MError(ctxx, jsValue);
391         }
392         NAPI_CHECK_FATAL(napi_is_date(env, jsValue, &isInstanceof));
393         if (isInstanceof) {
394             return MDate(ctxx, jsValue);
395         }
396         if (IsConstructor(env, jsValue, CONSTRUCTOR_NAME_NUMBER)) {
397             return BuiltinConvert<JSConvertStdlibDouble>(ctxx, env, jsValue);
398         }
399         if (IsConstructor(env, jsValue, CONSTRUCTOR_NAME_BOOLEAN)) {
400             return BuiltinConvert<JSConvertStdlibBoolean>(ctxx, env, jsValue);
401         }
402         if (IsConstructor(env, jsValue, CONSTRUCTOR_NAME_STRING)) {
403             return BuiltinConvert<JSConvertString>(ctxx, env, jsValue);
404         }
405         return BuiltinConvert<JSConvertJSValue>(ctxx, env, jsValue);
406     }
407 
MObject(InteropCtx * ctxx,napi_value jsValue,bool verified=true)408     EtsObject *MObject(InteropCtx *ctxx, napi_value jsValue, bool verified = true)
409     {
410         napi_env env = ctxx->GetJSEnv();
411         (void)verified;  // ignored for Object
412 
413         napi_valuetype jsType = GetValueType(env, jsValue);
414         switch (jsType) {
415             case napi_boolean:
416                 return BuiltinConvert<JSConvertStdlibBoolean>(ctxx, env, jsValue);
417             case napi_number:
418                 return BuiltinConvert<JSConvertStdlibDouble>(ctxx, env, jsValue);
419             case napi_string:
420                 return BuiltinConvert<JSConvertString>(ctxx, env, jsValue);
421             case napi_object:
422                 return MObjectObject(ctx_, jsValue);
423             case napi_null:
424                 return ctx_->GetNullValue();
425             case napi_symbol:
426                 [[fallthrough]];
427             case napi_function:
428                 [[fallthrough]];
429             case napi_external:
430                 [[fallthrough]];
431             case napi_bigint:
432                 return BuiltinConvert<JSConvertJSValue>(ctxx, env, jsValue);
433             default:
434                 ASSERT(!IsNullOrUndefined(env, jsValue));
435                 InteropCtx::Fatal("Bad jsType in Object value matcher");
436         };
437     }
438 
439 public:
CompatConvertorsRegisterer(InteropCtx * ctx)440     explicit CompatConvertorsRegisterer(InteropCtx *ctx) : ctx_(ctx)
441     {
442         auto env = ctx_->GetJSEnv();
443         NAPI_CHECK_FATAL(napi_create_object(env, &jsGlobalEts_));
444         NAPI_CHECK_FATAL(napi_set_named_property(env, GetGlobal(env), "ets", jsGlobalEts_));
445     }
446 
447     DEFAULT_MOVE_SEMANTIC(CompatConvertorsRegisterer);
448 
449     DEFAULT_COPY_SEMANTIC(CompatConvertorsRegisterer);
450 
451     ~CompatConvertorsRegisterer() = default;
452 
Run()453     void Run()
454     {
455         RegisterObject();
456 
457         RegisterExceptions();
458 
459         RegisterDate();
460         // #IC4UO2
461         RegisterClassWithLeafMatcher(descriptors::MAPENTRY, nullptr);
462         RegisterClassWithLeafMatcher(descriptors::MAPITERATOR, nullptr);
463         RegisterClassWithLeafMatcher(descriptors::EMPTYMAPITERATOR, nullptr);
464 
465         RegisterMap();
466         RegisterSet();
467 
468         RegisterClassWithLeafMatcher(descriptors::ARRAY_ENTRIES_ITERATOR_T, nullptr);
469         RegisterClassWithLeafMatcher(descriptors::ITERATOR_RESULT, nullptr);
470         RegisterClassWithLeafMatcher(descriptors::ARRAY_KEYS_ITERATOR, nullptr);
471         RegisterClassWithLeafMatcher(descriptors::ARRAY_VALUES_ITERATOR_T, nullptr);
472 
473         RegisterError();
474         RegisterArray();
475 
476         ASSERT(wError_ != nullptr);
477         wError_->SetJSBuiltinMatcher(
478             [self = *this](InteropCtx *ctxx, napi_value jsValue, bool verified = true) mutable {
479                 return self.MError(ctxx, jsValue, verified);
480             });
481 
482         ASSERT(wObject_ != nullptr);
483         wObject_->SetJSBuiltinMatcher(
484             [self = *this](InteropCtx *ctxx, napi_value jsValue, bool verified = true) mutable {
485                 return self.MObject(ctxx, jsValue, verified);
486             });
487 
488         ASSERT(wArray_ != nullptr);
489         wArray_->SetJSBuiltinMatcher(
490             [self = *this](InteropCtx *ctxx, napi_value jsValue, bool verified = true) mutable {
491                 return self.MArray(ctxx, jsValue, verified);
492             });
493     }
494 
495 private:
496     InteropCtx *ctx_;
497     napi_value jsGlobalEts_ {};
498     ets_proxy::EtsClassWrapper *wError_ {};
499     ets_proxy::EtsClassWrapper *wObject_ {};
500     ets_proxy::EtsClassWrapper *wArray_ {};
501     ets_proxy::EtsClassWrapper *wDate_ {};
502     ets_proxy::EtsClassWrapper *wMap_ {};
503     ets_proxy::EtsClassWrapper *wSet_ {};
504     ets_proxy::EtsClassWrapper *wRangeError_ {};
505     ets_proxy::EtsClassWrapper *wReferenceError_ {};
506     ets_proxy::EtsClassWrapper *wSyntaxError_ {};
507     ets_proxy::EtsClassWrapper *wURIError_ {};
508     ets_proxy::EtsClassWrapper *wTypeError_ {};
509 
510     napi_ref ctorTypeError_ {nullptr};
511     napi_ref ctorRangeError_ {nullptr};
512     napi_ref ctorReferenceError_ {nullptr};
513     napi_ref ctorSyntaxError_ = {nullptr};
514     napi_ref ctorURIError_ = {nullptr};
515 };
516 
517 static_assert(std::is_trivially_copy_constructible_v<CompatConvertorsRegisterer>);
518 static_assert(std::is_trivially_copy_assignable_v<CompatConvertorsRegisterer>);
519 static_assert(std::is_trivially_move_constructible_v<CompatConvertorsRegisterer>);
520 static_assert(std::is_trivially_move_assignable_v<CompatConvertorsRegisterer>);
521 static_assert(std::is_trivially_destructible_v<CompatConvertorsRegisterer>);
522 
523 }  // namespace
524 
RegisterCompatConvertors(InteropCtx * ctx)525 static void RegisterCompatConvertors(InteropCtx *ctx)
526 {
527     CompatConvertorsRegisterer(ctx).Run();
528 }
529 
RegisterBuiltinJSRefConvertors(InteropCtx * ctx)530 void RegisterBuiltinJSRefConvertors(InteropCtx *ctx)
531 {
532     auto cache = ctx->GetRefConvertCache();
533     auto coro = EtsCoroutine::GetCurrent();
534     ASSERT(coro != nullptr);
535     PandaEtsVM *vm = coro->GetPandaVM();
536     EtsClassLinkerExtension *linkerExt = vm->GetClassLinker()->GetEtsClassLinkerExtension();
537     auto ptypes = PlatformTypes(coro);
538 
539     RegisterBuiltinRefConvertor<JSConvertJSValue>(cache, ctx->GetJSValueClass());
540     RegisterBuiltinRefConvertor<JSConvertESError>(cache, ctx->GetESErrorClass());
541     RegisterBuiltinRefConvertor<JSConvertString>(cache, ctx->GetStringClass());
542     RegisterBuiltinRefConvertor<JSConvertBigInt>(cache, ctx->GetBigIntClass());
543     RegisterBuiltinRefConvertor<JSConvertPromise>(cache, ctx->GetPromiseClass());
544     RegisterBuiltinRefConvertor<JSConvertEtsNull>(cache, ctx->GetNullValueClass());
545 
546     RegisterBuiltinRefConvertor<JSConvertStdlibBoolean>(cache, ptypes->coreBoolean->GetRuntimeClass());
547     RegisterBuiltinRefConvertor<JSConvertStdlibByte>(cache, ptypes->coreByte->GetRuntimeClass());
548     RegisterBuiltinRefConvertor<JSConvertStdlibChar>(cache, ptypes->coreChar->GetRuntimeClass());
549     RegisterBuiltinRefConvertor<JSConvertStdlibShort>(cache, ptypes->coreShort->GetRuntimeClass());
550     RegisterBuiltinRefConvertor<JSConvertStdlibInt>(cache, ptypes->coreInt->GetRuntimeClass());
551     RegisterBuiltinRefConvertor<JSConvertStdlibLong>(cache, ptypes->coreLong->GetRuntimeClass());
552     RegisterBuiltinRefConvertor<JSConvertStdlibFloat>(cache, ptypes->coreFloat->GetRuntimeClass());
553     RegisterBuiltinRefConvertor<JSConvertStdlibDouble>(cache, ptypes->coreDouble->GetRuntimeClass());
554 
555     RegisterBuiltinArrayConvertor<ClassRoot::ARRAY_U1, JSConvertU1>(cache, linkerExt);
556     RegisterBuiltinArrayConvertor<ClassRoot::ARRAY_I32, JSConvertI32>(cache, linkerExt);
557     RegisterBuiltinArrayConvertor<ClassRoot::ARRAY_F32, JSConvertF32>(cache, linkerExt);
558     RegisterBuiltinArrayConvertor<ClassRoot::ARRAY_I64, JSConvertI64>(cache, linkerExt);
559     RegisterBuiltinArrayConvertor<ClassRoot::ARRAY_F64, JSConvertF64>(cache, linkerExt);
560     RegisterBuiltinArrayConvertor<ClassRoot::ARRAY_STRING, JSConvertString>(cache, linkerExt);
561     // NOTE(vpukhov): jsvalue[] specialization, currently uses JSRefConvertArrayRef
562 
563     RegisterCompatConvertors(ctx);
564 }
565 
566 }  // namespace ark::ets::interop::js
567