JSModuleNamespaceObject* AbstractModuleRecord::getModuleNamespace(ExecState* exec) { VM& vm = exec->vm(); auto scope = DECLARE_THROW_SCOPE(vm); // http://www.ecma-international.org/ecma-262/6.0/#sec-getmodulenamespace if (m_moduleNamespaceObject) return m_moduleNamespaceObject.get(); JSGlobalObject* globalObject = exec->lexicalGlobalObject(); IdentifierSet exportedNames; getExportedNames(exec, this, exportedNames); RETURN_IF_EXCEPTION(scope, nullptr); Vector<std::pair<Identifier, Resolution>> resolutions; for (auto& name : exportedNames) { Identifier ident = Identifier::fromUid(exec, name.get()); const Resolution resolution = resolveExport(exec, ident); RETURN_IF_EXCEPTION(scope, nullptr); switch (resolution.type) { case Resolution::Type::NotFound: throwSyntaxError(exec, scope, makeString("Exported binding name '", String(name.get()), "' is not found.")); return nullptr; case Resolution::Type::Error: throwSyntaxError(exec, scope, makeString("Exported binding name 'default' cannot be resolved by star export entries.")); return nullptr; case Resolution::Type::Ambiguous: break; case Resolution::Type::Resolved: resolutions.append({ WTFMove(ident), resolution }); break; } } auto* moduleNamespaceObject = JSModuleNamespaceObject::create(exec, globalObject, globalObject->moduleNamespaceObjectStructure(), this, WTFMove(resolutions)); RETURN_IF_EXCEPTION(scope, nullptr); m_moduleNamespaceObject.set(vm, this, moduleNamespaceObject); return moduleNamespaceObject; }
void JSModuleRecord::instantiateDeclarations(ExecState* exec, ModuleProgramExecutable* moduleProgramExecutable) { VM& vm = exec->vm(); auto scope = DECLARE_THROW_SCOPE(vm); // http://www.ecma-international.org/ecma-262/6.0/#sec-moduledeclarationinstantiation SymbolTable* symbolTable = moduleProgramExecutable->moduleEnvironmentSymbolTable(); JSModuleEnvironment* moduleEnvironment = JSModuleEnvironment::create(vm, exec->lexicalGlobalObject(), exec->lexicalGlobalObject(), symbolTable, jsTDZValue(), this); // http://www.ecma-international.org/ecma-262/6.0/#sec-moduledeclarationinstantiation // section 15.2.1.16.4 step 9. // Ensure all the indirect exports are correctly resolved to unique bindings. // Even if we avoided duplicate exports in the parser, still ambiguous exports occur due to the star export (`export * from "mod"`). // When we see this type of ambiguity for the indirect exports here, throw a syntax error. for (const auto& pair : exportEntries()) { const ExportEntry& exportEntry = pair.value; if (exportEntry.type == JSModuleRecord::ExportEntry::Type::Indirect) { Resolution resolution = resolveExport(exec, exportEntry.exportName); switch (resolution.type) { case Resolution::Type::NotFound: throwSyntaxError(exec, scope, makeString("Indirectly exported binding name '", String(exportEntry.exportName.impl()), "' is not found.")); return; case Resolution::Type::Ambiguous: throwSyntaxError(exec, scope, makeString("Indirectly exported binding name '", String(exportEntry.exportName.impl()), "' cannot be resolved due to ambiguous multiple bindings.")); return; case Resolution::Type::Error: throwSyntaxError(exec, scope, makeString("Indirectly exported binding name 'default' cannot be resolved by star export entries.")); return; case Resolution::Type::Resolved: break; } } } // http://www.ecma-international.org/ecma-262/6.0/#sec-moduledeclarationinstantiation // section 15.2.1.16.4 step 12. // Instantiate namespace objects and initialize the bindings with them if required. // And ensure that all the imports correctly resolved to unique bindings. for (const auto& pair : importEntries()) { const ImportEntry& importEntry = pair.value; AbstractModuleRecord* importedModule = hostResolveImportedModule(exec, importEntry.moduleRequest); if (importEntry.isNamespace(vm)) { JSModuleNamespaceObject* namespaceObject = importedModule->getModuleNamespace(exec); RETURN_IF_EXCEPTION(scope, void()); bool putResult = false; symbolTablePutTouchWatchpointSet(moduleEnvironment, exec, importEntry.localName, namespaceObject, /* shouldThrowReadOnlyError */ false, /* ignoreReadOnlyErrors */ true, putResult); } else { Resolution resolution = importedModule->resolveExport(exec, importEntry.importName); switch (resolution.type) { case Resolution::Type::NotFound: throwSyntaxError(exec, scope, makeString("Importing binding name '", String(importEntry.importName.impl()), "' is not found.")); return; case Resolution::Type::Ambiguous: throwSyntaxError(exec, scope, makeString("Importing binding name '", String(importEntry.importName.impl()), "' cannot be resolved due to ambiguous multiple bindings.")); return; case Resolution::Type::Error: throwSyntaxError(exec, scope, makeString("Importing binding name 'default' cannot be resolved by star export entries.")); return; case Resolution::Type::Resolved: break; } } } // http://www.ecma-international.org/ecma-262/6.0/#sec-moduledeclarationinstantiation // section 15.2.1.16.4 step 14. // Module environment contains the heap allocated "var", "function", "let", "const", and "class". // When creating the environment, we initialized all the slots with empty, it's ok for lexical values. // But for "var" and "function", we should initialize it with undefined. They are contained in the declared variables. for (const auto& variable : declaredVariables()) { SymbolTableEntry entry = symbolTable->get(variable.key.get()); VarOffset offset = entry.varOffset(); if (!offset.isStack()) { bool putResult = false; symbolTablePutTouchWatchpointSet(moduleEnvironment, exec, Identifier::fromUid(exec, variable.key.get()), jsUndefined(), /* shouldThrowReadOnlyError */ false, /* ignoreReadOnlyErrors */ true, putResult); } } // http://www.ecma-international.org/ecma-262/6.0/#sec-moduledeclarationinstantiation // section 15.2.1.16.4 step 16-a-iv. // Initialize heap allocated function declarations. // They can be called before the body of the module is executed under circular dependencies. UnlinkedModuleProgramCodeBlock* unlinkedCodeBlock = moduleProgramExecutable->unlinkedModuleProgramCodeBlock(); for (size_t i = 0, numberOfFunctions = unlinkedCodeBlock->numberOfFunctionDecls(); i < numberOfFunctions; ++i) { UnlinkedFunctionExecutable* unlinkedFunctionExecutable = unlinkedCodeBlock->functionDecl(i); SymbolTableEntry entry = symbolTable->get(unlinkedFunctionExecutable->name().impl()); VarOffset offset = entry.varOffset(); if (!offset.isStack()) { ASSERT(!unlinkedFunctionExecutable->name().isEmpty()); if (vm.typeProfiler() || vm.controlFlowProfiler()) { vm.functionHasExecutedCache()->insertUnexecutedRange(moduleProgramExecutable->sourceID(), unlinkedFunctionExecutable->typeProfilingStartOffset(), unlinkedFunctionExecutable->typeProfilingEndOffset()); } JSFunction* function = JSFunction::create(vm, unlinkedFunctionExecutable->link(vm, moduleProgramExecutable->source()), moduleEnvironment); bool putResult = false; symbolTablePutTouchWatchpointSet(moduleEnvironment, exec, unlinkedFunctionExecutable->name(), function, /* shouldThrowReadOnlyError */ false, /* ignoreReadOnlyErrors */ true, putResult); } } m_moduleEnvironment.set(vm, this, moduleEnvironment); }