!3005 Add import *,import {a} mode when ESM require CommonJS

Merge pull request !3005 from yaochaonan/import
This commit is contained in:
openharmony_ci 2022-11-25 13:15:18 +00:00 committed by Gitee
commit ef4671b753
No known key found for this signature in database
GPG Key ID: 173E9B9CA92EEF8F
8 changed files with 212 additions and 18 deletions

View File

@ -93,7 +93,20 @@ JSTaggedValue ModuleManager::GetModuleValueOutterInternal(int32_t index, JSTagge
SourceTextModule *module = SourceTextModule::Cast(resolvedModule.GetTaggedObject());
if (module->GetTypes() == ModuleTypes::CJSMODULE) {
JSHandle<JSTaggedValue> cjsModuleName(thread, module->GetEcmaModuleFilename());
return CjsModule::SearchFromModuleCache(thread, cjsModuleName).GetTaggedValue();
JSTaggedValue cjsExports = CjsModule::SearchFromModuleCache(thread, cjsModuleName).GetTaggedValue();
// if cjsModule is not CjsExports, means cjs uses default exports.
if (!cjsExports.IsCjsExports()) {
if (cjsExports.IsHole()) {
LOG_FULL(FATAL) << "CAN NOT SEARCH FROM CJSMODULECACHE";
}
return cjsExports;
}
int32_t idx = binding->GetIndex();
JSObject *cjsObject = JSObject::Cast(cjsExports);
JSHClass *jsHclass = cjsObject->GetJSHClass();
LayoutInfo *layoutInfo = LayoutInfo::Cast(jsHclass->GetLayout().GetTaggedObject());
PropertyAttributes attr = layoutInfo->GetAttr(idx);
return cjsObject->GetProperty(jsHclass, attr);
}
return SourceTextModule::Cast(resolvedModule.GetTaggedObject())->GetModuleValue(thread,
binding->GetIndex(), false);
@ -502,7 +515,12 @@ JSTaggedValue ModuleManager::GetModuleNamespaceInternal(int32_t index, JSTaggedV
requiredModule = SourceTextModule::HostResolveImportedModuleWithMerge(thread,
JSHandle<SourceTextModule>(thread, module), JSHandle<JSTaggedValue>(thread, moduleName));
}
// if requiredModule is CommonJS
if (requiredModule->GetTypes() == ModuleTypes::CJSMODULE) {
JSHandle<JSTaggedValue> cjsModuleName(thread, requiredModule->GetEcmaModuleFilename());
return CjsModule::SearchFromModuleCache(thread, cjsModuleName).GetTaggedValue();
}
// if requiredModule is ESM
JSHandle<JSTaggedValue> moduleNamespace = SourceTextModule::GetModuleNamespace(thread, requiredModule);
ASSERT(moduleNamespace->IsModuleNamespace());
return moduleNamespace.GetTaggedValue();

View File

@ -122,22 +122,69 @@ JSHandle<SourceTextModule> SourceTextModule::HostResolveImportedModule(JSThread
return thread->GetEcmaVM()->GetModuleManager()->HostResolveImportedModule(baseFilename, moduleFilename);
}
bool SourceTextModule::CheckCircularImport(const JSHandle<SourceTextModule> &module,
const JSHandle<JSTaggedValue> &exportName,
CVector<std::pair<JSHandle<SourceTextModule>, JSHandle<JSTaggedValue>>> &resolveSet)
{
for (auto rr : resolveSet) {
// a. If module and r.[[Module]] are the same Module Record and
// SameValue(exportName, r.[[ExportName]]) is true, then
if (JSTaggedValue::SameValue(rr.first.GetTaggedValue(), module.GetTaggedValue()) &&
JSTaggedValue::SameValue(rr.second, exportName)) {
// i. Assert: This is a circular import request.
// ii. Return true.
return true;
}
}
return false;
}
JSHandle<JSTaggedValue> SourceTextModule::ResolveCjsExport(JSThread *thread, const JSHandle<SourceTextModule> &module,
const JSHandle<JSTaggedValue> &cjsModule,
const JSHandle<JSTaggedValue> &exportName,
CVector<std::pair<JSHandle<SourceTextModule>, JSHandle<JSTaggedValue>>> &resolveSet)
{
// 1. Let module be this Source Text Module Record.
auto globalConstants = thread->GlobalConstants();
// Check if circular import request.
// 2.For each Record { [[Module]], [[ExportName]] } r in resolveSet, do
if (CheckCircularImport(module, exportName, resolveSet)) {
return globalConstants->GetHandledNull();
}
// 3. Append the Record { [[Module]]: module, [[ExportName]]: exportName } to resolveSet.
resolveSet.emplace_back(std::make_pair(module, exportName));
// 4. if cjsModule IsCjsExports, means the cjs module has multiple outputs
if (cjsModule->IsCjsExports()) {
JSHClass *jsHclass = JSObject::Cast(cjsModule.GetTaggedValue())->GetJSHClass();
// Get layoutInfo and compare the input and output names of files
LayoutInfo *layoutInfo = LayoutInfo::Cast(jsHclass->GetLayout().GetTaggedObject());
if (layoutInfo->NumberOfElements() != 0) {
JSHandle<JSTaggedValue> resolution = ResolveCjsLocalExport(thread, layoutInfo, exportName, module);
if (!resolution->IsUndefined()) {
return resolution;
}
}
}
// 5. If cjsModule != IsCjsExports, means the cjs module use default output
JSHandle<JSTaggedValue> defaultString = globalConstants->GetHandledDefaultString();
if (JSTaggedValue::SameValue(exportName, defaultString)) {
// bind with a number
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
return JSHandle<JSTaggedValue>::Cast(factory->NewResolvedIndexBindingRecord(module, -1));
}
return globalConstants->GetHandledNull();
}
JSHandle<JSTaggedValue> SourceTextModule::ResolveExport(JSThread *thread, const JSHandle<SourceTextModule> &module,
const JSHandle<JSTaggedValue> &exportName,
CVector<std::pair<JSHandle<SourceTextModule>, JSHandle<JSTaggedValue>>> &resolveSet)
{
// 1. Let module be this Source Text Module Record.
// 2. For each Record { [[Module]], [[ExportName]] } r in resolveSet, do
auto globalConstants = thread->GlobalConstants();
for (auto rr : resolveSet) {
// a. If module and r.[[Module]] are the same Module Record and
// SameValue(exportName, r.[[ExportName]]) is true, then
if (JSTaggedValue::SameValue(rr.first.GetTaggedValue(), module.GetTaggedValue()) &&
JSTaggedValue::SameValue(rr.second, exportName)) {
// i. Assert: This is a circular import request.
// ii. Return null.
return globalConstants->GetHandledNull();
}
// Check if circular import request.
// 2.For each Record { [[Module]], [[ExportName]] } r in resolveSet, do
if (CheckCircularImport(module, exportName, resolveSet)) {
return globalConstants->GetHandledNull();
}
// 3. Append the Record { [[Module]]: module, [[ExportName]]: exportName } to resolveSet.
resolveSet.emplace_back(std::make_pair(module, exportName));
@ -190,6 +237,60 @@ JSHandle<JSTaggedValue> SourceTextModule::ResolveExport(JSThread *thread, const
return starResolution;
}
void SourceTextModule::CJSInstantiate(JSThread *thread, const JSHandle<SourceTextModule> &module,
const JSHandle<SourceTextModule> &requiredModule)
{
JSHandle<JSTaggedValue> cjsModuleName(thread, requiredModule->GetEcmaModuleFilename());
// Get exported cjs module
JSHandle<JSTaggedValue> cjsExports = CjsModule::SearchFromModuleCache(thread, cjsModuleName);
// Get esm environment
JSHandle<JSTaggedValue> moduleEnvironment(thread, SourceTextModule::Cast(
module.GetTaggedValue().GetTaggedObject())->GetEnvironment());
auto globalConstants = thread->GlobalConstants();
if (moduleEnvironment->IsUndefined()) {
CString msg = "moduleEnvironment is Undefined";
THROW_ERROR(thread, ErrorType::RANGE_ERROR, msg.c_str());
}
JSHandle<TaggedArray> environment(thread, TaggedArray::Cast(moduleEnvironment->GetTaggedObject()));
size_t length = environment->GetLength();
JSHandle<TaggedArray> importEntries(thread, module->GetImportEntries());
JSMutableHandle<ImportEntry> host(thread, globalConstants->GetUndefined());
JSMutableHandle<JSTaggedValue> moduleRequest(thread, globalConstants->GetUndefined());
JSMutableHandle<JSTaggedValue> importName(thread, globalConstants->GetUndefined());
// update required module
for (size_t idx = 0; idx < length; idx++) {
JSTaggedValue resolvedBinding = environment->Get(idx);
// if resolvedBinding.IsHole(), means that importname is * .
if (resolvedBinding.IsHole()) {
continue;
}
ResolvedIndexBinding *binding = ResolvedIndexBinding::Cast(resolvedBinding.GetTaggedObject());
JSTaggedValue resolvedModule = binding->GetModule();
JSHandle<SourceTextModule> requestedModule(thread, resolvedModule);
JSHandle<JSTaggedValue> moduleName(thread, requestedModule->GetEcmaModuleFilename());
// if not the same module, then don't have to update
if (!JSTaggedValue::SameValue(moduleName, cjsModuleName)) {
continue;
}
// rebinding here
host.Update(importEntries->Get(idx));
importName.Update(host->GetImportName());
// i. Let resolution be ? importedModule.ResolveExport(in.[[ImportName]], « »).
CVector<std::pair<JSHandle<SourceTextModule>, JSHandle<JSTaggedValue>>> resolveSet;
JSHandle<JSTaggedValue> resolution =
SourceTextModule::ResolveCjsExport(thread, requestedModule, cjsExports, importName, resolveSet);
// ii. If resolution is null or "ambiguous", throw a SyntaxError exception.
if (resolution->IsNull() || resolution->IsString()) {
CString msg = "find importName " + ConvertToString(importName.GetTaggedValue()) + " failed";
THROW_ERROR(thread, ErrorType::SYNTAX_ERROR, msg.c_str());
}
// iii. Call envRec.CreateImportBinding(
// in.[[LocalName]], resolution.[[Module]], resolution.[[BindingName]]).
environment->Set(thread, idx, resolution);
}
module->SetEnvironment(thread, environment);
}
int SourceTextModule::Instantiate(JSThread *thread, const JSHandle<SourceTextModule> &module)
{
// 1. Let module be this Source Text Module Record.
@ -626,6 +727,10 @@ int SourceTextModule::InnerModuleEvaluation(JSThread *thread, const JSHandle<Mod
int dfsAncIdx = std::min(module->GetDFSAncestorIndex(), requiredModule->GetDFSAncestorIndex());
module->SetDFSAncestorIndex(dfsAncIdx);
}
// if requiredModule == CommonJS, instantiate here (after CommonJS execution).
if ((requiredModule->GetTypes() == ModuleTypes::CJSMODULE)) {
CJSInstantiate(thread, module, requiredModule);
}
}
}
@ -963,6 +1068,20 @@ void SourceTextModule::AddExportName(JSThread *thread, const JSTaggedValue &expo
}
}
JSHandle<JSTaggedValue> SourceTextModule::ResolveCjsLocalExport(JSThread *thread,
LayoutInfo *layoutInfo,
const JSHandle<JSTaggedValue> &exportName,
const JSHandle<SourceTextModule> &module)
{
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
int propertiesNumber = layoutInfo->NumberOfElements();
int idx = layoutInfo->FindElementWithCache(thread, nullptr, exportName.GetTaggedValue(), propertiesNumber);
if (idx != -1) {
return JSHandle<JSTaggedValue>::Cast(factory->NewResolvedIndexBindingRecord(module, idx));
}
return thread->GlobalConstants()->GetHandledUndefined();
}
JSHandle<JSTaggedValue> SourceTextModule::ResolveLocalExport(JSThread *thread,
const JSHandle<JSTaggedValue> &exportEntry,
const JSHandle<JSTaggedValue> &exportName,
@ -977,7 +1096,9 @@ JSHandle<JSTaggedValue> SourceTextModule::ResolveLocalExport(JSThread *thread,
for (size_t idx = 0; idx < localExportEntriesLen; idx++) {
ee.Update(localExportEntries->Get(idx));
// a. If SameValue(exportName, e.[[ExportName]]) is true, then
if (JSTaggedValue::SameValue(ee->GetExportName(), exportName.GetTaggedValue())) {
// if module == CommonJS, export first, check after execution.
if ((JSTaggedValue::SameValue(ee->GetExportName(), exportName.GetTaggedValue())) ||
(module->GetTypes() == ModuleTypes::CJSMODULE)) {
// Adapter new module
if (module->GetIsNewBcVersion()) {
return JSHandle<JSTaggedValue>::Cast(factory->NewResolvedIndexBindingRecord(module, idx));

View File

@ -47,7 +47,11 @@ public:
static JSHandle<JSTaggedValue> ResolveExport(JSThread *thread, const JSHandle<SourceTextModule> &module,
const JSHandle<JSTaggedValue> &exportName,
CVector<std::pair<JSHandle<SourceTextModule>, JSHandle<JSTaggedValue>>> &resolveSet);
static JSHandle<JSTaggedValue> ResolveCjsExport(JSThread *thread,
const JSHandle<SourceTextModule> &module,
const JSHandle<JSTaggedValue> &cjsModule,
const JSHandle<JSTaggedValue> &exportName,
CVector<std::pair<JSHandle<SourceTextModule>, JSHandle<JSTaggedValue>>> &resolveSet);
// 15.2.1.16.4.1 InnerModuleInstantiation ( module, stack, index )
static int InnerModuleInstantiation(JSThread *thread, const JSHandle<ModuleRecord> &moduleRecord,
CVector<JSHandle<SourceTextModule>> &stack, int index);
@ -111,6 +115,8 @@ public:
const void *buffer = nullptr, size_t size = 0, bool excuteFromJob = false);
// 15.2.1.16.4 Instantiate()
static void CJSInstantiate(JSThread *thread, const JSHandle<SourceTextModule> &module,
const JSHandle<SourceTextModule> &requiredModule);
static int Instantiate(JSThread *thread, const JSHandle<SourceTextModule> &module);
JSTaggedValue GetModuleValue(JSThread *thread, int32_t index, bool isThrow);
@ -140,6 +146,13 @@ private:
static JSHandle<JSTaggedValue> ResolveLocalExport(JSThread *thread, const JSHandle<JSTaggedValue> &exportEntry,
const JSHandle<JSTaggedValue> &exportName,
const JSHandle<SourceTextModule> &module);
static JSHandle<JSTaggedValue> ResolveCjsLocalExport(JSThread *thread,
LayoutInfo *layoutInfo,
const JSHandle<JSTaggedValue> &exportName,
const JSHandle<SourceTextModule> &module);
static bool CheckCircularImport(const JSHandle<SourceTextModule> &module,
const JSHandle<JSTaggedValue> &exportName,
CVector<std::pair<JSHandle<SourceTextModule>, JSHandle<JSTaggedValue>>> &resolveSet);
static void CheckResolvedBinding(JSThread *thread, const JSHandle<SourceTextModule> &module);
static void CheckResolvedIndexBinding(JSThread *thread, const JSHandle<SourceTextModule> &module);
static JSTaggedValue FindByExport(const JSTaggedValue &exportEntriesTv, const JSTaggedValue &key,

View File

@ -43,7 +43,6 @@ void CjsModule::InitializeModule(JSThread *thread, JSHandle<CjsModule> &module,
JSHandle<JSTaggedValue> CjsModule::SearchFromModuleCache(JSThread *thread, JSHandle<JSTaggedValue> &filename)
{
[[maybe_unused]] EcmaHandleScope handleScope(thread);
JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
const GlobalEnvConstants *globalConst = thread->GlobalConstants();
@ -56,7 +55,7 @@ JSHandle<JSTaggedValue> CjsModule::SearchFromModuleCache(JSThread *thread, JSHan
JSHandle<CjsModuleCache> moduleCache = JSHandle<CjsModuleCache>(thread, modCache);
if (moduleCache->ContainsModule(filename.GetTaggedValue())) {
JSHandle<CjsModule> cachedModule = JSHandle<CjsModule>(thread,
moduleCache->GetModule(filename.GetTaggedValue()));
moduleCache->GetModule(filename.GetTaggedValue()));
JSHandle<JSTaggedValue> exportsName = globalConst->GetHandledCjsExportsString();
JSTaggedValue cachedExports = SlowRuntimeStub::LdObjByName(thread, cachedModule.GetTaggedValue(),
exportsName.GetTaggedValue(),

View File

@ -18,8 +18,16 @@ host_moduletest_action("Cjs") {
is_commonjs = true
}
host_moduletest_action("someArgsCjs") {
deps = []
is_commonjs = true
}
host_moduletest_action("moduleUseCjs") {
extra_modules = [ "Cjs" ]
deps = [ ":gen_Cjs_abc" ]
deps = [
":gen_Cjs_abc",
":gen_someArgsCjs_abc",
]
is_module = true
}

View File

@ -12,3 +12,6 @@
# limitations under the License.
"module use cjsModule"
"moduleJson"
jscall 1
true

View File

@ -20,4 +20,10 @@
* @tc.require: issueI5NO8G
*/
import cjs from "./Cjs"
print(JSON.stringify(cjs))
import * as ns from "./someArgsCjs"
import {json, fun} from "./someArgsCjs"
print(JSON.stringify(cjs));
print(JSON.stringify(json));
fun();
print(ns.tag);

View File

@ -0,0 +1,26 @@
/*
* Copyright (c) 2022 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* @tc.name:moduleUseCjs
* @tc.desc:test module CJS
* @tc.type: FUNC
* @tc.require: issueI5NO8G
*/
module.exports.json = "moduleJson";
module.exports.fun = function foo1 () {
print("jscall 1");
};
exports.tag = true;