• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2024 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 "ecmascript/module/module_manager_helper.h"
16 
17 #include "ecmascript/interpreter/slow_runtime_stub.h"
18 #include "ecmascript/jspandafile/js_pandafile_executor.h"
19 #include "ecmascript/require/js_cjs_module.h"
20 #include "ecmascript/module/module_path_helper.h"
21 
22 namespace panda::ecmascript {
GetModuleValue(JSThread * thread,JSHandle<SourceTextModule> module,int index)23 JSTaggedValue ModuleManagerHelper::GetModuleValue(JSThread *thread, JSHandle<SourceTextModule> module, int index)
24 {
25     ModuleTypes moduleType = module->GetTypes();
26     if (SourceTextModule::IsNativeModule(moduleType) || SourceTextModule::IsCjsModule(moduleType)) {
27         return GetNativeOrCjsModuleValue(thread, module.GetTaggedValue(), index);
28     }
29     return module->GetModuleValue(thread, index, false);
30 }
31 
GetNativeOrCjsModuleValue(JSThread * thread,JSTaggedValue resolvedModule,int32_t index)32 JSTaggedValue ModuleManagerHelper::GetNativeOrCjsModuleValue(JSThread *thread,
33                                                              JSTaggedValue resolvedModule,
34                                                              int32_t index)
35 {
36     JSHandle<JSTaggedValue> exports = GetNativeOrCjsExports(thread, resolvedModule);
37     RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSTaggedValue::Exception());
38     return SourceTextModule::GetValueFromExportObject(thread, exports, index);
39 }
40 
GetNativeOrCjsExports(JSThread * thread,JSTaggedValue resolvedModule)41 JSHandle<JSTaggedValue> ModuleManagerHelper::GetNativeOrCjsExports(JSThread *thread, JSTaggedValue resolvedModule)
42 {
43     JSHandle<SourceTextModule> module(thread, resolvedModule);
44     // if cjsModule is not JSObject, means cjs uses default exports.
45     JSMutableHandle<JSTaggedValue> exports(thread, thread->GlobalConstants()->GetUndefined());
46     ModuleTypes moduleType = module->GetTypes();
47     if (SourceTextModule::IsNativeModule(moduleType)) {
48         exports.Update(module->GetModuleValue(thread, 0, false));
49         if (!exports->IsJSObject()) {
50             LOG_FULL(WARN) << "Load native module failed, so is " << SourceTextModule::GetModuleName(resolvedModule);
51         }
52         return exports;
53     }
54     if (SourceTextModule::IsCjsModule(moduleType)) {
55         CString cjsModuleName = SourceTextModule::GetModuleName(module.GetTaggedValue());
56         JSHandle<JSTaggedValue> moduleNameHandle(thread->GetEcmaVM()->GetFactory()->NewFromUtf8(cjsModuleName));
57         exports.Update(CjsModule::SearchFromModuleCache(thread, moduleNameHandle).GetTaggedValue());
58         if (exports->IsHole()) {
59             CString errorMsg =
60                 "Loading cjs module:" + SourceTextModule::GetModuleName(module.GetTaggedValue()) + ", failed";
61             JSHandle<JSTaggedValue> exception(thread, JSTaggedValue::Exception());
62             THROW_NEW_ERROR_WITH_MSG_AND_RETURN_VALUE(thread,
63                 ErrorType::SYNTAX_ERROR, errorMsg.c_str(), exception);
64         }
65         return exports;
66     }
67     return exports;
68 }
69 
GetModuleValue(JSThread * thread,JSHandle<SourceTextModule> module,JSTaggedValue bindingName)70 JSTaggedValue ModuleManagerHelper::GetModuleValue(JSThread *thread, JSHandle<SourceTextModule> module,
71     JSTaggedValue bindingName)
72 {
73     JSHandle<JSTaggedValue> exports = GetNativeOrCjsExports(thread, module.GetTaggedValue());
74     RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSTaggedValue::Exception());
75     if (UNLIKELY(JSTaggedValue::SameValue(
76         bindingName, thread->GlobalConstants()->GetHandledDefaultString().GetTaggedValue()))) {
77         return exports.GetTaggedValue();
78     }
79     // need fix
80     return JSHandle<JSTaggedValue>(thread, SlowRuntimeStub::LdObjByName(thread,
81                                                                         exports.GetTaggedValue(),
82                                                                         bindingName,
83                                                                         false,
84                                                                         JSTaggedValue::Undefined())).GetTaggedValue();
85 }
86 
GetModuleValueFromIndexBinding(JSThread * thread,JSHandle<SourceTextModule> module,JSTaggedValue resolvedBinding)87 JSTaggedValue ModuleManagerHelper::GetModuleValueFromIndexBinding(JSThread *thread,
88                                                                   JSHandle<SourceTextModule> module,
89                                                                   JSTaggedValue resolvedBinding)
90 {
91     JSHandle<ResolvedRecordIndexBinding> binding(thread, resolvedBinding);
92     JSHandle<SourceTextModule> resolvedModule = GetResolvedRecordIndexBindingModule(thread, module, binding);
93     return GetModuleValue(thread, resolvedModule, binding->GetIndex());
94 }
95 
GetResolvedRecordIndexBindingModule(JSThread * thread,JSHandle<SourceTextModule> module,JSHandle<ResolvedRecordIndexBinding> binding)96 JSHandle<SourceTextModule> ModuleManagerHelper::GetResolvedRecordIndexBindingModule(
97     JSThread *thread, JSHandle<SourceTextModule> module, JSHandle<ResolvedRecordIndexBinding> binding)
98 {
99     JSHandle<JSTaggedValue> recordName(thread, binding->GetModuleRecord());
100     ASSERT(recordName->IsString());
101     // recordName is string, find at current vm
102     ModuleManager *moduleManager = thread->GetCurrentEcmaContext()->GetModuleManager();
103     CString recordNameStr = ModulePathHelper::Utf8ConvertToString(recordName.GetTaggedValue());
104     if (!moduleManager->IsEvaluatedModule(recordNameStr)) {
105         auto isMergedAbc = !module->GetEcmaModuleRecordNameString().empty();
106         CString fileName = ModulePathHelper::Utf8ConvertToString((binding->GetAbcFileName()));
107         if (!JSPandaFileExecutor::LazyExecuteModule(thread,
108             recordNameStr, fileName, isMergedAbc)) { // LCOV_EXCL_BR_LINE
109             LOG_ECMA(FATAL) << "LazyExecuteModule failed";
110         }
111     }
112     return moduleManager->HostGetImportedModule(recordNameStr);
113 }
114 
GetModuleValueFromRecordBinding(JSThread * thread,JSHandle<SourceTextModule> module,JSTaggedValue resolvedBinding)115 JSTaggedValue ModuleManagerHelper::GetModuleValueFromRecordBinding(JSThread *thread,
116                                                                    JSHandle<SourceTextModule> module,
117                                                                    JSTaggedValue resolvedBinding)
118 {
119     JSHandle<ResolvedRecordBinding> binding(thread, resolvedBinding);
120     JSHandle<SourceTextModule> resolvedModule = GetResolvedRecordBindingModule(thread, module, binding);
121     return GetModuleValue(thread, resolvedModule, binding->GetBindingName());
122 }
123 
GetResolvedRecordBindingModule(JSThread * thread,JSHandle<SourceTextModule> module,JSHandle<ResolvedRecordBinding> binding)124 JSHandle<SourceTextModule> ModuleManagerHelper::GetResolvedRecordBindingModule(JSThread *thread,
125                                                                                JSHandle<SourceTextModule> module,
126                                                                                JSHandle<ResolvedRecordBinding> binding)
127 {
128     JSHandle<JSTaggedValue> recordName(thread, binding->GetModuleRecord());
129     ASSERT(recordName->IsString());
130     CString recordNameStr = ModulePathHelper::Utf8ConvertToString(recordName.GetTaggedValue());
131     // moduleRecord is string, find at current vm
132     ModuleManager *moduleManager = thread->GetCurrentEcmaContext()->GetModuleManager();
133     if (!moduleManager->IsEvaluatedModule(recordNameStr)) {
134         auto isMergedAbc = !module->GetEcmaModuleRecordNameString().empty();
135         CString fileName = module->GetEcmaModuleFilenameString();
136         if (!JSPandaFileExecutor::LazyExecuteModule(thread,
137             recordNameStr, fileName, isMergedAbc)) { // LCOV_EXCL_BR_LINE
138             LOG_ECMA(FATAL) << "LazyExecuteModule failed";
139         }
140     }
141     return moduleManager->HostGetImportedModule(recordNameStr);
142 }
143 
GetLazyModuleValueFromIndexBinding(JSThread * thread,JSHandle<SourceTextModule> module,JSTaggedValue resolvedBinding)144 JSTaggedValue ModuleManagerHelper::GetLazyModuleValueFromIndexBinding(JSThread *thread,
145                                                                       JSHandle<SourceTextModule> module,
146                                                                       JSTaggedValue resolvedBinding)
147 {
148     JSHandle<ResolvedRecordIndexBinding> binding(thread, resolvedBinding);
149     JSHandle<JSTaggedValue> recordName(thread, binding->GetModuleRecord());
150     ASSERT(recordName->IsString());
151     // moduleRecord is string, find at current vm
152     ModuleManager *moduleManager = thread->GetCurrentEcmaContext()->GetModuleManager();
153     CString recordNameStr = ModulePathHelper::Utf8ConvertToString(recordName.GetTaggedValue());
154     JSHandle<SourceTextModule> resolvedModule;
155     if (moduleManager->IsLocalModuleLoaded(recordNameStr)) {
156         resolvedModule = moduleManager->HostGetImportedModule(recordNameStr);
157         if (!moduleManager->IsEvaluatedModule(recordNameStr)) {
158             SourceTextModule::Evaluate(thread, resolvedModule, nullptr);
159             RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSTaggedValue::Exception());
160         }
161     } else {
162         auto isMergedAbc = !module->GetEcmaModuleRecordNameString().empty();
163         CString fileName = ModulePathHelper::Utf8ConvertToString(binding->GetAbcFileName());
164         if (!JSPandaFileExecutor::LazyExecuteModule(thread,
165             recordNameStr, fileName, isMergedAbc)) { // LCOV_EXCL_BR_LINE
166             LOG_ECMA(FATAL) << "LazyExecuteModule failed";
167         }
168         resolvedModule = moduleManager->HostGetImportedModule(recordNameStr);
169     }
170     return GetModuleValue(thread, resolvedModule, binding->GetIndex());
171 }
172 
GetLazyModuleValueFromRecordBinding(JSThread * thread,JSHandle<SourceTextModule> module,JSTaggedValue resolvedBinding)173 JSTaggedValue ModuleManagerHelper::GetLazyModuleValueFromRecordBinding(
174     JSThread *thread, JSHandle<SourceTextModule> module, JSTaggedValue resolvedBinding)
175 {
176     JSHandle<ResolvedRecordBinding> binding(thread, resolvedBinding);
177     JSHandle<JSTaggedValue> recordName(thread, binding->GetModuleRecord());
178     ASSERT(recordName->IsString());
179     // moduleRecord is string, find at current vm
180     ModuleManager *moduleManager = thread->GetCurrentEcmaContext()->GetModuleManager();
181     CString recordNameStr = ModulePathHelper::Utf8ConvertToString(recordName.GetTaggedValue());
182     JSHandle<SourceTextModule> resolvedModule;
183     if (moduleManager->IsLocalModuleLoaded(recordNameStr)) {
184         resolvedModule = moduleManager->HostGetImportedModule(recordNameStr);
185         if (!moduleManager->IsEvaluatedModule(recordNameStr)) {
186             const ModuleTypes moduleType = resolvedModule->GetTypes();
187             if (SourceTextModule::IsNativeModule(moduleType)) {
188                 SourceTextModule::EvaluateNativeModule(thread, resolvedModule, moduleType);
189             } else {
190                 SourceTextModule::Evaluate(thread, resolvedModule, nullptr);
191             }
192             RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSTaggedValue::Exception());
193         }
194     } else {
195         auto isMergedAbc = !module->GetEcmaModuleRecordNameString().empty();
196         CString fileName = module->GetEcmaModuleFilenameString();
197         if (!JSPandaFileExecutor::LazyExecuteModule(thread,
198             recordNameStr, fileName, isMergedAbc)) { // LCOV_EXCL_BR_LINE
199             LOG_ECMA(FATAL) << "LazyExecuteModule failed";
200         }
201         resolvedModule = moduleManager->HostGetImportedModule(recordNameStr);
202     }
203     return GetModuleValue(thread, resolvedModule, binding->GetBindingName());
204 }
205 
UpdateBindingAndGetModuleValue(JSThread * thread,JSHandle<SourceTextModule> module,JSHandle<SourceTextModule> requiredModule,int32_t index,JSTaggedValue bindingName)206 JSTaggedValue ModuleManagerHelper::UpdateBindingAndGetModuleValue(JSThread *thread, JSHandle<SourceTextModule> module,
207     JSHandle<SourceTextModule> requiredModule, int32_t index, JSTaggedValue bindingName)
208 {
209     // Get esm environment
210     JSHandle<JSTaggedValue> moduleEnvironment(thread, module->GetEnvironment());
211     ASSERT(!moduleEnvironment->IsUndefined());
212     JSHandle<TaggedArray> environment = JSHandle<TaggedArray>::Cast(moduleEnvironment);
213     // rebinding here
214     JSHandle<JSTaggedValue> exports = GetNativeOrCjsExports(thread, requiredModule.GetTaggedValue());
215     RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSTaggedValue::Exception());
216     JSHandle<JSTaggedValue> exportName(thread, bindingName);
217     JSHandle<JSTaggedValue> resolution =
218         SourceTextModule::ResolveExportObject(thread, requiredModule, exports, exportName);
219     // ii. If resolution is null or "ambiguous", throw a SyntaxError exception.
220     if (resolution->IsNull() || resolution->IsString()) {
221         CString requestMod = ModulePathHelper::ReformatPath(SourceTextModule::GetModuleName(
222             requiredModule.GetTaggedValue()));
223         CString recordStr = ModulePathHelper::ReformatPath(SourceTextModule::GetModuleName(
224             module.GetTaggedValue()));
225         CString msg = "the requested module '" + requestMod + SourceTextModule::GetResolveErrorReason(resolution) +
226             ModulePathHelper::Utf8ConvertToString(bindingName) +
227             "' which imported by '" + recordStr + "'";
228         THROW_NEW_ERROR_WITH_MSG_AND_RETURN_VALUE(
229             thread, ErrorType::SYNTAX_ERROR, msg.c_str(), JSTaggedValue::Exception());
230     }
231     // iii. Call envRec.CreateImportBinding(
232     // in.[[LocalName]], resolution.[[Module]], resolution.[[BindingName]]).
233     environment->Set(thread, index, resolution);
234     ASSERT(resolution->IsResolvedIndexBinding());
235     ResolvedIndexBinding *binding = ResolvedIndexBinding::Cast(resolution.GetTaggedValue());
236     return SourceTextModule::GetValueFromExportObject(thread, exports, binding->GetIndex());
237 }
238 } // namespace panda::ecmascript
239