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/interop_js/js_value.h"
17 #include "plugins/ets/runtime/interop_js/js_convert.h"
18 #include "plugins/ets/runtime/types/ets_method.h"
19 #include "runtime/mem/local_object_handle.h"
20
21 namespace ark::ets::interop::js {
22
AttachFinalizer(EtsCoroutine * coro,JSValue * jsValue)23 [[nodiscard]] JSValue *JSValue::AttachFinalizer(EtsCoroutine *coro, JSValue *jsValue)
24 {
25 ASSERT(JSValue::IsFinalizableType(jsValue->GetType()));
26
27 auto ctx = InteropCtx::Current(coro);
28 if (ctx == nullptr) {
29 ThrowNoInteropContextException();
30 return nullptr;
31 }
32
33 LocalObjectHandle<JSValue> handle(coro, jsValue);
34
35 JSValue *mirror = AllocUndefined(coro, ctx);
36 if (UNLIKELY(mirror == nullptr)) {
37 FinalizeETSWeak(ctx, handle.GetPtr());
38 return nullptr;
39 }
40 mirror->type_ = handle->type_;
41 mirror->data_ = handle->data_;
42
43 if (UNLIKELY(!ctx->PushOntoFinalizationRegistry(coro, handle.GetPtr(), mirror))) {
44 FinalizeETSWeak(ctx, handle.GetPtr());
45 return nullptr;
46 }
47 return handle.GetPtr();
48 }
49
FinalizeETSWeak(InteropCtx * ctx,EtsObject * cbarg)50 void JSValue::FinalizeETSWeak(InteropCtx *ctx, EtsObject *cbarg)
51 {
52 auto jsValue = JSValue::FromEtsObject(cbarg);
53 ASSERT(JSValue::IsFinalizableType(jsValue->GetType()));
54
55 auto type = jsValue->GetType();
56 switch (type) {
57 case napi_string:
58 ctx->GetStringStor()->Release(jsValue->GetString());
59 return;
60 case napi_symbol:
61 [[fallthrough]];
62 case napi_object:
63 [[fallthrough]];
64 case napi_function:
65 NAPI_CHECK_FATAL(napi_delete_reference(ctx->GetJSEnv(), jsValue->GetNapiRef(ctx->GetJSEnv())));
66 return;
67 case napi_bigint:
68 delete jsValue->GetBigInt();
69 return;
70 default:
71 InteropCtx::Fatal("Finalizer called for non-finalizable type: " + std::to_string(type));
72 }
73 UNREACHABLE();
74 }
75
CreateByType(InteropCtx * ctx,napi_env env,napi_value nvalue,napi_valuetype jsType,JSValue * jsvalue)76 JSValue *JSValue::CreateByType(InteropCtx *ctx, napi_env env, napi_value nvalue, napi_valuetype jsType,
77 JSValue *jsvalue)
78 {
79 switch (jsType) {
80 case napi_undefined: {
81 jsvalue->SetUndefined();
82 return jsvalue;
83 }
84 case napi_null: {
85 jsvalue->SetNull();
86 return jsvalue;
87 }
88 case napi_boolean: {
89 bool v;
90 NAPI_ASSERT_OK(napi_get_value_bool(env, nvalue, &v));
91 jsvalue->SetBoolean(v);
92 return jsvalue;
93 }
94 case napi_number: {
95 double v;
96 NAPI_ASSERT_OK(napi_get_value_double(env, nvalue, &v));
97 jsvalue->SetNumber(v);
98 return jsvalue;
99 }
100 case napi_string: {
101 auto cachedStr = ctx->GetStringStor()->Get(interop::js::GetString(env, nvalue));
102 jsvalue->SetString(cachedStr);
103 return JSValue::AttachFinalizer(EtsCoroutine::GetCurrent(), jsvalue);
104 }
105 case napi_bigint: {
106 jsvalue->SetBigInt(interop::js::GetBigInt(env, nvalue));
107 return JSValue::AttachFinalizer(EtsCoroutine::GetCurrent(), jsvalue);
108 }
109 case napi_symbol:
110 [[fallthrough]];
111 case napi_object:
112 [[fallthrough]];
113 case napi_function:
114 [[fallthrough]];
115 case napi_external: {
116 jsvalue->SetRefValue(ctx, nvalue, jsType);
117 return jsvalue;
118 }
119 default: {
120 InteropCtx::Fatal("Unsupported JSValue.Type: " + std::to_string(jsType));
121 }
122 }
123 UNREACHABLE();
124 }
Create(EtsCoroutine * coro,InteropCtx * ctx,napi_value nvalue)125 JSValue *JSValue::Create(EtsCoroutine *coro, InteropCtx *ctx, napi_value nvalue)
126 {
127 auto env = ctx->GetJSEnv();
128 napi_valuetype jsType = GetValueType(env, nvalue);
129
130 auto jsvalue = AllocUndefined(coro, ctx);
131 if (UNLIKELY(jsvalue == nullptr)) {
132 return nullptr;
133 }
134
135 return CreateByType(ctx, env, nvalue, jsType, jsvalue);
136 }
137
GetNapiValue(napi_env env)138 napi_value JSValue::GetNapiValue(napi_env env)
139 {
140 napi_value jsValue {};
141
142 auto jsType = GetType();
143 switch (jsType) {
144 case napi_undefined: {
145 NAPI_ASSERT_OK(napi_get_undefined(env, &jsValue));
146 return jsValue;
147 }
148 case napi_null: {
149 NAPI_ASSERT_OK(napi_get_null(env, &jsValue));
150 return jsValue;
151 }
152 case napi_boolean: {
153 NAPI_ASSERT_OK(napi_get_boolean(env, GetBoolean(), &jsValue));
154 return jsValue;
155 }
156 case napi_number: {
157 NAPI_ASSERT_OK(napi_create_double(env, GetNumber(), &jsValue));
158 return jsValue;
159 }
160 case napi_string: {
161 std::string const *str = GetString().Data();
162 NAPI_ASSERT_OK(napi_create_string_utf8(env, str->data(), str->size(), &jsValue));
163 return jsValue;
164 }
165 case napi_bigint: {
166 auto [words, signBit] = *GetBigInt();
167 NAPI_ASSERT_OK(napi_create_bigint_words(env, signBit, words.size(), words.data(), &jsValue));
168 return jsValue;
169 }
170 case napi_symbol:
171 [[fallthrough]];
172 case napi_object:
173 [[fallthrough]];
174 case napi_function:
175 [[fallthrough]];
176 case napi_external: {
177 return GetRefValue(env);
178 }
179 default: {
180 InteropCtx::Fatal("Unsupported JSValue.Type: " + std::to_string(jsType));
181 }
182 }
183 UNREACHABLE();
184 }
185
186 } // namespace ark::ets::interop::js
187