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 <chrono>
17 #include <cmath>
18 #include <limits>
19 #include <string>
20 #include <string_view>
21 #include <type_traits>
22
23 #include "libpandabase/macros.h"
24 #include "libpandabase/utils/logger.h"
25 #include "libpandabase/utils/span.h"
26 #include "libpandabase/utils/time.h"
27 #include "runtime/compiler.h"
28 #include "runtime/include/exceptions.h"
29 #include "runtime/include/compiler_interface.h"
30 #include "runtime/include/coretypes/array.h"
31 #include "runtime/include/coretypes/string.h"
32 #include "runtime/include/panda_vm.h"
33 #include "runtime/include/runtime.h"
34 #include "runtime/include/thread.h"
35 #include "runtime/include/thread_status.h"
36 #include "runtime/interpreter/frame.h"
37 #include "runtime/coroutines/coroutine_manager.h"
38 #include "utils/math_helpers.h"
39 #include "intrinsics.h"
40
41 namespace ark::intrinsics {
42
IsInfF64(double v)43 uint8_t IsInfF64(double v)
44 {
45 return static_cast<uint8_t>(std::isinf(v));
46 }
47
IsInfF32(float v)48 uint8_t IsInfF32(float v)
49 {
50 return static_cast<uint8_t>(std::isinf(v));
51 }
52
AbsI32(int32_t v)53 int32_t AbsI32(int32_t v)
54 {
55 return std::abs(v);
56 }
57
AbsI64(int64_t v)58 int64_t AbsI64(int64_t v)
59 {
60 return std::abs(v);
61 }
62
AbsF32(float v)63 float AbsF32(float v)
64 {
65 return std::abs(v);
66 }
67
AbsF64(double v)68 double AbsF64(double v)
69 {
70 return std::abs(v);
71 }
72
SinF32(float v)73 float SinF32(float v)
74 {
75 return std::sin(v);
76 }
77
SinF64(double v)78 double SinF64(double v)
79 {
80 return std::sin(v);
81 }
82
CosF32(float v)83 float CosF32(float v)
84 {
85 return std::cos(v);
86 }
87
CosF64(double v)88 double CosF64(double v)
89 {
90 return std::cos(v);
91 }
92
PowF32(float base,float exp)93 float PowF32(float base, float exp)
94 {
95 return std::pow(base, exp);
96 }
97
PowF64(double base,double exp)98 double PowF64(double base, double exp)
99 {
100 return std::pow(base, exp);
101 }
102
SqrtF32(float v)103 float SqrtF32(float v)
104 {
105 return std::sqrt(v);
106 }
107
SqrtF64(double v)108 double SqrtF64(double v)
109 {
110 return std::sqrt(v);
111 }
112
MinI32(int32_t a,int32_t b)113 int32_t MinI32(int32_t a, int32_t b)
114 {
115 return std::min(a, b);
116 }
117
MinI64(int64_t a,int64_t b)118 int64_t MinI64(int64_t a, int64_t b)
119 {
120 return std::min(a, b);
121 }
122
MinF32(float a,float b)123 float MinF32(float a, float b)
124 {
125 return ark::helpers::math::Min(a, b);
126 }
127
MinF64(double a,double b)128 double MinF64(double a, double b)
129 {
130 return ark::helpers::math::Min(a, b);
131 }
132
MaxI32(int32_t a,int32_t b)133 int32_t MaxI32(int32_t a, int32_t b)
134 {
135 return std::max(a, b);
136 }
137
MaxI64(int64_t a,int64_t b)138 int64_t MaxI64(int64_t a, int64_t b)
139 {
140 return std::max(a, b);
141 }
142
MaxF32(float a,float b)143 float MaxF32(float a, float b)
144 {
145 return ark::helpers::math::Max(a, b);
146 }
147
MaxF64(double a,double b)148 double MaxF64(double a, double b)
149 {
150 return ark::helpers::math::Max(a, b);
151 }
152
153 template <bool IS_ERR, class T>
Print(T v)154 void Print(T v)
155 {
156 if (IS_ERR) {
157 std::cerr << v;
158 } else {
159 std::cout << v;
160 }
161 }
162
163 template <bool IS_ERR>
PrintStringInternal(coretypes::String * v)164 void PrintStringInternal(coretypes::String *v)
165 {
166 static auto &outstream = IS_ERR ? std::cerr : std::cout;
167 if (v->IsUtf16()) {
168 uint16_t *vdataPtr = v->GetDataUtf16();
169 uint32_t vlength = v->GetLength();
170 size_t mutf8Len = utf::Utf16ToMUtf8Size(vdataPtr, vlength);
171
172 PandaVector<uint8_t> out(mutf8Len);
173 utf::ConvertRegionUtf16ToMUtf8(vdataPtr, out.data(), vlength, mutf8Len, 0);
174
175 outstream << reinterpret_cast<const char *>(out.data());
176 } else {
177 outstream << std::string_view(reinterpret_cast<const char *>(v->GetDataMUtf8()), v->GetLength());
178 }
179 }
180
PrintString(coretypes::String * v)181 void PrintString(coretypes::String *v)
182 {
183 PrintStringInternal<false>(v);
184 }
185
PrintF32(float v)186 void PrintF32(float v)
187 {
188 Print<false>(v);
189 }
190
PrintF64(double v)191 void PrintF64(double v)
192 {
193 Print<false>(v);
194 }
195
PrintI32(int32_t v)196 void PrintI32(int32_t v)
197 {
198 Print<false>(v);
199 }
200
PrintU32(uint32_t v)201 void PrintU32(uint32_t v)
202 {
203 Print<false>(v);
204 }
205
PrintI64(int64_t v)206 void PrintI64(int64_t v)
207 {
208 Print<false>(v);
209 }
210
PrintU64(uint64_t v)211 void PrintU64(uint64_t v)
212 {
213 Print<false>(v);
214 }
215
NanoTime()216 int64_t NanoTime()
217 {
218 return time::GetCurrentTimeInNanos();
219 }
220
Assert(uint8_t cond)221 void Assert(uint8_t cond)
222 {
223 if (cond == 0) {
224 Runtime::Abort();
225 }
226 }
227
UnknownIntrinsic()228 void UnknownIntrinsic()
229 {
230 std::cerr << "UnknownIntrinsic\n";
231 Runtime::Abort();
232 }
233
AssertPrint(uint8_t cond,coretypes::String * s)234 void AssertPrint(uint8_t cond, coretypes::String *s)
235 {
236 if (cond == 0) {
237 PrintStringInternal<true>(s);
238 Runtime::Abort();
239 }
240 }
241
CheckTag(int64_t reg,int64_t expected)242 void CheckTag(int64_t reg, int64_t expected)
243 {
244 constexpr int ACC_NUM = std::numeric_limits<uint16_t>::max() + 1;
245 int64_t tag = 0;
246 auto *thread = ManagedThread::GetCurrent();
247 ASSERT(thread != nullptr);
248 StaticFrameHandler handler(thread->GetCurrentFrame());
249 if (reg == ACC_NUM) {
250 auto vreg = handler.GetAcc();
251 tag = vreg.GetTag();
252 } else {
253 auto vreg = handler.GetVReg(reg);
254 tag = vreg.GetTag();
255 }
256 if (tag != expected) {
257 std::cerr << "Error: "
258 << "Tag = " << tag << std::endl;
259 std::cerr << "Expected = " << expected << std::endl;
260 ark::PrintStack(std::cerr);
261 Runtime::Abort();
262 }
263 }
264
265 #ifndef PANDA_PRODUCT_BUILD
CompileMethod(coretypes::String * fullMethodName)266 uint8_t CompileMethod(coretypes::String *fullMethodName)
267 {
268 return ark::CompileMethodImpl(fullMethodName, panda_file::SourceLang::PANDA_ASSEMBLY);
269 }
270
CalculateDouble(uint32_t n,double s)271 double CalculateDouble(uint32_t n, double s)
272 {
273 double result = 0.0;
274 for (uint32_t i = 0U; i < n; ++i) {
275 result += i * s;
276 }
277 return result;
278 }
279
CalculateFloat(uint32_t n,float s)280 float CalculateFloat(uint32_t n, float s)
281 {
282 float result = 0.0F;
283 for (uint32_t i = 0U; i < n; ++i) {
284 result += i * s;
285 }
286 return result;
287 }
288 #endif // PANDA_PRODUCT_BUILD
289
290 // NOTE(kbaladurin) : Convert methods should be implemented in managed library
291
ConvertStringToI32(coretypes::String * s)292 int32_t ConvertStringToI32(coretypes::String *s)
293 {
294 return static_cast<int32_t>(PandaStringToLL(ConvertToString(s)));
295 }
296
ConvertStringToU32(coretypes::String * s)297 uint32_t ConvertStringToU32(coretypes::String *s)
298 {
299 return static_cast<uint32_t>(PandaStringToULL(ConvertToString(s)));
300 }
301
ConvertStringToI64(coretypes::String * s)302 int64_t ConvertStringToI64(coretypes::String *s)
303 {
304 return static_cast<int64_t>(PandaStringToLL(ConvertToString(s)));
305 }
306
ConvertStringToU64(coretypes::String * s)307 uint64_t ConvertStringToU64(coretypes::String *s)
308 {
309 return static_cast<uint64_t>(PandaStringToULL(ConvertToString(s)));
310 }
311
ConvertStringToF32(coretypes::String * s)312 float ConvertStringToF32(coretypes::String *s)
313 {
314 return PandaStringToF(ConvertToString(s));
315 }
316
ConvertStringToF64(coretypes::String * s)317 double ConvertStringToF64(coretypes::String *s)
318 {
319 return PandaStringToD(ConvertToString(s));
320 }
321
SystemExit(int32_t status)322 void SystemExit(int32_t status)
323 {
324 Runtime::Halt(status);
325 }
326
SystemScheduleCoroutine()327 void SystemScheduleCoroutine()
328 {
329 auto *coro = Coroutine::GetCurrent();
330 ASSERT(coro != nullptr);
331 auto *cm = static_cast<CoroutineManager *>(coro->GetVM()->GetThreadManager());
332 cm->Schedule();
333 }
334
SystemCoroutineGetWorkerId()335 int32_t SystemCoroutineGetWorkerId()
336 {
337 return os::thread::GetCurrentThreadId();
338 }
339
ObjectCreateNonMovable(coretypes::Class * cls)340 ObjectHeader *ObjectCreateNonMovable(coretypes::Class *cls)
341 {
342 ASSERT(cls != nullptr);
343 return ObjectHeader::CreateNonMovable(cls->GetRuntimeClass());
344 }
345
ObjectMonitorEnter(ObjectHeader * header)346 void ObjectMonitorEnter(ObjectHeader *header)
347 {
348 if (header == nullptr) {
349 ark::ThrowNullPointerException();
350 return;
351 }
352 auto res = Monitor::MonitorEnter(header);
353 // Expected results: OK, ILLEGAL
354 ASSERT(res != Monitor::State::INTERRUPTED);
355 if (UNLIKELY(res != Monitor::State::OK)) {
356 // This should never happen
357 // Object 'header' may be moved. It is no sence to wrap it into a handle just to print before exit
358 // SUPPRESS_CSA_NEXTLINE(alpha.core.WasteObjHeader)
359 LOG(FATAL, RUNTIME) << "MonitorEnter for " << header << " returned Illegal state!";
360 }
361 }
362
ObjectMonitorExit(ObjectHeader * header)363 void ObjectMonitorExit(ObjectHeader *header)
364 {
365 if (header == nullptr) {
366 ark::ThrowNullPointerException();
367 return;
368 }
369 auto res = Monitor::MonitorExit(header);
370 // Expected results: OK, ILLEGAL
371 ASSERT(res != Monitor::State::INTERRUPTED);
372 if (res == Monitor::State::ILLEGAL) {
373 PandaStringStream ss;
374 ss << "MonitorExit for object " << std::hex << header << " returned Illegal state";
375 ark::ThrowIllegalMonitorStateException(ss.str());
376 }
377 }
378
ObjectWait(ObjectHeader * header)379 void ObjectWait(ObjectHeader *header)
380 {
381 Monitor::State state = Monitor::Wait(header, ThreadStatus::IS_WAITING, 0, 0);
382 LOG_IF(state == Monitor::State::ILLEGAL, FATAL, RUNTIME) << "Monitor::Wait() failed";
383 }
384
ObjectTimedWait(ObjectHeader * header,uint64_t timeout)385 void ObjectTimedWait(ObjectHeader *header, uint64_t timeout)
386 {
387 Monitor::State state = Monitor::Wait(header, ThreadStatus::IS_TIMED_WAITING, timeout, 0);
388 LOG_IF(state == Monitor::State::ILLEGAL, FATAL, RUNTIME) << "Monitor::Wait() failed";
389 }
390
ObjectTimedWaitNanos(ObjectHeader * header,uint64_t timeout,uint64_t nanos)391 void ObjectTimedWaitNanos(ObjectHeader *header, uint64_t timeout, uint64_t nanos)
392 {
393 Monitor::State state = Monitor::Wait(header, ThreadStatus::IS_TIMED_WAITING, timeout, nanos);
394 LOG_IF(state == Monitor::State::ILLEGAL, FATAL, RUNTIME) << "Monitor::Wait() failed";
395 }
396
ObjectNotify(ObjectHeader * header)397 void ObjectNotify(ObjectHeader *header)
398 {
399 Monitor::State state = Monitor::Notify(header);
400 LOG_IF(state != Monitor::State::OK, FATAL, RUNTIME) << "Monitor::Notify() failed";
401 }
402
ObjectNotifyAll(ObjectHeader * header)403 void ObjectNotifyAll(ObjectHeader *header)
404 {
405 Monitor::State state = Monitor::NotifyAll(header);
406 LOG_IF(state != Monitor::State::OK, FATAL, RUNTIME) << "Monitor::NotifyAll() failed";
407 }
408
Memset8(ObjectHeader * array,uint8_t value,uint32_t initialIndex,uint32_t maxIndex)409 void Memset8(ObjectHeader *array, uint8_t value, uint32_t initialIndex, uint32_t maxIndex)
410 {
411 auto data = reinterpret_cast<uint8_t *>(ark::coretypes::Array::Cast(array)->GetData());
412 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
413 std::fill(data + initialIndex, data + maxIndex, value);
414 }
415
Memset16(ObjectHeader * array,uint16_t value,uint32_t initialIndex,uint32_t maxIndex)416 void Memset16(ObjectHeader *array, uint16_t value, uint32_t initialIndex, uint32_t maxIndex)
417 {
418 auto data = reinterpret_cast<uint16_t *>(ark::coretypes::Array::Cast(array)->GetData());
419 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
420 std::fill(data + initialIndex, data + maxIndex, value);
421 }
422
Memset32(ObjectHeader * array,uint32_t value,uint32_t initialIndex,uint32_t maxIndex)423 void Memset32(ObjectHeader *array, uint32_t value, uint32_t initialIndex, uint32_t maxIndex)
424 {
425 auto data = reinterpret_cast<uint32_t *>(ark::coretypes::Array::Cast(array)->GetData());
426 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
427 std::fill(data + initialIndex, data + maxIndex, value);
428 }
429
Memset64(ObjectHeader * array,uint64_t value,uint32_t initialIndex,uint32_t maxIndex)430 void Memset64(ObjectHeader *array, uint64_t value, uint32_t initialIndex, uint32_t maxIndex)
431 {
432 auto data = reinterpret_cast<uint64_t *>(ark::coretypes::Array::Cast(array)->GetData());
433 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
434 std::fill(data + initialIndex, data + maxIndex, value);
435 }
Memsetf32(ObjectHeader * array,float value,uint32_t initialIndex,uint32_t maxIndex)436 void Memsetf32(ObjectHeader *array, float value, uint32_t initialIndex, uint32_t maxIndex)
437 {
438 auto data = reinterpret_cast<float *>(ark::coretypes::Array::Cast(array)->GetData());
439 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
440 std::fill(data + initialIndex, data + maxIndex, value);
441 }
442
Memsetf64(ObjectHeader * array,double value,uint32_t initialIndex,uint32_t maxIndex)443 void Memsetf64(ObjectHeader *array, double value, uint32_t initialIndex, uint32_t maxIndex)
444 {
445 auto data = reinterpret_cast<double *>(ark::coretypes::Array::Cast(array)->GetData());
446 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
447 std::fill(data + initialIndex, data + maxIndex, value);
448 }
449 } // namespace ark::intrinsics
450
451 #include <intrinsics_gen.h>
452