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