• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 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 #include "plugins/ets/runtime/types/ets_type.h"
16 #include "plugins/ets/runtime/ets_vm.h"
17 #include "plugins/ets/runtime/types/ets_string.h"
18 #include "plugins/ets/runtime/ets_exceptions.h"
19 
20 #include "runtime/handle_scope.h"
21 #include "runtime/handle_scope-inl.h"
22 #include "runtime/include/thread.h"
23 
24 namespace ark::ets::intrinsics {
25 
26 /* make sure the class the intrinsic being called from belongs to the boot context */
EnsureBootContext()27 static bool EnsureBootContext()
28 {
29     auto *coro = EtsCoroutine::GetCurrent();
30     auto ctx = StackWalker::Create(coro).GetMethod()->GetClass()->GetLoadContext();
31     if (!ctx->IsBootContext()) {
32         auto e = panda_file_items::class_descriptors::ILLEGAL_STATE_EXCEPTION;
33         auto msg = "Unsafe intrinsics cannot be called outside of the boot context";
34         ThrowEtsException(coro, e, msg);
35         return false;
36     }
37     return true;
38 }
39 
40 template <typename T>
UnsafeMemoryRead(void * addr)41 static T UnsafeMemoryRead(void *addr)
42 {
43     if (EnsureBootContext()) {
44         return *reinterpret_cast<T *>(addr);
45     }
46     return static_cast<T>(-1);
47 }
48 
49 template <typename T>
UnsafeMemoryWrite(void * addr,T val)50 static void UnsafeMemoryWrite(void *addr, T val)
51 {
52     if (EnsureBootContext()) {
53         *reinterpret_cast<T *>(addr) = val;
54     }
55 }
56 
UnsafeMemoryReadBoolean(void * addr)57 extern "C" EtsByte UnsafeMemoryReadBoolean(void *addr)
58 {
59     return UnsafeMemoryRead<EtsByte>(addr);
60 }
61 
UnsafeMemoryReadInt8(void * addr)62 extern "C" EtsByte UnsafeMemoryReadInt8(void *addr)
63 {
64     return UnsafeMemoryRead<EtsByte>(addr);
65 }
66 
UnsafeMemoryReadInt16(void * addr)67 extern "C" EtsShort UnsafeMemoryReadInt16(void *addr)
68 {
69     return UnsafeMemoryRead<EtsShort>(addr);
70 }
71 
UnsafeMemoryReadInt32(void * addr)72 extern "C" EtsInt UnsafeMemoryReadInt32(void *addr)
73 {
74     return UnsafeMemoryRead<EtsInt>(addr);
75 }
76 
UnsafeMemoryReadInt64(void * addr)77 extern "C" EtsLong UnsafeMemoryReadInt64(void *addr)
78 {
79     return UnsafeMemoryRead<EtsLong>(addr);
80 }
81 
UnsafeMemoryReadFloat32(void * addr)82 extern "C" EtsFloat UnsafeMemoryReadFloat32(void *addr)
83 {
84     return UnsafeMemoryRead<EtsFloat>(addr);
85 }
86 
UnsafeMemoryReadFloat64(void * addr)87 extern "C" EtsDouble UnsafeMemoryReadFloat64(void *addr)
88 {
89     return UnsafeMemoryRead<EtsDouble>(addr);
90 }
91 
UnsafeMemoryReadNumber(void * addr)92 extern "C" EtsDouble UnsafeMemoryReadNumber(void *addr)
93 {
94     return UnsafeMemoryRead<EtsDouble>(addr);
95 }
96 
UnsafeMemoryWriteBoolean(void * addr,EtsBoolean val)97 extern "C" void UnsafeMemoryWriteBoolean(void *addr, EtsBoolean val)
98 {
99     UnsafeMemoryWrite<EtsByte>(addr, val);
100 }
101 
UnsafeMemoryWriteInt8(void * addr,EtsByte val)102 extern "C" void UnsafeMemoryWriteInt8(void *addr, EtsByte val)
103 {
104     UnsafeMemoryWrite<EtsByte>(addr, val);
105 }
106 
UnsafeMemoryWriteInt16(void * addr,EtsShort val)107 extern "C" void UnsafeMemoryWriteInt16(void *addr, EtsShort val)
108 {
109     UnsafeMemoryWrite<EtsShort>(addr, val);
110 }
111 
UnsafeMemoryWriteInt32(void * addr,EtsInt val)112 extern "C" void UnsafeMemoryWriteInt32(void *addr, EtsInt val)
113 {
114     UnsafeMemoryWrite<EtsInt>(addr, val);
115 }
116 
UnsafeMemoryWriteInt64(void * addr,EtsLong val)117 extern "C" void UnsafeMemoryWriteInt64(void *addr, EtsLong val)
118 {
119     UnsafeMemoryWrite<EtsLong>(addr, val);
120 }
121 
UnsafeMemoryWriteFloat32(void * addr,EtsFloat val)122 extern "C" void UnsafeMemoryWriteFloat32(void *addr, EtsFloat val)
123 {
124     UnsafeMemoryWrite<EtsFloat>(addr, val);
125 }
126 
UnsafeMemoryWriteFloat64(void * addr,EtsDouble val)127 extern "C" void UnsafeMemoryWriteFloat64(void *addr, EtsDouble val)
128 {
129     UnsafeMemoryWrite<EtsDouble>(addr, val);
130 }
131 
UnsafeMemoryWriteNumber(void * addr,EtsDouble val)132 extern "C" void UnsafeMemoryWriteNumber(void *addr, EtsDouble val)
133 {
134     UnsafeMemoryWrite<EtsDouble>(addr, val);
135 }
136 
137 /* get the size of the buffer to hold the string content add additional
138    2 bytes for the leading byte-order mark which is used in the UTF-16
139    case */
UnsafeMemoryStringGetSizeInBytes(EtsString * str)140 extern "C" int UnsafeMemoryStringGetSizeInBytes(EtsString *str)
141 {
142     auto coroutine = EtsCoroutine::GetCurrent();
143     [[maybe_unused]] HandleScope<ObjectHeader *> scope(coroutine);
144     EtsHandle<EtsString> handle(coroutine, str);
145 
146     if (!EnsureBootContext()) {
147         return -1;
148     }
149 
150     str = handle.GetPtr();
151 
152     uint32_t shift = str->IsUtf16() ? 1 : 0;
153     uint32_t addend = str->IsUtf16() ? 2 : 0;
154     auto length = static_cast<uint32_t>(str->GetLength());
155     int size = (length << shift) + addend;
156     return size;
157 }
158 
159 static constexpr uint16_t UTF16_BOM = 0xFEFF;
160 
UnsafeMemoryReadString(void * buf,int len)161 extern "C" EtsString *UnsafeMemoryReadString(void *buf, int len)
162 {
163     if (!EnsureBootContext()) {
164         return nullptr;
165     }
166 
167     ObjectHeader *res = nullptr;
168     auto vm = ManagedThread::GetCurrent()->GetVM();
169     auto ctx = Runtime::GetCurrent()->GetLanguageContext(panda_file::SourceLang::ETS);
170     auto mark = reinterpret_cast<uint16_t *>(buf);
171     auto size = static_cast<uint32_t>(len);
172 
173     if (*mark == UTF16_BOM) {
174         auto addr = ++mark;
175         /* size is in bytes but CreateFromUtf16 takes it as chars, so,
176            we divide it by half and subtract the length of the BOM */
177         res = coretypes::String::CreateFromUtf16(addr, (size / 2U) - 1, false, ctx, vm);
178     } else {
179         auto addr = reinterpret_cast<const uint8_t *>(buf);
180         res = coretypes::String::CreateFromMUtf8(addr, size, size, true, ctx, vm);
181     }
182 
183     return reinterpret_cast<EtsString *>(res);
184 }
185 
UnsafeMemoryWriteString(void * addr,EtsString * str)186 extern "C" int UnsafeMemoryWriteString(void *addr, EtsString *str)
187 {
188     auto coroutine = EtsCoroutine::GetCurrent();
189     [[maybe_unused]] HandleScope<ObjectHeader *> scope(coroutine);
190     EtsHandle<EtsString> handle(coroutine, str);
191 
192     if (!EnsureBootContext()) {
193         return -1;
194     }
195 
196     str = handle.GetPtr();
197 
198     auto size = static_cast<uint32_t>(str->GetLength());
199     if (str->IsUtf16()) {
200         *reinterpret_cast<uint16_t *>(addr) = UTF16_BOM;
201         // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
202         addr = reinterpret_cast<char *>(addr) + 2U;
203         size <<= 1U;
204         return memcpy_s(addr, size, str->GetDataUtf16(), size) == 0 ? size + 2U : -1;
205     }
206     return memcpy_s(addr, size, str->GetDataMUtf8(), size) == 0 ? size : -1;
207 }
208 
209 }  // namespace ark::ets::intrinsics
210