Title: [210522] trunk
Revision
210522
Author
utatane....@gmail.com
Date
2017-01-09 14:02:47 -0800 (Mon, 09 Jan 2017)

Log Message

[JSC] Prototype dynamic-import
https://bugs.webkit.org/show_bug.cgi?id=165724

Reviewed by Saam Barati.

JSTests:

* stress/import-basic.js: Added.
(async.async.load):
(async):
(catch):
* stress/import-from-eval.js: Added.
(async):
(catch):
* stress/import-syntax.js: Added.
(testSyntaxError):
* stress/import-tests/cocoa.js: Added.
(export.Cocoa):
(export.hello):
* stress/import-tests/multiple.js: Added.
(export.result):
* stress/import-tests/multiple2.js: Added.
(export.ok):
* stress/import-tests/should.js: Added.
(export.shouldBe):
(export.shouldThrow):
* stress/modules-syntax-error.js:

Source/_javascript_Core:

In this patch, we implement stage3 dynamic-import proposal[1].
This patch adds a new special operator `import`. And by using it, we can import
the module dynamically from modules and scripts. Before this feature, the module
is always imported statically and before executing the modules, importing the modules
needs to be done. And especially, the module can only be imported from the module.
So the classic script cannot import and use the modules. This dynamic-import relaxes
the above restrictions.

The typical dynamic-import form is the following.

    import("...").then(function (namespace) { ... });

You can pass any AssignmentExpression for the import operator. So you can determine
the importing modules dynamically.

    import(value).then(function (namespace) { ... });

And previously the module import declaration is only allowed in the top level statements.
But this import operator is just an _expression_. So you can use it in the function.
And you can use it conditionally.

    async function go(cond)
    {
        if (cond)
            return import("...");
        return undefined;
    }
    await go(true);

Currently, this patch just implements this feature only for the JSC shell.
JSC module loader requires a new hook, `importModule`. And the JSC shell implements
this hook. So, for now, this dynamic-import is not available in the browser side.
If you write this `import` call, it always returns the rejected promise.

import is implemented like a special operator similar to `super`.
This is because import is context-sensitive. If you call the `import`, the module
key resolution is done based on the caller's running context.

For example, if you are running the script which filename is "./ok/hello.js", the module
key for the call`import("./resource/syntax.js")` becomes `"./ok/resource/syntax.js"`.
But if you write the completely same import form in the script "./error/hello.js", the
key becomes "./error/resource/syntax.js". So exposing this feature as the `import`
function is misleading: this function becomes caller's context-sensitive. That's why
dynamic-import is specified as a special operator.

To resolve the module key, we need the caller's context information like the filename of
the caller. This is provided by the SourceOrigin implemented in r210149.
In the JSC shell implementation, this SourceOrigin holds the filename of the caller. So
based on this implementation, the module loader resolve the module key.
In the near future, we will extend this SourceOrigin to hold more information needed for
the browser-side import implementation.

[1]: https://tc39.github.io/proposal-dynamic-import/

* builtins/ModuleLoaderPrototype.js:
(importModule):
* bytecompiler/BytecodeGenerator.cpp:
(JSC::BytecodeGenerator::emitGetTemplateObject):
(JSC::BytecodeGenerator::emitGetGlobalPrivate):
* bytecompiler/BytecodeGenerator.h:
* bytecompiler/NodesCodegen.cpp:
(JSC::ImportNode::emitBytecode):
* jsc.cpp:
(absolutePath):
(GlobalObject::moduleLoaderImportModule):
(functionRun):
(functionLoad):
(functionCheckSyntax):
(runWithScripts):
* parser/ASTBuilder.h:
(JSC::ASTBuilder::createImportExpr):
* parser/NodeConstructors.h:
(JSC::ImportNode::ImportNode):
* parser/Nodes.h:
(JSC::ExpressionNode::isImportNode):
* parser/Parser.cpp:
(JSC::Parser<LexerType>::parseMemberExpression):
* parser/SyntaxChecker.h:
(JSC::SyntaxChecker::createImportExpr):
* runtime/JSGlobalObject.cpp:
(JSC::JSGlobalObject::init):
* runtime/JSGlobalObject.h:
* runtime/JSGlobalObjectFunctions.cpp:
(JSC::globalFuncImportModule):
* runtime/JSGlobalObjectFunctions.h:
* runtime/JSModuleLoader.cpp:
(JSC::JSModuleLoader::importModule):
(JSC::JSModuleLoader::getModuleNamespaceObject):
* runtime/JSModuleLoader.h:
* runtime/ModuleLoaderPrototype.cpp:
(JSC::moduleLoaderPrototypeGetModuleNamespaceObject):

Source/WebCore:

We do not set a handler for import for now.
So dynamic import feature is only enabled in the JSC shell right now.

* bindings/js/JSDOMWindowBase.cpp:
* bindings/js/JSWorkerGlobalScopeBase.cpp:

LayoutTests:

* sputnik/Conformance/07_Lexical_Conventions/7.5_Tokens/7.5.3_Future_Reserved_Words/S7.5.3_A1.16-expected.txt:

Modified Paths

Added Paths

Diff

Modified: trunk/JSTests/ChangeLog (210521 => 210522)


--- trunk/JSTests/ChangeLog	2017-01-09 21:45:56 UTC (rev 210521)
+++ trunk/JSTests/ChangeLog	2017-01-09 22:02:47 UTC (rev 210522)
@@ -1,3 +1,31 @@
+2017-01-09  Yusuke Suzuki  <utatane....@gmail.com>
+
+        [JSC] Prototype dynamic-import
+        https://bugs.webkit.org/show_bug.cgi?id=165724
+
+        Reviewed by Saam Barati.
+
+        * stress/import-basic.js: Added.
+        (async.async.load):
+        (async):
+        (catch):
+        * stress/import-from-eval.js: Added.
+        (async):
+        (catch):
+        * stress/import-syntax.js: Added.
+        (testSyntaxError):
+        * stress/import-tests/cocoa.js: Added.
+        (export.Cocoa):
+        (export.hello):
+        * stress/import-tests/multiple.js: Added.
+        (export.result):
+        * stress/import-tests/multiple2.js: Added.
+        (export.ok):
+        * stress/import-tests/should.js: Added.
+        (export.shouldBe):
+        (export.shouldThrow):
+        * stress/modules-syntax-error.js:
+
 2017-01-09  Commit Queue  <commit-qu...@webkit.org>
 
         Unreviewed, rolling out r210476.

Added: trunk/JSTests/stress/import-basic.js (0 => 210522)


--- trunk/JSTests/stress/import-basic.js	                        (rev 0)
+++ trunk/JSTests/stress/import-basic.js	2017-01-09 22:02:47 UTC (rev 210522)
@@ -0,0 +1,53 @@
+(async function () {
+    const { shouldBe } = await import('./import-tests/should.js');
+    {
+        let a = await import('./import-tests/cocoa.js');
+        let b = await import('./import-tests/cocoa.js');
+        shouldBe(a, b);
+        shouldBe(a.hello(), 42);
+    }
+
+    {
+        let a = await import('./import-tests/multiple.js');
+        let a2 = await a.result();
+        shouldBe(a !== a2, true);
+        shouldBe(a2.ok(), 42);
+        let a3 = await a.result();
+        shouldBe(a2, a3);
+    }
+
+    {
+        let error = null;
+        try {
+            let a = await import({ toString() { throw new Error('out'); } });
+        } catch (e) {
+            error = e;
+        }
+        shouldBe(error !== null, true);
+        shouldBe(String(error), `Error: out`);
+    }
+
+    {
+        async function load(cond) {
+            if (cond)
+                return import('./import-tests/cocoa.js');
+            return undefined;
+        }
+
+        let v = await load(false);
+        shouldBe(v, undefined);
+        let v2 = await load(true);
+        let v3 = await import('./import-tests/cocoa.js');
+        shouldBe(v2, v2);
+    }
+
+    {
+        let value = './import-tests/cocoa.js';
+        let v = await import(value);
+        let v2 = await import('./import-tests/cocoa.js');
+        shouldBe(v, v2);
+    }
+}()).catch((error) => {
+    print(String(error));
+    abort();
+});

Added: trunk/JSTests/stress/import-from-eval.js (0 => 210522)


--- trunk/JSTests/stress/import-from-eval.js	                        (rev 0)
+++ trunk/JSTests/stress/import-from-eval.js	2017-01-09 22:02:47 UTC (rev 210522)
@@ -0,0 +1,36 @@
+(async function () {
+    const { shouldBe, shouldThrow } = await import("./import-tests/should.js");
+
+    {
+        let cocoa = await eval(`import("./import-tests/cocoa.js")`);
+        shouldBe(cocoa.hello(), 42);
+    }
+
+    {
+        let cocoa = await (0, eval)(`import("./import-tests/cocoa.js")`);
+        shouldBe(cocoa.hello(), 42);
+    }
+
+    {
+        let cocoa = await eval(`eval('import("./import-tests/cocoa.js")')`);
+        shouldBe(cocoa.hello(), 42);
+    }
+
+    {
+        let cocoa = await ((new Function(`return eval('import("./import-tests/cocoa.js")')`))());
+        shouldBe(cocoa.hello(), 42);
+    }
+
+    {
+        let cocoa = await eval(`(new Function('return import("./import-tests/cocoa.js")'))()`);
+        shouldBe(cocoa.hello(), 42);
+    }
+
+    {
+        let cocoa = await [`import("./import-tests/cocoa.js")`].map(eval)[0];
+        shouldBe(cocoa.hello(), 42);
+    }
+}()).catch((error) => {
+    print(String(error));
+    abort();
+});

Added: trunk/JSTests/stress/import-syntax.js (0 => 210522)


--- trunk/JSTests/stress/import-syntax.js	                        (rev 0)
+++ trunk/JSTests/stress/import-syntax.js	2017-01-09 22:02:47 UTC (rev 210522)
@@ -0,0 +1,59 @@
+function testSyntaxError(script, message) {
+    var error = null;
+    try {
+        eval(script);
+    } catch (e) {
+        error = e;
+    }
+    if (!error)
+        throw new Error("Expected syntax error not thrown");
+
+    if (String(error) !== message)
+        throw new Error(`Bad error: ${String(error)}`);
+}
+
+async function testSyntax(script, message) {
+    var error = null;
+    try {
+        await eval(script);
+    } catch (e) {
+        error = e;
+    }
+    if (error) {
+        if (error instanceof SyntaxError)
+            throw new Error("Syntax error thrown");
+    }
+}
+
+testSyntaxError(`import)`, `SyntaxError: Unexpected token ')'. import call expects exactly one argument.`);
+testSyntaxError(`new import(`, `SyntaxError: Cannot use new with import.`);
+testSyntaxError(`import.hello()`, `SyntaxError: Unexpected token '.'. import call expects exactly one argument.`);
+testSyntaxError(`import[`, `SyntaxError: Unexpected token '['. import call expects exactly one argument.`);
+testSyntaxError(`import<`, `SyntaxError: Unexpected token '<'. import call expects exactly one argument.`);
+
+testSyntaxError(`import()`, `SyntaxError: Unexpected token ')'`);
+testSyntaxError(`import(a, b)`, `SyntaxError: Unexpected token ','. import call expects exactly one argument.`);
+testSyntaxError(`import(a, b, c)`, `SyntaxError: Unexpected token ','. import call expects exactly one argument.`);
+testSyntaxError(`import(...a)`, `SyntaxError: Unexpected token '...'`);
+testSyntaxError(`import(,a)`, `SyntaxError: Unexpected token ','`);
+testSyntaxError(`import(,)`, `SyntaxError: Unexpected token ','`);
+testSyntaxError(`import("Hello";`, `SyntaxError: Unexpected token ';'. import call expects exactly one argument.`);
+testSyntaxError(`import("Hello"];`, `SyntaxError: Unexpected token ']'. import call expects exactly one argument.`);
+testSyntaxError(`import("Hello",;`, `SyntaxError: Unexpected token ','. import call expects exactly one argument.`);
+testSyntaxError(`import("Hello", "Hello2";`, `SyntaxError: Unexpected token ','. import call expects exactly one argument.`);
+
+
+testSyntaxError(`import = 42`, `SyntaxError: Unexpected token '='. import call expects exactly one argument.`);
+testSyntaxError(`[import] = 42`, `SyntaxError: Unexpected token ']'. import call expects exactly one argument.`);
+testSyntaxError(`{import} = 42`, `SyntaxError: Unexpected token '}'. import call expects exactly one argument.`);
+testSyntaxError(`let import = 42`, `SyntaxError: Unexpected keyword 'import'`);
+testSyntaxError(`var import = 42`, `SyntaxError: Cannot use the keyword 'import' as a variable name.`);
+testSyntaxError(`const import = 42`, `SyntaxError: Cannot use the keyword 'import' as a lexical variable name.`);
+
+(async function () {
+    await testSyntax(`import("./import-tests/cocoa.js")`);
+    await testSyntax(`import("./import-tests/../import-tests/cocoa.js")`);
+}()).catch((error) => {
+    print(String(error));
+    abort();
+});

Added: trunk/JSTests/stress/import-tests/cocoa.js (0 => 210522)


--- trunk/JSTests/stress/import-tests/cocoa.js	                        (rev 0)
+++ trunk/JSTests/stress/import-tests/cocoa.js	2017-01-09 22:02:47 UTC (rev 210522)
@@ -0,0 +1,7 @@
+export class Cocoa {
+}
+
+export function hello()
+{
+    return 42;
+}

Added: trunk/JSTests/stress/import-tests/multiple.js (0 => 210522)


--- trunk/JSTests/stress/import-tests/multiple.js	                        (rev 0)
+++ trunk/JSTests/stress/import-tests/multiple.js	2017-01-09 22:02:47 UTC (rev 210522)
@@ -0,0 +1,4 @@
+export function result()
+{
+    return import('./multiple2.js');
+}

Added: trunk/JSTests/stress/import-tests/multiple2.js (0 => 210522)


--- trunk/JSTests/stress/import-tests/multiple2.js	                        (rev 0)
+++ trunk/JSTests/stress/import-tests/multiple2.js	2017-01-09 22:02:47 UTC (rev 210522)
@@ -0,0 +1,4 @@
+export function ok()
+{
+    return 42;
+}

Added: trunk/JSTests/stress/import-tests/should.js (0 => 210522)


--- trunk/JSTests/stress/import-tests/should.js	                        (rev 0)
+++ trunk/JSTests/stress/import-tests/should.js	2017-01-09 22:02:47 UTC (rev 210522)
@@ -0,0 +1,19 @@
+export function shouldBe(actual, expected) {
+    if (actual !== expected)
+        throw new Error(`bad value: ${String(actual)}`);
+}
+
+export function shouldThrow(func, errorMessage) {
+    var errorThrown = false;
+    var error = null;
+    try {
+        func();
+    } catch (e) {
+        errorThrown = true;
+        error = e;
+    }
+    if (!errorThrown)
+        throw new Error('not thrown');
+    if (String(error) !== errorMessage)
+        throw new Error(`bad error: ${String(error)}`);
+}

Modified: trunk/JSTests/stress/modules-syntax-error.js (210521 => 210522)


--- trunk/JSTests/stress/modules-syntax-error.js	2017-01-09 21:45:56 UTC (rev 210521)
+++ trunk/JSTests/stress/modules-syntax-error.js	2017-01-09 22:02:47 UTC (rev 210522)
@@ -107,25 +107,25 @@
 function noTopLevel() {
     import * as from from "Cocoa"
 }
-`, `SyntaxError: Unexpected keyword 'import':3`);
+`, `SyntaxError: Unexpected token '*'. import call expects exactly one argument.:3`);
 
 checkModuleSyntaxError(String.raw`
 if (noTopLevel) {
     import * as from from "Cocoa"
 }
-`, `SyntaxError: Unexpected keyword 'import':3`);
+`, `SyntaxError: Unexpected token '*'. import call expects exactly one argument.:3`);
 
 checkModuleSyntaxError(String.raw`
 {
     import * as from from "Cocoa"
 }
-`, `SyntaxError: Unexpected keyword 'import':3`);
+`, `SyntaxError: Unexpected token '*'. import call expects exactly one argument.:3`);
 
 checkModuleSyntaxError(String.raw`
 for (var i = 0; i < 1000; ++i) {
     import * as from from "Cocoa"
 }
-`, `SyntaxError: Unexpected keyword 'import':3`);
+`, `SyntaxError: Unexpected token '*'. import call expects exactly one argument.:3`);
 
 checkModuleSyntaxError(String.raw`
 import for from "Cocoa";

Modified: trunk/LayoutTests/ChangeLog (210521 => 210522)


--- trunk/LayoutTests/ChangeLog	2017-01-09 21:45:56 UTC (rev 210521)
+++ trunk/LayoutTests/ChangeLog	2017-01-09 22:02:47 UTC (rev 210522)
@@ -1,3 +1,12 @@
+2017-01-09  Yusuke Suzuki  <utatane....@gmail.com>
+
+        [JSC] Prototype dynamic-import
+        https://bugs.webkit.org/show_bug.cgi?id=165724
+
+        Reviewed by Saam Barati.
+
+        * sputnik/Conformance/07_Lexical_Conventions/7.5_Tokens/7.5.3_Future_Reserved_Words/S7.5.3_A1.16-expected.txt:
+
 2017-01-09  Andy Estes  <aes...@apple.com>
 
         [QuickLook] Add a layout test for webkit.org/b/135651

Modified: trunk/LayoutTests/sputnik/Conformance/07_Lexical_Conventions/7.5_Tokens/7.5.3_Future_Reserved_Words/S7.5.3_A1.16-expected.txt (210521 => 210522)


--- trunk/LayoutTests/sputnik/Conformance/07_Lexical_Conventions/7.5_Tokens/7.5.3_Future_Reserved_Words/S7.5.3_A1.16-expected.txt	2017-01-09 21:45:56 UTC (rev 210521)
+++ trunk/LayoutTests/sputnik/Conformance/07_Lexical_Conventions/7.5_Tokens/7.5.3_Future_Reserved_Words/S7.5.3_A1.16-expected.txt	2017-01-09 22:02:47 UTC (rev 210522)
@@ -1,4 +1,4 @@
-CONSOLE MESSAGE: line 76: SyntaxError: Unexpected keyword 'import'
+CONSOLE MESSAGE: line 76: SyntaxError: Unexpected token '='. import call expects exactly one argument.
 S7.5.3_A1.16
 
 PASS Expected parsing failure

Modified: trunk/Source/_javascript_Core/ChangeLog (210521 => 210522)


--- trunk/Source/_javascript_Core/ChangeLog	2017-01-09 21:45:56 UTC (rev 210521)
+++ trunk/Source/_javascript_Core/ChangeLog	2017-01-09 22:02:47 UTC (rev 210522)
@@ -1,3 +1,102 @@
+2017-01-09  Yusuke Suzuki  <utatane....@gmail.com>
+
+        [JSC] Prototype dynamic-import
+        https://bugs.webkit.org/show_bug.cgi?id=165724
+
+        Reviewed by Saam Barati.
+
+        In this patch, we implement stage3 dynamic-import proposal[1].
+        This patch adds a new special operator `import`. And by using it, we can import
+        the module dynamically from modules and scripts. Before this feature, the module
+        is always imported statically and before executing the modules, importing the modules
+        needs to be done. And especially, the module can only be imported from the module.
+        So the classic script cannot import and use the modules. This dynamic-import relaxes
+        the above restrictions.
+
+        The typical dynamic-import form is the following.
+
+            import("...").then(function (namespace) { ... });
+
+        You can pass any AssignmentExpression for the import operator. So you can determine
+        the importing modules dynamically.
+
+            import(value).then(function (namespace) { ... });
+
+        And previously the module import declaration is only allowed in the top level statements.
+        But this import operator is just an _expression_. So you can use it in the function.
+        And you can use it conditionally.
+
+            async function go(cond)
+            {
+                if (cond)
+                    return import("...");
+                return undefined;
+            }
+            await go(true);
+
+        Currently, this patch just implements this feature only for the JSC shell.
+        JSC module loader requires a new hook, `importModule`. And the JSC shell implements
+        this hook. So, for now, this dynamic-import is not available in the browser side.
+        If you write this `import` call, it always returns the rejected promise.
+
+        import is implemented like a special operator similar to `super`.
+        This is because import is context-sensitive. If you call the `import`, the module
+        key resolution is done based on the caller's running context.
+
+        For example, if you are running the script which filename is "./ok/hello.js", the module
+        key for the call`import("./resource/syntax.js")` becomes `"./ok/resource/syntax.js"`.
+        But if you write the completely same import form in the script "./error/hello.js", the
+        key becomes "./error/resource/syntax.js". So exposing this feature as the `import`
+        function is misleading: this function becomes caller's context-sensitive. That's why
+        dynamic-import is specified as a special operator.
+
+        To resolve the module key, we need the caller's context information like the filename of
+        the caller. This is provided by the SourceOrigin implemented in r210149.
+        In the JSC shell implementation, this SourceOrigin holds the filename of the caller. So
+        based on this implementation, the module loader resolve the module key.
+        In the near future, we will extend this SourceOrigin to hold more information needed for
+        the browser-side import implementation.
+
+        [1]: https://tc39.github.io/proposal-dynamic-import/
+
+        * builtins/ModuleLoaderPrototype.js:
+        (importModule):
+        * bytecompiler/BytecodeGenerator.cpp:
+        (JSC::BytecodeGenerator::emitGetTemplateObject):
+        (JSC::BytecodeGenerator::emitGetGlobalPrivate):
+        * bytecompiler/BytecodeGenerator.h:
+        * bytecompiler/NodesCodegen.cpp:
+        (JSC::ImportNode::emitBytecode):
+        * jsc.cpp:
+        (absolutePath):
+        (GlobalObject::moduleLoaderImportModule):
+        (functionRun):
+        (functionLoad):
+        (functionCheckSyntax):
+        (runWithScripts):
+        * parser/ASTBuilder.h:
+        (JSC::ASTBuilder::createImportExpr):
+        * parser/NodeConstructors.h:
+        (JSC::ImportNode::ImportNode):
+        * parser/Nodes.h:
+        (JSC::ExpressionNode::isImportNode):
+        * parser/Parser.cpp:
+        (JSC::Parser<LexerType>::parseMemberExpression):
+        * parser/SyntaxChecker.h:
+        (JSC::SyntaxChecker::createImportExpr):
+        * runtime/JSGlobalObject.cpp:
+        (JSC::JSGlobalObject::init):
+        * runtime/JSGlobalObject.h:
+        * runtime/JSGlobalObjectFunctions.cpp:
+        (JSC::globalFuncImportModule):
+        * runtime/JSGlobalObjectFunctions.h:
+        * runtime/JSModuleLoader.cpp:
+        (JSC::JSModuleLoader::importModule):
+        (JSC::JSModuleLoader::getModuleNamespaceObject):
+        * runtime/JSModuleLoader.h:
+        * runtime/ModuleLoaderPrototype.cpp:
+        (JSC::moduleLoaderPrototypeGetModuleNamespaceObject):
+
 2017-01-08  Filip Pizlo  <fpi...@apple.com>
 
         Make the collector's fixpoint smart about scheduling work

Modified: trunk/Source/_javascript_Core/builtins/ModuleLoaderPrototype.js (210521 => 210522)


--- trunk/Source/_javascript_Core/builtins/ModuleLoaderPrototype.js	2017-01-09 21:45:56 UTC (rev 210521)
+++ trunk/Source/_javascript_Core/builtins/ModuleLoaderPrototype.js	2017-01-09 22:02:47 UTC (rev 210522)
@@ -470,3 +470,19 @@
     this.link(entry, initiator);
     return this.moduleEvaluation(entry.module, initiator);
 }
+
+function importModule(moduleName, referrer, initiator)
+{
+    "use strict";
+
+    // Loader.resolve hook point.
+    // resolve: moduleName => Promise(moduleKey)
+    // Take the name and resolve it to the unique identifier for the resource location.
+    // For example, take the "jquery" and return the URL for the resource.
+    return this.resolve(moduleName, referrer, initiator).then((key) => {
+        return this.requestInstantiateAll(key, initiator);
+    }).then((entry) => {
+        this.linkAndEvaluateModule(entry.key, initiator);
+        return this.getModuleNamespaceObject(entry.module);
+    });
+}

Modified: trunk/Source/_javascript_Core/bytecompiler/BytecodeGenerator.cpp (210521 => 210522)


--- trunk/Source/_javascript_Core/bytecompiler/BytecodeGenerator.cpp	2017-01-09 21:45:56 UTC (rev 210521)
+++ trunk/Source/_javascript_Core/bytecompiler/BytecodeGenerator.cpp	2017-01-09 22:02:47 UTC (rev 210522)
@@ -4261,22 +4261,24 @@
         cookedStrings.append(templateString->value()->cooked().impl());
     }
 
-    RefPtr<RegisterID> getTemplateObject = nullptr;
-    Variable var = variable(propertyNames().builtinNames().getTemplateObjectPrivateName());
-    if (RegisterID* local = var.local())
-        getTemplateObject = emitMove(newTemporary(), local);
-    else {
-        getTemplateObject = newTemporary();
-        RefPtr<RegisterID> scope = newTemporary();
-        moveToDestinationIfNeeded(scope.get(), emitResolveScope(scope.get(), var));
-        emitGetFromScope(getTemplateObject.get(), scope.get(), var, ThrowIfNotFound);
-    }
-
+    RefPtr<RegisterID> getTemplateObject = emitGetGlobalPrivate(newTemporary(), propertyNames().builtinNames().getTemplateObjectPrivateName());
     CallArguments arguments(*this, nullptr);
     emitLoad(arguments.thisRegister(), JSValue(addTemplateRegistryKeyConstant(m_vm->templateRegistryKeyTable().createKey(rawStrings, cookedStrings))));
     return emitCall(dst, getTemplateObject.get(), NoExpectedFunction, arguments, taggedTemplate->divot(), taggedTemplate->divotStart(), taggedTemplate->divotEnd(), DebuggableCall::No);
 }
 
+RegisterID* BytecodeGenerator::emitGetGlobalPrivate(RegisterID* dst, const Identifier& property)
+{
+    dst = tempDestination(dst);
+    Variable var = variable(property);
+    if (RegisterID* local = var.local())
+        return emitMove(dst, local);
+
+    RefPtr<RegisterID> scope = newTemporary();
+    moveToDestinationIfNeeded(scope.get(), emitResolveScope(scope.get(), var));
+    return emitGetFromScope(dst, scope.get(), var, ThrowIfNotFound);
+}
+
 RegisterID* BytecodeGenerator::emitGetEnumerableLength(RegisterID* dst, RegisterID* base)
 {
     emitOpcode(op_get_enumerable_length);

Modified: trunk/Source/_javascript_Core/bytecompiler/BytecodeGenerator.h (210521 => 210522)


--- trunk/Source/_javascript_Core/bytecompiler/BytecodeGenerator.h	2017-01-09 21:45:56 UTC (rev 210521)
+++ trunk/Source/_javascript_Core/bytecompiler/BytecodeGenerator.h	2017-01-09 22:02:47 UTC (rev 210522)
@@ -678,6 +678,7 @@
         void emitEnumeration(ThrowableExpressionData* enumerationNode, ExpressionNode* subjectNode, const std::function<void(BytecodeGenerator&, RegisterID*)>& callBack, ForOfNode* = nullptr, RegisterID* forLoopSymbolTable = nullptr);
 
         RegisterID* emitGetTemplateObject(RegisterID* dst, TaggedTemplateNode*);
+        RegisterID* emitGetGlobalPrivate(RegisterID* dst, const Identifier& property);
 
         enum class ReturnFrom { Normal, Finally };
         RegisterID* emitReturn(RegisterID* src, ReturnFrom = ReturnFrom::Normal);

Modified: trunk/Source/_javascript_Core/bytecompiler/NodesCodegen.cpp (210521 => 210522)


--- trunk/Source/_javascript_Core/bytecompiler/NodesCodegen.cpp	2017-01-09 21:45:56 UTC (rev 210521)
+++ trunk/Source/_javascript_Core/bytecompiler/NodesCodegen.cpp	2017-01-09 22:02:47 UTC (rev 210522)
@@ -190,6 +190,17 @@
     return generator.moveToDestinationIfNeeded(generator.finalDestination(dst), result);
 }
 
+// ------------------------------ ImportNode -------------------------------------
+
+RegisterID* ImportNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
+{
+    RefPtr<RegisterID> importModule = generator.emitGetGlobalPrivate(generator.newTemporary(), generator.propertyNames().builtinNames().importModulePrivateName());
+    CallArguments arguments(generator, nullptr, 1);
+    generator.emitLoad(arguments.thisRegister(), jsUndefined());
+    generator.emitNode(arguments.argumentRegister(0), m_expr);
+    return generator.emitCall(generator.finalDestination(dst, importModule.get()), importModule.get(), NoExpectedFunction, arguments, divot(), divotStart(), divotEnd(), DebuggableCall::No);
+}
+
 // ------------------------------ NewTargetNode ----------------------------------
 
 RegisterID* NewTargetNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)

Modified: trunk/Source/_javascript_Core/jsc.cpp (210521 => 210522)


--- trunk/Source/_javascript_Core/jsc.cpp	2017-01-09 21:45:56 UTC (rev 210521)
+++ trunk/Source/_javascript_Core/jsc.cpp	2017-01-09 22:02:47 UTC (rev 210522)
@@ -25,6 +25,7 @@
 #include "ArrayBuffer.h"
 #include "ArrayPrototype.h"
 #include "BuiltinExecutableCreator.h"
+#include "BuiltinNames.h"
 #include "ButterflyInlines.h"
 #include "CodeBlock.h"
 #include "Completion.h"
@@ -48,6 +49,7 @@
 #include "JSInternalPromise.h"
 #include "JSInternalPromiseDeferred.h"
 #include "JSLock.h"
+#include "JSModuleLoader.h"
 #include "JSNativeStdFunction.h"
 #include "JSONObject.h"
 #include "JSProxy.h"
@@ -1101,10 +1103,10 @@
 }
 
 template<typename Vector>
-static inline SourceCode jscSource(const Vector& utf8, const String& filename)
+static inline SourceCode jscSource(const Vector& utf8, const SourceOrigin& sourceOrigin, const String& filename)
 {
     String str = stringFromUTF(utf8);
-    return makeSource(str, SourceOrigin { filename }, filename);
+    return makeSource(str, sourceOrigin, filename);
 }
 
 class GlobalObject : public JSGlobalObject {
@@ -1277,6 +1279,7 @@
         putDirect(vm, identifier, JSFunction::create(vm, this, arguments, identifier.string(), function, NoIntrinsic, function));
     }
 
+    static JSInternalPromise* moduleLoaderImportModule(JSGlobalObject*, ExecState*, JSModuleLoader*, JSString*, const SourceOrigin&);
     static JSInternalPromise* moduleLoaderResolve(JSGlobalObject*, ExecState*, JSModuleLoader*, JSValue, JSValue, JSValue);
     static JSInternalPromise* moduleLoaderFetch(JSGlobalObject*, ExecState*, JSModuleLoader*, JSValue, JSValue);
 };
@@ -1288,6 +1291,7 @@
     &_javascript_RuntimeFlags,
     nullptr,
     &shouldInterruptScriptBeforeTimeout,
+    &moduleLoaderImportModule,
     &moduleLoaderResolve,
     &moduleLoaderFetch,
     nullptr,
@@ -1420,6 +1424,29 @@
     return builder.toString();
 }
 
+static String absolutePath(const String& fileName)
+{
+    auto directoryName = currentWorkingDirectory();
+    if (!directoryName)
+        return fileName;
+    return resolvePath(directoryName.value(), ModuleName(fileName.impl()));
+}
+
+JSInternalPromise* GlobalObject::moduleLoaderImportModule(JSGlobalObject*, ExecState* exec, JSModuleLoader* moduleLoader, JSString* moduleName, const SourceOrigin& sourceOrigin)
+{
+    auto* function = jsCast<JSObject*>(moduleLoader->get(exec, exec->propertyNames().builtinNames().importModulePublicName()));
+    CallData callData;
+    auto callType = JSC::getCallData(function, callData);
+    ASSERT(callType != CallType::None);
+
+    MarkedArgumentBuffer arguments;
+    arguments.append(moduleName);
+    arguments.append(jsString(exec, sourceOrigin.string()));
+    arguments.append(jsUndefined());
+
+    return jsCast<JSInternalPromise*>(call(exec, function, callType, callData, moduleLoader, arguments));
+}
+
 JSInternalPromise* GlobalObject::moduleLoaderResolve(JSGlobalObject* globalObject, ExecState* exec, JSModuleLoader*, JSValue keyValue, JSValue referrerValue, JSValue)
 {
     VM& vm = globalObject->vm();
@@ -1924,7 +1951,7 @@
     NakedPtr<Exception> exception;
     StopWatch stopWatch;
     stopWatch.start();
-    evaluate(globalObject->globalExec(), jscSource(script, fileName), JSValue(), exception);
+    evaluate(globalObject->globalExec(), jscSource(script, SourceOrigin { absolutePath(fileName) }, fileName), JSValue(), exception);
     stopWatch.stop();
 
     if (exception) {
@@ -1976,7 +2003,7 @@
     JSGlobalObject* globalObject = exec->lexicalGlobalObject();
     
     NakedPtr<Exception> evaluationException;
-    JSValue result = evaluate(globalObject->globalExec(), jscSource(script, fileName), JSValue(), evaluationException);
+    JSValue result = evaluate(globalObject->globalExec(), jscSource(script, SourceOrigin { absolutePath(fileName) }, fileName), JSValue(), evaluationException);
     if (evaluationException)
         throwException(exec, scope, evaluationException);
     return JSValue::encode(result);
@@ -2047,7 +2074,7 @@
     stopWatch.start();
 
     JSValue syntaxException;
-    bool validSyntax = checkSyntax(globalObject->globalExec(), jscSource(script, fileName), &syntaxException);
+    bool validSyntax = checkSyntax(globalObject->globalExec(), jscSource(script, SourceOrigin { absolutePath(fileName) }, fileName), &syntaxException);
     stopWatch.stop();
 
     if (!validSyntax)
@@ -2909,7 +2936,7 @@
         bool isLastFile = i == scripts.size() - 1;
         if (isModule) {
             if (!promise)
-                promise = loadAndEvaluateModule(globalObject->globalExec(), jscSource(scriptBuffer, fileName));
+                promise = loadAndEvaluateModule(globalObject->globalExec(), jscSource(scriptBuffer, SourceOrigin { absolutePath(fileName) }, fileName));
             scope.clearException();
 
             JSFunction* fulfillHandler = JSNativeStdFunction::create(vm, globalObject, 1, String(), [&, isLastFile](ExecState* exec) {
@@ -2926,7 +2953,7 @@
             vm.drainMicrotasks();
         } else {
             NakedPtr<Exception> evaluationException;
-            JSValue returnValue = evaluate(globalObject->globalExec(), jscSource(scriptBuffer, fileName), JSValue(), evaluationException);
+            JSValue returnValue = evaluate(globalObject->globalExec(), jscSource(scriptBuffer, SourceOrigin { absolutePath(fileName) }, fileName), JSValue(), evaluationException);
             ASSERT(!scope.exception());
             if (evaluationException)
                 returnValue = evaluationException->value();
@@ -2999,7 +3026,7 @@
             break;
 
         NakedPtr<Exception> evaluationException;
-        JSValue returnValue = evaluate(globalObject->globalExec(), jscSource(line, sourceOrigin.string()), JSValue(), evaluationException);
+        JSValue returnValue = evaluate(globalObject->globalExec(), jscSource(line, sourceOrigin, sourceOrigin.string()), JSValue(), evaluationException);
 #endif
         if (evaluationException)
             printf("Exception: %s\n", evaluationException->value().toWTFString(globalObject->globalExec()).utf8().data());

Modified: trunk/Source/_javascript_Core/parser/ASTBuilder.h (210521 => 210522)


--- trunk/Source/_javascript_Core/parser/ASTBuilder.h	2017-01-09 21:45:56 UTC (rev 210521)
+++ trunk/Source/_javascript_Core/parser/ASTBuilder.h	2017-01-09 22:02:47 UTC (rev 210522)
@@ -178,6 +178,12 @@
     {
         return new (m_parserArena) SuperNode(location);
     }
+    ExpressionNode* createImportExpr(const JSTokenLocation& location, ExpressionNode* expr, const JSTextPosition& start, const JSTextPosition& divot, const JSTextPosition& end)
+    {
+        auto* node = new (m_parserArena) ImportNode(location, expr);
+        setExceptionLocation(node, start, divot, end);
+        return node;
+    }
     ExpressionNode* createNewTargetExpr(const JSTokenLocation location)
     {
         usesNewTarget();

Modified: trunk/Source/_javascript_Core/parser/NodeConstructors.h (210521 => 210522)


--- trunk/Source/_javascript_Core/parser/NodeConstructors.h	2017-01-09 21:45:56 UTC (rev 210521)
+++ trunk/Source/_javascript_Core/parser/NodeConstructors.h	2017-01-09 22:02:47 UTC (rev 210522)
@@ -167,6 +167,12 @@
     {
     }
 
+    inline ImportNode::ImportNode(const JSTokenLocation& location, ExpressionNode* expr)
+        : ExpressionNode(location)
+        , m_expr(expr)
+    {
+    }
+
     inline NewTargetNode::NewTargetNode(const JSTokenLocation& location)
         : ExpressionNode(location)
     {

Modified: trunk/Source/_javascript_Core/parser/Nodes.h (210521 => 210522)


--- trunk/Source/_javascript_Core/parser/Nodes.h	2017-01-09 21:45:56 UTC (rev 210521)
+++ trunk/Source/_javascript_Core/parser/Nodes.h	2017-01-09 22:02:47 UTC (rev 210522)
@@ -186,6 +186,7 @@
         virtual bool isBoolean() const { return false; }
         virtual bool isSpreadExpression() const { return false; }
         virtual bool isSuperNode() const { return false; }
+        virtual bool isImportNode() const { return false; }
         virtual bool isNewTarget() const { return false; }
         virtual bool isBytecodeIntrinsicNode() const { return false; }
 
@@ -570,6 +571,17 @@
         RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) override;
     };
 
+    class ImportNode : public ExpressionNode, public ThrowableExpressionData {
+    public:
+        ImportNode(const JSTokenLocation&, ExpressionNode*);
+
+    private:
+        bool isImportNode() const override { return true; }
+        RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) override;
+
+        ExpressionNode* m_expr;
+    };
+
     class NewTargetNode final : public ExpressionNode {
     public:
         NewTargetNode(const JSTokenLocation&);

Modified: trunk/Source/_javascript_Core/parser/Parser.cpp (210521 => 210522)


--- trunk/Source/_javascript_Core/parser/Parser.cpp	2017-01-09 21:45:56 UTC (rev 210521)
+++ trunk/Source/_javascript_Core/parser/Parser.cpp	2017-01-09 22:02:47 UTC (rev 210522)
@@ -4343,7 +4343,8 @@
     }
 
     bool baseIsSuper = match(SUPER);
-    semanticFailIfTrue(baseIsSuper && newCount, "Cannot use new with super");
+    bool baseIsImport = match(IMPORT);
+    semanticFailIfTrue((baseIsSuper || baseIsImport) && newCount, "Cannot use new with ", getToken());
 
     bool baseIsNewTarget = false;
     if (newCount && match(DOT)) {
@@ -4383,6 +4384,14 @@
                 semanticFailIfTrue(functionSuperBinding == SuperBinding::NotNeeded, "super is not valid in this context");
             }
         }
+    } else if (baseIsImport) {
+        JSTextPosition expressionEnd = lastTokenEndPosition();
+        next();
+        consumeOrFail(OPENPAREN, "import call expects exactly one argument");
+        TreeExpression expr = parseAssignmentExpression(context);
+        failIfFalse(expr, "Cannot parse _expression_");
+        consumeOrFail(CLOSEPAREN, "import call expects exactly one argument");
+        return context.createImportExpr(location, expr, expressionStart, expressionEnd, lastTokenEndPosition());
     } else if (!baseIsNewTarget) {
         const bool isAsync = match(ASYNC);
 

Modified: trunk/Source/_javascript_Core/parser/SyntaxChecker.h (210521 => 210522)


--- trunk/Source/_javascript_Core/parser/SyntaxChecker.h	2017-01-09 21:45:56 UTC (rev 210521)
+++ trunk/Source/_javascript_Core/parser/SyntaxChecker.h	2017-01-09 22:02:47 UTC (rev 210522)
@@ -71,7 +71,7 @@
     enum { NoneExpr = 0,
         ResolveEvalExpr, ResolveExpr, IntegerExpr, DoubleExpr, StringExpr,
         ThisExpr, NullExpr, BoolExpr, RegExpExpr, ObjectLiteralExpr,
-        FunctionExpr, ClassExpr, SuperExpr, BracketExpr, DotExpr, CallExpr,
+        FunctionExpr, ClassExpr, SuperExpr, ImportExpr, BracketExpr, DotExpr, CallExpr,
         NewExpr, PreExpr, PostExpr, UnaryExpr, BinaryExpr,
         ConditionalExpr, AssignmentExpr, TypeofExpr, NewTargetExpr,
         DeleteExpr, ArrayLiteralExpr, BindingDestructuring, RestParameter,
@@ -156,6 +156,7 @@
     ExpressionType createLogicalNot(const JSTokenLocation&, ExpressionType) { return UnaryExpr; }
     ExpressionType createUnaryPlus(const JSTokenLocation&, ExpressionType) { return UnaryExpr; }
     ExpressionType createVoid(const JSTokenLocation&, ExpressionType) { return UnaryExpr; }
+    ExpressionType createImportExpr(const JSTokenLocation&, ExpressionType, int, int, int) { return ImportExpr; }
     ExpressionType createThisExpr(const JSTokenLocation&) { return ThisExpr; }
     ExpressionType createSuperExpr(const JSTokenLocation&) { return SuperExpr; }
     ExpressionType createNewTargetExpr(const JSTokenLocation&) { return NewTargetExpr; }

Modified: trunk/Source/_javascript_Core/runtime/JSGlobalObject.cpp (210521 => 210522)


--- trunk/Source/_javascript_Core/runtime/JSGlobalObject.cpp	2017-01-09 21:45:56 UTC (rev 210521)
+++ trunk/Source/_javascript_Core/runtime/JSGlobalObject.cpp	2017-01-09 22:02:47 UTC (rev 210522)
@@ -256,6 +256,7 @@
     nullptr,
     nullptr,
     nullptr,
+    nullptr,
     nullptr
 };
 
@@ -732,6 +733,7 @@
     JSFunction* privateFuncTrunc = JSFunction::create(vm, this, 0, String(), mathProtoFuncTrunc, TruncIntrinsic);
 
     JSFunction* privateFuncGetTemplateObject = JSFunction::create(vm, this, 0, String(), getTemplateObject);
+    JSFunction* privateFuncImportModule = JSFunction::create(vm, this, 0, String(), globalFuncImportModule);
     JSFunction* privateFuncTypedArrayLength = JSFunction::create(vm, this, 0, String(), typedArrayViewPrivateFuncLength);
     JSFunction* privateFuncTypedArrayGetOriginalConstructor = JSFunction::create(vm, this, 0, String(), typedArrayViewPrivateFuncGetOriginalConstructor);
     JSFunction* privateFuncTypedArraySort = JSFunction::create(vm, this, 0, String(), typedArrayViewPrivateFuncSort);
@@ -785,6 +787,7 @@
         GlobalPropertyInfo(vm.propertyNames->undefinedKeyword, jsUndefined(), DontEnum | DontDelete | ReadOnly),
         GlobalPropertyInfo(vm.propertyNames->builtinNames().ownEnumerablePropertyKeysPrivateName(), JSFunction::create(vm, this, 0, String(), ownEnumerablePropertyKeys), DontEnum | DontDelete | ReadOnly),
         GlobalPropertyInfo(vm.propertyNames->builtinNames().getTemplateObjectPrivateName(), privateFuncGetTemplateObject, DontEnum | DontDelete | ReadOnly),
+        GlobalPropertyInfo(vm.propertyNames->builtinNames().importModulePrivateName(), privateFuncImportModule, DontEnum | DontDelete | ReadOnly),
         GlobalPropertyInfo(vm.propertyNames->builtinNames().enqueueJobPrivateName(), JSFunction::create(vm, this, 0, String(), enqueueJob), DontEnum | DontDelete | ReadOnly),
         GlobalPropertyInfo(vm.propertyNames->builtinNames().ErrorPrivateName(), m_errorConstructor.get(), DontEnum | DontDelete | ReadOnly),
         GlobalPropertyInfo(vm.propertyNames->builtinNames().RangeErrorPrivateName(), m_rangeErrorConstructor.get(), DontEnum | DontDelete | ReadOnly),

Modified: trunk/Source/_javascript_Core/runtime/JSGlobalObject.h (210521 => 210522)


--- trunk/Source/_javascript_Core/runtime/JSGlobalObject.h	2017-01-09 21:45:56 UTC (rev 210521)
+++ trunk/Source/_javascript_Core/runtime/JSGlobalObject.h	2017-01-09 22:02:47 UTC (rev 210522)
@@ -184,6 +184,9 @@
     typedef bool (*ShouldInterruptScriptBeforeTimeoutPtr)(const JSGlobalObject*);
     ShouldInterruptScriptBeforeTimeoutPtr shouldInterruptScriptBeforeTimeout;
 
+    typedef JSInternalPromise* (*ModuleLoaderImportModulePtr)(JSGlobalObject*, ExecState*, JSModuleLoader*, JSString*, const SourceOrigin&);
+    ModuleLoaderImportModulePtr moduleLoaderImportModule;
+
     typedef JSInternalPromise* (*ModuleLoaderResolvePtr)(JSGlobalObject*, ExecState*, JSModuleLoader*, JSValue, JSValue, JSValue);
     ModuleLoaderResolvePtr moduleLoaderResolve;
 

Modified: trunk/Source/_javascript_Core/runtime/JSGlobalObjectFunctions.cpp (210521 => 210522)


--- trunk/Source/_javascript_Core/runtime/JSGlobalObjectFunctions.cpp	2017-01-09 21:45:56 UTC (rev 210521)
+++ trunk/Source/_javascript_Core/runtime/JSGlobalObjectFunctions.cpp	2017-01-09 22:02:47 UTC (rev 210522)
@@ -27,10 +27,14 @@
 
 #include "CallFrame.h"
 #include "EvalExecutable.h"
+#include "Exception.h"
 #include "IndirectEvalExecutable.h"
 #include "Interpreter.h"
 #include "JSFunction.h"
 #include "JSGlobalObject.h"
+#include "JSInternalPromise.h"
+#include "JSModuleLoader.h"
+#include "JSPromiseDeferred.h"
 #include "JSString.h"
 #include "JSStringBuilder.h"
 #include "Lexer.h"
@@ -925,4 +929,39 @@
     return JSValue::encode(jsUndefined());
 }
 
+EncodedJSValue JSC_HOST_CALL globalFuncImportModule(ExecState* exec)
+{
+    VM& vm = exec->vm();
+    auto catchScope = DECLARE_CATCH_SCOPE(vm);
+
+    auto* globalObject = exec->lexicalGlobalObject();
+
+    auto* promise = JSPromiseDeferred::create(exec, globalObject);
+    RETURN_IF_EXCEPTION(catchScope, { });
+
+    auto sourceOrigin = exec->callerSourceOrigin();
+    if (sourceOrigin.isNull()) {
+        promise->reject(exec, createError(exec, ASCIILiteral("Could not resolve the module specifier.")));
+        return JSValue::encode(promise->promise());
+    }
+
+    RELEASE_ASSERT(exec->argumentCount() == 1);
+    auto* specifier = exec->uncheckedArgument(0).toString(exec);
+    if (Exception* exception = catchScope.exception()) {
+        catchScope.clearException();
+        promise->reject(exec, exception);
+        return JSValue::encode(promise->promise());
+    }
+
+    auto* internalPromise = globalObject->moduleLoader()->importModule(exec, specifier, sourceOrigin);
+    if (Exception* exception = catchScope.exception()) {
+        catchScope.clearException();
+        promise->reject(exec, exception);
+        return JSValue::encode(promise->promise());
+    }
+    promise->resolve(exec, internalPromise);
+
+    return JSValue::encode(promise->promise());
+}
+
 } // namespace JSC

Modified: trunk/Source/_javascript_Core/runtime/JSGlobalObjectFunctions.h (210521 => 210522)


--- trunk/Source/_javascript_Core/runtime/JSGlobalObjectFunctions.h	2017-01-09 21:45:56 UTC (rev 210521)
+++ trunk/Source/_javascript_Core/runtime/JSGlobalObjectFunctions.h	2017-01-09 22:02:47 UTC (rev 210522)
@@ -50,6 +50,7 @@
 EncodedJSValue JSC_HOST_CALL globalFuncProtoGetter(ExecState*);
 EncodedJSValue JSC_HOST_CALL globalFuncProtoSetter(ExecState*);
 EncodedJSValue JSC_HOST_CALL globalFuncBuiltinLog(ExecState*);
+EncodedJSValue JSC_HOST_CALL globalFuncImportModule(ExecState*);
 
 static const double mantissaOverflowLowerBound = 9007199254740992.0;
 double parseIntOverflow(const LChar*, unsigned length, int radix);

Modified: trunk/Source/_javascript_Core/runtime/JSModuleLoader.cpp (210521 => 210522)


--- trunk/Source/_javascript_Core/runtime/JSModuleLoader.cpp	2017-01-09 21:45:56 UTC (rev 210521)
+++ trunk/Source/_javascript_Core/runtime/JSModuleLoader.cpp	2017-01-09 22:02:47 UTC (rev 210522)
@@ -134,6 +134,30 @@
     return call(exec, function, callType, callData, this, arguments);
 }
 
+JSInternalPromise* JSModuleLoader::importModule(ExecState* exec, JSString* moduleName, const SourceOrigin& referrer)
+{
+    if (Options::dumpModuleLoadingState())
+        dataLog("Loader [import] ", printableModuleKey(exec, moduleName), "\n");
+
+    auto* globalObject = exec->lexicalGlobalObject();
+    VM& vm = globalObject->vm();
+    auto scope = DECLARE_CATCH_SCOPE(vm);
+
+    if (globalObject->globalObjectMethodTable()->moduleLoaderImportModule)
+        return globalObject->globalObjectMethodTable()->moduleLoaderImportModule(globalObject, exec, this, moduleName, referrer);
+
+    auto* deferred = JSInternalPromiseDeferred::create(exec, globalObject);
+    auto moduleNameString = moduleName->value(exec);
+    if (UNLIKELY(scope.exception())) {
+        JSValue exception = scope.exception()->value();
+        scope.clearException();
+        deferred->reject(exec, exception);
+        return deferred->promise();
+    }
+    deferred->reject(exec, createError(exec, makeString("Could not import the module '", moduleNameString, "'.")));
+    return deferred->promise();
+}
+
 JSInternalPromise* JSModuleLoader::resolve(ExecState* exec, JSValue name, JSValue referrer, JSValue initiator)
 {
     if (Options::dumpModuleLoadingState())
@@ -197,4 +221,19 @@
     return moduleRecord->evaluate(exec);
 }
 
+JSModuleNamespaceObject* JSModuleLoader::getModuleNamespaceObject(ExecState* exec, JSValue moduleRecordValue)
+{
+    VM& vm = exec->vm();
+    auto scope = DECLARE_THROW_SCOPE(vm);
+
+    auto* moduleRecord = jsDynamicCast<AbstractModuleRecord*>(moduleRecordValue);
+    if (!moduleRecord) {
+        throwTypeError(exec, scope);
+        return nullptr;
+    }
+
+    scope.release();
+    return moduleRecord->getModuleNamespace(exec);
+}
+
 } // namespace JSC

Modified: trunk/Source/_javascript_Core/runtime/JSModuleLoader.h (210521 => 210522)


--- trunk/Source/_javascript_Core/runtime/JSModuleLoader.h	2017-01-09 21:45:56 UTC (rev 210521)
+++ trunk/Source/_javascript_Core/runtime/JSModuleLoader.h	2017-01-09 22:02:47 UTC (rev 210522)
@@ -31,6 +31,7 @@
 namespace JSC {
 
 class JSInternalPromise;
+class JSModuleNamespaceObject;
 
 class JSModuleLoader : public JSNonFinalObject {
 private:
@@ -67,6 +68,7 @@
     JSValue linkAndEvaluateModule(ExecState*, JSValue moduleKey, JSValue initiator);
 
     // Platform dependent hooked APIs.
+    JSInternalPromise* importModule(ExecState*, JSString* moduleName, const SourceOrigin& referrer);
     JSInternalPromise* resolve(ExecState*, JSValue name, JSValue referrer, JSValue initiator);
     JSInternalPromise* fetch(ExecState*, JSValue key, JSValue initiator);
     JSInternalPromise* instantiate(ExecState*, JSValue key, JSValue source, JSValue initiator);
@@ -74,6 +76,9 @@
     // Additional platform dependent hooked APIs.
     JSValue evaluate(ExecState*, JSValue key, JSValue moduleRecord, JSValue initiator);
 
+    // Utility functions.
+    JSModuleNamespaceObject* getModuleNamespaceObject(ExecState*, JSValue moduleRecord);
+
 protected:
     void finishCreation(ExecState*, VM&, JSGlobalObject*);
 };

Modified: trunk/Source/_javascript_Core/runtime/ModuleLoaderPrototype.cpp (210521 => 210522)


--- trunk/Source/_javascript_Core/runtime/ModuleLoaderPrototype.cpp	2017-01-09 21:45:56 UTC (rev 210521)
+++ trunk/Source/_javascript_Core/runtime/ModuleLoaderPrototype.cpp	2017-01-09 22:02:47 UTC (rev 210522)
@@ -37,6 +37,7 @@
 #include "JSMap.h"
 #include "JSModuleEnvironment.h"
 #include "JSModuleLoader.h"
+#include "JSModuleNamespaceObject.h"
 #include "JSModuleRecord.h"
 #include "ModuleAnalyzer.h"
 #include "Nodes.h"
@@ -52,6 +53,7 @@
 static EncodedJSValue JSC_HOST_CALL moduleLoaderPrototypeResolve(ExecState*);
 static EncodedJSValue JSC_HOST_CALL moduleLoaderPrototypeFetch(ExecState*);
 static EncodedJSValue JSC_HOST_CALL moduleLoaderPrototypeInstantiate(ExecState*);
+static EncodedJSValue JSC_HOST_CALL moduleLoaderPrototypeGetModuleNamespaceObject(ExecState*);
 
 }
 
@@ -85,6 +87,8 @@
     loadAndEvaluateModule          JSBuiltin                                           DontEnum|Function 3
     loadModule                     JSBuiltin                                           DontEnum|Function 3
     linkAndEvaluateModule          JSBuiltin                                           DontEnum|Function 2
+    importModule                   JSBuiltin                                           DontEnum|Function 3
+    getModuleNamespaceObject       moduleLoaderPrototypeGetModuleNamespaceObject       DontEnum|Function 1
     parseModule                    moduleLoaderPrototypeParseModule                    DontEnum|Function 2
     requestedModules               moduleLoaderPrototypeRequestedModules               DontEnum|Function 1
     resolve                        moduleLoaderPrototypeResolve                        DontEnum|Function 2
@@ -211,6 +215,19 @@
     return JSValue::encode(loader->instantiate(exec, exec->argument(0), exec->argument(1), exec->argument(2)));
 }
 
+EncodedJSValue JSC_HOST_CALL moduleLoaderPrototypeGetModuleNamespaceObject(ExecState* exec)
+{
+    VM& vm = exec->vm();
+    auto scope = DECLARE_THROW_SCOPE(vm);
+
+    auto* loader = jsDynamicCast<JSModuleLoader*>(exec->thisValue());
+    if (!loader)
+        return JSValue::encode(jsUndefined());
+    auto* moduleNamespaceObject = loader->getModuleNamespaceObject(exec, exec->argument(0));
+    RETURN_IF_EXCEPTION(scope, encodedJSValue());
+    return JSValue::encode(moduleNamespaceObject);
+}
+
 // ------------------- Additional Hook Functions ---------------------------
 
 EncodedJSValue JSC_HOST_CALL moduleLoaderPrototypeEvaluate(ExecState* exec)

Modified: trunk/Source/WebCore/ChangeLog (210521 => 210522)


--- trunk/Source/WebCore/ChangeLog	2017-01-09 21:45:56 UTC (rev 210521)
+++ trunk/Source/WebCore/ChangeLog	2017-01-09 22:02:47 UTC (rev 210522)
@@ -1,3 +1,16 @@
+2017-01-09  Yusuke Suzuki  <utatane....@gmail.com>
+
+        [JSC] Prototype dynamic-import
+        https://bugs.webkit.org/show_bug.cgi?id=165724
+
+        Reviewed by Saam Barati.
+
+        We do not set a handler for import for now.
+        So dynamic import feature is only enabled in the JSC shell right now.
+
+        * bindings/js/JSDOMWindowBase.cpp:
+        * bindings/js/JSWorkerGlobalScopeBase.cpp:
+
 2017-01-09  Youenn Fablet  <youe...@gmail.com>
 
         Merging ThreadableLoader redundant options on filtering responses

Modified: trunk/Source/WebCore/bindings/js/JSDOMWindowBase.cpp (210521 => 210522)


--- trunk/Source/WebCore/bindings/js/JSDOMWindowBase.cpp	2017-01-09 21:45:56 UTC (rev 210521)
+++ trunk/Source/WebCore/bindings/js/JSDOMWindowBase.cpp	2017-01-09 22:02:47 UTC (rev 210522)
@@ -64,6 +64,7 @@
     &_javascript_RuntimeFlags,
     &queueTaskToEventLoop,
     &shouldInterruptScriptBeforeTimeout,
+    nullptr,
     &moduleLoaderResolve,
     &moduleLoaderFetch,
     nullptr,

Modified: trunk/Source/WebCore/bindings/js/JSWorkerGlobalScopeBase.cpp (210521 => 210522)


--- trunk/Source/WebCore/bindings/js/JSWorkerGlobalScopeBase.cpp	2017-01-09 21:45:56 UTC (rev 210521)
+++ trunk/Source/WebCore/bindings/js/JSWorkerGlobalScopeBase.cpp	2017-01-09 22:02:47 UTC (rev 210522)
@@ -57,6 +57,7 @@
     nullptr,
     nullptr,
     nullptr,
+    nullptr,
     &defaultLanguage
 };
 
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to