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