[ES6] Introduce ModuleProgramExecutable families and compile Module code to bytecode
authorutatane.tea@gmail.com <utatane.tea@gmail.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 1 Sep 2015 02:05:30 +0000 (02:05 +0000)
committerutatane.tea@gmail.com <utatane.tea@gmail.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 1 Sep 2015 02:05:30 +0000 (02:05 +0000)
https://bugs.webkit.org/show_bug.cgi?id=148581

Reviewed by Saam Barati.

Source/JavaScriptCore:

This patch introduces ModuleProgramExecutable, that is new executable type for the ES6 modules.
And related code block types, UninkedModuleProgramCodeBlock and ModuleProgramCodeBlock are also
introduced. BytecodeGenerator now recognizes these types and emits the bytecode and constructs
the symbol table for the module environment. While this patch introduces the bytecode generation
for the ES6 modules, the module environment instantiation initialization and imported binding
resolution are not included in this patch. They will be implemented in the subsequent patch.

The interesting part is the symbol table construction for the module environment.
Since the module code will be only executed once, the module environment need not to be allocated
and instantiated inside the module code; In the case of the function code, the function code need
to allocate the environment inside the prologue of it because the function code can be executed
more than once and the function environments are different in each time of the executions.
The module environment will be instantiated outside the module code before executing the module code.
This is required because we need to link the module environments to import the bindings before
executing the any module code in the dependency graph. And this is because the function inside the
module may be executed before the module top-level body is executed. (See the code comment for more
detailed situations)

The module environment will hold the top-most heap allocated variables in the module code.
This has the following benefits.
1) This enables JSC to perform the usual LocalClosureVar operations onto it.
2) It also makes the exported lexical variables just the heap allocated lexical variables.
3) Make it possible to initialize the heap allocated function declarations before executing the module
   code. It is required under the circular dependency (see the code comment for more details).

To do so, the module environment will be constructed with the symbol table that is generated by the
bytecode generator. And the symbol table is held by the unlinked code block. That means, once the module
environment is instantiated, we cannot clear the unlinked code block before executing the module since
the layout of the instantiated module environment is coupled with the unlinked code block. This is OK
because the module code can be cleared once we executed the module code. If we failed to execute the
module (some errors occur), we can throw away the both, the module environment and the unlinked code block.

The unlinked module program code block holds the symbol table, but it does not hold the module environment.
So the unlinked module program code block can be cached. While unlinked code block can be cached, the linked
code block cannot be cached because it is already linked to the specific set of the module environment to
resolve the imported bindings.

* JavaScriptCore.xcodeproj/project.pbxproj:
* bytecode/BytecodeList.json:
* bytecode/CodeBlock.cpp:
(JSC::CodeBlock::inferredName):
(JSC::ModuleProgramCodeBlock::replacement):
(JSC::ProgramCodeBlock::capabilityLevelInternal):
(JSC::ModuleProgramCodeBlock::capabilityLevelInternal):
* bytecode/CodeBlock.h:
(JSC::ModuleProgramCodeBlock::ModuleProgramCodeBlock):
(JSC::EvalCodeBlock::EvalCodeBlock):
(JSC::FunctionCodeBlock::FunctionCodeBlock):
* bytecode/CodeType.cpp:
(WTF::printInternal):
* bytecode/CodeType.h:
* bytecode/UnlinkedCodeBlock.cpp:
(JSC::UnlinkedModuleProgramCodeBlock::visitChildren):
(JSC::UnlinkedModuleProgramCodeBlock::destroy):
(JSC::UnlinkedCodeBlock::visitChildren): Deleted.
* bytecode/UnlinkedCodeBlock.h:
(JSC::UnlinkedCodeBlock::finishCreation): Deleted.
* bytecompiler/BytecodeGenerator.cpp:
(JSC::BytecodeGenerator::generate):
(JSC::BytecodeGenerator::BytecodeGenerator):
(JSC::BytecodeGenerator::instantiateLexicalVariables):
(JSC::BytecodeGenerator::emitPrefillStackTDZVariables):
(JSC::BytecodeGenerator::pushLexicalScopeInternal):
* bytecompiler/BytecodeGenerator.h:
* bytecompiler/NodesCodegen.cpp:
(JSC::emitProgramNodeBytecode):
(JSC::ProgramNode::emitBytecode):
(JSC::ModuleProgramNode::emitBytecode):
(JSC::ImportDeclarationNode::emitBytecode):
(JSC::ExportAllDeclarationNode::emitBytecode):
(JSC::ExportDefaultDeclarationNode::emitBytecode):
(JSC::ExportLocalDeclarationNode::emitBytecode):
(JSC::ExportNamedDeclarationNode::emitBytecode):
* interpreter/Interpreter.cpp:
(JSC::StackFrame::friendlySourceURL):
(JSC::StackFrame::friendlyFunctionName):
(JSC::getStackFrameCodeType):
* interpreter/Interpreter.h:
* interpreter/StackVisitor.cpp:
(JSC::StackVisitor::Frame::codeType):
(JSC::StackVisitor::Frame::functionName):
(JSC::StackVisitor::Frame::sourceURL):
* interpreter/StackVisitor.h:
* jit/JIT.cpp:
(JSC::JIT::privateCompile):
* llint/LLIntData.cpp:
(JSC::LLInt::Data::performAssertions):
* llint/LLIntEntrypoint.cpp:
(JSC::LLInt::setModuleProgramEntrypoint):
(JSC::LLInt::setEntrypoint):
* llint/LLIntOffsetsExtractor.cpp:
* llint/LLIntThunks.cpp:
(JSC::LLInt::moduleProgramEntryThunkGenerator):
* llint/LLIntThunks.h:
* llint/LowLevelInterpreter.asm:
* parser/ModuleAnalyzer.cpp:
(JSC::ModuleAnalyzer::exportVariable):
* parser/Parser.cpp:
(JSC::Parser<LexerType>::parseImportClauseItem):
(JSC::Parser<LexerType>::parseExportDeclaration):
* parser/Parser.h:
(JSC::Scope::declareLexicalVariable):
* parser/VariableEnvironment.h:
(JSC::VariableEnvironmentEntry::isImportedNamespace):
(JSC::VariableEnvironmentEntry::setIsImportedNamespace):
(JSC::VariableEnvironment::find):
* runtime/CodeCache.cpp:
(JSC::CodeCache::getGlobalCodeBlock):
(JSC::CodeCache::getModuleProgramCodeBlock):
* runtime/CodeCache.h:
* runtime/Executable.cpp:
(JSC::ScriptExecutable::installCode):
(JSC::ScriptExecutable::newCodeBlockFor):
(JSC::ScriptExecutable::newReplacementCodeBlockFor):
(JSC::ModuleProgramExecutable::ModuleProgramExecutable):
(JSC::ModuleProgramExecutable::create):
(JSC::ModuleProgramExecutable::destroy):
(JSC::ModuleProgramExecutable::visitChildren):
(JSC::ModuleProgramExecutable::clearCode):
(JSC::ExecutableBase::dump):
* runtime/Executable.h:
(JSC::ExecutableBase::isModuleProgramExecutable):
(JSC::ExecutableBase::clearCodeVirtual):
* runtime/JSGlobalObject.cpp:
(JSC::JSGlobalObject::createModuleProgramCodeBlock):
* runtime/JSGlobalObject.h:
* runtime/JSModuleRecord.cpp:
(JSC::JSModuleRecord::visitChildren):
(JSC::JSModuleRecord::link):
* runtime/JSModuleRecord.h:
(JSC::JSModuleRecord::moduleProgramExecutable):
* runtime/JSType.h:
* runtime/ModuleLoaderObject.cpp:
(JSC::moduleLoaderObjectModuleDeclarationInstantiation):
* runtime/VM.cpp:
(JSC::VM::VM):
* runtime/VM.h:

Source/WebCore:

Add the ModuleProgramExecutable case.

* testing/Internals.cpp:
(WebCore::Internals::parserMetaData):

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@189201 268f45cc-cd09-0410-ab3c-d52691b4dbfc

41 files changed:
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj
Source/JavaScriptCore/bytecode/BytecodeList.json
Source/JavaScriptCore/bytecode/CodeBlock.cpp
Source/JavaScriptCore/bytecode/CodeBlock.h
Source/JavaScriptCore/bytecode/CodeType.cpp
Source/JavaScriptCore/bytecode/CodeType.h
Source/JavaScriptCore/bytecode/UnlinkedCodeBlock.cpp
Source/JavaScriptCore/bytecode/UnlinkedCodeBlock.h
Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp
Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h
Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp
Source/JavaScriptCore/interpreter/Interpreter.cpp
Source/JavaScriptCore/interpreter/Interpreter.h
Source/JavaScriptCore/interpreter/StackVisitor.cpp
Source/JavaScriptCore/interpreter/StackVisitor.h
Source/JavaScriptCore/jit/JIT.cpp
Source/JavaScriptCore/llint/LLIntData.cpp
Source/JavaScriptCore/llint/LLIntEntrypoint.cpp
Source/JavaScriptCore/llint/LLIntOffsetsExtractor.cpp
Source/JavaScriptCore/llint/LLIntThunks.cpp
Source/JavaScriptCore/llint/LLIntThunks.h
Source/JavaScriptCore/llint/LowLevelInterpreter.asm
Source/JavaScriptCore/parser/ModuleAnalyzer.cpp
Source/JavaScriptCore/parser/Parser.cpp
Source/JavaScriptCore/parser/Parser.h
Source/JavaScriptCore/parser/VariableEnvironment.h
Source/JavaScriptCore/runtime/CodeCache.cpp
Source/JavaScriptCore/runtime/CodeCache.h
Source/JavaScriptCore/runtime/Executable.cpp
Source/JavaScriptCore/runtime/Executable.h
Source/JavaScriptCore/runtime/JSGlobalObject.cpp
Source/JavaScriptCore/runtime/JSGlobalObject.h
Source/JavaScriptCore/runtime/JSModuleRecord.cpp
Source/JavaScriptCore/runtime/JSModuleRecord.h
Source/JavaScriptCore/runtime/JSType.h
Source/JavaScriptCore/runtime/ModuleLoaderObject.cpp
Source/JavaScriptCore/runtime/VM.cpp
Source/JavaScriptCore/runtime/VM.h
Source/WebCore/ChangeLog
Source/WebCore/testing/Internals.cpp

index 2c64e55..60d2e5c 100644 (file)
@@ -1,3 +1,148 @@
+2015-08-31  Yusuke Suzuki  <utatane.tea@gmail.com>
+
+        [ES6] Introduce ModuleProgramExecutable families and compile Module code to bytecode
+        https://bugs.webkit.org/show_bug.cgi?id=148581
+
+        Reviewed by Saam Barati.
+
+        This patch introduces ModuleProgramExecutable, that is new executable type for the ES6 modules.
+        And related code block types, UninkedModuleProgramCodeBlock and ModuleProgramCodeBlock are also
+        introduced. BytecodeGenerator now recognizes these types and emits the bytecode and constructs
+        the symbol table for the module environment. While this patch introduces the bytecode generation
+        for the ES6 modules, the module environment instantiation initialization and imported binding
+        resolution are not included in this patch. They will be implemented in the subsequent patch.
+
+        The interesting part is the symbol table construction for the module environment.
+        Since the module code will be only executed once, the module environment need not to be allocated
+        and instantiated inside the module code; In the case of the function code, the function code need
+        to allocate the environment inside the prologue of it because the function code can be executed
+        more than once and the function environments are different in each time of the executions.
+        The module environment will be instantiated outside the module code before executing the module code.
+        This is required because we need to link the module environments to import the bindings before
+        executing the any module code in the dependency graph. And this is because the function inside the
+        module may be executed before the module top-level body is executed. (See the code comment for more
+        detailed situations)
+
+        The module environment will hold the top-most heap allocated variables in the module code.
+        This has the following benefits.
+        1) This enables JSC to perform the usual LocalClosureVar operations onto it.
+        2) It also makes the exported lexical variables just the heap allocated lexical variables.
+        3) Make it possible to initialize the heap allocated function declarations before executing the module
+           code. It is required under the circular dependency (see the code comment for more details).
+
+        To do so, the module environment will be constructed with the symbol table that is generated by the
+        bytecode generator. And the symbol table is held by the unlinked code block. That means, once the module
+        environment is instantiated, we cannot clear the unlinked code block before executing the module since
+        the layout of the instantiated module environment is coupled with the unlinked code block. This is OK
+        because the module code can be cleared once we executed the module code. If we failed to execute the
+        module (some errors occur), we can throw away the both, the module environment and the unlinked code block.
+
+        The unlinked module program code block holds the symbol table, but it does not hold the module environment.
+        So the unlinked module program code block can be cached. While unlinked code block can be cached, the linked
+        code block cannot be cached because it is already linked to the specific set of the module environment to
+        resolve the imported bindings.
+
+        * JavaScriptCore.xcodeproj/project.pbxproj:
+        * bytecode/BytecodeList.json:
+        * bytecode/CodeBlock.cpp:
+        (JSC::CodeBlock::inferredName):
+        (JSC::ModuleProgramCodeBlock::replacement):
+        (JSC::ProgramCodeBlock::capabilityLevelInternal):
+        (JSC::ModuleProgramCodeBlock::capabilityLevelInternal):
+        * bytecode/CodeBlock.h:
+        (JSC::ModuleProgramCodeBlock::ModuleProgramCodeBlock):
+        (JSC::EvalCodeBlock::EvalCodeBlock):
+        (JSC::FunctionCodeBlock::FunctionCodeBlock):
+        * bytecode/CodeType.cpp:
+        (WTF::printInternal):
+        * bytecode/CodeType.h:
+        * bytecode/UnlinkedCodeBlock.cpp:
+        (JSC::UnlinkedModuleProgramCodeBlock::visitChildren):
+        (JSC::UnlinkedModuleProgramCodeBlock::destroy):
+        (JSC::UnlinkedCodeBlock::visitChildren): Deleted.
+        * bytecode/UnlinkedCodeBlock.h:
+        (JSC::UnlinkedCodeBlock::finishCreation): Deleted.
+        * bytecompiler/BytecodeGenerator.cpp:
+        (JSC::BytecodeGenerator::generate):
+        (JSC::BytecodeGenerator::BytecodeGenerator):
+        (JSC::BytecodeGenerator::instantiateLexicalVariables):
+        (JSC::BytecodeGenerator::emitPrefillStackTDZVariables):
+        (JSC::BytecodeGenerator::pushLexicalScopeInternal):
+        * bytecompiler/BytecodeGenerator.h:
+        * bytecompiler/NodesCodegen.cpp:
+        (JSC::emitProgramNodeBytecode):
+        (JSC::ProgramNode::emitBytecode):
+        (JSC::ModuleProgramNode::emitBytecode):
+        (JSC::ImportDeclarationNode::emitBytecode):
+        (JSC::ExportAllDeclarationNode::emitBytecode):
+        (JSC::ExportDefaultDeclarationNode::emitBytecode):
+        (JSC::ExportLocalDeclarationNode::emitBytecode):
+        (JSC::ExportNamedDeclarationNode::emitBytecode):
+        * interpreter/Interpreter.cpp:
+        (JSC::StackFrame::friendlySourceURL):
+        (JSC::StackFrame::friendlyFunctionName):
+        (JSC::getStackFrameCodeType):
+        * interpreter/Interpreter.h:
+        * interpreter/StackVisitor.cpp:
+        (JSC::StackVisitor::Frame::codeType):
+        (JSC::StackVisitor::Frame::functionName):
+        (JSC::StackVisitor::Frame::sourceURL):
+        * interpreter/StackVisitor.h:
+        * jit/JIT.cpp:
+        (JSC::JIT::privateCompile):
+        * llint/LLIntData.cpp:
+        (JSC::LLInt::Data::performAssertions):
+        * llint/LLIntEntrypoint.cpp:
+        (JSC::LLInt::setModuleProgramEntrypoint):
+        (JSC::LLInt::setEntrypoint):
+        * llint/LLIntOffsetsExtractor.cpp:
+        * llint/LLIntThunks.cpp:
+        (JSC::LLInt::moduleProgramEntryThunkGenerator):
+        * llint/LLIntThunks.h:
+        * llint/LowLevelInterpreter.asm:
+        * parser/ModuleAnalyzer.cpp:
+        (JSC::ModuleAnalyzer::exportVariable):
+        * parser/Parser.cpp:
+        (JSC::Parser<LexerType>::parseImportClauseItem):
+        (JSC::Parser<LexerType>::parseExportDeclaration):
+        * parser/Parser.h:
+        (JSC::Scope::declareLexicalVariable):
+        * parser/VariableEnvironment.h:
+        (JSC::VariableEnvironmentEntry::isImportedNamespace):
+        (JSC::VariableEnvironmentEntry::setIsImportedNamespace):
+        (JSC::VariableEnvironment::find):
+        * runtime/CodeCache.cpp:
+        (JSC::CodeCache::getGlobalCodeBlock):
+        (JSC::CodeCache::getModuleProgramCodeBlock):
+        * runtime/CodeCache.h:
+        * runtime/Executable.cpp:
+        (JSC::ScriptExecutable::installCode):
+        (JSC::ScriptExecutable::newCodeBlockFor):
+        (JSC::ScriptExecutable::newReplacementCodeBlockFor):
+        (JSC::ModuleProgramExecutable::ModuleProgramExecutable):
+        (JSC::ModuleProgramExecutable::create):
+        (JSC::ModuleProgramExecutable::destroy):
+        (JSC::ModuleProgramExecutable::visitChildren):
+        (JSC::ModuleProgramExecutable::clearCode):
+        (JSC::ExecutableBase::dump):
+        * runtime/Executable.h:
+        (JSC::ExecutableBase::isModuleProgramExecutable):
+        (JSC::ExecutableBase::clearCodeVirtual):
+        * runtime/JSGlobalObject.cpp:
+        (JSC::JSGlobalObject::createModuleProgramCodeBlock):
+        * runtime/JSGlobalObject.h:
+        * runtime/JSModuleRecord.cpp:
+        (JSC::JSModuleRecord::visitChildren):
+        (JSC::JSModuleRecord::link):
+        * runtime/JSModuleRecord.h:
+        (JSC::JSModuleRecord::moduleProgramExecutable):
+        * runtime/JSType.h:
+        * runtime/ModuleLoaderObject.cpp:
+        (JSC::moduleLoaderObjectModuleDeclarationInstantiation):
+        * runtime/VM.cpp:
+        (JSC::VM::VM):
+        * runtime/VM.h:
+
 2015-08-31  Basile Clement  <basile_clement@apple.com>
 
         Unreviewed, build fix after r189292
index 6ec8820..f22e716 100644 (file)
                E124A8F70E555775003091F1 /* OpaqueJSString.h in Headers */ = {isa = PBXBuildFile; fileRef = E124A8F50E555775003091F1 /* OpaqueJSString.h */; settings = {ATTRIBUTES = (Private, ); }; };
                E124A8F80E555775003091F1 /* OpaqueJSString.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E124A8F60E555775003091F1 /* OpaqueJSString.cpp */; };
                E18E3A590DF9278C00D90B34 /* VM.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E18E3A570DF9278C00D90B34 /* VM.cpp */; };
+               E30677981B8BC6F5003F87F0 /* ModuleLoaderObject.js in Resources */ = {isa = PBXBuildFile; fileRef = E30677971B8BC6F5003F87F0 /* ModuleLoaderObject.js */; };
                E33637A51B63220200EE0840 /* ReflectObject.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E33637A31B63220200EE0840 /* ReflectObject.cpp */; };
                E33637A61B63220200EE0840 /* ReflectObject.h in Headers */ = {isa = PBXBuildFile; fileRef = E33637A41B63220200EE0840 /* ReflectObject.h */; settings = {ATTRIBUTES = (Private, ); }; };
                E33B3E261B7ABD750048DB2E /* InspectorInstrumentationObject.lut.h in Headers */ = {isa = PBXBuildFile; fileRef = E33B3E251B7ABD750048DB2E /* InspectorInstrumentationObject.lut.h */; };
                E178636C0D9BEEC300D74E75 /* InitializeThreading.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = InitializeThreading.cpp; sourceTree = "<group>"; };
                E18E3A560DF9278C00D90B34 /* VM.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = VM.h; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; };
                E18E3A570DF9278C00D90B34 /* VM.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; path = VM.cpp; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.cpp; };
+               E30677971B8BC6F5003F87F0 /* ModuleLoaderObject.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = ModuleLoaderObject.js; sourceTree = "<group>"; };
                E33637A31B63220200EE0840 /* ReflectObject.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ReflectObject.cpp; sourceTree = "<group>"; };
                E33637A41B63220200EE0840 /* ReflectObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ReflectObject.h; sourceTree = "<group>"; };
                E33B3E251B7ABD750048DB2E /* InspectorInstrumentationObject.lut.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InspectorInstrumentationObject.lut.h; sourceTree = "<group>"; };
                                E35E03611B7AB4850073AD2A /* InspectorInstrumentationObject.js */,
                                E33F50881B844A1A00413856 /* InternalPromiseConstructor.js */,
                                7CF9BC5B1B65D9A3009DB1EF /* Iterator.prototype.js */,
+                               E30677971B8BC6F5003F87F0 /* ModuleLoaderObject.js */,
                                7CF9BC5C1B65D9B1009DB1EF /* ObjectConstructor.js */,
                                7CF9BC5D1B65D9B1009DB1EF /* Operations.Promise.js */,
                                7CFBAC1C18B535E500D00750 /* Promise.prototype.js */,
                        isa = PBXResourcesBuildPhase;
                        buildActionMask = 2147483647;
                        files = (
+                               E30677981B8BC6F5003F87F0 /* ModuleLoaderObject.js in Resources */,
                                A53F1AC018C90F8F0072EB6D /* framework.sb in Resources */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
index 4e5a96c..020ec24 100644 (file)
         "bytecodes" : [
             { "name" : "llint_program_prologue" },
             { "name" : "llint_eval_prologue" },
+            { "name" : "llint_module_program_prologue" },
             { "name" : "llint_function_for_call_prologue" },
             { "name" : "llint_function_for_construct_prologue" },
             { "name" : "llint_function_for_call_arity_check" },
index f8a0f4b..c4c66d3 100644 (file)
@@ -87,6 +87,8 @@ CString CodeBlock::inferredName() const
         return "<eval>";
     case FunctionCode:
         return jsCast<FunctionExecutable*>(ownerExecutable())->inferredName().utf8();
+    case ModuleCode:
+        return "<module>";
     default:
         CRASH();
         return CString("", 0);
@@ -3062,6 +3064,11 @@ CodeBlock* ProgramCodeBlock::replacement()
     return jsCast<ProgramExecutable*>(ownerExecutable())->codeBlock();
 }
 
+CodeBlock* ModuleProgramCodeBlock::replacement()
+{
+    return jsCast<ModuleProgramExecutable*>(ownerExecutable())->codeBlock();
+}
+
 CodeBlock* EvalCodeBlock::replacement()
 {
     return jsCast<EvalExecutable*>(ownerExecutable())->codeBlock();
@@ -3077,6 +3084,11 @@ DFG::CapabilityLevel ProgramCodeBlock::capabilityLevelInternal()
     return DFG::programCapabilityLevel(this);
 }
 
+DFG::CapabilityLevel ModuleProgramCodeBlock::capabilityLevelInternal()
+{
+    return DFG::programCapabilityLevel(this);
+}
+
 DFG::CapabilityLevel EvalCodeBlock::capabilityLevelInternal()
 {
     return DFG::evalCapabilityLevel(this);
index cb9ebd6..bddd036 100644 (file)
@@ -1102,10 +1102,29 @@ protected:
 #endif
 };
 
+class ModuleProgramCodeBlock : public GlobalCodeBlock {
+public:
+    ModuleProgramCodeBlock(CopyParsedBlockTag, ModuleProgramCodeBlock& other)
+        : GlobalCodeBlock(CopyParsedBlock, other)
+    {
+    }
+
+    ModuleProgramCodeBlock(ModuleProgramExecutable* ownerExecutable, UnlinkedModuleProgramCodeBlock* unlinkedCodeBlock, JSScope* scope, PassRefPtr<SourceProvider> sourceProvider, unsigned firstLineColumnOffset)
+        : GlobalCodeBlock(ownerExecutable, unlinkedCodeBlock, scope, sourceProvider, 0, firstLineColumnOffset)
+    {
+    }
+
+#if ENABLE(JIT)
+protected:
+    virtual CodeBlock* replacement() override;
+    virtual DFG::CapabilityLevel capabilityLevelInternal() override;
+#endif
+};
+
 class EvalCodeBlock : public GlobalCodeBlock {
 public:
     EvalCodeBlock(CopyParsedBlockTag, EvalCodeBlock& other)
-    : GlobalCodeBlock(CopyParsedBlock, other)
+        : GlobalCodeBlock(CopyParsedBlock, other)
     {
     }
         
@@ -1130,7 +1149,7 @@ private:
 class FunctionCodeBlock : public CodeBlock {
 public:
     FunctionCodeBlock(CopyParsedBlockTag, FunctionCodeBlock& other)
-    : CodeBlock(CopyParsedBlock, other)
+        : CodeBlock(CopyParsedBlock, other)
     {
     }
 
index 8b2cad5..0c7043d 100644 (file)
@@ -42,6 +42,9 @@ void printInternal(PrintStream& out, JSC::CodeType codeType)
     case JSC::FunctionCode:
         out.print("Function");
         return;
+    case JSC::ModuleCode:
+        out.print("Module");
+        return;
     default:
         CRASH();
         return;
index b8e107d..9941d51 100644 (file)
@@ -28,7 +28,7 @@
 
 namespace JSC {
 
-enum CodeType { GlobalCode, EvalCode, FunctionCode };
+enum CodeType { GlobalCode, EvalCode, FunctionCode, ModuleCode };
 
 } // namespace JSC
 
index 574b1e4..2fe1bb8 100644 (file)
@@ -47,6 +47,7 @@ namespace JSC {
 const ClassInfo UnlinkedCodeBlock::s_info = { "UnlinkedCodeBlock", 0, 0, CREATE_METHOD_TABLE(UnlinkedCodeBlock) };
 const ClassInfo UnlinkedGlobalCodeBlock::s_info = { "UnlinkedGlobalCodeBlock", &Base::s_info, 0, CREATE_METHOD_TABLE(UnlinkedGlobalCodeBlock) };
 const ClassInfo UnlinkedProgramCodeBlock::s_info = { "UnlinkedProgramCodeBlock", &Base::s_info, 0, CREATE_METHOD_TABLE(UnlinkedProgramCodeBlock) };
+const ClassInfo UnlinkedModuleProgramCodeBlock::s_info = { "UnlinkedModuleProgramCodeBlock", &Base::s_info, nullptr, CREATE_METHOD_TABLE(UnlinkedModuleProgramCodeBlock) };
 const ClassInfo UnlinkedEvalCodeBlock::s_info = { "UnlinkedEvalCodeBlock", &Base::s_info, 0, CREATE_METHOD_TABLE(UnlinkedEvalCodeBlock) };
 const ClassInfo UnlinkedFunctionCodeBlock::s_info = { "UnlinkedFunctionCodeBlock", &Base::s_info, 0, CREATE_METHOD_TABLE(UnlinkedFunctionCodeBlock) };
 
@@ -89,7 +90,6 @@ void UnlinkedCodeBlock::visitChildren(JSCell* cell, SlotVisitor& visitor)
     UnlinkedCodeBlock* thisObject = jsCast<UnlinkedCodeBlock*>(cell);
     ASSERT_GC_OBJECT_INHERITS(thisObject, info());
     Base::visitChildren(thisObject, visitor);
-    visitor.append(&thisObject->m_symbolTable);
     for (FunctionExpressionVector::iterator ptr = thisObject->m_functionDecls.begin(), end = thisObject->m_functionDecls.end(); ptr != end; ++ptr)
         visitor.append(ptr);
     for (FunctionExpressionVector::iterator ptr = thisObject->m_functionExprs.begin(), end = thisObject->m_functionExprs.end(); ptr != end; ++ptr)
@@ -292,6 +292,14 @@ void UnlinkedProgramCodeBlock::visitChildren(JSCell* cell, SlotVisitor& visitor)
     Base::visitChildren(thisObject, visitor);
 }
 
+void UnlinkedModuleProgramCodeBlock::visitChildren(JSCell* cell, SlotVisitor& visitor)
+{
+    UnlinkedModuleProgramCodeBlock* thisObject = jsCast<UnlinkedModuleProgramCodeBlock*>(cell);
+    ASSERT_GC_OBJECT_INHERITS(thisObject, info());
+    Base::visitChildren(thisObject, visitor);
+    visitor.append(&thisObject->m_moduleEnvironmentSymbolTable);
+}
+
 UnlinkedCodeBlock::~UnlinkedCodeBlock()
 {
 }
@@ -301,6 +309,11 @@ void UnlinkedProgramCodeBlock::destroy(JSCell* cell)
     jsCast<UnlinkedProgramCodeBlock*>(cell)->~UnlinkedProgramCodeBlock();
 }
 
+void UnlinkedModuleProgramCodeBlock::destroy(JSCell* cell)
+{
+    jsCast<UnlinkedModuleProgramCodeBlock*>(cell)->~UnlinkedModuleProgramCodeBlock();
+}
+
 void UnlinkedEvalCodeBlock::destroy(JSCell* cell)
 {
     jsCast<UnlinkedEvalCodeBlock*>(cell)->~UnlinkedEvalCodeBlock();
index 322d261..4095a90 100644 (file)
@@ -360,9 +360,6 @@ protected:
     void finishCreation(VM& vm)
     {
         Base::finishCreation(vm);
-        if (codeType() == GlobalCode)
-            return;
-        m_symbolTable.set(vm, this, SymbolTable::create(vm));
     }
 
 private:
@@ -412,8 +409,6 @@ private:
     FunctionExpressionVector m_functionDecls;
     FunctionExpressionVector m_functionExprs;
 
-    WriteBarrier<SymbolTable> m_symbolTable;
-
     Vector<unsigned> m_propertyAccessInstructions;
 
 #if ENABLE(BYTECODE_COMMENTS)
@@ -514,6 +509,71 @@ public:
     DECLARE_INFO;
 };
 
+class UnlinkedModuleProgramCodeBlock final : public UnlinkedGlobalCodeBlock {
+private:
+    friend class CodeCache;
+    static UnlinkedModuleProgramCodeBlock* create(VM* vm, const ExecutableInfo& info)
+    {
+        UnlinkedModuleProgramCodeBlock* instance = new (NotNull, allocateCell<UnlinkedModuleProgramCodeBlock>(vm->heap)) UnlinkedModuleProgramCodeBlock(vm, vm->unlinkedModuleProgramCodeBlockStructure.get(), info);
+        instance->finishCreation(*vm);
+        return instance;
+    }
+
+public:
+    typedef UnlinkedGlobalCodeBlock Base;
+    static const unsigned StructureFlags = Base::StructureFlags | StructureIsImmortal;
+
+    static void destroy(JSCell*);
+
+    static void visitChildren(JSCell*, SlotVisitor&);
+
+    // This symbol table represents the layout of the module environment. This symbol table will be modified by the byte
+    // code generator since the module environment includes the top-most lexical captured variables inside the module code.
+    // This means that, once the module environment is allocated and instantiated from this symbol table, it is titely
+    // coupled with the specific unlinked module program code block and the symbol table. So before executing the module
+    // code, we should not clear the unlinked module program code block in the module executable. This requirement is met
+    // because the garbage collector only clears unlinked code in (1) unmarked executables and (2) function executables.
+    //
+    // Since the function code may be executed repeatedly and the environment of each function execution is different,
+    // the function code need to allocate and instantiate the environment in the prologue of the function code. On the
+    // other hand, the module code is executed only once. So we can instantiate the module environment outside the module
+    // code. At that time, we construct the module environment by using this symbol table before executing the module code.
+    // Instantiating the module environment before executing the module code is required to link the imported bindings
+    // between the modules.
+    //
+    // The unlinked module program code block only holds the symbol table. It does not hold the module environment. So while
+    // the module environment requires the specific unlinked module program code block, the unlinked module code block
+    // can be used for the module environment instantiated from this unlinked code block. There is 1:N relation between
+    // the unlinked module code block and the module environments. So the unlinked module program code block can be cached.
+    //
+    // On the other hand, the linked code block for the module environment includes the resolved references to the imported
+    // bindings. The imported binding references the other module environment, so the linked code block is titly coupled
+    // with the specific set of the module environments. Thus, the linked code block should not be cached.
+    SymbolTable* moduleEnvironmentSymbolTable() { return m_moduleEnvironmentSymbolTable.get(); }
+
+private:
+    UnlinkedModuleProgramCodeBlock(VM* vm, Structure* structure, const ExecutableInfo& info)
+        : Base(vm, structure, ModuleCode, info)
+    {
+    }
+
+    void finishCreation(VM& vm)
+    {
+        Base::finishCreation(vm);
+        m_moduleEnvironmentSymbolTable.set(vm, this, SymbolTable::create(vm));
+    }
+
+    WriteBarrier<SymbolTable> m_moduleEnvironmentSymbolTable;
+
+public:
+    static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue proto)
+    {
+        return Structure::create(vm, globalObject, proto, TypeInfo(UnlinkedModuleProgramCodeBlockType, StructureFlags), info());
+    }
+
+    DECLARE_INFO;
+};
+
 class UnlinkedEvalCodeBlock final : public UnlinkedGlobalCodeBlock {
 private:
     friend class CodeCache;
index 62c2d3b..783b215 100644 (file)
@@ -70,7 +70,9 @@ ParserError BytecodeGenerator::generate()
     if (m_needToInitializeArguments)
         initializeVariable(variable(propertyNames().arguments), m_argumentsRegister);
 
-    pushLexicalScope(m_scopeNode, true);
+    // For ModuleCode, we already instantiated the environment for the lexical variables.
+    if (m_codeType != ModuleCode)
+        pushLexicalScope(m_scopeNode, true);
 
     {
         RefPtr<RegisterID> temp = newTemporary();
@@ -504,6 +506,146 @@ BytecodeGenerator::BytecodeGenerator(VM& vm, EvalNode* evalNode, UnlinkedEvalCod
     m_TDZStack.append(std::make_pair(*parentScopeTDZVariables, false));
 }
 
+BytecodeGenerator::BytecodeGenerator(VM& vm, ModuleProgramNode* moduleProgramNode, UnlinkedModuleProgramCodeBlock* codeBlock, DebuggerMode debuggerMode, ProfilerMode profilerMode, const VariableEnvironment* parentScopeTDZVariables)
+    : m_shouldEmitDebugHooks(Options::forceDebuggerBytecodeGeneration() || debuggerMode == DebuggerOn)
+    , m_shouldEmitProfileHooks(Options::forceProfilerBytecodeGeneration() || profilerMode == ProfilerOn)
+    , m_scopeNode(moduleProgramNode)
+    , m_codeBlock(vm, codeBlock)
+    , m_thisRegister(CallFrame::thisArgumentOffset())
+    , m_codeType(ModuleCode)
+    , m_vm(&vm)
+    , m_usesNonStrictEval(false)
+{
+    ASSERT_UNUSED(parentScopeTDZVariables, !parentScopeTDZVariables->size());
+
+    for (auto& constantRegister : m_linkTimeConstantRegisters)
+        constantRegister = nullptr;
+
+    if (m_isBuiltinFunction)
+        m_shouldEmitDebugHooks = false;
+
+    // Use the symbol table allocated in the unlinked code block. This symbol table
+    // will be used to allocate and instantiate the module environment.
+    SymbolTable* moduleEnvironmentSymbolTable = codeBlock->moduleEnvironmentSymbolTable();
+    moduleEnvironmentSymbolTable->setUsesNonStrictEval(m_usesNonStrictEval);
+    moduleEnvironmentSymbolTable->setScopeType(SymbolTable::ScopeType::LexicalScope);
+
+    bool shouldCaptureSomeOfTheThings = m_shouldEmitDebugHooks || m_codeBlock->needsFullScopeChain();
+    bool shouldCaptureAllOfTheThings = m_shouldEmitDebugHooks || codeBlock->usesEval();
+    if (shouldCaptureAllOfTheThings)
+        moduleProgramNode->varDeclarations().markAllVariablesAsCaptured();
+
+    auto captures = [&] (UniquedStringImpl* uid) -> bool {
+        if (!shouldCaptureSomeOfTheThings)
+            return false;
+        return moduleProgramNode->captures(uid);
+    };
+    auto lookUpVarKind = [&] (UniquedStringImpl* uid, const VariableEnvironmentEntry& entry) -> VarKind {
+        // Allocate the exported variables in the module environment.
+        if (entry.isExported())
+            return VarKind::Scope;
+
+        // Allocate the namespace variables in the module environment to instantiate
+        // it from the outside of the module code.
+        if (entry.isImportedNamespace())
+            return VarKind::Scope;
+
+        if (entry.isCaptured())
+            return VarKind::Scope;
+        return captures(uid) ? VarKind::Scope : VarKind::Stack;
+    };
+
+    emitOpcode(op_enter);
+
+    allocateAndEmitScope();
+
+    m_calleeRegister.setIndex(JSStack::Callee);
+
+    m_codeBlock->setNumParameters(1); // Allocate space for "this"
+
+    // Now declare all variables.
+
+    for (auto& entry : moduleProgramNode->varDeclarations()) {
+        ASSERT(!entry.value.isLet() && !entry.value.isConst());
+        if (!entry.value.isVar()) // This is either a parameter or callee.
+            continue;
+        // Imported bindings are not allocated in the module environment as usual variables' way.
+        // These references remain the "Dynamic" in the unlinked code block. Later, when linking
+        // the code block, we resolve the reference to the "ModuleVar".
+        if (entry.value.isImported() && !entry.value.isImportedNamespace())
+            continue;
+        createVariable(Identifier::fromUid(m_vm, entry.key.get()), lookUpVarKind(entry.key.get(), entry.value), moduleEnvironmentSymbolTable, IgnoreExisting);
+    }
+
+    VariableEnvironment& lexicalVariables = moduleProgramNode->lexicalVariables();
+    instantiateLexicalVariables(lexicalVariables, moduleEnvironmentSymbolTable, ScopeRegisterType::Block, lookUpVarKind);
+
+    RegisterID* constantSymbolTable = nullptr;
+    if (vm.typeProfiler())
+        constantSymbolTable = addConstantValue(moduleEnvironmentSymbolTable);
+    else
+        constantSymbolTable = addConstantValue(moduleEnvironmentSymbolTable->cloneScopePart(*m_vm));
+
+    m_TDZStack.append(std::make_pair(lexicalVariables, true));
+    m_symbolTableStack.append(SymbolTableStackEntry { Strong<SymbolTable>(*m_vm, moduleEnvironmentSymbolTable), m_topMostScope, false, constantSymbolTable->index() });
+    emitPrefillStackTDZVariables(lexicalVariables, moduleEnvironmentSymbolTable);
+
+    // makeFunction assumes that there's correct TDZ stack entries.
+    // So it should be called after putting our lexical environment to the TDZ stack correctly.
+
+    for (FunctionMetadataNode* function : moduleProgramNode->functionStack()) {
+        const auto& iterator = moduleProgramNode->varDeclarations().find(function->ident().impl());
+        RELEASE_ASSERT(iterator != moduleProgramNode->varDeclarations().end());
+        RELEASE_ASSERT(!iterator->value.isImported());
+
+        VarKind varKind = lookUpVarKind(iterator->key.get(), iterator->value);
+        if (varKind == VarKind::Scope) {
+            // http://www.ecma-international.org/ecma-262/6.0/#sec-moduledeclarationinstantiation
+            // Section 15.2.1.16.4, step 16-a-iv-1.
+            // All heap allocated function declarations should be instantiated when the module environment
+            // is created. They include the exported function declarations and not-exported-but-heap-allocated
+            // function declarations. This is required because exported function should be instantiated before
+            // executing the any module in the dependency graph. This enables the modules to link the imported
+            // bindings before executing the any module code.
+            //
+            // And since function declarations are instantiated before executing the module body code, the spec
+            // allows the functions inside the module to be executed before its module body is executed under
+            // the circular dependencies. The following is the example.
+            //
+            // Module A (executed first):
+            //    import { b } from "B";
+            //    // Here, the module "B" is not executed yet, but the function declaration is already instantiated.
+            //    // So we can call the function exported from "B".
+            //    b();
+            //
+            //    export function a() {
+            //    }
+            //
+            // Module B (executed second):
+            //    import { a } from "A";
+            //
+            //    export function b() {
+            //        c();
+            //    }
+            //
+            //    // c is not exported, but since it is referenced from the b, we should instantiate it before
+            //    // executing the "B" module code.
+            //    function c() {
+            //        a();
+            //    }
+            //
+            // Module EntryPoint (executed last):
+            //    import "B";
+            //    import "A";
+            //
+            m_codeBlock->addFunctionDecl(makeFunction(function));
+        } else {
+            // Stack allocated functions can be allocated when executing the module's body.
+            m_functionsToInitialize.append(std::make_pair(function, NormalFunctionVariable));
+        }
+    }
+}
+
 BytecodeGenerator::~BytecodeGenerator()
 {
 }
@@ -1367,6 +1509,71 @@ RegisterID* BytecodeGenerator::emitLoadGlobalObject(RegisterID* dst)
     return m_globalObjectRegister;
 }
 
+template<typename LookUpVarKindFunctor>
+bool BytecodeGenerator::instantiateLexicalVariables(const VariableEnvironment& lexicalVariables, SymbolTable* symbolTable, ScopeRegisterType scopeRegisterType, LookUpVarKindFunctor lookUpVarKind)
+{
+    bool hasCapturedVariables = false;
+    {
+        ConcurrentJITLocker locker(symbolTable->m_lock);
+        for (auto& entry : lexicalVariables) {
+            ASSERT(entry.value.isLet() || entry.value.isConst());
+            ASSERT(!entry.value.isVar());
+            SymbolTableEntry symbolTableEntry = symbolTable->get(locker, entry.key.get());
+            ASSERT(symbolTableEntry.isNull());
+
+            // Imported bindings which are not the namespace bindings are not allocated
+            // in the module environment as usual variables' way.
+            // And since these types of the variables only seen in the module environment,
+            // other lexical environment need not to take care this.
+            if (entry.value.isImported() && !entry.value.isImportedNamespace())
+                continue;
+
+            VarKind varKind = lookUpVarKind(entry.key.get(), entry.value);
+            VarOffset varOffset;
+            if (varKind == VarKind::Scope) {
+                varOffset = VarOffset(symbolTable->takeNextScopeOffset(locker));
+                hasCapturedVariables = true;
+            } else {
+                ASSERT(varKind == VarKind::Stack);
+                RegisterID* local;
+                if (scopeRegisterType == ScopeRegisterType::Block) {
+                    local = newBlockScopeVariable();
+                    local->ref();
+                } else
+                    local = addVar();
+                varOffset = VarOffset(local->virtualRegister());
+            }
+
+            SymbolTableEntry newEntry(varOffset, entry.value.isConst() ? ReadOnly : 0);
+            symbolTable->add(locker, entry.key.get(), newEntry);
+        }
+    }
+    return hasCapturedVariables;
+}
+
+void BytecodeGenerator::emitPrefillStackTDZVariables(const VariableEnvironment& lexicalVariables, SymbolTable* symbolTable)
+{
+    // Prefill stack variables with the TDZ empty value.
+    // Scope variables will be initialized to the TDZ empty value when JSLexicalEnvironment is allocated.
+    for (auto& entry : lexicalVariables) {
+        // Imported bindings which are not the namespace bindings are not allocated
+        // in the module environment as usual variables' way.
+        // And since these types of the variables only seen in the module environment,
+        // other lexical environment need not to take care this.
+        if (entry.value.isImported() && !entry.value.isImportedNamespace())
+            continue;
+
+        SymbolTableEntry symbolTableEntry = symbolTable->get(entry.key.get());
+        ASSERT(!symbolTableEntry.isNull());
+        VarOffset offset = symbolTableEntry.varOffset();
+        if (offset.isScope())
+            continue;
+
+        ASSERT(offset.isStack());
+        emitMoveEmptyValue(&registerFor(offset.stackOffset()));
+    }
+}
+
 void BytecodeGenerator::pushLexicalScope(VariableEnvironmentNode* node, bool canOptimizeTDZChecks, RegisterID** constantSymbolTableResult)
 {
     VariableEnvironment& environment = node->lexicalVariables();
@@ -1395,35 +1602,11 @@ void BytecodeGenerator::pushLexicalScopeInternal(VariableEnvironment& environmen
         break;
     }
 
-    bool hasCapturedVariables = false;
-    {
-        ConcurrentJITLocker locker(symbolTable->m_lock);
-        for (auto& entry : environment) {
-            ASSERT(entry.value.isLet() || entry.value.isConst());
-            ASSERT(!entry.value.isVar());
-            SymbolTableEntry symbolTableEntry = symbolTable->get(locker, entry.key.get());
-            ASSERT(symbolTableEntry.isNull());
-
-            VarKind varKind = entry.value.isCaptured() ? VarKind::Scope : VarKind::Stack;
-            VarOffset varOffset;
-            if (varKind == VarKind::Scope) {
-                varOffset = VarOffset(symbolTable->takeNextScopeOffset(locker));
-                hasCapturedVariables = true;
-            } else {
-                ASSERT(varKind == VarKind::Stack);
-                RegisterID* local;
-                if (scopeRegisterType == ScopeRegisterType::Block) {
-                    local = newBlockScopeVariable();
-                    local->ref();
-                } else
-                    local = addVar();
-                varOffset = VarOffset(local->virtualRegister());
-            }
+    auto lookUpVarKind = [] (UniquedStringImpl*, const VariableEnvironmentEntry& entry) -> VarKind {
+        return entry.isCaptured() ? VarKind::Scope : VarKind::Stack;
+    };
 
-            SymbolTableEntry newEntry(varOffset, entry.value.isConst() ? ReadOnly : 0);
-            symbolTable->add(locker, entry.key.get(), newEntry);
-        }
-    }
+    bool hasCapturedVariables = instantiateLexicalVariables(environment, symbolTable.get(), scopeRegisterType, lookUpVarKind);
 
     RegisterID* newScope = nullptr;
     RegisterID* constantSymbolTable = nullptr;
@@ -1461,21 +1644,8 @@ void BytecodeGenerator::pushLexicalScopeInternal(VariableEnvironment& environmen
     if (tdzRequirement == TDZRequirement::UnderTDZ)
         m_TDZStack.append(std::make_pair(environment, canOptimizeTDZChecks));
 
-    if (tdzRequirement == TDZRequirement::UnderTDZ) {
-        // Prefill stack variables with the TDZ empty value.
-        // Scope variables will be initialized to the TDZ empty value when JSLexicalEnvironment is allocated.
-        for (auto& entry : environment) {
-            SymbolTableEntry symbolTableEntry = symbolTable->get(entry.key.get());
-            ASSERT(!symbolTableEntry.isNull());
-            VarOffset offset = symbolTableEntry.varOffset();
-            if (offset.isScope()) {
-                ASSERT(newScope);
-                continue;
-            }
-            ASSERT(offset.isStack());
-            emitMoveEmptyValue(&registerFor(offset.stackOffset()));
-        }
-    }
+    if (tdzRequirement == TDZRequirement::UnderTDZ)
+        emitPrefillStackTDZVariables(environment, symbolTable.get());
 }
 
 void BytecodeGenerator::popLexicalScope(VariableEnvironmentNode* node)
index 89cdead..ebf7d17 100644 (file)
@@ -269,6 +269,7 @@ namespace JSC {
         BytecodeGenerator(VM&, ProgramNode*, UnlinkedProgramCodeBlock*, DebuggerMode, ProfilerMode, const VariableEnvironment*);
         BytecodeGenerator(VM&, FunctionNode*, UnlinkedFunctionCodeBlock*, DebuggerMode, ProfilerMode, const VariableEnvironment*);
         BytecodeGenerator(VM&, EvalNode*, UnlinkedEvalCodeBlock*, DebuggerMode, ProfilerMode, const VariableEnvironment*);
+        BytecodeGenerator(VM&, ModuleProgramNode*, UnlinkedModuleProgramCodeBlock*, DebuggerMode, ProfilerMode, const VariableEnvironment*);
 
         ~BytecodeGenerator();
         
@@ -635,6 +636,9 @@ namespace JSC {
         enum class ScopeRegisterType { Var, Block };
         void pushLexicalScopeInternal(VariableEnvironment&, bool canOptimizeTDZChecks, RegisterID** constantSymbolTableResult, TDZRequirement, ScopeType, ScopeRegisterType);
         void popLexicalScopeInternal(VariableEnvironment&, TDZRequirement);
+        template<typename LookUpVarKindFunctor>
+        bool instantiateLexicalVariables(const VariableEnvironment&, SymbolTable*, ScopeRegisterType, LookUpVarKindFunctor);
+        void emitPrefillStackTDZVariables(const VariableEnvironment&, SymbolTable*);
         void emitPopScope(RegisterID* dst, RegisterID* scope);
         RegisterID* emitGetParentScope(RegisterID* dst, RegisterID* scope);
         void emitPushFunctionNameScope(const Identifier& property, RegisterID* value, bool isCaptured);
index 9c6e76f..d328778 100644 (file)
@@ -2878,25 +2878,31 @@ inline void ScopeNode::emitStatementsBytecode(BytecodeGenerator& generator, Regi
     m_statements->emitBytecode(generator, dst);
 }
 
-// ------------------------------ ProgramNode -----------------------------
-
-void ProgramNode::emitBytecode(BytecodeGenerator& generator, RegisterID*)
+static void emitProgramNodeBytecode(BytecodeGenerator& generator, ScopeNode& scopeNode)
 {
-    generator.emitDebugHook(WillExecuteProgram, startLine(), startStartOffset(), startLineStartOffset());
+    generator.emitDebugHook(WillExecuteProgram, scopeNode.startLine(), scopeNode.startStartOffset(), scopeNode.startLineStartOffset());
 
     RefPtr<RegisterID> dstRegister = generator.newTemporary();
     generator.emitLoad(dstRegister.get(), jsUndefined());
-    generator.emitProfileControlFlow(startStartOffset());
-    emitStatementsBytecode(generator, dstRegister.get());
+    generator.emitProfileControlFlow(scopeNode.startStartOffset());
+    scopeNode.emitStatementsBytecode(generator, dstRegister.get());
 
-    generator.emitDebugHook(DidExecuteProgram, lastLine(), startOffset(), lineStartOffset());
+    generator.emitDebugHook(DidExecuteProgram, scopeNode.lastLine(), scopeNode.startOffset(), scopeNode.lineStartOffset());
     generator.emitEnd(dstRegister.get());
 }
 
+// ------------------------------ ProgramNode -----------------------------
+
+void ProgramNode::emitBytecode(BytecodeGenerator& generator, RegisterID*)
+{
+    emitProgramNodeBytecode(generator, *this);
+}
+
 // ------------------------------ ModuleProgramNode --------------------
 
-void ModuleProgramNode::emitBytecode(BytecodeGenerator&, RegisterID*)
+void ModuleProgramNode::emitBytecode(BytecodeGenerator& generator, RegisterID*)
 {
+    emitProgramNodeBytecode(generator, *this);
 }
 
 // ------------------------------ EvalNode -----------------------------
@@ -3057,30 +3063,37 @@ RegisterID* ClassExprNode::emitBytecode(BytecodeGenerator& generator, RegisterID
 
 void ImportDeclarationNode::emitBytecode(BytecodeGenerator&, RegisterID*)
 {
+    // Do nothing at runtime.
 }
 
 // ------------------------------ ExportAllDeclarationNode --------------------
 
 void ExportAllDeclarationNode::emitBytecode(BytecodeGenerator&, RegisterID*)
 {
+    // Do nothing at runtime.
 }
 
 // ------------------------------ ExportDefaultDeclarationNode ----------------
 
-void ExportDefaultDeclarationNode::emitBytecode(BytecodeGenerator&, RegisterID*)
+void ExportDefaultDeclarationNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
 {
+    ASSERT(m_declaration);
+    generator.emitNode(dst, m_declaration);
 }
 
 // ------------------------------ ExportLocalDeclarationNode ------------------
 
-void ExportLocalDeclarationNode::emitBytecode(BytecodeGenerator&, RegisterID*)
+void ExportLocalDeclarationNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
 {
+    ASSERT(m_declaration);
+    generator.emitNode(dst, m_declaration);
 }
 
 // ------------------------------ ExportNamedDeclarationNode ------------------
 
 void ExportNamedDeclarationNode::emitBytecode(BytecodeGenerator&, RegisterID*)
 {
+    // Do nothing at runtime.
 }
 
 // ------------------------------ DestructuringAssignmentNode -----------------
index 66fa8ec..fa62ea6 100644 (file)
@@ -97,6 +97,7 @@ String StackFrame::friendlySourceURL() const
     
     switch (codeType) {
     case StackFrameEvalCode:
+    case StackFrameModuleCode:
     case StackFrameFunctionCode:
     case StackFrameGlobalCode:
         if (!sourceURL.isEmpty())
@@ -118,6 +119,9 @@ String StackFrame::friendlyFunctionName(CallFrame* callFrame) const
     case StackFrameEvalCode:
         traceLine = "eval code";
         break;
+    case StackFrameModuleCode:
+        traceLine = "module code";
+        break;
     case StackFrameNativeCode:
         if (callee)
             traceLine = getCalculatedDisplayName(callFrame, stackFrameCallee).impl();
@@ -451,6 +455,8 @@ static StackFrameCodeType getStackFrameCodeType(StackVisitor& visitor)
     switch (visitor->codeType()) {
     case StackVisitor::Frame::Eval:
         return StackFrameEvalCode;
+    case StackVisitor::Frame::Module:
+        return StackFrameModuleCode;
     case StackVisitor::Frame::Function:
         return StackFrameFunctionCode;
     case StackVisitor::Frame::Global:
index 132c95d..038bca5 100644 (file)
@@ -54,8 +54,10 @@ namespace JSC {
     class JSArrowFunction;
     class JSFunction;
     class JSGlobalObject;
+    class JSModuleRecord;
     class LLIntOffsetsExtractor;
     class ProgramExecutable;
+    class ModuleProgramExecutable;
     class Register;
     class JSScope;
     class SamplingTool;
@@ -76,6 +78,7 @@ namespace JSC {
     enum StackFrameCodeType {
         StackFrameGlobalCode,
         StackFrameEvalCode,
+        StackFrameModuleCode,
         StackFrameFunctionCode,
         StackFrameNativeCode
     };
index 3f2b914..75f1772 100644 (file)
@@ -181,6 +181,8 @@ StackVisitor::Frame::CodeType StackVisitor::Frame::codeType() const
     switch (codeBlock()->codeType()) {
     case EvalCode:
         return CodeType::Eval;
+    case ModuleCode:
+        return CodeType::Module;
     case FunctionCode:
         return CodeType::Function;
     case GlobalCode:
@@ -199,6 +201,9 @@ String StackVisitor::Frame::functionName()
     case CodeType::Eval:
         traceLine = ASCIILiteral("eval code");
         break;
+    case CodeType::Module:
+        traceLine = ASCIILiteral("module code");
+        break;
     case CodeType::Native:
         if (callee)
             traceLine = getCalculatedDisplayName(callFrame(), callee).impl();
@@ -219,6 +224,7 @@ String StackVisitor::Frame::sourceURL()
 
     switch (codeType()) {
     case CodeType::Eval:
+    case CodeType::Module:
     case CodeType::Function:
     case CodeType::Global: {
         String sourceURL = codeBlock()->ownerScriptExecutable()->sourceURL();
index 0036a78..41bfc70 100644 (file)
@@ -52,6 +52,7 @@ public:
             Global,
             Eval,
             Function,
+            Module,
             Native
         };
 
index bbc8523..84f36d5 100644 (file)
@@ -486,6 +486,7 @@ CompilationResult JIT::privateCompile(JITCompilationEffort effort)
     
     switch (m_codeBlock->codeType()) {
     case GlobalCode:
+    case ModuleCode:
     case EvalCode:
         m_codeBlock->m_shouldAlwaysBeInlined = false;
         break;
index 7313fce..777cfde 100644 (file)
@@ -132,8 +132,8 @@ void Data::performAssertions(VM& vm)
     ASSERT(maxFrameExtentForSlowPathCall == 64);
 #endif
     ASSERT(StringType == 6);
-    ASSERT(ObjectType == 19);
-    ASSERT(FinalObjectType == 20);
+    ASSERT(ObjectType == 21);
+    ASSERT(FinalObjectType == 22);
     ASSERT(MasqueradesAsUndefined == 1);
     ASSERT(ImplementsHasInstance == 2);
     ASSERT(ImplementsDefaultHasInstance == 8);
@@ -141,6 +141,7 @@ void Data::performAssertions(VM& vm)
     ASSERT(GlobalCode == 0);
     ASSERT(EvalCode == 1);
     ASSERT(FunctionCode == 2);
+    ASSERT(ModuleCode == 3);
 
     static_assert(GlobalProperty == 0, "LLInt assumes GlobalProperty ResultType is == 0");
     static_assert(GlobalVar == 1, "LLInt assumes GlobalVar ResultType is == 1");
index 9d00106..a6c3d27 100644 (file)
@@ -97,12 +97,30 @@ static void setProgramEntrypoint(VM& vm, CodeBlock* codeBlock)
         adoptRef(new DirectJITCode(MacroAssemblerCodeRef::createLLIntCodeRef(llint_program_prologue), MacroAssemblerCodePtr(), JITCode::InterpreterThunk)));
 }
 
+static void setModuleProgramEntrypoint(VM& vm, CodeBlock* codeBlock)
+{
+#if ENABLE(JIT)
+    if (vm.canUseJIT()) {
+        codeBlock->setJITCode(
+            adoptRef(new DirectJITCode(vm.getCTIStub(moduleProgramEntryThunkGenerator), MacroAssemblerCodePtr(), JITCode::InterpreterThunk)));
+        return;
+    }
+#endif // ENABLE(JIT)
+
+    UNUSED_PARAM(vm);
+    codeBlock->setJITCode(
+        adoptRef(new DirectJITCode(MacroAssemblerCodeRef::createLLIntCodeRef(llint_module_program_prologue), MacroAssemblerCodePtr(), JITCode::InterpreterThunk)));
+}
+
 void setEntrypoint(VM& vm, CodeBlock* codeBlock)
 {
     switch (codeBlock->codeType()) {
     case GlobalCode:
         setProgramEntrypoint(vm, codeBlock);
         return;
+    case ModuleCode:
+        setModuleProgramEntrypoint(vm, codeBlock);
+        return;
     case EvalCode:
         setEvalEntrypoint(vm, codeBlock);
         return;
index a2a6b2b..9e3f448 100644 (file)
@@ -42,6 +42,7 @@
 #include "VM.h"
 #include "JSEnvironmentRecord.h"
 #include "JSGlobalObject.h"
+#include "JSModuleRecord.h"
 #include "JSObject.h"
 #include "JSStack.h"
 #include "JSString.h"
index 8ab96b3..af6884e 100644 (file)
@@ -88,6 +88,11 @@ MacroAssemblerCodeRef programEntryThunkGenerator(VM* vm)
     return generateThunkWithJumpTo(vm, LLInt::getCodeFunctionPtr(llint_program_prologue), "program");
 }
 
+MacroAssemblerCodeRef moduleProgramEntryThunkGenerator(VM* vm)
+{
+    return generateThunkWithJumpTo(vm, LLInt::getCodeFunctionPtr(llint_module_program_prologue), "module_program");
+}
+
 } // namespace LLInt
 
 #else // ENABLE(JIT)
index 0d1be6b..95b0f44 100644 (file)
@@ -46,6 +46,7 @@ MacroAssemblerCodeRef functionForCallArityCheckThunkGenerator(VM*);
 MacroAssemblerCodeRef functionForConstructArityCheckThunkGenerator(VM*);
 MacroAssemblerCodeRef evalEntryThunkGenerator(VM*);
 MacroAssemblerCodeRef programEntryThunkGenerator(VM*);
+MacroAssemblerCodeRef moduleProgramEntryThunkGenerator(VM*);
 
 } } // namespace JSC::LLInt
 
index 136c916..75c91f8 100644 (file)
@@ -161,8 +161,8 @@ const SlowPutArrayStorageShape = 30
 
 # Type constants.
 const StringType = 6
-const ObjectType = 19
-const FinalObjectType = 20
+const ObjectType = 21
+const FinalObjectType = 22
 
 # Type flags constants.
 const MasqueradesAsUndefined = 1
@@ -176,6 +176,7 @@ const FirstConstantRegisterIndex = 0x40000000
 const GlobalCode = 0
 const EvalCode = 1
 const FunctionCode = 2
+const ModuleCode = 3
 
 # The interpreter steals the tag word of the argument count.
 const LLIntReturnPC = ArgumentCount + TagOffset
@@ -884,6 +885,11 @@ _llint_program_prologue:
     dispatch(0)
 
 
+_llint_module_program_prologue:
+    prologue(notFunctionCodeBlockGetter, notFunctionCodeBlockSetter, _llint_entry_osr, _llint_trace_prologue)
+    dispatch(0)
+
+
 _llint_eval_prologue:
     prologue(notFunctionCodeBlockGetter, notFunctionCodeBlockSetter, _llint_entry_osr, _llint_trace_prologue)
     dispatch(0)
index 2fa81aa..f6238fb 100644 (file)
@@ -83,7 +83,7 @@ void ModuleAnalyzer::exportVariable(const RefPtr<UniquedStringImpl>& localName,
     }
 
     const auto& importEntry = moduleRecord()->lookUpImportEntry(localName);
-    if (importEntry.isNamespace(vm())) {
+    if (variable.isImportedNamespace()) {
         // Exported namespace binding.
         // import * as namespace from "mod"
         // export { namespace }
index 8a93615..7f0501c 100644 (file)
@@ -2319,7 +2319,7 @@ template <class TreeBuilder> typename TreeBuilder::ImportSpecifier Parser<LexerT
     }
 
     semanticFailIfTrue(localNameToken.m_type & KeywordTokenFlag, "Cannot use keyword as imported binding name");
-    DeclarationResultMask declarationResult = declareVariable(localName, DeclarationType::ConstDeclaration, DeclarationImportType::Imported);
+    DeclarationResultMask declarationResult = declareVariable(localName, DeclarationType::ConstDeclaration, (specifierType == ImportSpecifierType::NamespaceImport) ? DeclarationImportType::ImportedNamespace : DeclarationImportType::Imported);
     if (declarationResult != DeclarationResult::Valid) {
         failIfTrueIfStrict(declarationResult & DeclarationResult::InvalidStrictMode, "Cannot declare an imported binding named ", localName->impl(), " in strict mode");
         if (declarationResult & DeclarationResult::InvalidDuplicateDeclaration)
@@ -2560,10 +2560,8 @@ template <class TreeBuilder> TreeStatement Parser<LexerType>::parseExportDeclara
             // does not have effect on the current module's scope. But,
             //   export { A, B, C as D }
             // will reference the current module's bindings.
-            for (const Identifier* localName : maybeLocalNames) {
-                currentScope()->useVariable(localName, m_vm->propertyNames->eval == *localName);
+            for (const Identifier* localName : maybeLocalNames)
                 currentScope()->moduleScopeData().exportBinding(*localName);
-            }
         }
 
         return context.createExportNamedDeclaration(exportLocation, specifierList, moduleName);
index c2e6a65..f697be3 100644 (file)
@@ -100,6 +100,7 @@ enum class DeclarationType {
 
 enum class DeclarationImportType {
     Imported,
+    ImportedNamespace,
     NotImported
 };
 
@@ -335,6 +336,10 @@ struct Scope {
 
         if (importType == DeclarationImportType::Imported)
             addResult.iterator->value.setIsImported();
+        else if (importType == DeclarationImportType::ImportedNamespace) {
+            addResult.iterator->value.setIsImported();
+            addResult.iterator->value.setIsImportedNamespace();
+        }
 
         if (!addResult.isNewEntry)
             result |= DeclarationResult::InvalidDuplicateDeclaration;
index 5ed2a6b..76c7096 100644 (file)
@@ -40,6 +40,7 @@ public:
     ALWAYS_INLINE bool isLet() const { return m_bits & IsLet; }
     ALWAYS_INLINE bool isExported() const { return m_bits & IsExported; }
     ALWAYS_INLINE bool isImported() const { return m_bits & IsImported; }
+    ALWAYS_INLINE bool isImportedNamespace() const { return m_bits & IsImportedNamespace; }
 
     ALWAYS_INLINE void setIsCaptured() { m_bits |= IsCaptured; }
     ALWAYS_INLINE void setIsConst() { m_bits |= IsConst; }
@@ -47,6 +48,7 @@ public:
     ALWAYS_INLINE void setIsLet() { m_bits |= IsLet; }
     ALWAYS_INLINE void setIsExported() { m_bits |= IsExported; }
     ALWAYS_INLINE void setIsImported() { m_bits |= IsImported; }
+    ALWAYS_INLINE void setIsImportedNamespace() { m_bits |= IsImportedNamespace; }
 
     ALWAYS_INLINE void clearIsVar() { m_bits &= ~IsVar; }
 
@@ -57,7 +59,8 @@ private:
         IsVar = 1 << 2,
         IsLet = 1 << 3,
         IsExported = 1 << 4,
-        IsImported = 1 << 5
+        IsImported = 1 << 5,
+        IsImportedNamespace = 1 << 6
     };
     uint8_t m_bits { 0 };
 };
@@ -79,6 +82,8 @@ public:
     ALWAYS_INLINE unsigned size() const { return m_map.size(); }
     ALWAYS_INLINE bool contains(const RefPtr<UniquedStringImpl>& identifier) const { return m_map.contains(identifier); }
     ALWAYS_INLINE bool remove(const RefPtr<UniquedStringImpl>& identifier) { return m_map.remove(identifier); }
+    ALWAYS_INLINE Map::iterator find(const RefPtr<UniquedStringImpl>& identifier) { return m_map.find(identifier); }
+    ALWAYS_INLINE Map::const_iterator find(const RefPtr<UniquedStringImpl>& identifier) const { return m_map.find(identifier); }
     void swap(VariableEnvironment& other);
     void markVariableAsCapturedIfDefined(const RefPtr<UniquedStringImpl>& identifier);
     void markVariableAsCaptured(const RefPtr<UniquedStringImpl>& identifier);
index ab70eab..f13b25e 100644 (file)
@@ -67,11 +67,19 @@ template <typename T> struct CacheTypes { };
 template <> struct CacheTypes<UnlinkedProgramCodeBlock> {
     typedef JSC::ProgramNode RootNode;
     static const SourceCodeKey::CodeType codeType = SourceCodeKey::ProgramType;
+    static const SourceParseMode parseMode = SourceParseMode::ProgramMode;
 };
 
 template <> struct CacheTypes<UnlinkedEvalCodeBlock> {
     typedef JSC::EvalNode RootNode;
     static const SourceCodeKey::CodeType codeType = SourceCodeKey::EvalType;
+    static const SourceParseMode parseMode = SourceParseMode::ProgramMode;
+};
+
+template <> struct CacheTypes<UnlinkedModuleProgramCodeBlock> {
+    typedef JSC::ModuleProgramNode RootNode;
+    static const SourceCodeKey::CodeType codeType = SourceCodeKey::ModuleType;
+    static const SourceParseMode parseMode = SourceParseMode::ModuleEvaluateMode;
 };
 
 template <class UnlinkedCodeBlockType, class ExecutableType>
@@ -95,7 +103,7 @@ UnlinkedCodeBlockType* CodeCache::getGlobalCodeBlock(VM& vm, ExecutableType* exe
     typedef typename CacheTypes<UnlinkedCodeBlockType>::RootNode RootNode;
     std::unique_ptr<RootNode> rootNode = parse<RootNode>(
         &vm, source, Identifier(), builtinMode, strictMode,
-        SourceParseMode::ProgramMode, error, nullptr, ConstructorKind::None, thisTDZMode);
+        CacheTypes<UnlinkedCodeBlockType>::parseMode, error, nullptr, ConstructorKind::None, thisTDZMode);
     if (!rootNode)
         return nullptr;
 
@@ -132,6 +140,12 @@ UnlinkedEvalCodeBlock* CodeCache::getEvalCodeBlock(VM& vm, EvalExecutable* execu
     return getGlobalCodeBlock<UnlinkedEvalCodeBlock>(vm, executable, source, builtinMode, strictMode, thisTDZMode, debuggerMode, profilerMode, error, variablesUnderTDZ);
 }
 
+UnlinkedModuleProgramCodeBlock* CodeCache::getModuleProgramCodeBlock(VM& vm, ModuleProgramExecutable* executable, const SourceCode& source, JSParserBuiltinMode builtinMode, DebuggerMode debuggerMode, ProfilerMode profilerMode, ParserError& error)
+{
+    VariableEnvironment emptyParentTDZVariables;
+    return getGlobalCodeBlock<UnlinkedModuleProgramCodeBlock>(vm, executable, source, builtinMode, JSParserStrictMode::Strict, ThisTDZMode::CheckIfNeeded, debuggerMode, profilerMode, error, &emptyParentTDZVariables);
+}
+
 // FIXME: There's no need to add the function's name to the key here. It's already in the source code.
 UnlinkedFunctionExecutable* CodeCache::getFunctionExecutableFromGlobalCode(VM& vm, const Identifier& name, const SourceCode& source, ParserError& error)
 {
index af7dac7..7175fe3 100644 (file)
@@ -45,8 +45,10 @@ class Identifier;
 class JSScope;
 class ParserError;
 class ProgramExecutable;
+class ModuleProgramExecutable;
 class UnlinkedCodeBlock;
 class UnlinkedEvalCodeBlock;
+class UnlinkedModuleProgramCodeBlock;
 class UnlinkedFunctionCodeBlock;
 class UnlinkedFunctionExecutable;
 class UnlinkedProgramCodeBlock;
@@ -56,7 +58,7 @@ class SourceProvider;
 
 class SourceCodeKey {
 public:
-    enum CodeType { EvalType, ProgramType, FunctionType };
+    enum CodeType { EvalType, ProgramType, FunctionType, ModuleType };
 
     SourceCodeKey()
     {
@@ -257,6 +259,7 @@ public:
 
     UnlinkedProgramCodeBlock* getProgramCodeBlock(VM&, ProgramExecutable*, const SourceCode&, JSParserBuiltinMode, JSParserStrictMode, DebuggerMode, ProfilerMode, ParserError&);
     UnlinkedEvalCodeBlock* getEvalCodeBlock(VM&, EvalExecutable*, const SourceCode&, JSParserBuiltinMode, JSParserStrictMode, ThisTDZMode, DebuggerMode, ProfilerMode, ParserError&, const VariableEnvironment*);
+    UnlinkedModuleProgramCodeBlock* getModuleProgramCodeBlock(VM&, ModuleProgramExecutable*, const SourceCode&, JSParserBuiltinMode, DebuggerMode, ProfilerMode, ParserError&);
     UnlinkedFunctionExecutable* getFunctionExecutableFromGlobalCode(VM&, const Identifier&, const SourceCode&, ParserError&);
 
     void clear()
index e485479..b1d0055 100644 (file)
@@ -161,7 +161,18 @@ void ScriptExecutable::installCode(CodeBlock* genericCodeBlock)
         executable->m_programCodeBlock = codeBlock;
         break;
     }
-        
+
+    case ModuleCode: {
+        ModuleProgramExecutable* executable = jsCast<ModuleProgramExecutable*>(this);
+        ModuleProgramCodeBlock* codeBlock = static_cast<ModuleProgramCodeBlock*>(genericCodeBlock);
+
+        ASSERT(kind == CodeForCall);
+
+        oldCodeBlock = executable->m_moduleProgramCodeBlock;
+        executable->m_moduleProgramCodeBlock = codeBlock;
+        break;
+    }
+
     case EvalCode: {
         EvalExecutable* executable = jsCast<EvalExecutable*>(this);
         EvalCodeBlock* codeBlock = static_cast<EvalCodeBlock*>(genericCodeBlock);
@@ -228,7 +239,17 @@ RefPtr<CodeBlock> ScriptExecutable::newCodeBlockFor(
             executable, executable->m_unlinkedProgramCodeBlock.get(), scope,
             executable->source().provider(), executable->source().startColumn()));
     }
-    
+
+    if (classInfo() == ModuleProgramExecutable::info()) {
+        ModuleProgramExecutable* executable = jsCast<ModuleProgramExecutable*>(this);
+        RELEASE_ASSERT(kind == CodeForCall);
+        RELEASE_ASSERT(!executable->m_moduleProgramCodeBlock);
+        RELEASE_ASSERT(!function);
+        return adoptRef(new ModuleProgramCodeBlock(
+            executable, executable->m_unlinkedModuleProgramCodeBlock.get(), scope,
+            executable->source().provider(), executable->source().startColumn()));
+    }
+
     RELEASE_ASSERT(classInfo() == FunctionExecutable::info());
     RELEASE_ASSERT(function);
     FunctionExecutable* executable = jsCast<FunctionExecutable*>(this);
@@ -285,6 +306,17 @@ PassRefPtr<CodeBlock> ScriptExecutable::newReplacementCodeBlockFor(
         return result;
     }
 
+    if (classInfo() == ModuleProgramExecutable::info()) {
+        RELEASE_ASSERT(kind == CodeForCall);
+        ModuleProgramExecutable* executable = jsCast<ModuleProgramExecutable*>(this);
+        ModuleProgramCodeBlock* baseline = static_cast<ModuleProgramCodeBlock*>(
+            executable->m_moduleProgramCodeBlock->baselineVersion());
+        RefPtr<ModuleProgramCodeBlock> result = adoptRef(new ModuleProgramCodeBlock(
+            CodeBlock::CopyParsedBlock, *baseline));
+        result->setAlternative(baseline);
+        return result;
+    }
+
     RELEASE_ASSERT(classInfo() == FunctionExecutable::info());
     FunctionExecutable* executable = jsCast<FunctionExecutable*>(this);
     FunctionCodeBlock* baseline = static_cast<FunctionCodeBlock*>(
@@ -385,6 +417,36 @@ void ProgramExecutable::destroy(JSCell* cell)
     static_cast<ProgramExecutable*>(cell)->ProgramExecutable::~ProgramExecutable();
 }
 
+const ClassInfo ModuleProgramExecutable::s_info = { "ModuleProgramExecutable", &ScriptExecutable::s_info, 0, CREATE_METHOD_TABLE(ModuleProgramExecutable) };
+
+ModuleProgramExecutable::ModuleProgramExecutable(ExecState* exec, const SourceCode& source)
+    : ScriptExecutable(exec->vm().moduleProgramExecutableStructure.get(), exec->vm(), source, false)
+{
+    m_typeProfilingStartOffset = 0;
+    m_typeProfilingEndOffset = source.length() - 1;
+    if (exec->vm().typeProfiler() || exec->vm().controlFlowProfiler())
+        exec->vm().functionHasExecutedCache()->insertUnexecutedRange(sourceID(), m_typeProfilingStartOffset, m_typeProfilingEndOffset);
+}
+
+ModuleProgramExecutable* ModuleProgramExecutable::create(ExecState* exec, const SourceCode& source)
+{
+    JSGlobalObject* globalObject = exec->lexicalGlobalObject();
+    ModuleProgramExecutable* executable = new (NotNull, allocateCell<ModuleProgramExecutable>(*exec->heap())) ModuleProgramExecutable(exec, source);
+    executable->finishCreation(exec->vm());
+
+    UnlinkedModuleProgramCodeBlock* unlinkedModuleProgramCode = globalObject->createModuleProgramCodeBlock(exec, executable);
+    if (!unlinkedModuleProgramCode)
+        return nullptr;
+    executable->m_unlinkedModuleProgramCodeBlock.set(exec->vm(), executable, unlinkedModuleProgramCode);
+
+    return executable;
+}
+
+void ModuleProgramExecutable::destroy(JSCell* cell)
+{
+    static_cast<ModuleProgramExecutable*>(cell)->ModuleProgramExecutable::~ModuleProgramExecutable();
+}
+
 const ClassInfo FunctionExecutable::s_info = { "FunctionExecutable", &ScriptExecutable::s_info, 0, CREATE_METHOD_TABLE(FunctionExecutable) };
 
 FunctionExecutable::FunctionExecutable(VM& vm, const SourceCode& source, 
@@ -517,6 +579,23 @@ void ProgramExecutable::clearCode()
     Base::clearCode();
 }
 
+void ModuleProgramExecutable::visitChildren(JSCell* cell, SlotVisitor& visitor)
+{
+    ModuleProgramExecutable* thisObject = jsCast<ModuleProgramExecutable*>(cell);
+    ASSERT_GC_OBJECT_INHERITS(thisObject, info());
+    ScriptExecutable::visitChildren(thisObject, visitor);
+    visitor.append(&thisObject->m_unlinkedModuleProgramCodeBlock);
+    if (thisObject->m_moduleProgramCodeBlock)
+        thisObject->m_moduleProgramCodeBlock->visitAggregate(visitor);
+}
+
+void ModuleProgramExecutable::clearCode()
+{
+    m_moduleProgramCodeBlock = nullptr;
+    m_unlinkedModuleProgramCodeBlock.clear();
+    Base::clearCode();
+}
+
 FunctionCodeBlock* FunctionExecutable::baselineCodeBlockFor(CodeSpecializationKind kind)
 {
     FunctionCodeBlock* result;
@@ -647,6 +726,15 @@ void ExecutableBase::dump(PrintStream& out) const
             out.print("ProgramExecutable w/o CodeBlock");
         return;
     }
+
+    if (classInfo() == ModuleProgramExecutable::info()) {
+        ModuleProgramExecutable* executable = jsCast<ModuleProgramExecutable*>(realThis);
+        if (CodeBlock* codeBlock = executable->codeBlock())
+            out.print(*codeBlock);
+        else
+            out.print("ModuleProgramExecutable w/o CodeBlock");
+        return;
+    }
     
     FunctionExecutable* function = jsCast<FunctionExecutable*>(realThis);
     if (!function->eitherCodeBlock())
index a9c41c4..cdceb30 100644 (file)
@@ -54,8 +54,10 @@ class JSScope;
 class JSWASMModule;
 class LLIntOffsetsExtractor;
 class ProgramCodeBlock;
+class ModuleProgramCodeBlock;
+class JSScope;
 class WebAssemblyCodeBlock;
-    
+
 enum CompilationKind { FirstCompilation, OptimizingCompilation };
 
 inline bool isCall(CodeSpecializationKind kind)
@@ -106,6 +108,11 @@ public:
     {
         return type() == ProgramExecutableType;
     }
+    bool isModuleProgramExecutable()
+    {
+        return type() == ModuleProgramExecutableType;
+    }
+
 
     bool isHostFunction() const
     {
@@ -550,6 +557,49 @@ private:
     RefPtr<ProgramCodeBlock> m_programCodeBlock;
 };
 
+class ModuleProgramExecutable final : public ScriptExecutable {
+    friend class LLIntOffsetsExtractor;
+public:
+    typedef ScriptExecutable Base;
+    static const unsigned StructureFlags = Base::StructureFlags | StructureIsImmortal;
+
+    static ModuleProgramExecutable* create(ExecState*, const SourceCode&);
+
+    static void destroy(JSCell*);
+
+    ModuleProgramCodeBlock* codeBlock()
+    {
+        return m_moduleProgramCodeBlock.get();
+    }
+
+    PassRefPtr<JITCode> generatedJITCode()
+    {
+        return generatedJITCodeForCall();
+    }
+
+    static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue proto)
+    {
+        return Structure::create(vm, globalObject, proto, TypeInfo(ModuleProgramExecutableType, StructureFlags), info());
+    }
+
+    DECLARE_INFO;
+
+    void clearCode();
+
+    ExecutableInfo executableInfo() const { return ExecutableInfo(needsActivation(), usesEval(), isStrictMode(), false, false, ConstructorKind::None, false); }
+    UnlinkedModuleProgramCodeBlock* unlinkedModuleProgramCodeBlock() { return m_unlinkedModuleProgramCodeBlock.get(); }
+
+private:
+    friend class ScriptExecutable;
+
+    ModuleProgramExecutable(ExecState*, const SourceCode&);
+
+    static void visitChildren(JSCell*, SlotVisitor&);
+
+    WriteBarrier<UnlinkedModuleProgramCodeBlock> m_unlinkedModuleProgramCodeBlock;
+    RefPtr<ModuleProgramCodeBlock> m_moduleProgramCodeBlock;
+};
+
 class FunctionExecutable final : public ScriptExecutable {
     friend class JIT;
     friend class LLIntOffsetsExtractor;
@@ -742,6 +792,8 @@ inline void ExecutableBase::clearCodeVirtual(ExecutableBase* executable)
     case WebAssemblyExecutableType:
         return jsCast<WebAssemblyExecutable*>(executable)->clearCode();
 #endif
+    case ModuleProgramExecutableType:
+        return jsCast<ModuleProgramExecutable*>(executable)->clearCode();
     default:
         return jsCast<NativeExecutable*>(executable)->clearCode();
     }
index ae41c26..4e094fd 100644 (file)
@@ -933,6 +933,25 @@ UnlinkedEvalCodeBlock* JSGlobalObject::createEvalCodeBlock(CallFrame* callFrame,
     return unlinkedCodeBlock;
 }
 
+UnlinkedModuleProgramCodeBlock* JSGlobalObject::createModuleProgramCodeBlock(CallFrame* callFrame, ModuleProgramExecutable* executable)
+{
+    ParserError error;
+    DebuggerMode debuggerMode = hasDebugger() ? DebuggerOn : DebuggerOff;
+    ProfilerMode profilerMode = hasProfiler() ? ProfilerOn : ProfilerOff;
+    UnlinkedModuleProgramCodeBlock* unlinkedCodeBlock = vm().codeCache()->getModuleProgramCodeBlock(
+        vm(), executable, executable->source(), JSParserBuiltinMode::NotBuiltin, debuggerMode, profilerMode, error);
+
+    if (hasDebugger())
+        debugger()->sourceParsed(callFrame, executable->source().provider(), error.line(), error.message());
+
+    if (error.isValid()) {
+        throwVMError(callFrame, error.toErrorObject(this, executable->source()));
+        return nullptr;
+    }
+
+    return unlinkedCodeBlock;
+}
+
 void JSGlobalObject::setRemoteDebuggingEnabled(bool enabled)
 {
 #if ENABLE(REMOTE_INSPECTOR)
index 1a5250c..1ca31b7 100644 (file)
@@ -78,6 +78,7 @@ class JSStack;
 class LLIntOffsetsExtractor;
 class Microtask;
 class ModuleLoaderObject;
+class ModuleProgramExecutable;
 class NativeErrorConstructor;
 class ObjectConstructor;
 class ProgramCodeBlock;
@@ -85,6 +86,7 @@ class ProgramExecutable;
 class RegExpConstructor;
 class RegExpPrototype;
 class SourceCode;
+class UnlinkedModuleProgramCodeBlock;
 class NullGetterFunction;
 class NullSetterFunction;
 enum class ThisTDZMode;
@@ -643,6 +645,7 @@ public:
 
     UnlinkedProgramCodeBlock* createProgramCodeBlock(CallFrame*, ProgramExecutable*, JSObject** exception);
     UnlinkedEvalCodeBlock* createEvalCodeBlock(CallFrame*, EvalExecutable*, ThisTDZMode, const VariableEnvironment*);
+    UnlinkedModuleProgramCodeBlock* createModuleProgramCodeBlock(CallFrame*, ModuleProgramExecutable*);
 
 protected:
     struct GlobalPropertyInfo {
index 5d15ebc..7b60637 100644 (file)
@@ -26,6 +26,8 @@
 #include "config.h"
 #include "JSModuleRecord.h"
 
+#include "Error.h"
+#include "Executable.h"
 #include "IdentifierInlines.h"
 #include "JSCJSValueInlines.h"
 #include "JSCellInlines.h"
@@ -58,6 +60,7 @@ void JSModuleRecord::visitChildren(JSCell* cell, SlotVisitor& visitor)
 {
     JSModuleRecord* thisObject = jsCast<JSModuleRecord*>(cell);
     Base::visitChildren(thisObject, visitor);
+    visitor.append(&thisObject->m_moduleProgramExecutable);
     visitor.append(&thisObject->m_dependenciesMap);
 }
 
@@ -90,8 +93,14 @@ JSModuleRecord* JSModuleRecord::hostResolveImportedModule(ExecState* exec, const
     return jsCast<JSModuleRecord*>(pair.get(exec, Identifier::fromString(exec, "value")));
 }
 
-void JSModuleRecord::link(ExecState*)
+void JSModuleRecord::link(ExecState* exec)
 {
+    ModuleProgramExecutable* executable = ModuleProgramExecutable::create(exec, sourceCode());
+    if (!executable) {
+        throwSyntaxError(exec);
+        return;
+    }
+    m_moduleProgramExecutable.set(exec->vm(), this, executable);
 }
 
 JSValue JSModuleRecord::execute(ExecState*)
index 936263c..81da396 100644 (file)
@@ -117,6 +117,8 @@ public:
     void link(ExecState*);
     JSValue execute(ExecState*);
 
+    ModuleProgramExecutable* moduleProgramExecutable() const { return m_moduleProgramExecutable.get(); }
+
 private:
     JSModuleRecord(VM& vm, Structure* structure, const Identifier& moduleKey, const SourceCode& sourceCode, const VariableEnvironment& declaredVariables, const VariableEnvironment& lexicalVariables)
         : Base(vm, structure)
@@ -154,6 +156,7 @@ private:
     // http://www.ecma-international.org/ecma-262/6.0/#sec-moduleevaluation
     OrderedIdentifierSet m_requestedModules;
 
+    WriteBarrier<ModuleProgramExecutable> m_moduleProgramExecutable;
     WriteBarrier<JSMap> m_dependenciesMap;
 };
 
index 1596e65..110f8b5 100644 (file)
@@ -41,11 +41,13 @@ enum JSType : uint8_t {
 
     EvalExecutableType,
     ProgramExecutableType,
+    ModuleProgramExecutableType,
     FunctionExecutableType,
     WebAssemblyExecutableType,
 
     UnlinkedFunctionExecutableType,
     UnlinkedProgramCodeBlockType,
+    UnlinkedModuleProgramCodeBlockType,
     UnlinkedEvalCodeBlockType,
     UnlinkedFunctionCodeBlockType,
 
index e67fa38..28e0bad 100644 (file)
@@ -274,6 +274,9 @@ EncodedJSValue JSC_HOST_CALL moduleLoaderObjectModuleDeclarationInstantiation(Ex
         dataLog("Loader [link] ", moduleRecord->moduleKey(), "\n");
 
     moduleRecord->link(exec);
+    if (exec->hadException())
+        return JSValue::encode(jsUndefined());
+
     return JSValue::encode(jsUndefined());
 }
 
index 962dc52..827bb36 100644 (file)
@@ -225,6 +225,7 @@ VM::VM(VMType vmType, HeapType heapType)
 #if ENABLE(WEBASSEMBLY)
     webAssemblyExecutableStructure.set(*this, WebAssemblyExecutable::createStructure(*this, 0, jsNull()));
 #endif
+    moduleProgramExecutableStructure.set(*this, ModuleProgramExecutable::createStructure(*this, 0, jsNull()));
     regExpStructure.set(*this, RegExp::createStructure(*this, 0, jsNull()));
     symbolStructure.set(*this, Symbol::createStructure(*this, 0, jsNull()));
     symbolTableStructure.set(*this, SymbolTable::createStructure(*this, 0, jsNull()));
@@ -236,6 +237,7 @@ VM::VM(VMType vmType, HeapType heapType)
     unlinkedProgramCodeBlockStructure.set(*this, UnlinkedProgramCodeBlock::createStructure(*this, 0, jsNull()));
     unlinkedEvalCodeBlockStructure.set(*this, UnlinkedEvalCodeBlock::createStructure(*this, 0, jsNull()));
     unlinkedFunctionCodeBlockStructure.set(*this, UnlinkedFunctionCodeBlock::createStructure(*this, 0, jsNull()));
+    unlinkedModuleProgramCodeBlockStructure.set(*this, UnlinkedModuleProgramCodeBlock::createStructure(*this, 0, jsNull()));
     propertyTableStructure.set(*this, PropertyTable::createStructure(*this, 0, jsNull()));
     weakMapDataStructure.set(*this, WeakMapData::createStructure(*this, 0, jsNull()));
     inferredValueStructure.set(*this, InferredValue::createStructure(*this, 0, jsNull()));
index c4e8037..84a535a 100644 (file)
@@ -103,6 +103,7 @@ class UnlinkedCodeBlock;
 class UnlinkedEvalCodeBlock;
 class UnlinkedFunctionExecutable;
 class UnlinkedProgramCodeBlock;
+class UnlinkedModuleProgramCodeBlock;
 class VirtualRegister;
 class VMEntryScope;
 class Watchdog;
@@ -282,6 +283,7 @@ public:
 #if ENABLE(WEBASSEMBLY)
     Strong<Structure> webAssemblyExecutableStructure;
 #endif
+    Strong<Structure> moduleProgramExecutableStructure;
     Strong<Structure> regExpStructure;
     Strong<Structure> symbolStructure;
     Strong<Structure> symbolTableStructure;
@@ -293,6 +295,7 @@ public:
     Strong<Structure> unlinkedProgramCodeBlockStructure;
     Strong<Structure> unlinkedEvalCodeBlockStructure;
     Strong<Structure> unlinkedFunctionCodeBlockStructure;
+    Strong<Structure> unlinkedModuleProgramCodeBlockStructure;
     Strong<Structure> propertyTableStructure;
     Strong<Structure> weakMapDataStructure;
     Strong<Structure> inferredValueStructure;
index a0aff95..ea3788a 100644 (file)
@@ -1,3 +1,15 @@
+2015-08-31  Yusuke Suzuki  <utatane.tea@gmail.com>
+
+        [ES6] Introduce ModuleProgramExecutable families and compile Module code to bytecode
+        https://bugs.webkit.org/show_bug.cgi?id=148581
+
+        Reviewed by Saam Barati.
+
+        Add the ModuleProgramExecutable case.
+
+        * testing/Internals.cpp:
+        (WebCore::Internals::parserMetaData):
+
 2015-08-31  Brent Fulgham  <bfulgham@apple.com>
 
         [Win] WebKit cannot load pages based on "file://" URLs
index 2a5c7eb..5dd446a 100644 (file)
@@ -1485,6 +1485,8 @@ String Internals::parserMetaData(Deprecated::ScriptValue value)
         result.append('"');
     } else if (executable->isEvalExecutable())
         result.appendLiteral("eval");
+    else if (executable->isModuleProgramExecutable())
+        result.appendLiteral("module");
     else if (executable->isProgramExecutable())
         result.appendLiteral("program");
 #if ENABLE(WEBASSEMBLY)