• 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 #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 namespace ark::ets::interop::js {
26 
27 // JSRefConvert adapter for builtin reference types
28 template <typename Conv>
29 class JSRefConvertBuiltin : public JSRefConvert {
30 public:
JSRefConvertBuiltin()31     JSRefConvertBuiltin() : JSRefConvert(this) {}
32 
WrapImpl(InteropCtx * ctx,EtsObject * obj)33     napi_value WrapImpl(InteropCtx *ctx, EtsObject *obj)
34     {
35         using ObjType = std::remove_pointer_t<typename Conv::cpptype>;
36         return Conv::Wrap(ctx->GetJSEnv(), FromEtsObject<ObjType>(obj));
37     }
38 
UnwrapImpl(InteropCtx * ctx,napi_value jsValue)39     EtsObject *UnwrapImpl(InteropCtx *ctx, napi_value jsValue)
40     {
41         auto res = Conv::Unwrap(ctx, ctx->GetJSEnv(), jsValue);
42         if (!res) {
43             return nullptr;
44         }
45         return AsEtsObject(res.value());
46     }
47 };
48 
49 template <typename Conv>
RegisterBuiltinRefConvertor(JSRefConvertCache * cache,Class * klass)50 static inline void RegisterBuiltinRefConvertor(JSRefConvertCache *cache, Class *klass)
51 {
52     [[maybe_unused]] bool res = CheckClassInitialized<true>(klass);
53     ASSERT(res);
54     cache->Insert(klass, std::make_unique<JSRefConvertBuiltin<Conv>>());
55 }
56 
RegisterEtsProxyForStdClass(InteropCtx * ctx,std::string_view descriptor,char const * jsBuiltinName=nullptr,const ets_proxy::EtsClassWrapper::OverloadsMap * overloads=nullptr)57 static ets_proxy::EtsClassWrapper *RegisterEtsProxyForStdClass(
58     InteropCtx *ctx, std::string_view descriptor, char const *jsBuiltinName = nullptr,
59     const ets_proxy::EtsClassWrapper::OverloadsMap *overloads = nullptr)
60 {
61     auto coro = EtsCoroutine::GetCurrent();
62     PandaEtsVM *vm = coro->GetPandaVM();
63     EtsClassLinker *etsClassLinker = vm->GetClassLinker();
64     auto etsClass = etsClassLinker->GetClass(descriptor.data());
65     if (UNLIKELY(etsClass == nullptr)) {
66         ctx->Fatal(std::string("nonexisting class ") + descriptor.data());
67     }
68 
69     // create ets_proxy bound to js builtin-constructor
70     ets_proxy::EtsClassWrappersCache *cache = ctx->GetEtsClassWrappersCache();
71     std::unique_ptr<ets_proxy::EtsClassWrapper> wrapper =
72         ets_proxy::EtsClassWrapper::Create(ctx, etsClass, jsBuiltinName, overloads);
73     if (UNLIKELY(wrapper == nullptr)) {
74         ctx->Fatal(std::string("ets_proxy creation failed for ") + etsClass->GetDescriptor());
75     }
76     return cache->Insert(etsClass, std::move(wrapper));
77 }
78 
79 namespace {
80 
81 namespace descriptors = panda_file_items::class_descriptors;
82 
83 [[maybe_unused]] constexpr const ets_proxy::EtsClassWrapper::OverloadsMap *NO_OVERLOADS = nullptr;
84 constexpr const char *NO_MIRROR = nullptr;
85 
86 class CompatConvertorsRegisterer {
87 private:
NotImplemented(char const * name)88     [[noreturn]] void NotImplemented(char const *name) __attribute__((noinline))
89     {
90         InteropCtx::Fatal(std::string("compat.") + name + " box is not implemented");
91     }
92 
NotAssignable(char const * name)93     EtsObject *NotAssignable(char const *name) __attribute__((noinline))
94     {
95         JSConvertTypeCheckFailed(name);
96         return nullptr;
97     };
98 
StdCtorRef(InteropCtx * ctxx,char const * name)99     napi_ref StdCtorRef(InteropCtx *ctxx, char const *name)
100     {
101         napi_env env = ctxx->GetJSEnv();
102         napi_value val;
103         NAPI_CHECK_FATAL(napi_get_named_property(env, GetGlobal(env), name, &val));
104         INTEROP_FATAL_IF(IsUndefined(env, val));
105         napi_ref ref;
106         NAPI_CHECK_FATAL(napi_create_reference(env, val, 1, &ref));
107         return ref;
108     }
109 
CheckInstanceof(napi_env env,napi_value val,napi_ref ctorRef)110     bool CheckInstanceof(napi_env env, napi_value val, napi_ref ctorRef)
111     {
112         bool result;
113         NAPI_CHECK_FATAL(napi_instanceof(env, val, GetReferenceValue(env, ctorRef), &result));
114         return result;
115     }
116 
117     template <typename ConvTag>
BuiltinConvert(InteropCtx * inCtx,napi_env env,napi_value jsValue)118     EtsObject *BuiltinConvert(InteropCtx *inCtx, napi_env env, napi_value jsValue)
119     {
120         auto res = ConvTag::UnwrapImpl(inCtx, env, jsValue);
121         if (UNLIKELY(!res.has_value())) {
122             return nullptr;
123         }
124         return AsEtsObject(res.value());
125     }
126 
RegisterExceptions()127     void RegisterExceptions()
128     {
129         static const ets_proxy::EtsClassWrapper::OverloadsMap W_ERROR_OVERLOADS {
130             {utf::CStringAsMutf8("<ctor>"), "Lstd/core/Object;Lstd/core/Object;:V"}};
131         static const ets_proxy::EtsClassWrapper::OverloadsMap W_EXCEPTION_OVERLOADS {
132             {utf::CStringAsMutf8("<ctor>"), "Lstd/core/String;:V"}};
133         wError_ = RegisterClass(descriptors::ERROR, "Error", &W_ERROR_OVERLOADS);
134         RegisterClass(descriptors::EXCEPTION, nullptr, &W_EXCEPTION_OVERLOADS);
135 
136         static const std::array STD_EXCEPTIONS_LIST = {
137             // Errors
138             std::make_tuple("Lstd/core/AssertionError;", NO_MIRROR, &W_ERROR_OVERLOADS),
139             std::make_tuple("Lstd/core/DivideByZeroError;", NO_MIRROR, &W_ERROR_OVERLOADS),
140             std::make_tuple("Lstd/core/NullPointerError;", NO_MIRROR, &W_ERROR_OVERLOADS),
141             std::make_tuple("Lstd/core/UncatchedExceptionError;", NO_MIRROR, &W_ERROR_OVERLOADS),
142             std::make_tuple("Lstd/core/RangeError;", NO_MIRROR, &W_ERROR_OVERLOADS),
143             std::make_tuple("Lstd/core/ArithmeticError;", NO_MIRROR, &W_ERROR_OVERLOADS),
144             std::make_tuple("Lstd/core/ClassCastError;", NO_MIRROR, &W_ERROR_OVERLOADS),
145             std::make_tuple("Lstd/core/IndexOutOfBoundsError;", NO_MIRROR, &W_ERROR_OVERLOADS),
146             std::make_tuple("Lstd/core/ArrayStoreError;", NO_MIRROR, &W_ERROR_OVERLOADS),
147             std::make_tuple("Lstd/core/NegativeArraySizeError;", NO_MIRROR, &W_ERROR_OVERLOADS),
148             // Exceptions
149             std::make_tuple("Lstd/core/NullPointerException;", NO_MIRROR, &W_EXCEPTION_OVERLOADS),
150             std::make_tuple("Lstd/core/NoDataException;", NO_MIRROR, &W_EXCEPTION_OVERLOADS),
151             std::make_tuple("Lstd/core/ArgumentOutOfRangeException;", NO_MIRROR, &W_EXCEPTION_OVERLOADS),
152             std::make_tuple("Lstd/core/IllegalStateException;", NO_MIRROR, &W_EXCEPTION_OVERLOADS),
153             std::make_tuple("Lstd/core/ClassNotFoundException;", NO_MIRROR, &W_EXCEPTION_OVERLOADS),
154             std::make_tuple("Lstd/core/UnsupportedOperationException;", NO_MIRROR, &W_EXCEPTION_OVERLOADS),
155             std::make_tuple("Lstd/core/IllegalMonitorStateException;", NO_MIRROR, &W_EXCEPTION_OVERLOADS),
156             std::make_tuple("Lstd/core/IllegalArgumentException;", NO_MIRROR, &W_EXCEPTION_OVERLOADS),
157         };
158         for (const auto &[descr, mirror, ovl] : STD_EXCEPTIONS_LIST) {
159             RegisterClass(descr, mirror, ovl);
160         }
161     }
162 
RegisterClass(std::string_view descriptor,char const * jsBuiltinName=nullptr,const ets_proxy::EtsClassWrapper::OverloadsMap * overloads=nullptr)163     ets_proxy::EtsClassWrapper *RegisterClass(std::string_view descriptor, char const *jsBuiltinName = nullptr,
164                                               const ets_proxy::EtsClassWrapper::OverloadsMap *overloads = nullptr)
165     {
166         ets_proxy::EtsClassWrapper *wclass = RegisterEtsProxyForStdClass(ctx_, descriptor, jsBuiltinName, overloads);
167         auto env = ctx_->GetJSEnv();
168         auto name = wclass->GetEtsClass()->GetRuntimeClass()->GetName();
169         auto jsCtor = wclass->GetJsCtor(env);
170         NAPI_CHECK_FATAL(napi_set_named_property(env, jsGlobalEts_, name.c_str(), jsCtor));
171         if (jsBuiltinName != nullptr) {
172             NAPI_CHECK_FATAL(napi_set_named_property(env, jsGlobalEts_, jsBuiltinName, jsCtor));
173         }
174         return wclass;
175     }
176 
RegisterArray()177     void RegisterArray()
178     {
179         static const ets_proxy::EtsClassWrapper::OverloadsMap W_ARRAY_OVERLOADS = {
180             {utf::CStringAsMutf8("at"), "I:Lstd/core/Object;"},
181             {utf::CStringAsMutf8("$_get"), "D:Lstd/core/Object;"},
182             {utf::CStringAsMutf8("$_set"), "DLstd/core/Object;:V"},
183             {utf::CStringAsMutf8("with"), "DLstd/core/Object;:Lescompat/Array;"},
184             {utf::CStringAsMutf8("map"), "Lstd/core/Function1;:Lescompat/Array;"},
185             {utf::CStringAsMutf8("forEach"), "Lstd/core/Function1;:V"},
186             {utf::CStringAsMutf8("pop"), ":Lstd/core/Object;"},
187             {utf::CStringAsMutf8("fill"), "Lstd/core/Object;Lstd/core/Object;Lstd/core/Object;:Lescompat/Array;"},
188             {utf::CStringAsMutf8("flat"), ":Lescompat/Array;"},
189             {utf::CStringAsMutf8("join"), "Lstd/core/Object;:Lstd/core/String;"},
190             {utf::CStringAsMutf8("push"), "[Lstd/core/Object;:D"},
191             {utf::CStringAsMutf8("some"), "Lstd/core/Function1;:Z"},
192             {utf::CStringAsMutf8("sort"), ":Lescompat/Array;"},
193             {utf::CStringAsMutf8("every"), "Lstd/core/Function1;:Z"},
194             {utf::CStringAsMutf8("shift"), ":Lstd/core/Object;"},
195             {utf::CStringAsMutf8("slice"), "Lstd/core/Object;Lstd/core/Object;:Lescompat/Array;"},
196             {utf::CStringAsMutf8("<ctor>"), ":V"},
197             {utf::CStringAsMutf8("filter"), "Lstd/core/Function1;:Lescompat/Array;"},
198             {utf::CStringAsMutf8("<get>length"), ":D"},
199             {utf::CStringAsMutf8("reduce"), "Lstd/core/Function2;:Lstd/core/Object;"},
200             {utf::CStringAsMutf8("splice"), "DLstd/core/Object;[Lstd/core/Object;:Lescompat/Array;"},
201             {utf::CStringAsMutf8("findLast"), "Lstd/core/Function1;:Lstd/core/Object;"},
202             {utf::CStringAsMutf8("toSorted"), ":Lescompat/Array;"},
203             {utf::CStringAsMutf8("findIndex"), "Lstd/core/Function1;:D"},
204             {utf::CStringAsMutf8("findLastIndex"), "Lstd/core/Function1;:D"},
205             {utf::CStringAsMutf8("toSpliced"), "Lstd/core/Object;Lstd/core/Object;:Lescompat/Array;"},
206             {utf::CStringAsMutf8("copyWithin"), "II:Lescompat/Array;"},
207             {utf::CStringAsMutf8("toReversed"), ":Lescompat/Array;"},
208             {utf::CStringAsMutf8("indexOf"), "Lstd/core/Object;Lstd/core/Object;:D"},
209             {utf::CStringAsMutf8("includes"), "Lstd/core/Object;Lstd/core/Object;:Z"},
210             {utf::CStringAsMutf8("lastIndexOf"), "Lstd/core/Object;Lstd/core/Object;:D"},
211             {utf::CStringAsMutf8("reduceRight"), "Lstd/core/Function2;:Lstd/core/Object;"},
212             {utf::CStringAsMutf8("find"), "Lstd/core/Function1;:Lstd/core/Object;"},
213             {utf::CStringAsMutf8("isArray"), "Lstd/core/Object;:Z"},
214             {utf::CStringAsMutf8("flatMap"), "Lstd/core/Function2;:Lescompat/Array;"},
215             {utf::CStringAsMutf8("toLocaleString"), ":Lstd/core/String;"},
216             {utf::CStringAsMutf8("from"), "Lescompat/Iterable;:Lescompat/Array;"},
217         };
218         wArray_ = RegisterClass(descriptors::ARRAY, "Array", &W_ARRAY_OVERLOADS);
219 
220         NAPI_CHECK_FATAL(napi_object_seal(ctx_->GetJSEnv(), jsGlobalEts_));
221     }
222 
MArray(InteropCtx * ctxx,napi_value jsValue,bool verified=true)223     EtsObject *MArray(InteropCtx *ctxx, napi_value jsValue, bool verified = true)
224     {
225         napi_env env = ctxx->GetJSEnv();
226         bool isInstanceof;
227         if (!verified) {
228             NAPI_CHECK_FATAL(napi_is_array(env, jsValue, &isInstanceof));
229             if (!isInstanceof) {
230                 return NotAssignable("Array");
231             }
232         }
233         return wArray_->CreateJSBuiltinProxy(ctxx, jsValue);
234     }
235 
MError(InteropCtx * ctxx,napi_value jsValue,bool verified=true)236     EtsObject *MError(InteropCtx *ctxx, napi_value jsValue, bool verified = true)
237     {
238         napi_env env = ctxx->GetJSEnv();
239         bool isInstanceof;
240         if (!verified) {
241             NAPI_CHECK_FATAL(napi_is_error(env, jsValue, &isInstanceof));
242             if (!isInstanceof) {
243                 return NotAssignable("Error");
244             }
245         }
246         // NOTE(vpukhov): compat: remove when compat/Error is implemented
247         return BuiltinConvert<JSConvertJSError>(ctxx, env, jsValue);
248 
249         if (CheckInstanceof(env, jsValue, ctorTypeError_)) {
250             NotImplemented("TypeError");
251         }
252         if (CheckInstanceof(env, jsValue, ctorRangeError_)) {
253             NotImplemented("RangeError");
254         }
255         if (CheckInstanceof(env, jsValue, ctorReferenceError_)) {
256             NotImplemented("ReferenceError");
257         }
258         NotImplemented("Error");
259     }
260 
MObjectObject(InteropCtx * ctxx,napi_value jsValue)261     EtsObject *MObjectObject(InteropCtx *ctxx, napi_value jsValue)
262     {
263         napi_env env = ctxx->GetJSEnv();
264         bool isInstanceof;
265         NAPI_CHECK_FATAL(napi_is_array(env, jsValue, &isInstanceof));
266         if (isInstanceof) {
267             return MArray(ctxx, jsValue);
268         }
269         NAPI_CHECK_FATAL(napi_is_arraybuffer(env, jsValue, &isInstanceof));
270         if (isInstanceof) {
271             return BuiltinConvert<JSConvertArrayBuffer>(ctxx, env, jsValue);
272         }
273         NAPI_CHECK_FATAL(napi_is_typedarray(env, jsValue, &isInstanceof));
274         if (isInstanceof) {
275             NotImplemented("TypedArray");
276         }
277         NAPI_CHECK_FATAL(napi_is_promise(env, jsValue, &isInstanceof));
278         if (isInstanceof) {
279             return BuiltinConvert<JSConvertPromise>(ctxx, env, jsValue);
280         }
281         NAPI_CHECK_FATAL(napi_is_error(env, jsValue, &isInstanceof));
282         if (isInstanceof) {
283             return MError(ctxx, jsValue);
284         }
285         NAPI_CHECK_FATAL(napi_is_date(env, jsValue, &isInstanceof));
286         if (isInstanceof) {
287             NotImplemented("Date");
288         }
289         NAPI_CHECK_FATAL(napi_is_dataview(env, jsValue, &isInstanceof));
290         if (isInstanceof) {
291             NotImplemented("DataView");
292         }
293         // NOTE(vpukhov): Boolean, Number...
294         return BuiltinConvert<JSConvertJSValue>(ctxx, env, jsValue);
295     }
296 
MObject(InteropCtx * ctxx,napi_value jsValue,bool verified=true)297     EtsObject *MObject(InteropCtx *ctxx, napi_value jsValue, bool verified = true)
298     {
299         napi_env env = ctxx->GetJSEnv();
300         (void)verified;  // ignored for Object
301 
302         napi_valuetype jsType = GetValueType(env, jsValue);
303         switch (jsType) {
304             case napi_boolean:
305                 return BuiltinConvert<JSConvertStdlibBoolean>(ctxx, env, jsValue);
306             case napi_number:
307                 return BuiltinConvert<JSConvertStdlibDouble>(ctxx, env, jsValue);
308             case napi_string:
309                 return BuiltinConvert<JSConvertString>(ctxx, env, jsValue);
310             case napi_object:
311                 return MObjectObject(ctx_, jsValue);
312             case napi_undefined:
313                 return ctx_->GetUndefinedObject();
314             case napi_symbol:
315                 [[fallthrough]];
316             case napi_function:
317                 [[fallthrough]];
318             case napi_external:
319                 [[fallthrough]];
320             case napi_bigint:
321                 return BuiltinConvert<JSConvertJSValue>(ctxx, env, jsValue);
322             default:
323                 ASSERT(!IsNullOrUndefined(env, jsValue));
324                 InteropCtx::Fatal("Bad jsType in Object value matcher");
325         };
326     }
327 
328 public:
CompatConvertorsRegisterer(InteropCtx * ctx)329     explicit CompatConvertorsRegisterer(InteropCtx *ctx) : ctx_(ctx)
330     {
331         auto env = ctx_->GetJSEnv();
332         NAPI_CHECK_FATAL(napi_create_object(env, &jsGlobalEts_));
333         NAPI_CHECK_FATAL(napi_set_named_property(env, GetGlobal(env), "ets", jsGlobalEts_));
334     }
335 
336     DEFAULT_MOVE_SEMANTIC(CompatConvertorsRegisterer);
337 
338     DEFAULT_COPY_SEMANTIC(CompatConvertorsRegisterer);
339 
340     ~CompatConvertorsRegisterer() = default;
341 
Run()342     void Run()
343     {
344         wObject_ = RegisterClass(descriptors::OBJECT, "Object");
345 
346         RegisterExceptions();
347 
348         RegisterArray();
349 
350         // NOTE(vpukhov): compat: obtain from class wrappers when implemented
351         ctorTypeError_ = StdCtorRef(ctx_, "TypeError");
352         ctorRangeError_ = StdCtorRef(ctx_, "RangeError");
353         ctorReferenceError_ = StdCtorRef(ctx_, "ReferenceError");
354 
355         ASSERT(wError_ != nullptr);
356         wError_->SetJSBuiltinMatcher(
357             [self = *this](InteropCtx *ctxx, napi_value jsValue, bool verified = true) mutable {
358                 return self.MError(ctxx, jsValue, verified);
359             });
360 
361         ASSERT(wObject_ != nullptr);
362         wObject_->SetJSBuiltinMatcher(
363             [self = *this](InteropCtx *ctxx, napi_value jsValue, bool verified = true) mutable {
364                 return self.MObject(ctxx, jsValue, verified);
365             });
366 
367         ASSERT(wArray_ != nullptr);
368         wArray_->SetJSBuiltinMatcher(
369             [self = *this](InteropCtx *ctxx, napi_value jsValue, bool verified = true) mutable {
370                 return self.MArray(ctxx, jsValue, verified);
371             });
372     }
373 
374 private:
375     InteropCtx *ctx_;
376     napi_value jsGlobalEts_ {};
377     ets_proxy::EtsClassWrapper *wError_ {};
378     ets_proxy::EtsClassWrapper *wObject_ {};
379     ets_proxy::EtsClassWrapper *wArray_ {};
380 
381     napi_ref ctorTypeError_ {nullptr};
382     napi_ref ctorRangeError_ {nullptr};
383     napi_ref ctorReferenceError_ {nullptr};
384 };
385 
386 static_assert(std::is_trivially_copy_constructible_v<CompatConvertorsRegisterer>);
387 static_assert(std::is_trivially_copy_assignable_v<CompatConvertorsRegisterer>);
388 static_assert(std::is_trivially_move_constructible_v<CompatConvertorsRegisterer>);
389 static_assert(std::is_trivially_move_assignable_v<CompatConvertorsRegisterer>);
390 static_assert(std::is_trivially_destructible_v<CompatConvertorsRegisterer>);
391 
392 }  // namespace
393 
RegisterCompatConvertors(InteropCtx * ctx)394 static void RegisterCompatConvertors(InteropCtx *ctx)
395 {
396     CompatConvertorsRegisterer(ctx).Run();
397 }
398 
RegisterBuiltinJSRefConvertors(InteropCtx * ctx)399 void RegisterBuiltinJSRefConvertors(InteropCtx *ctx)
400 {
401     auto cache = ctx->GetRefConvertCache();
402     auto coro = EtsCoroutine::GetCurrent();
403     PandaEtsVM *vm = coro->GetPandaVM();
404     EtsClassLinkerExtension *linkerExt = vm->GetClassLinker()->GetEtsClassLinkerExtension();
405 
406     RegisterBuiltinRefConvertor<JSConvertJSValue>(cache, ctx->GetJSValueClass());
407     RegisterBuiltinRefConvertor<JSConvertJSError>(cache, ctx->GetJSErrorClass());
408     RegisterBuiltinRefConvertor<JSConvertString>(cache, ctx->GetStringClass());
409     RegisterBuiltinRefConvertor<JSConvertBigInt>(cache, ctx->GetBigIntClass());
410     RegisterBuiltinRefConvertor<JSConvertPromise>(cache, ctx->GetPromiseClass());
411     RegisterBuiltinRefConvertor<JSConvertArrayBuffer>(cache, ctx->GetArrayBufferClass());
412     RegisterBuiltinRefConvertor<JSConvertEtsUndefined>(cache, ctx->GetUndefinedClass());
413 
414     RegisterBuiltinRefConvertor<JSConvertStdlibBoolean>(cache, linkerExt->GetBoxBooleanClass());
415     RegisterBuiltinRefConvertor<JSConvertStdlibByte>(cache, linkerExt->GetBoxByteClass());
416     RegisterBuiltinRefConvertor<JSConvertStdlibChar>(cache, linkerExt->GetBoxCharClass());
417     RegisterBuiltinRefConvertor<JSConvertStdlibShort>(cache, linkerExt->GetBoxShortClass());
418     RegisterBuiltinRefConvertor<JSConvertStdlibInt>(cache, linkerExt->GetBoxIntClass());
419     RegisterBuiltinRefConvertor<JSConvertStdlibLong>(cache, linkerExt->GetBoxLongClass());
420     RegisterBuiltinRefConvertor<JSConvertStdlibFloat>(cache, linkerExt->GetBoxFloatClass());
421     RegisterBuiltinRefConvertor<JSConvertStdlibDouble>(cache, linkerExt->GetBoxDoubleClass());
422 
423     RegisterBuiltinArrayConvertor<ClassRoot::ARRAY_U1, JSConvertU1>(cache, linkerExt);
424     RegisterBuiltinArrayConvertor<ClassRoot::ARRAY_I32, JSConvertI32>(cache, linkerExt);
425     RegisterBuiltinArrayConvertor<ClassRoot::ARRAY_F32, JSConvertF32>(cache, linkerExt);
426     RegisterBuiltinArrayConvertor<ClassRoot::ARRAY_I64, JSConvertI64>(cache, linkerExt);
427     RegisterBuiltinArrayConvertor<ClassRoot::ARRAY_F64, JSConvertF64>(cache, linkerExt);
428     RegisterBuiltinArrayConvertor<ClassRoot::ARRAY_STRING, JSConvertString>(cache, linkerExt);
429     // NOTE(vpukhov): jsvalue[] specialization, currently uses JSRefConvertArrayRef
430 
431     RegisterCompatConvertors(ctx);
432 }
433 
434 }  // namespace ark::ets::interop::js
435