• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/interop_context.h"
17 #include "plugins/ets/runtime/interop_js/interop_common.h"
18 
19 namespace ark::ets::interop::js {
20 
InteropFatal(const char * message)21 [[noreturn]] void InteropFatal(const char *message)
22 {
23     InteropCtx::Fatal(message);
24     UNREACHABLE();
25 }
26 
InteropFatal(const std::string & message)27 [[noreturn]] void InteropFatal(const std::string &message)
28 {
29     InteropCtx::Fatal(message.c_str());
30     UNREACHABLE();
31 }
32 
InteropFatal(const char * message,napi_status status)33 [[noreturn]] void InteropFatal(const char *message, napi_status status)
34 {
35     InteropCtx::Fatal(std::string(message) + " status=" + std::to_string(status));
36     UNREACHABLE();
37 }
38 
InteropTrace(const char * func,const char * file,int line)39 void InteropTrace(const char *func, const char *file, int line)
40 {
41     INTEROP_LOG(DEBUG) << "trace: " << func << ":" << file << ":" << line;
42 }
43 
GetBigInt(napi_env env,napi_value jsVal)44 std::pair<SmallVector<uint64_t, 4U>, int> GetBigInt(napi_env env, napi_value jsVal)
45 {
46     size_t wordCount;
47     NAPI_ASSERT_OK(napi_get_value_bigint_words(env, jsVal, nullptr, &wordCount, nullptr));
48 
49     int signBit;
50     SmallVector<uint64_t, 4U> words;
51     if (wordCount == 0) {
52         bool lossless;
53         signBit = 0;
54         words.resize(1);
55         NAPI_ASSERT_OK(napi_get_value_bigint_uint64(env, jsVal, &words[0], &lossless));
56     } else {
57         words.resize(wordCount);
58         NAPI_ASSERT_OK(napi_get_value_bigint_words(env, jsVal, &signBit, &wordCount, words.data()));
59     }
60 
61     return {words, signBit};
62 }
63 
ConvertBigIntArrayFromEtsToJs(const std::vector<uint32_t> & etsArray)64 SmallVector<uint64_t, 4U> ConvertBigIntArrayFromEtsToJs(const std::vector<uint32_t> &etsArray)
65 {
66     ASSERT(BIT_64 % BIGINT_BITS_NUM == 0);
67     // BigInt in ArkTS is stored in EtsInt array. Put these bits into int64_t array
68     size_t jsArraySize = etsArray.size() / 2 + etsArray.size() % 2;
69     SmallVector<uint64_t, 4U> jsArray;
70     jsArray.resize(jsArraySize, 0);
71 
72     size_t curJSArrayElemPos = 0;
73     size_t curBitPos = 0;
74     for (auto etsElem : etsArray) {
75         jsArray[curJSArrayElemPos] |= static_cast<uint64_t>(etsElem) << curBitPos;
76         curBitPos = curBitPos + BIGINT_BITS_NUM;
77         if (curBitPos == BIT_64) {
78             curBitPos = 0;
79             ++curJSArrayElemPos;
80         }
81     }
82 
83     return jsArray;
84 }
85 
GetBigIntEtsArraySize(size_t jsArraySize,uint64_t lastElem)86 static inline size_t GetBigIntEtsArraySize(size_t jsArraySize, uint64_t lastElem)
87 {
88     if (jsArraySize == 1 && lastElem == 0) {
89         return 0;
90     }
91 
92     size_t etsSize = jsArraySize * 2 - 1;
93 
94     if ((lastElem >> BIGINT_BITS_NUM) > 0) {
95         ++etsSize;
96     }
97 
98     return etsSize;
99 }
100 
ConvertBigIntArrayFromJsToEts(SmallVector<uint64_t,4U> & jsArray)101 std::vector<EtsInt> ConvertBigIntArrayFromJsToEts(SmallVector<uint64_t, 4U> &jsArray)
102 {
103     size_t etsArraySize = GetBigIntEtsArraySize(jsArray.size(), jsArray.back());
104     std::vector<EtsInt> etsArray(etsArraySize, 0);
105 
106     size_t curJSArrayElemPos = 0;
107     size_t curBitPos = 0;
108     for (size_t i = 0; i < etsArraySize; ++i) {
109         etsArray[i] = static_cast<uint32_t>(jsArray[curJSArrayElemPos] >> curBitPos);
110 
111         curBitPos = curBitPos + BIGINT_BITS_NUM;
112         if (curBitPos == BIT_64) {
113             curBitPos = 0;
114             ++curJSArrayElemPos;
115         }
116     }
117 
118     return etsArray;
119 }
120 
ThrowNoInteropContextException()121 void ThrowNoInteropContextException()
122 {
123     auto *thread = ManagedThread::GetCurrent();
124     ASSERT(thread != nullptr);
125     auto ctx = thread->GetVM()->GetLanguageContext();
126     auto descriptor = utf::CStringAsMutf8(panda_file_items::class_descriptors::NO_INTEROP_CONTEXT_ERROR.data());
127     PandaString msg = "Interop call may be done only from _main_ or exclusive worker";
128     ThrowException(ctx, thread, descriptor, utf::CStringAsMutf8(msg.c_str()));
129 }
130 
GetPropertyStatusHandling(napi_env env,napi_status rc)131 static bool GetPropertyStatusHandling([[maybe_unused]] napi_env env, napi_status rc)
132 {
133 #if !defined(PANDA_TARGET_OHOS) && !defined(PANDA_JS_ETS_HYBRID_MODE)
134     if (UNLIKELY(rc == napi_object_expected || NapiThrownGeneric(rc))) {
135         ASSERT(NapiIsExceptionPending(env));
136         return false;
137     }
138 #else
139     if (UNLIKELY(rc == napi_object_expected && !NapiIsExceptionPending(env))) {
140         InteropCtx::ThrowJSTypeError(env, "Cannot convert undefined or null to object");
141         return false;
142     }
143 
144     if (UNLIKELY(rc == napi_pending_exception || NapiThrownGeneric(rc))) {
145         ASSERT(NapiIsExceptionPending(env));
146         return false;
147     }
148 #endif
149     INTEROP_FATAL_IF(rc != napi_ok);
150     return true;
151 }
152 
NapiGetProperty(napi_env env,napi_value object,napi_value key,napi_value * result)153 bool NapiGetProperty(napi_env env, napi_value object, napi_value key, napi_value *result)
154 {
155     napi_status rc = napi_get_property(env, object, key, result);
156     return GetPropertyStatusHandling(env, rc);
157 }
158 
NapiGetNamedProperty(napi_env env,napi_value object,const char * utf8name,napi_value * result)159 bool NapiGetNamedProperty(napi_env env, napi_value object, const char *utf8name, napi_value *result)
160 {
161     napi_status rc = napi_get_named_property(env, object, utf8name, result);
162     return GetPropertyStatusHandling(env, rc);
163 }
164 
165 }  // namespace ark::ets::interop::js
166