• 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             // NOTE(kprokopenko) make [Lstd/core/Object;:D when #14756 is fixed
191             {utf::CStringAsMutf8("push"), "Lstd/core/Object;:D"},
192             {utf::CStringAsMutf8("some"), "Lstd/core/Function1;:Z"},
193             {utf::CStringAsMutf8("sort"), ":Lescompat/Array;"},
194             {utf::CStringAsMutf8("every"), "Lstd/core/Function1;:Z"},
195             {utf::CStringAsMutf8("shift"), ":Lstd/core/Object;"},
196             {utf::CStringAsMutf8("slice"), "Lstd/core/Object;Lstd/core/Object;:Lescompat/Array;"},
197             {utf::CStringAsMutf8("<ctor>"), ":V"},
198             {utf::CStringAsMutf8("filter"), "Lstd/core/Function1;:Lescompat/Array;"},
199             {utf::CStringAsMutf8("<get>length"), ":D"},
200             {utf::CStringAsMutf8("reduce"), "Lstd/core/Function2;:Lstd/core/Object;"},
201             {utf::CStringAsMutf8("splice"), "DLstd/core/Object;[Lstd/core/Object;:Lescompat/Array;"},
202             {utf::CStringAsMutf8("findLast"), "Lstd/core/Function1;:Lstd/core/Object;"},
203             {utf::CStringAsMutf8("toSorted"), ":Lescompat/Array;"},
204             {utf::CStringAsMutf8("findIndex"), "Lstd/core/Function1;:D"},
205             {utf::CStringAsMutf8("findLastIndex"), "Lstd/core/Function1;:D"},
206             {utf::CStringAsMutf8("toSpliced"), "Lstd/core/Object;Lstd/core/Object;:Lescompat/Array;"},
207             {utf::CStringAsMutf8("copyWithin"), "II:Lescompat/Array;"},
208             {utf::CStringAsMutf8("toReversed"), ":Lescompat/Array;"},
209             {utf::CStringAsMutf8("indexOf"), "Lstd/core/Object;Lstd/core/Object;:D"},
210             {utf::CStringAsMutf8("includes"), "Lstd/core/Object;Lstd/core/Object;:Z"},
211             {utf::CStringAsMutf8("lastIndexOf"), "Lstd/core/Object;Lstd/core/Object;:D"},
212             {utf::CStringAsMutf8("reduceRight"), "Lstd/core/Function2;:Lstd/core/Object;"},
213             {utf::CStringAsMutf8("find"), "Lstd/core/Function1;:Lstd/core/Object;"},
214             {utf::CStringAsMutf8("isArray"), "Lstd/core/Object;:Z"},
215             {utf::CStringAsMutf8("flatMap"), "Lstd/core/Function2;:Lescompat/Array;"},
216             {utf::CStringAsMutf8("toLocaleString"), ":Lstd/core/String;"},
217             {utf::CStringAsMutf8("from"), "Lescompat/Iterable;:Lescompat/Array;"},
218         };
219         wArray_ = RegisterClass(descriptors::ARRAY, "Array", &W_ARRAY_OVERLOADS);
220 
221         NAPI_CHECK_FATAL(napi_object_seal(ctx_->GetJSEnv(), jsGlobalEts_));
222     }
223 
MArray(InteropCtx * ctxx,napi_value jsValue,bool verified=true)224     EtsObject *MArray(InteropCtx *ctxx, napi_value jsValue, bool verified = true)
225     {
226         napi_env env = ctxx->GetJSEnv();
227         bool isInstanceof;
228         if (!verified) {
229             NAPI_CHECK_FATAL(napi_is_array(env, jsValue, &isInstanceof));
230             if (!isInstanceof) {
231                 return NotAssignable("Array");
232             }
233         }
234         return wArray_->CreateJSBuiltinProxy(ctxx, jsValue);
235     }
236 
MError(InteropCtx * ctxx,napi_value jsValue,bool verified=true)237     EtsObject *MError(InteropCtx *ctxx, napi_value jsValue, bool verified = true)
238     {
239         napi_env env = ctxx->GetJSEnv();
240         bool isInstanceof;
241         if (!verified) {
242             NAPI_CHECK_FATAL(napi_is_error(env, jsValue, &isInstanceof));
243             if (!isInstanceof) {
244                 return NotAssignable("Error");
245             }
246         }
247         // NOTE(vpukhov): compat: remove when compat/Error is implemented
248         return BuiltinConvert<JSConvertJSError>(ctxx, env, jsValue);
249 
250         if (CheckInstanceof(env, jsValue, ctorTypeError_)) {
251             NotImplemented("TypeError");
252         }
253         if (CheckInstanceof(env, jsValue, ctorRangeError_)) {
254             NotImplemented("RangeError");
255         }
256         if (CheckInstanceof(env, jsValue, ctorReferenceError_)) {
257             NotImplemented("ReferenceError");
258         }
259         NotImplemented("Error");
260     }
261 
MObjectObject(InteropCtx * ctxx,napi_value jsValue)262     EtsObject *MObjectObject(InteropCtx *ctxx, napi_value jsValue)
263     {
264         napi_env env = ctxx->GetJSEnv();
265         bool isInstanceof;
266         NAPI_CHECK_FATAL(napi_is_array(env, jsValue, &isInstanceof));
267         if (isInstanceof) {
268             return MArray(ctxx, jsValue);
269         }
270         NAPI_CHECK_FATAL(napi_is_arraybuffer(env, jsValue, &isInstanceof));
271         if (isInstanceof) {
272             return BuiltinConvert<JSConvertArrayBuffer>(ctxx, env, jsValue);
273         }
274         NAPI_CHECK_FATAL(napi_is_typedarray(env, jsValue, &isInstanceof));
275         if (isInstanceof) {
276             NotImplemented("TypedArray");
277         }
278         NAPI_CHECK_FATAL(napi_is_promise(env, jsValue, &isInstanceof));
279         if (isInstanceof) {
280             return BuiltinConvert<JSConvertPromise>(ctxx, env, jsValue);
281         }
282         NAPI_CHECK_FATAL(napi_is_error(env, jsValue, &isInstanceof));
283         if (isInstanceof) {
284             return MError(ctxx, jsValue);
285         }
286         NAPI_CHECK_FATAL(napi_is_date(env, jsValue, &isInstanceof));
287         if (isInstanceof) {
288             NotImplemented("Date");
289         }
290         NAPI_CHECK_FATAL(napi_is_dataview(env, jsValue, &isInstanceof));
291         if (isInstanceof) {
292             NotImplemented("DataView");
293         }
294         // NOTE(vpukhov): Boolean, Number...
295         return BuiltinConvert<JSConvertJSValue>(ctxx, env, jsValue);
296     }
297 
MObject(InteropCtx * ctxx,napi_value jsValue,bool verified=true)298     EtsObject *MObject(InteropCtx *ctxx, napi_value jsValue, bool verified = true)
299     {
300         napi_env env = ctxx->GetJSEnv();
301         (void)verified;  // ignored for Object
302 
303         napi_valuetype jsType = GetValueType(env, jsValue);
304         switch (jsType) {
305             case napi_boolean:
306                 return BuiltinConvert<JSConvertStdlibBoolean>(ctxx, env, jsValue);
307             case napi_number:
308                 return BuiltinConvert<JSConvertStdlibDouble>(ctxx, env, jsValue);
309             case napi_string:
310                 return BuiltinConvert<JSConvertString>(ctxx, env, jsValue);
311             case napi_object:
312                 return MObjectObject(ctx_, jsValue);
313             case napi_undefined:
314                 return ctx_->GetUndefinedObject();
315             case napi_symbol:
316                 [[fallthrough]];
317             case napi_function:
318                 [[fallthrough]];
319             case napi_external:
320                 [[fallthrough]];
321             case napi_bigint:
322                 return BuiltinConvert<JSConvertJSValue>(ctxx, env, jsValue);
323             default:
324                 ASSERT(!IsNullOrUndefined(env, jsValue));
325                 InteropCtx::Fatal("Bad jsType in Object value matcher");
326         };
327     }
328 
329 public:
CompatConvertorsRegisterer(InteropCtx * ctx)330     explicit CompatConvertorsRegisterer(InteropCtx *ctx) : ctx_(ctx)
331     {
332         auto env = ctx_->GetJSEnv();
333         NAPI_CHECK_FATAL(napi_create_object(env, &jsGlobalEts_));
334         NAPI_CHECK_FATAL(napi_set_named_property(env, GetGlobal(env), "ets", jsGlobalEts_));
335     }
336 
337     DEFAULT_MOVE_SEMANTIC(CompatConvertorsRegisterer);
338 
339     DEFAULT_COPY_SEMANTIC(CompatConvertorsRegisterer);
340 
341     ~CompatConvertorsRegisterer() = default;
342 
Run()343     void Run()
344     {
345         wObject_ = RegisterClass(descriptors::OBJECT, "Object");
346 
347         RegisterExceptions();
348 
349         RegisterArray();
350 
351         // NOTE(vpukhov): compat: obtain from class wrappers when implemented
352         ctorTypeError_ = StdCtorRef(ctx_, "TypeError");
353         ctorRangeError_ = StdCtorRef(ctx_, "RangeError");
354         ctorReferenceError_ = StdCtorRef(ctx_, "ReferenceError");
355 
356         ASSERT(wError_ != nullptr);
357         wError_->SetJSBuiltinMatcher(
358             [self = *this](InteropCtx *ctxx, napi_value jsValue, bool verified = true) mutable {
359                 return self.MError(ctxx, jsValue, verified);
360             });
361 
362         ASSERT(wObject_ != nullptr);
363         wObject_->SetJSBuiltinMatcher(
364             [self = *this](InteropCtx *ctxx, napi_value jsValue, bool verified = true) mutable {
365                 return self.MObject(ctxx, jsValue, verified);
366             });
367 
368         ASSERT(wArray_ != nullptr);
369         wArray_->SetJSBuiltinMatcher(
370             [self = *this](InteropCtx *ctxx, napi_value jsValue, bool verified = true) mutable {
371                 return self.MArray(ctxx, jsValue, verified);
372             });
373     }
374 
375 private:
376     InteropCtx *ctx_;
377     napi_value jsGlobalEts_ {};
378     ets_proxy::EtsClassWrapper *wError_ {};
379     ets_proxy::EtsClassWrapper *wObject_ {};
380     ets_proxy::EtsClassWrapper *wArray_ {};
381 
382     napi_ref ctorTypeError_ {nullptr};
383     napi_ref ctorRangeError_ {nullptr};
384     napi_ref ctorReferenceError_ {nullptr};
385 };
386 
387 static_assert(std::is_trivially_copy_constructible_v<CompatConvertorsRegisterer>);
388 static_assert(std::is_trivially_copy_assignable_v<CompatConvertorsRegisterer>);
389 static_assert(std::is_trivially_move_constructible_v<CompatConvertorsRegisterer>);
390 static_assert(std::is_trivially_move_assignable_v<CompatConvertorsRegisterer>);
391 static_assert(std::is_trivially_destructible_v<CompatConvertorsRegisterer>);
392 
393 }  // namespace
394 
RegisterCompatConvertors(InteropCtx * ctx)395 static void RegisterCompatConvertors(InteropCtx *ctx)
396 {
397     CompatConvertorsRegisterer(ctx).Run();
398 }
399 
RegisterBuiltinJSRefConvertors(InteropCtx * ctx)400 void RegisterBuiltinJSRefConvertors(InteropCtx *ctx)
401 {
402     auto cache = ctx->GetRefConvertCache();
403     auto coro = EtsCoroutine::GetCurrent();
404     PandaEtsVM *vm = coro->GetPandaVM();
405     EtsClassLinkerExtension *linkerExt = vm->GetClassLinker()->GetEtsClassLinkerExtension();
406 
407     RegisterBuiltinRefConvertor<JSConvertJSValue>(cache, ctx->GetJSValueClass());
408     RegisterBuiltinRefConvertor<JSConvertJSError>(cache, ctx->GetJSErrorClass());
409     RegisterBuiltinRefConvertor<JSConvertString>(cache, ctx->GetStringClass());
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