• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <cstdint>
17 #include <optional>
18 #include <sstream>
19 #include <string>
20 #include <utility>
21 #include "libpandabase/macros.h"
22 #include "libpandabase/os/mutex.h"
23 #include "runtime/include/runtime.h"
24 #include "runtime/include/panda_vm.h"
25 #include "runtime/include/object_header.h"
26 #include "plugins/ets/runtime/ets_vm.h"
27 #include "plugins/ets/runtime/types/ets_array.h"
28 #include "plugins/ets/runtime/types/ets_shared_memory.h"
29 #include "plugins/ets/runtime/types/ets_shared_memory-inl.h"
30 #include "plugins/ets/runtime/ets_coroutine.h"
31 
32 namespace ark::ets::intrinsics {
33 
34 // NOLINTBEGIN(cppcoreguidelines-macro-usage)
35 #define SHARED_MEMORY_AT(type, postfix)                                          \
36     extern "C" type SharedMemoryAt##postfix(EtsSharedMemory *mem, int32_t index) \
37     {                                                                            \
38         return mem->GetElement<type>(index);                                     \
39     }
40 
41 #define SHARED_MEMORY_SET(type, postfix)                                                      \
42     extern "C" void SharedMemorySet##postfix(EtsSharedMemory *mem, int32_t index, type value) \
43     {                                                                                         \
44         mem->SetElement<type>(index, value);                                                  \
45     }
46 
47 #define SHARED_MEMORY_ADD(type, postfix)                                                      \
48     extern "C" type SharedMemoryAdd##postfix(EtsSharedMemory *mem, int32_t index, type value) \
49     {                                                                                         \
50         auto add = [value](type oldValue) { return oldValue + value; };                       \
51         auto result = mem->ReadModifyWrite<type>(index, add);                                 \
52         return result.first;                                                                  \
53     }
54 
55 #define SHARED_MEMORY_AND_SIGNED(type, postfix)                                                   \
56     extern "C" type SharedMemoryAnd##postfix(EtsSharedMemory *mem, int32_t index, type value)     \
57     {                                                                                             \
58         auto bitwiseAnd = [value](type oldValue) {                                                \
59             return static_cast<type>((bit_cast<u##type>(oldValue)) & (bit_cast<u##type>(value))); \
60         };                                                                                        \
61         auto result = mem->ReadModifyWrite<type>(index, bitwiseAnd);                              \
62         return result.first;                                                                      \
63     }
64 
65 #define SHARED_MEMORY_AND_UNSIGNED(type, postfix)                                                     \
66     extern "C" type SharedMemoryAnd##postfix(EtsSharedMemory *mem, int32_t index, type value)         \
67     {                                                                                                 \
68         auto bitwiseAnd = [value](type oldValue) { return static_cast<type>((oldValue) & (value)); }; \
69         auto result = mem->ReadModifyWrite<type>(index, bitwiseAnd);                                  \
70         return result.first;                                                                          \
71     }
72 
73 #define SHARED_MEMORY_COMPARE_EXCHANGE(type, postfix)                                                             \
74     extern "C" type SharedMemoryCompareExchange##postfix(EtsSharedMemory *mem, int32_t index, type expectedValue, \
75                                                          type replacementValue)                                   \
76     {                                                                                                             \
77         auto compareExchange = [expectedValue, replacementValue](type oldValue) {                                 \
78             return oldValue == expectedValue ? replacementValue : oldValue;                                       \
79         };                                                                                                        \
80         auto result = mem->ReadModifyWrite<type>(index, compareExchange);                                         \
81         return result.first;                                                                                      \
82     }
83 
84 #define SHARED_MEMORY_EXCHANGE(type, postfix)                                                      \
85     extern "C" type SharedMemoryExchange##postfix(EtsSharedMemory *mem, int32_t index, type value) \
86     {                                                                                              \
87         auto exchange = [value]([[maybe_unused]] type oldValue) { return value; };                 \
88         auto result = mem->ReadModifyWrite<type>(index, exchange);                                 \
89         return result.first;                                                                       \
90     }
91 
92 #define SHARED_MEMORY_LOAD(type, postfix)                                          \
93     extern "C" type SharedMemoryLoad##postfix(EtsSharedMemory *mem, int32_t index) \
94     {                                                                              \
95         auto load = [](type value) { return value; };                              \
96         auto result = mem->ReadModifyWrite<type>(index, load);                     \
97         return result.first;                                                       \
98     }
99 
100 #define SHARED_MEMORY_OR_SIGNED(type, postfix)                                                    \
101     extern "C" type SharedMemoryOr##postfix(EtsSharedMemory *mem, int32_t index, type value)      \
102     {                                                                                             \
103         auto orBitwise = [value](type oldValue) {                                                 \
104             return static_cast<type>((bit_cast<u##type>(oldValue)) | (bit_cast<u##type>(value))); \
105         };                                                                                        \
106         auto result = mem->ReadModifyWrite<type>(index, orBitwise);                               \
107         return result.first;                                                                      \
108     }
109 
110 #define SHARED_MEMORY_OR_UNSIGNED(type, postfix)                                                     \
111     extern "C" type SharedMemoryOr##postfix(EtsSharedMemory *mem, int32_t index, type value)         \
112     {                                                                                                \
113         auto orBitwise = [value](type oldValue) { return static_cast<type>((oldValue) | (value)); }; \
114         auto result = mem->ReadModifyWrite<type>(index, orBitwise);                                  \
115         return result.first;                                                                         \
116     }
117 
118 #define SHARED_MEMORY_STORE(type, postfix)                                                      \
119     extern "C" type SharedMemoryStore##postfix(EtsSharedMemory *mem, int32_t index, type value) \
120     {                                                                                           \
121         auto store = [value]([[maybe_unused]] type oldValue) { return value; };                 \
122         auto result = mem->ReadModifyWrite<type>(index, store);                                 \
123         return result.second;                                                                   \
124     }
125 
126 #define SHARED_MEMORY_SUB(type, postfix)                                                      \
127     extern "C" type SharedMemorySub##postfix(EtsSharedMemory *mem, int32_t index, type value) \
128     {                                                                                         \
129         auto add = [value](type oldValue) { return oldValue - value; };                       \
130         auto result = mem->ReadModifyWrite<type>(index, add);                                 \
131         return result.first;                                                                  \
132     }
133 
134 #define SHARED_MEMORY_XOR_SIGNED(type, postfix)                                                   \
135     extern "C" type SharedMemoryXor##postfix(EtsSharedMemory *mem, int32_t index, type value)     \
136     {                                                                                             \
137         auto xorBitwise = [value](type oldValue) {                                                \
138             return static_cast<type>((bit_cast<u##type>(oldValue)) ^ (bit_cast<u##type>(value))); \
139         };                                                                                        \
140         auto result = mem->ReadModifyWrite<type>(index, xorBitwise);                              \
141         return result.first;                                                                      \
142     }
143 
144 #define SHARED_MEMORY_XOR_UNSIGNED(type, postfix)                                                     \
145     extern "C" type SharedMemoryXor##postfix(EtsSharedMemory *mem, int32_t index, type value)         \
146     {                                                                                                 \
147         auto xorBitwise = [value](type oldValue) { return static_cast<type>((oldValue) ^ (value)); }; \
148         auto result = mem->ReadModifyWrite<type>(index, xorBitwise);                                  \
149         return result.first;                                                                          \
150     }
151 
152 #define FOR_ALL_TYPES(sharedMemoryMethod)                                                                     \
153     SHARED_MEMORY_##sharedMemoryMethod(int8_t, I8) SHARED_MEMORY_##sharedMemoryMethod(int16_t, I16)           \
154         SHARED_MEMORY_##sharedMemoryMethod(int32_t, I32) SHARED_MEMORY_##sharedMemoryMethod(int64_t, I64)     \
155             SHARED_MEMORY_##sharedMemoryMethod(uint8_t, U8) SHARED_MEMORY_##sharedMemoryMethod(uint16_t, U16) \
156                 SHARED_MEMORY_##sharedMemoryMethod(uint32_t, U32) SHARED_MEMORY_##sharedMemoryMethod(uint64_t, U64)
157 
158 #define FOR_SIGNED_TYPES(sharedMemoryMethod)                                                        \
159     SHARED_MEMORY_##sharedMemoryMethod(int8_t, I8) SHARED_MEMORY_##sharedMemoryMethod(int16_t, I16) \
160         SHARED_MEMORY_##sharedMemoryMethod(int32_t, I32) SHARED_MEMORY_##sharedMemoryMethod(int64_t, I64)
161 
162 #define FOR_UNSIGNED_TYPES(sharedMemoryMethod)                                                        \
163     SHARED_MEMORY_##sharedMemoryMethod(uint8_t, U8) SHARED_MEMORY_##sharedMemoryMethod(uint16_t, U16) \
164         SHARED_MEMORY_##sharedMemoryMethod(uint32_t, U32) SHARED_MEMORY_##sharedMemoryMethod(uint64_t, U64)
165 
166 // NOLINTEND(cppcoreguidelines-macro-usage)
167 
168 FOR_ALL_TYPES(AT)
FOR_ALL_TYPES(SET)169 FOR_ALL_TYPES(SET)
170 FOR_ALL_TYPES(ADD)
171 FOR_ALL_TYPES(COMPARE_EXCHANGE)
172 FOR_ALL_TYPES(EXCHANGE)
173 FOR_ALL_TYPES(LOAD)
174 FOR_ALL_TYPES(STORE)
175 FOR_ALL_TYPES(SUB)
176 FOR_SIGNED_TYPES(OR_SIGNED)
177 FOR_UNSIGNED_TYPES(OR_UNSIGNED)
178 FOR_SIGNED_TYPES(AND_SIGNED)
179 FOR_UNSIGNED_TYPES(AND_UNSIGNED)
180 FOR_SIGNED_TYPES(XOR_SIGNED)
181 FOR_UNSIGNED_TYPES(XOR_UNSIGNED)
182 
183 extern "C" EtsSharedMemory *SharedMemoryCreate(int32_t byteLength)
184 {
185     return EtsSharedMemory::Create(byteLength);
186 }
187 
SharedMemoryGetByteLength(EtsSharedMemory * mem)188 extern "C" int32_t SharedMemoryGetByteLength(EtsSharedMemory *mem)
189 {
190     return static_cast<int32_t>(mem->GetLength());
191 }
192 
PrintWaiters(EtsSharedMemory & mem)193 std::string PrintWaiters(EtsSharedMemory &mem)
194 {
195     std::stringstream stream;
196     auto curWaiter = mem.GetHeadWaiter();
197     while (curWaiter != nullptr) {
198         stream << reinterpret_cast<size_t>(curWaiter) << " -> ";
199         curWaiter = curWaiter->GetNext();
200     }
201     return stream.str();
202 }
203 
SharedMemoryWaitI32(EtsSharedMemory * mem,int32_t byteOffset,int32_t expectedValue)204 extern "C" int32_t SharedMemoryWaitI32(EtsSharedMemory *mem, int32_t byteOffset, int32_t expectedValue)
205 {
206     auto result = mem->WaitI32(byteOffset, expectedValue, std::nullopt);
207     return static_cast<int32_t>(result);
208 }
209 
SharedMemoryWaitI64(EtsSharedMemory * mem,int32_t byteOffset,int64_t expectedValue)210 extern "C" int32_t SharedMemoryWaitI64(EtsSharedMemory *mem, int32_t byteOffset, int64_t expectedValue)
211 {
212     auto result = mem->WaitI64(byteOffset, expectedValue, std::nullopt);
213     return static_cast<int32_t>(result);
214 }
215 
SharedMemoryTimedWaitI32(EtsSharedMemory * mem,int32_t byteOffset,int32_t expectedValue,int64_t ms)216 extern "C" int32_t SharedMemoryTimedWaitI32(EtsSharedMemory *mem, int32_t byteOffset, int32_t expectedValue, int64_t ms)
217 {
218     ASSERT(ms >= 0);
219     auto uMs = static_cast<uint64_t>(ms);
220     auto result = mem->WaitI32(byteOffset, expectedValue, std::optional(uMs));
221     return static_cast<int32_t>(result);
222 }
223 
SharedMemoryTimedWaitI64(EtsSharedMemory * mem,int32_t byteOffset,int64_t expectedValue,int64_t ms)224 extern "C" int32_t SharedMemoryTimedWaitI64(EtsSharedMemory *mem, int32_t byteOffset, int64_t expectedValue, int64_t ms)
225 {
226     auto *currentCoro = EtsCoroutine::GetCurrent();
227     [[maybe_unused]] EtsHandleScope scope(currentCoro);
228     EtsHandle<EtsSharedMemory> hmem(currentCoro, mem);
229 
230     ASSERT(ms >= 0);
231     auto uMs = static_cast<uint64_t>(ms);
232     ScopedNativeCodeThread n(currentCoro);
233 
234     auto result = hmem->WaitI64(byteOffset, expectedValue, std::optional(uMs));
235     return static_cast<int32_t>(result);
236 }
237 
SharedMemoryNotify(EtsSharedMemory * mem,int32_t byteOffset)238 extern "C" int32_t SharedMemoryNotify(EtsSharedMemory *mem, int32_t byteOffset)
239 {
240     return mem->NotifyI32(byteOffset, std::nullopt);
241 }
242 
SharedMemoryBoundedNotify(EtsSharedMemory * mem,int32_t byteOffset,int32_t count)243 extern "C" int32_t SharedMemoryBoundedNotify(EtsSharedMemory *mem, int32_t byteOffset, int32_t count)
244 {
245     ASSERT(count >= 0);
246     return mem->NotifyI32(byteOffset, std::optional(count));
247 }
248 
249 #undef SHARED_MEMORY_AT
250 #undef SHARED_MEMORY_SET
251 #undef SHARED_MEMORY_ADD
252 #undef SHARED_MEMORY_AND_SIGNED
253 #undef SHARED_MEMORY_AND_UNSIGNED
254 #undef SHARED_MEMORY_COMPARE_EXCHANGE
255 #undef SHARED_MEMORY_EXCHANGE
256 #undef SHARED_MEMORY_LOAD
257 #undef SHARED_MEMORY_OR_SIGNED
258 #undef SHARED_MEMORY_OR_UNSIGNED
259 #undef SHARED_MEMORY_STORE
260 #undef SHARED_MEMORY_SUB
261 #undef SHARED_MEMORY_XOR_SIGNED
262 #undef SHARED_MEMORY_XOR_UNSIGNED
263 #undef FOR_ALL_TYPES
264 #undef FOR_SIGNED_TYPES
265 #undef FOR_UNSIGNED_TYPES
266 
267 }  // namespace ark::ets::intrinsics
268