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 default:
64 InteropCtx::Fatal("Finalizer called for non-finalizable type: " + std::to_string(type));
65 }
66 UNREACHABLE();
67 }
68
Create(EtsCoroutine * coro,InteropCtx * ctx,napi_value nvalue)69 JSValue *JSValue::Create(EtsCoroutine *coro, InteropCtx *ctx, napi_value nvalue)
70 {
71 auto env = ctx->GetJSEnv();
72 napi_valuetype jsType = GetValueType(env, nvalue);
73
74 auto jsvalue = AllocUndefined(coro, ctx);
75 if (UNLIKELY(jsvalue == nullptr)) {
76 return nullptr;
77 }
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_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 }
121
GetNapiValue(napi_env env)122 napi_value JSValue::GetNapiValue(napi_env env)
123 {
124 napi_value jsValue {};
125
126 auto jsType = GetType();
127 switch (jsType) {
128 case napi_undefined: {
129 NAPI_ASSERT_OK(napi_get_undefined(env, &jsValue));
130 return jsValue;
131 }
132 case napi_null: {
133 NAPI_ASSERT_OK(napi_get_null(env, &jsValue));
134 return jsValue;
135 }
136 case napi_boolean: {
137 NAPI_ASSERT_OK(napi_get_boolean(env, GetBoolean(), &jsValue));
138 return jsValue;
139 }
140 case napi_number: {
141 NAPI_ASSERT_OK(napi_create_double(env, GetNumber(), &jsValue));
142 return jsValue;
143 }
144 case napi_string: {
145 std::string const *str = GetString().Data();
146 NAPI_ASSERT_OK(napi_create_string_utf8(env, str->data(), str->size(), &jsValue));
147 return jsValue;
148 }
149 case napi_symbol:
150 [[fallthrough]];
151 case napi_object:
152 [[fallthrough]];
153 case napi_function:
154 [[fallthrough]];
155 case napi_external: {
156 return GetRefValue(env);
157 }
158 default: {
159 InteropCtx::Fatal("Unsupported JSValue.Type: " + std::to_string(jsType));
160 }
161 }
162 UNREACHABLE();
163 }
164
165 } // namespace ark::ets::interop::js
166