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/integrate/ets_ani_expo.h"
16 #include "plugins/ets/runtime/ets_coroutine.h"
17 #include "plugins/ets/runtime/ets_napi_env.h"
18 #include "plugins/ets/runtime/ets_vm.h"
19 #include "plugins/ets/runtime/interop_js/interop_context_api.h"
20 #include "plugins/ets/runtime/types/ets_method.h"
21 #include "runtime/include/file_manager.h"
22 #include "runtime/include/thread_scopes.h"
23
24 namespace ark::ets {
Prefork(ani_env * env)25 PANDA_PUBLIC_API void ETSAni::Prefork(ani_env *env)
26 {
27 PandaEtsVM *vm = PandaEnv::FromAniEnv(env)->GetEtsVM();
28 ProcessTaskpoolWorker(true);
29 vm->PreZygoteFork();
30 }
31
Postfork(ani_env * env,const std::vector<ani_option> & options,bool postZygoteFork)32 PANDA_PUBLIC_API void ETSAni::Postfork(ani_env *env, const std::vector<ani_option> &options, bool postZygoteFork)
33 {
34 [[maybe_unused]] EtsCoroutine *coroutine = EtsCoroutine::GetCurrent();
35 ASSERT(coroutine != nullptr);
36
37 bool loadAppAotFile = false;
38 std::string appAotFileName;
39 for (auto &opt : options) {
40 std::string option(opt.option);
41 if (option == INTEROP_OPTION_PREFIX) {
42 #ifdef PANDA_ETS_INTEROP_JS
43 if (!interop::js::CreateMainInteropContext(coroutine, opt.extra)) {
44 LOG(ERROR, RUNTIME) << "Cannot create interop context";
45 }
46 #endif
47 } else if (option.rfind(AOT_FILE_OPTION_PREFIX, 0) == 0) {
48 loadAppAotFile = true;
49 appAotFileName = option.substr(AOT_FILE_OPTION_PREFIX.size());
50 } else if (option == ENABLE_AN_OPTION) {
51 TryLoadAotFileForBoot();
52 } else {
53 LOG(ERROR, RUNTIME) << "Unprocessed or invalid option parameter." << option;
54 }
55 }
56
57 PandaEtsVM *vm = PandaEnv::FromAniEnv(env)->GetEtsVM();
58 if (vm->GetLanguageContext().IsEnabledCHA()) {
59 vm->GetRuntime()->GetClassLinker()->GetAotManager()->VerifyClassHierarchy();
60 }
61
62 if (loadAppAotFile) {
63 LoadAotFileForApp(appAotFileName);
64 }
65
66 if (postZygoteFork) {
67 vm->PostZygoteFork();
68 ProcessTaskpoolWorker(false);
69 }
70 }
71
LoadAotFileForApp(std::string const & aotFileName)72 void ETSAni::LoadAotFileForApp(std::string const &aotFileName)
73 {
74 auto res = FileManager::LoadAnFile(aotFileName, true);
75 if (!res) {
76 LOG(ERROR, AOT) << "Failed to load AOT file: " << res.Error();
77 return;
78 }
79 if (!res.Value()) {
80 LOG(ERROR, AOT) << "Failed to load " << aotFileName << "with unkown reason";
81 return;
82 }
83 }
84
TryLoadAotFileForBoot()85 void ETSAni::TryLoadAotFileForBoot()
86 {
87 Runtime *runtime = Runtime::GetCurrent();
88 ClassLinker *linker = runtime->GetClassLinker();
89 const PandaVector<const panda_file::File *> bootPandaFiles = linker->GetBootPandaFiles();
90 for (const auto *pf : bootPandaFiles) {
91 const std::string location = pf->GetFilename();
92 FileManager::TryLoadAnFileForLocation(location);
93 const compiler::AotPandaFile *aotFile = linker->GetAotManager()->FindPandaFile(location);
94 if (aotFile != nullptr) {
95 pf->SetClassHashTable(aotFile->GetClassHashTable());
96 }
97 }
98 }
99
ProcessTaskpoolWorker(bool preFork)100 void ETSAni::ProcessTaskpoolWorker(bool preFork)
101 {
102 auto &taskpoolMode =
103 Runtime::GetCurrent()->GetOptions().GetTaskpoolMode(plugins::LangToRuntimeType(panda_file::SourceLang::ETS));
104
105 const char *taskpoolEAWorkerMode = "eaworker";
106 if (taskpoolMode != taskpoolEAWorkerMode) {
107 return;
108 }
109
110 if (preFork) {
111 bool res = DestroyExclusiveWorkerForTaskpoolIfExists();
112 LOG(INFO, COROUTINES) << "DestroyExclusiveWorkerForTaskpoolIfExists done: " << res;
113 } else {
114 bool res = PreCreateExclusiveWorkerForTaskpool();
115 LOG(INFO, COROUTINES) << "PreCreateExclusiveWorkerForTaskpool done: " << res;
116 }
117 }
118
PreCreateExclusiveWorkerForTaskpool()119 bool ETSAni::PreCreateExclusiveWorkerForTaskpool()
120 {
121 auto *runtime = Runtime::GetCurrent();
122 auto *classLinker = runtime->GetClassLinker();
123 ClassLinkerExtension *ext = classLinker->GetExtension(SourceLanguage::ETS);
124 auto mutf8Name = reinterpret_cast<const uint8_t *>("Lescompat/taskpool;");
125 auto *klass = ext->GetClass(mutf8Name);
126 if (klass == nullptr) {
127 LOG(ERROR, COROUTINES) << "Load taskpool failed in post zygote fork";
128 return false;
129 }
130 auto method = ets::EtsClass::FromRuntimeClass(klass)->GetStaticMethod("initWorkerPool", ":V");
131 if (method == nullptr) {
132 LOG(ERROR, COROUTINES) << "Load taskpool initWorkerPool failed in post zygote fork";
133 return false;
134 }
135 ScopedManagedCodeThread managedScope(Coroutine::GetCurrent());
136 method->GetPandaMethod()->Invoke(Coroutine::GetCurrent(), nullptr);
137 return true;
138 }
139
DestroyExclusiveWorkerForTaskpoolIfExists()140 bool ETSAni::DestroyExclusiveWorkerForTaskpoolIfExists()
141 {
142 auto *runtime = Runtime::GetCurrent();
143 auto *classLinker = runtime->GetClassLinker();
144 ClassLinkerExtension *ext = classLinker->GetExtension(SourceLanguage::ETS);
145 auto mutf8Name = reinterpret_cast<const uint8_t *>("Lescompat/taskpool;");
146 auto *klass = ext->GetClass(mutf8Name);
147 if (klass == nullptr) {
148 LOG(ERROR, COROUTINES) << "Load taskpool failed in pre zygote fork";
149 return false;
150 }
151 auto method = ets::EtsClass::FromRuntimeClass(klass)->GetStaticMethod("stopAllWorkers", ":V");
152 if (method == nullptr) {
153 LOG(ERROR, COROUTINES) << "Load taskpool::stopAllWorkers failed in pre zygote fork";
154 return false;
155 }
156 ScopedManagedCodeThread managedScope(Coroutine::GetCurrent());
157 method->GetPandaMethod()->Invoke(Coroutine::GetCurrent(), nullptr);
158 return true;
159 }
160 } // namespace ark::ets
161