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 "runtime/runtime_helpers.h"
17 #include "plugins/ets/runtime/ets_coroutine.h"
18 #include "plugins/ets/runtime/ets_exceptions.h"
19 #include "plugins/ets/runtime/ets_panda_file_items.h"
20 #include "plugins/ets/runtime/ets_vm.h"
21 #include "plugins/ets/runtime/types/ets_atomic_flag.h"
22 #include "plugins/ets/runtime/types/ets_method.h"
23 #include "plugins/ets/runtime/types/ets_string.h"
24 #include "runtime/include/thread_scopes.h"
25
26 #include "runtime/include/stack_walker.h"
27 #include "runtime/include/thread.h"
28 #include "runtime/interpreter/runtime_interface.h"
29 #include "runtime/handle_scope.h"
30 #include "runtime/handle_scope-inl.h"
31 #include "types/ets_primitives.h"
32
33 namespace ark::ets::intrinsics {
34
StdCoreStackTraceLines()35 extern "C" EtsArray *StdCoreStackTraceLines()
36 {
37 auto runtime = Runtime::GetCurrent();
38 auto linker = runtime->GetClassLinker();
39 auto ext = linker->GetExtension(panda_file::SourceLang::ETS);
40 auto klass = ext->GetClassRoot(ClassRoot::ARRAY_STRING);
41
42 auto ctx = runtime->GetLanguageContext(panda_file::SourceLang::ETS);
43
44 auto thread = ManagedThread::GetCurrent();
45 auto walker = StackWalker::Create(thread);
46
47 std::vector<std::string> lines;
48
49 for (auto stack = StackWalker::Create(thread); stack.HasFrame(); stack.NextFrame()) {
50 Method *method = stack.GetMethod();
51 auto *source = method->GetClassSourceFile().data;
52 auto lineNum = method->GetLineNumFromBytecodeOffset(stack.GetBytecodePc());
53
54 if (source == nullptr) {
55 source = utf::CStringAsMutf8("<unknown>");
56 }
57
58 std::stringstream ss;
59 ss << method->GetClass()->GetName() << "." << method->GetName().data << " at " << source << ":" << lineNum;
60 lines.push_back(ss.str());
61 }
62
63 auto coroutine = Coroutine::GetCurrent();
64 [[maybe_unused]] HandleScope<ObjectHeader *> scope(coroutine);
65 auto *arr = ark::coretypes::Array::Create(klass, lines.size());
66
67 VMHandle<coretypes::Array> arrayHandle(coroutine, arr);
68
69 for (ark::ArraySizeT i = 0; i < (ark::ArraySizeT)lines.size(); i++) {
70 auto *str = coretypes::String::CreateFromMUtf8(utf::CStringAsMutf8(lines[i].data()), lines[i].length(), ctx,
71 thread->GetVM());
72 arrayHandle.GetPtr()->Set(i, str);
73 }
74
75 return reinterpret_cast<EtsArray *>(arrayHandle.GetPtr());
76 }
77
StdCorePrintStackTrace()78 extern "C" void StdCorePrintStackTrace()
79 {
80 ark::PrintStackTrace();
81 }
82
ResolveLibraryName(const PandaString & name)83 static PandaString ResolveLibraryName(const PandaString &name)
84 {
85 #ifdef PANDA_TARGET_UNIX
86 return PandaString("lib") + name + ".so";
87 #else
88 // Unsupported on windows platform
89 UNREACHABLE();
90 #endif // PANDA_TARGET_UNIX
91 }
92
LoadNativeLibraryHandler(ark::ets::EtsString * name,bool shouldVerifyPermission,ark::ets::EtsString * fileName=nullptr)93 void LoadNativeLibraryHandler(ark::ets::EtsString *name, bool shouldVerifyPermission,
94 ark::ets::EtsString *fileName = nullptr)
95 {
96 ASSERT(name->AsObject()->IsStringClass());
97 auto coroutine = EtsCoroutine::GetCurrent();
98 if (shouldVerifyPermission) {
99 ASSERT(fileName != nullptr);
100 ASSERT(fileName->AsObject()->IsStringClass());
101 }
102
103 if (name->IsUtf16()) {
104 LOG(FATAL, RUNTIME) << "UTF-16 native library pathes are not supported";
105 return;
106 }
107
108 auto nameStr = name->GetMutf8();
109 if (nameStr.empty()) {
110 ThrowEtsException(coroutine, panda_file_items::class_descriptors::FILE_NOT_FOUND_ERROR,
111 "The native library path is empty");
112 return;
113 }
114 PandaString fileNameStr = fileName != nullptr ? fileName->GetMutf8() : "";
115 LOG(INFO, RUNTIME) << "load library name is " << nameStr.c_str()
116 << "; shouldVerifyPermission: " << shouldVerifyPermission
117 << "; fileName: " << fileNameStr.c_str();
118 ScopedNativeCodeThread snct(coroutine);
119 auto env = coroutine->GetEtsNapiEnv();
120 if (!coroutine->GetPandaVM()->LoadNativeLibrary(env, ResolveLibraryName(nameStr), shouldVerifyPermission,
121 fileNameStr)) {
122 ScopedManagedCodeThread smct(coroutine);
123
124 PandaStringStream ss;
125 ss << "Cannot load native library " << nameStr;
126
127 ThrowEtsException(coroutine, panda_file_items::class_descriptors::EXCEPTION_IN_INITIALIZER_ERROR, ss.str());
128 }
129 }
130
LoadLibrary(ark::ets::EtsString * name)131 extern "C" void LoadLibrary(ark::ets::EtsString *name)
132 {
133 LoadNativeLibraryHandler(name, false);
134 }
135
LoadLibraryWithPermissionCheck(ark::ets::EtsString * name,ark::ets::EtsString * fileName)136 extern "C" void LoadLibraryWithPermissionCheck(ark::ets::EtsString *name, ark::ets::EtsString *fileName)
137 {
138 LoadNativeLibraryHandler(name, true, fileName);
139 }
140
StdSystemScheduleCoroutine()141 extern "C" void StdSystemScheduleCoroutine()
142 {
143 EtsCoroutine *coro = EtsCoroutine::GetCurrent();
144 if (coro->GetCoroutineManager()->IsCoroutineSwitchDisabled()) {
145 ThrowEtsException(coro, panda_file_items::class_descriptors::INVALID_COROUTINE_OPERATION_ERROR,
146 "Cannot switch coroutines in the current context!");
147 return;
148 }
149
150 ScopedNativeCodeThread nativeScope(coro);
151 coro->GetCoroutineManager()->Schedule();
152 }
153
StdSystemSetCoroutineSchedulingPolicy(int32_t policy)154 extern "C" void StdSystemSetCoroutineSchedulingPolicy(int32_t policy)
155 {
156 constexpr auto POLICIES_MAPPING =
157 std::array {CoroutineSchedulingPolicy::ANY_WORKER, CoroutineSchedulingPolicy::NON_MAIN_WORKER};
158 ASSERT((policy >= 0) && (static_cast<size_t>(policy) < POLICIES_MAPPING.size()));
159 CoroutineSchedulingPolicy newPolicy = POLICIES_MAPPING[policy];
160
161 auto *cm = static_cast<CoroutineManager *>(Coroutine::GetCurrent()->GetVM()->GetThreadManager());
162 cm->SetSchedulingPolicy(newPolicy);
163 }
164
StdSystemGetCoroutineId()165 extern "C" int32_t StdSystemGetCoroutineId()
166 {
167 return EtsCoroutine::GetCurrent()->GetCoroutineId();
168 }
169
StdSystemIsMainWorker()170 extern "C" EtsBoolean StdSystemIsMainWorker()
171 {
172 auto *coro = EtsCoroutine::GetCurrent();
173 return static_cast<EtsBoolean>(coro->GetCoroutineManager()->IsMainWorker(coro));
174 }
175
StdSystemWorkerHasExternalScheduler()176 extern "C" EtsBoolean StdSystemWorkerHasExternalScheduler()
177 {
178 auto *coro = EtsCoroutine::GetCurrent();
179 return static_cast<EtsBoolean>(coro->GetWorker()->IsExternalSchedulingEnabled());
180 }
181
StdSystemScaleWorkersPool(int32_t scaler)182 extern "C" void StdSystemScaleWorkersPool(int32_t scaler)
183 {
184 if (UNLIKELY(scaler == 0)) {
185 return;
186 }
187 auto *coro = EtsCoroutine::GetCurrent();
188 auto *vm = coro->GetPandaVM();
189 auto *runtime = vm->GetRuntime();
190 if (scaler > 0) {
191 coro->GetManager()->CreateWorkers(scaler, runtime, vm);
192 return;
193 }
194 ScopedNativeCodeThread nativeScope(coro);
195 Coroutine::GetCurrent()->GetManager()->FinalizeWorkers(std::abs(scaler), runtime, vm);
196 }
197
StdSystemStopTaskpool()198 extern "C" void StdSystemStopTaskpool()
199 {
200 auto *runtime = Runtime::GetCurrent();
201 auto *classLinker = runtime->GetClassLinker();
202 ClassLinkerExtension *cle = classLinker->GetExtension(SourceLanguage::ETS);
203 auto mutf8Name = reinterpret_cast<const uint8_t *>("Lescompat/taskpool;");
204 auto klass = cle->GetClass(mutf8Name);
205 if (klass == nullptr) {
206 return;
207 }
208 auto *method = EtsClass::FromRuntimeClass(klass)->GetStaticMethod("stopAllWorkers", ":V");
209 ASSERT(method != nullptr);
210 auto coro = EtsCoroutine::GetCurrent();
211 method->GetPandaMethod()->Invoke(coro, nullptr);
212 }
213
StdSystemIncreaseTaskpoolWorkersToN(int32_t workersNum)214 extern "C" void StdSystemIncreaseTaskpoolWorkersToN(int32_t workersNum)
215 {
216 if (UNLIKELY(workersNum == 0)) {
217 return;
218 }
219 auto *runtime = Runtime::GetCurrent();
220 auto *classLinker = runtime->GetClassLinker();
221 ClassLinkerExtension *cle = classLinker->GetExtension(SourceLanguage::ETS);
222 auto mutf8Name = reinterpret_cast<const uint8_t *>("Lescompat/taskpool;");
223 auto klass = cle->GetClass(mutf8Name);
224 if (klass == nullptr) {
225 return;
226 }
227 auto *method = EtsClass::FromRuntimeClass(klass)->GetStaticMethod("increaseWorkersToN", "I:V");
228 ASSERT(method != nullptr);
229 auto coro = EtsCoroutine::GetCurrent();
230 std::array args = {Value(workersNum)};
231 method->GetPandaMethod()->Invoke(coro, args.data());
232 }
233
StdSystemAtomicFlagSet(EtsAtomicFlag * instance,EtsBoolean v)234 extern "C" void StdSystemAtomicFlagSet(EtsAtomicFlag *instance, EtsBoolean v)
235 {
236 instance->SetValue(v);
237 }
238
StdSystemAtomicFlagGet(EtsAtomicFlag * instance)239 extern "C" EtsBoolean StdSystemAtomicFlagGet(EtsAtomicFlag *instance)
240 {
241 return instance->GetValue();
242 }
243
244 } // namespace ark::ets::intrinsics
245