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