1 /*
2 * Copyright (c) 2022 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 "ecmascript/jspandafile/js_pandafile_executor.h"
17
18 #include "ecmascript/base/path_helper.h"
19 #include "ecmascript/ecma_vm.h"
20 #include "ecmascript/jspandafile/js_pandafile_manager.h"
21 #include "ecmascript/jspandafile/program_object.h"
22 #include "ecmascript/jspandafile/quick_fix_manager.h"
23 #include "ecmascript/mem/c_string.h"
24 #include "ecmascript/mem/c_containers.h"
25 #include "ecmascript/module/js_module_manager.h"
26
27 namespace panda::ecmascript {
28 using PathHelper = base::PathHelper;
ExecuteFromFile(JSThread * thread,const CString & filename,std::string_view entryPoint,bool needUpdate,bool excuteFromJob)29 Expected<JSTaggedValue, bool> JSPandaFileExecutor::ExecuteFromFile(JSThread *thread, const CString &filename,
30 std::string_view entryPoint, bool needUpdate, bool excuteFromJob)
31 {
32 LOG_ECMA(DEBUG) << "JSPandaFileExecutor::ExecuteFromFile filename " << filename;
33 CString entry;
34 CString name;
35 CString normalName = PathHelper::NormalizePath(filename);
36 EcmaVM *vm = thread->GetEcmaVM();
37 if (!vm->IsBundlePack()) {
38 #if defined(PANDA_TARGET_LINUX) || defined(OHOS_UNIT_TEST)
39 name = filename;
40 entry = entryPoint.data();
41 #else
42 if (excuteFromJob) {
43 entry = entryPoint.data();
44 } else {
45 entry = PathHelper::ParseOhmUrl(vm, normalName, name);
46 }
47 #if !WIN_OR_MAC_OR_IOS_PLATFORM
48 if (name.empty()) {
49 name = vm->GetAssetPath();
50 }
51 #elif defined(PANDA_TARGET_WINDOWS)
52 CString assetPath = vm->GetAssetPath();
53 name = assetPath + "\\" + JSPandaFile::MERGE_ABC_NAME;
54 #else
55 CString assetPath = vm->GetAssetPath();
56 name = assetPath + "/" + JSPandaFile::MERGE_ABC_NAME;
57 #endif
58 #endif
59 } else {
60 name = filename;
61 entry = entryPoint.data();
62 }
63
64 const JSPandaFile *jsPandaFile =
65 JSPandaFileManager::GetInstance()->LoadJSPandaFile(thread, name, entry, needUpdate);
66 if (jsPandaFile == nullptr) {
67 CString msg = "Load file with filename '" + name + "' failed, recordName '" + entry + "'";
68 THROW_REFERENCE_ERROR_AND_RETURN(thread, msg.c_str(), Unexpected(false));
69 }
70 CString realEntry = entry;
71 // If it is an old record, delete the bundleName and moduleName
72 if (!jsPandaFile->IsBundlePack() && !excuteFromJob && !vm->GetBundleName().empty()) {
73 const_cast<JSPandaFile *>(jsPandaFile)->CheckIsRecordWithBundleName(vm);
74 if (!jsPandaFile->IsRecordWithBundleName()) {
75 PathHelper::CroppingRecord(realEntry);
76 }
77 }
78 bool isModule = jsPandaFile->IsModule(thread, realEntry, entry);
79 if (thread->HasPendingException()) {
80 vm->HandleUncaughtException(thread->GetException().GetTaggedObject());
81 return Unexpected(false);
82 }
83 if (isModule) {
84 [[maybe_unused]] EcmaHandleScope scope(thread);
85 ModuleManager *moduleManager = vm->GetModuleManager();
86 JSHandle<JSTaggedValue> moduleRecord(thread->GlobalConstants()->GetHandledUndefined());
87 if (jsPandaFile->IsBundlePack()) {
88 moduleRecord = moduleManager->HostResolveImportedModule(name);
89 } else {
90 moduleRecord = moduleManager->HostResolveImportedModuleWithMerge(name, realEntry);
91 }
92 SourceTextModule::Instantiate(thread, moduleRecord);
93 if (thread->HasPendingException()) {
94 if (!excuteFromJob) {
95 vm->HandleUncaughtException(thread->GetException().GetTaggedObject());
96 }
97 return Unexpected(false);
98 }
99 JSHandle<SourceTextModule> module = JSHandle<SourceTextModule>::Cast(moduleRecord);
100 module->SetStatus(ModuleStatus::INSTANTIATED);
101 SourceTextModule::Evaluate(thread, module, nullptr, 0, excuteFromJob);
102 return JSTaggedValue::Undefined();
103 }
104 return JSPandaFileExecutor::Execute(thread, jsPandaFile, realEntry.c_str(), excuteFromJob);
105 }
106
ExecuteFromBuffer(JSThread * thread,const void * buffer,size_t size,std::string_view entryPoint,const CString & filename,bool needUpdate)107 Expected<JSTaggedValue, bool> JSPandaFileExecutor::ExecuteFromBuffer(JSThread *thread,
108 const void *buffer, size_t size, std::string_view entryPoint, const CString &filename, bool needUpdate)
109 {
110 LOG_ECMA(DEBUG) << "JSPandaFileExecutor::ExecuteFromBuffer filename " << filename;
111 CString normalName = PathHelper::NormalizePath(filename);
112 const JSPandaFile *jsPandaFile =
113 JSPandaFileManager::GetInstance()->LoadJSPandaFile(thread, normalName, entryPoint, buffer, size, needUpdate);
114 if (jsPandaFile == nullptr) {
115 CString msg = "Load file with filename '" + normalName + "' failed, recordName '" + entryPoint.data() + "'";
116 THROW_REFERENCE_ERROR_AND_RETURN(thread, msg.c_str(), Unexpected(false));
117 }
118
119 CString entry = entryPoint.data();
120 bool isModule = jsPandaFile->IsModule(thread, entry);
121 if (isModule) {
122 bool isBundle = jsPandaFile->IsBundlePack();
123 return CommonExecuteBuffer(thread, isBundle, normalName, entry, buffer, size);
124 }
125 return JSPandaFileExecutor::Execute(thread, jsPandaFile, entry);
126 }
127
ExecuteModuleBuffer(JSThread * thread,const void * buffer,size_t size,const CString & filename,bool needUpdate)128 Expected<JSTaggedValue, bool> JSPandaFileExecutor::ExecuteModuleBuffer(
129 JSThread *thread, const void *buffer, size_t size, const CString &filename, bool needUpdate)
130 {
131 LOG_ECMA(DEBUG) << "JSPandaFileExecutor::ExecuteModuleBuffer filename " << filename;
132 CString name;
133 EcmaVM *vm = thread->GetEcmaVM();
134 #if !WIN_OR_MAC_OR_IOS_PLATFORM
135 name = vm->GetAssetPath();
136 #elif defined(PANDA_TARGET_WINDOWS)
137 CString assetPath = vm->GetAssetPath();
138 name = assetPath + "\\" + JSPandaFile::MERGE_ABC_NAME;
139 #else
140 CString assetPath = vm->GetAssetPath();
141 name = assetPath + "/" + JSPandaFile::MERGE_ABC_NAME;
142 #endif
143 CString normalName = PathHelper::NormalizePath(filename);
144 CString entry = PathHelper::ParseOhmUrl(vm, normalName, name);
145 const JSPandaFile *jsPandaFile =
146 JSPandaFileManager::GetInstance()->LoadJSPandaFile(thread, name, entry, buffer, size, needUpdate);
147 if (jsPandaFile == nullptr) {
148 CString msg = "Load file with filename '" + name + "' failed, recordName '" + entry + "'";
149 THROW_REFERENCE_ERROR_AND_RETURN(thread, msg.c_str(), Unexpected(false));
150 }
151 bool isBundle = jsPandaFile->IsBundlePack();
152 CString realEntry = entry;
153 if (!isBundle) {
154 const_cast<JSPandaFile *>(jsPandaFile)->CheckIsRecordWithBundleName(vm);
155 if (!jsPandaFile->IsRecordWithBundleName()) {
156 PathHelper::CroppingRecord(realEntry);
157 }
158 }
159 // will be refactored, temporarily use the function IsModule to verify realEntry
160 [[maybe_unused]] bool isModule = jsPandaFile->IsModule(thread, realEntry, entry);
161 if (thread->HasPendingException()) {
162 vm->HandleUncaughtException(thread->GetException().GetTaggedObject());
163 return Unexpected(false);
164 }
165 ASSERT(isModule);
166 return CommonExecuteBuffer(thread, isBundle, name, realEntry, buffer, size);
167 }
168
CommonExecuteBuffer(JSThread * thread,bool isBundle,const CString & filename,const CString & entry,const void * buffer,size_t size)169 Expected<JSTaggedValue, bool> JSPandaFileExecutor::CommonExecuteBuffer(JSThread *thread,
170 bool isBundle, const CString &filename, const CString &entry, const void *buffer, size_t size)
171 {
172 [[maybe_unused]] EcmaHandleScope scope(thread);
173 EcmaVM *vm = thread->GetEcmaVM();
174 ModuleManager *moduleManager = vm->GetModuleManager();
175 moduleManager->SetExecuteMode(true);
176 JSHandle<JSTaggedValue> moduleRecord(thread->GlobalConstants()->GetHandledUndefined());
177 if (isBundle) {
178 moduleRecord = moduleManager->HostResolveImportedModule(buffer, size, filename);
179 } else {
180 moduleRecord = moduleManager->HostResolveImportedModuleWithMerge(filename, entry);
181 }
182 SourceTextModule::Instantiate(thread, moduleRecord);
183 if (thread->HasPendingException()) {
184 vm->HandleUncaughtException(thread->GetException().GetTaggedObject());
185 return Unexpected(false);
186 }
187 JSHandle<SourceTextModule> module = JSHandle<SourceTextModule>::Cast(moduleRecord);
188 module->SetStatus(ModuleStatus::INSTANTIATED);
189 SourceTextModule::Evaluate(thread, module, buffer, size);
190 return JSTaggedValue::Undefined();
191 }
192
Execute(JSThread * thread,const JSPandaFile * jsPandaFile,std::string_view entryPoint,bool excuteFromJob)193 Expected<JSTaggedValue, bool> JSPandaFileExecutor::Execute(JSThread *thread, const JSPandaFile *jsPandaFile,
194 std::string_view entryPoint, bool excuteFromJob)
195 {
196 // For Ark application startup
197 EcmaVM *vm = thread->GetEcmaVM();
198 Expected<JSTaggedValue, bool> result = vm->InvokeEcmaEntrypoint(jsPandaFile, entryPoint, excuteFromJob);
199 if (result) {
200 QuickFixManager *quickFixManager = vm->GetQuickFixManager();
201 quickFixManager->LoadPatchIfNeeded(thread, CstringConvertToStdString(jsPandaFile->GetJSPandaFileDesc()));
202 }
203 return result;
204 }
205 } // namespace panda::ecmascript
206