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