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/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
GetBigIntJSArraySize(size_t etsArraySize,uint64_t lastElem)64 static inline size_t GetBigIntJSArraySize(size_t etsArraySize, uint64_t lastElem)
65 {
66 size_t bitsNum = (etsArraySize - 1) * BIGINT_BITS_NUM;
67 size_t tailBits = 0;
68
69 while (lastElem > 0) {
70 lastElem >>= 1U;
71 ++tailBits;
72 }
73 bitsNum += tailBits;
74 return (bitsNum + BIT_64 - 1) / BIT_64;
75 }
76
ConvertBigIntArrayFromEtsToJs(const std::vector<uint32_t> & etsArray)77 SmallVector<uint64_t, 4U> ConvertBigIntArrayFromEtsToJs(const std::vector<uint32_t> &etsArray)
78 {
79 // BigInt in ArkTS is stored in EtsInt array but only 30 bits have meaning. Put these bits into int64_t array
80 size_t jsArraySize = GetBigIntJSArraySize(etsArray.size(), etsArray.back());
81 SmallVector<uint64_t, 4U> jsArray;
82 jsArray.resize(jsArraySize, 0);
83
84 size_t curJSArrayElemPos = 0;
85 size_t curBitPos = 0;
86 for (auto etsElem : etsArray) {
87 jsArray[curJSArrayElemPos] |= static_cast<uint64_t>(etsElem) << curBitPos;
88 if (curBitPos + BIGINT_BITS_NUM <= BIT_64) {
89 curBitPos = curBitPos + BIGINT_BITS_NUM;
90 } else {
91 if (++curJSArrayElemPos != jsArray.size()) {
92 size_t leftoverBitNums = BIT_64 - curBitPos;
93 jsArray[curJSArrayElemPos] |= static_cast<uint32_t>(etsElem) >> leftoverBitNums;
94 curBitPos = BIGINT_BITS_NUM - leftoverBitNums;
95 }
96 }
97 }
98
99 return jsArray;
100 }
101
GetBigIntEtsArraySize(size_t jsArraySize,uint64_t lastElem)102 static inline size_t GetBigIntEtsArraySize(size_t jsArraySize, uint64_t lastElem)
103 {
104 size_t bitsNum = (jsArraySize - 1) * BIT_64;
105 size_t tailBits = 0;
106
107 while (lastElem > 0) {
108 lastElem >>= 1U;
109 ++tailBits;
110 }
111 bitsNum += tailBits;
112 return (bitsNum + BIGINT_BITS_NUM - 1) / BIGINT_BITS_NUM;
113 }
114
ConvertToTwosComplement(std::vector<EtsInt> & array)115 static inline void ConvertToTwosComplement(std::vector<EtsInt> &array)
116 {
117 uint8_t extraBit = 1;
118 for (auto &elem : array) {
119 elem = (~static_cast<uint32_t>(elem) + extraBit) & BIGINT_BITMASK_30;
120 if (elem != 0) {
121 extraBit = 0;
122 }
123 }
124 }
125
ConvertBigIntArrayFromJsToEts(SmallVector<uint64_t,4U> & jsArray,int signBit)126 std::vector<EtsInt> ConvertBigIntArrayFromJsToEts(SmallVector<uint64_t, 4U> &jsArray, int signBit)
127 {
128 size_t etsArraySize = GetBigIntEtsArraySize(jsArray.size(), jsArray.back());
129 std::vector<EtsInt> etsArray(etsArraySize + 1, 0);
130
131 size_t curJSArrayElemPos = 0;
132 size_t curBitPos = 0;
133 for (size_t i = 0; i < etsArraySize; ++i) {
134 auto etsElem = static_cast<uint32_t>(jsArray[curJSArrayElemPos] >> curBitPos);
135
136 if (curBitPos + BIGINT_BITS_NUM <= BIT_64) {
137 curBitPos = curBitPos + BIGINT_BITS_NUM;
138 } else {
139 if (++curJSArrayElemPos != jsArray.size()) {
140 size_t leftoverBitNums = BIT_64 - curBitPos;
141 etsElem |= static_cast<uint32_t>(jsArray[curJSArrayElemPos]) << leftoverBitNums;
142 curBitPos = BIGINT_BITS_NUM - leftoverBitNums;
143 }
144 }
145
146 etsArray[i] = etsElem & BIGINT_BITMASK_30;
147 }
148
149 if (signBit == 1) {
150 ConvertToTwosComplement(etsArray);
151 }
152 etsArray.back() = (signBit == 1) ? BIGINT_BITMASK_30 : 0;
153
154 return etsArray;
155 }
156
157 } // namespace ark::ets::interop::js
158
159 namespace ark::ets::ts2ets::GlobalCtx { // NOLINT(readability-identifier-naming)
160
Init()161 void Init()
162 {
163 interop::js::InteropCtx::Init(EtsCoroutine::GetCurrent(), nullptr);
164 }
165
166 } // namespace ark::ets::ts2ets::GlobalCtx
167