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