diff options
author | Lorry Tar Creator <lorry-tar-importer@lorry> | 2017-06-27 06:07:23 +0000 |
---|---|---|
committer | Lorry Tar Creator <lorry-tar-importer@lorry> | 2017-06-27 06:07:23 +0000 |
commit | 1bf1084f2b10c3b47fd1a588d85d21ed0eb41d0c (patch) | |
tree | 46dcd36c86e7fbc6e5df36deb463b33e9967a6f7 /Source/JavaScriptCore/runtime/JSModuleRecord.cpp | |
parent | 32761a6cee1d0dee366b885b7b9c777e67885688 (diff) | |
download | WebKitGtk-tarball-master.tar.gz |
webkitgtk-2.16.5HEADwebkitgtk-2.16.5master
Diffstat (limited to 'Source/JavaScriptCore/runtime/JSModuleRecord.cpp')
-rw-r--r-- | Source/JavaScriptCore/runtime/JSModuleRecord.cpp | 213 |
1 files changed, 213 insertions, 0 deletions
diff --git a/Source/JavaScriptCore/runtime/JSModuleRecord.cpp b/Source/JavaScriptCore/runtime/JSModuleRecord.cpp new file mode 100644 index 000000000..ecb05842b --- /dev/null +++ b/Source/JavaScriptCore/runtime/JSModuleRecord.cpp @@ -0,0 +1,213 @@ +/* + * Copyright (C) 2015-2016 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "JSModuleRecord.h" + +#include "Error.h" +#include "Interpreter.h" +#include "JSCInlines.h" +#include "JSModuleEnvironment.h" +#include "JSModuleNamespaceObject.h" +#include "UnlinkedModuleProgramCodeBlock.h" + +namespace JSC { + +const ClassInfo JSModuleRecord::s_info = { "ModuleRecord", &Base::s_info, 0, CREATE_METHOD_TABLE(JSModuleRecord) }; + + +Structure* JSModuleRecord::createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) +{ + return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info()); +} + +JSModuleRecord* JSModuleRecord::create(ExecState* exec, VM& vm, Structure* structure, const Identifier& moduleKey, const SourceCode& sourceCode, const VariableEnvironment& declaredVariables, const VariableEnvironment& lexicalVariables) +{ + JSModuleRecord* instance = new (NotNull, allocateCell<JSModuleRecord>(vm.heap)) JSModuleRecord(vm, structure, moduleKey, sourceCode, declaredVariables, lexicalVariables); + instance->finishCreation(exec, vm); + return instance; +} +JSModuleRecord::JSModuleRecord(VM& vm, Structure* structure, const Identifier& moduleKey, const SourceCode& sourceCode, const VariableEnvironment& declaredVariables, const VariableEnvironment& lexicalVariables) + : Base(vm, structure, moduleKey) + , m_sourceCode(sourceCode) + , m_declaredVariables(declaredVariables) + , m_lexicalVariables(lexicalVariables) +{ +} + +void JSModuleRecord::destroy(JSCell* cell) +{ + JSModuleRecord* thisObject = static_cast<JSModuleRecord*>(cell); + thisObject->JSModuleRecord::~JSModuleRecord(); +} + +void JSModuleRecord::finishCreation(ExecState* exec, VM& vm) +{ + Base::finishCreation(exec, vm); + ASSERT(inherits(vm, info())); +} + +void JSModuleRecord::visitChildren(JSCell* cell, SlotVisitor& visitor) +{ + JSModuleRecord* thisObject = jsCast<JSModuleRecord*>(cell); + Base::visitChildren(thisObject, visitor); + visitor.append(thisObject->m_moduleProgramExecutable); +} + +void JSModuleRecord::link(ExecState* exec) +{ + VM& vm = exec->vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + ModuleProgramExecutable* executable = ModuleProgramExecutable::create(exec, sourceCode()); + if (!executable) { + throwSyntaxError(exec, scope); + return; + } + instantiateDeclarations(exec, executable); + RETURN_IF_EXCEPTION(scope, void()); + m_moduleProgramExecutable.set(vm, this, executable); +} + +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); +} + +JSValue JSModuleRecord::evaluate(ExecState* exec) +{ + if (!m_moduleProgramExecutable) + return jsUndefined(); + JSValue result = exec->interpreter()->execute(m_moduleProgramExecutable.get(), exec, m_moduleEnvironment.get()); + m_moduleProgramExecutable.clear(); + return result; +} + +} // namespace JSC |