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