• 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 <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