Changeset 210522 in webkit


Ignore:
Timestamp:
Jan 9, 2017 2:02:47 PM (7 years ago)
Author:
Yusuke Suzuki
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/JavaScriptCore:

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 callimport("./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:
Location:
trunk
Files:
8 added
25 edited

Legend:

Unmodified
Added
Removed
  • trunk/JSTests/ChangeLog

    r210518 r210522  
     12017-01-09  Yusuke Suzuki  <utatane.tea@gmail.com>
     2
     3        [JSC] Prototype dynamic-import
     4        https://bugs.webkit.org/show_bug.cgi?id=165724
     5
     6        Reviewed by Saam Barati.
     7
     8        * stress/import-basic.js: Added.
     9        (async.async.load):
     10        (async):
     11        (catch):
     12        * stress/import-from-eval.js: Added.
     13        (async):
     14        (catch):
     15        * stress/import-syntax.js: Added.
     16        (testSyntaxError):
     17        * stress/import-tests/cocoa.js: Added.
     18        (export.Cocoa):
     19        (export.hello):
     20        * stress/import-tests/multiple.js: Added.
     21        (export.result):
     22        * stress/import-tests/multiple2.js: Added.
     23        (export.ok):
     24        * stress/import-tests/should.js: Added.
     25        (export.shouldBe):
     26        (export.shouldThrow):
     27        * stress/modules-syntax-error.js:
     28
    1292017-01-09  Commit Queue  <commit-queue@webkit.org>
    230
  • trunk/JSTests/stress/modules-syntax-error.js

    r199927 r210522  
    108108    import * as from from "Cocoa"
    109109}
    110 `, `SyntaxError: Unexpected keyword 'import':3`);
     110`, `SyntaxError: Unexpected token '*'. import call expects exactly one argument.:3`);
    111111
    112112checkModuleSyntaxError(String.raw`
     
    114114    import * as from from "Cocoa"
    115115}
    116 `, `SyntaxError: Unexpected keyword 'import':3`);
     116`, `SyntaxError: Unexpected token '*'. import call expects exactly one argument.:3`);
    117117
    118118checkModuleSyntaxError(String.raw`
     
    120120    import * as from from "Cocoa"
    121121}
    122 `, `SyntaxError: Unexpected keyword 'import':3`);
     122`, `SyntaxError: Unexpected token '*'. import call expects exactly one argument.:3`);
    123123
    124124checkModuleSyntaxError(String.raw`
     
    126126    import * as from from "Cocoa"
    127127}
    128 `, `SyntaxError: Unexpected keyword 'import':3`);
     128`, `SyntaxError: Unexpected token '*'. import call expects exactly one argument.:3`);
    129129
    130130checkModuleSyntaxError(String.raw`
  • trunk/LayoutTests/ChangeLog

    r210519 r210522  
     12017-01-09  Yusuke Suzuki  <utatane.tea@gmail.com>
     2
     3        [JSC] Prototype dynamic-import
     4        https://bugs.webkit.org/show_bug.cgi?id=165724
     5
     6        Reviewed by Saam Barati.
     7
     8        * sputnik/Conformance/07_Lexical_Conventions/7.5_Tokens/7.5.3_Future_Reserved_Words/S7.5.3_A1.16-expected.txt:
     9
    1102017-01-09  Andy Estes  <aestes@apple.com>
    211
  • trunk/LayoutTests/sputnik/Conformance/07_Lexical_Conventions/7.5_Tokens/7.5.3_Future_Reserved_Words/S7.5.3_A1.16-expected.txt

    r187890 r210522  
    1 CONSOLE MESSAGE: line 76: SyntaxError: Unexpected keyword 'import'
     1CONSOLE MESSAGE: line 76: SyntaxError: Unexpected token '='. import call expects exactly one argument.
    22S7.5.3_A1.16
    33
  • trunk/Source/JavaScriptCore/ChangeLog

    r210521 r210522  
     12017-01-09  Yusuke Suzuki  <utatane.tea@gmail.com>
     2
     3        [JSC] Prototype dynamic-import
     4        https://bugs.webkit.org/show_bug.cgi?id=165724
     5
     6        Reviewed by Saam Barati.
     7
     8        In this patch, we implement stage3 dynamic-import proposal[1].
     9        This patch adds a new special operator `import`. And by using it, we can import
     10        the module dynamically from modules and scripts. Before this feature, the module
     11        is always imported statically and before executing the modules, importing the modules
     12        needs to be done. And especially, the module can only be imported from the module.
     13        So the classic script cannot import and use the modules. This dynamic-import relaxes
     14        the above restrictions.
     15
     16        The typical dynamic-import form is the following.
     17
     18            import("...").then(function (namespace) { ... });
     19
     20        You can pass any AssignmentExpression for the import operator. So you can determine
     21        the importing modules dynamically.
     22
     23            import(value).then(function (namespace) { ... });
     24
     25        And previously the module import declaration is only allowed in the top level statements.
     26        But this import operator is just an expression. So you can use it in the function.
     27        And you can use it conditionally.
     28
     29            async function go(cond)
     30            {
     31                if (cond)
     32                    return import("...");
     33                return undefined;
     34            }
     35            await go(true);
     36
     37        Currently, this patch just implements this feature only for the JSC shell.
     38        JSC module loader requires a new hook, `importModule`. And the JSC shell implements
     39        this hook. So, for now, this dynamic-import is not available in the browser side.
     40        If you write this `import` call, it always returns the rejected promise.
     41
     42        import is implemented like a special operator similar to `super`.
     43        This is because import is context-sensitive. If you call the `import`, the module
     44        key resolution is done based on the caller's running context.
     45
     46        For example, if you are running the script which filename is "./ok/hello.js", the module
     47        key for the call`import("./resource/syntax.js")` becomes `"./ok/resource/syntax.js"`.
     48        But if you write the completely same import form in the script "./error/hello.js", the
     49        key becomes "./error/resource/syntax.js". So exposing this feature as the `import`
     50        function is misleading: this function becomes caller's context-sensitive. That's why
     51        dynamic-import is specified as a special operator.
     52
     53        To resolve the module key, we need the caller's context information like the filename of
     54        the caller. This is provided by the SourceOrigin implemented in r210149.
     55        In the JSC shell implementation, this SourceOrigin holds the filename of the caller. So
     56        based on this implementation, the module loader resolve the module key.
     57        In the near future, we will extend this SourceOrigin to hold more information needed for
     58        the browser-side import implementation.
     59
     60        [1]: https://tc39.github.io/proposal-dynamic-import/
     61
     62        * builtins/ModuleLoaderPrototype.js:
     63        (importModule):
     64        * bytecompiler/BytecodeGenerator.cpp:
     65        (JSC::BytecodeGenerator::emitGetTemplateObject):
     66        (JSC::BytecodeGenerator::emitGetGlobalPrivate):
     67        * bytecompiler/BytecodeGenerator.h:
     68        * bytecompiler/NodesCodegen.cpp:
     69        (JSC::ImportNode::emitBytecode):
     70        * jsc.cpp:
     71        (absolutePath):
     72        (GlobalObject::moduleLoaderImportModule):
     73        (functionRun):
     74        (functionLoad):
     75        (functionCheckSyntax):
     76        (runWithScripts):
     77        * parser/ASTBuilder.h:
     78        (JSC::ASTBuilder::createImportExpr):
     79        * parser/NodeConstructors.h:
     80        (JSC::ImportNode::ImportNode):
     81        * parser/Nodes.h:
     82        (JSC::ExpressionNode::isImportNode):
     83        * parser/Parser.cpp:
     84        (JSC::Parser<LexerType>::parseMemberExpression):
     85        * parser/SyntaxChecker.h:
     86        (JSC::SyntaxChecker::createImportExpr):
     87        * runtime/JSGlobalObject.cpp:
     88        (JSC::JSGlobalObject::init):
     89        * runtime/JSGlobalObject.h:
     90        * runtime/JSGlobalObjectFunctions.cpp:
     91        (JSC::globalFuncImportModule):
     92        * runtime/JSGlobalObjectFunctions.h:
     93        * runtime/JSModuleLoader.cpp:
     94        (JSC::JSModuleLoader::importModule):
     95        (JSC::JSModuleLoader::getModuleNamespaceObject):
     96        * runtime/JSModuleLoader.h:
     97        * runtime/ModuleLoaderPrototype.cpp:
     98        (JSC::moduleLoaderPrototypeGetModuleNamespaceObject):
     99
    11002017-01-08  Filip Pizlo  <fpizlo@apple.com>
    2101
  • trunk/Source/JavaScriptCore/builtins/ModuleLoaderPrototype.js

    r209848 r210522  
    471471    return this.moduleEvaluation(entry.module, initiator);
    472472}
     473
     474function importModule(moduleName, referrer, initiator)
     475{
     476    "use strict";
     477
     478    // Loader.resolve hook point.
     479    // resolve: moduleName => Promise(moduleKey)
     480    // Take the name and resolve it to the unique identifier for the resource location.
     481    // For example, take the "jquery" and return the URL for the resource.
     482    return this.resolve(moduleName, referrer, initiator).then((key) => {
     483        return this.requestInstantiateAll(key, initiator);
     484    }).then((entry) => {
     485        this.linkAndEvaluateModule(entry.key, initiator);
     486        return this.getModuleNamespaceObject(entry.module);
     487    });
     488}
  • trunk/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp

    r210119 r210522  
    42624262    }
    42634263
    4264     RefPtr<RegisterID> getTemplateObject = nullptr;
    4265     Variable var = variable(propertyNames().builtinNames().getTemplateObjectPrivateName());
    4266     if (RegisterID* local = var.local())
    4267         getTemplateObject = emitMove(newTemporary(), local);
    4268     else {
    4269         getTemplateObject = newTemporary();
    4270         RefPtr<RegisterID> scope = newTemporary();
    4271         moveToDestinationIfNeeded(scope.get(), emitResolveScope(scope.get(), var));
    4272         emitGetFromScope(getTemplateObject.get(), scope.get(), var, ThrowIfNotFound);
    4273     }
    4274 
     4264    RefPtr<RegisterID> getTemplateObject = emitGetGlobalPrivate(newTemporary(), propertyNames().builtinNames().getTemplateObjectPrivateName());
    42754265    CallArguments arguments(*this, nullptr);
    42764266    emitLoad(arguments.thisRegister(), JSValue(addTemplateRegistryKeyConstant(m_vm->templateRegistryKeyTable().createKey(rawStrings, cookedStrings))));
    42774267    return emitCall(dst, getTemplateObject.get(), NoExpectedFunction, arguments, taggedTemplate->divot(), taggedTemplate->divotStart(), taggedTemplate->divotEnd(), DebuggableCall::No);
     4268}
     4269
     4270RegisterID* BytecodeGenerator::emitGetGlobalPrivate(RegisterID* dst, const Identifier& property)
     4271{
     4272    dst = tempDestination(dst);
     4273    Variable var = variable(property);
     4274    if (RegisterID* local = var.local())
     4275        return emitMove(dst, local);
     4276
     4277    RefPtr<RegisterID> scope = newTemporary();
     4278    moveToDestinationIfNeeded(scope.get(), emitResolveScope(scope.get(), var));
     4279    return emitGetFromScope(dst, scope.get(), var, ThrowIfNotFound);
    42784280}
    42794281
  • trunk/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h

    r210119 r210522  
    679679
    680680        RegisterID* emitGetTemplateObject(RegisterID* dst, TaggedTemplateNode*);
     681        RegisterID* emitGetGlobalPrivate(RegisterID* dst, const Identifier& property);
    681682
    682683        enum class ReturnFrom { Normal, Finally };
  • trunk/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp

    r210116 r210522  
    189189    RegisterID* result = emitSuperBaseForCallee(generator);
    190190    return generator.moveToDestinationIfNeeded(generator.finalDestination(dst), result);
     191}
     192
     193// ------------------------------ ImportNode -------------------------------------
     194
     195RegisterID* ImportNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
     196{
     197    RefPtr<RegisterID> importModule = generator.emitGetGlobalPrivate(generator.newTemporary(), generator.propertyNames().builtinNames().importModulePrivateName());
     198    CallArguments arguments(generator, nullptr, 1);
     199    generator.emitLoad(arguments.thisRegister(), jsUndefined());
     200    generator.emitNode(arguments.argumentRegister(0), m_expr);
     201    return generator.emitCall(generator.finalDestination(dst, importModule.get()), importModule.get(), NoExpectedFunction, arguments, divot(), divotStart(), divotEnd(), DebuggableCall::No);
    191202}
    192203
  • trunk/Source/JavaScriptCore/jsc.cpp

    r210229 r210522  
    2626#include "ArrayPrototype.h"
    2727#include "BuiltinExecutableCreator.h"
     28#include "BuiltinNames.h"
    2829#include "ButterflyInlines.h"
    2930#include "CodeBlock.h"
     
    4950#include "JSInternalPromiseDeferred.h"
    5051#include "JSLock.h"
     52#include "JSModuleLoader.h"
    5153#include "JSNativeStdFunction.h"
    5254#include "JSONObject.h"
     
    11021104
    11031105template<typename Vector>
    1104 static inline SourceCode jscSource(const Vector& utf8, const String& filename)
     1106static inline SourceCode jscSource(const Vector& utf8, const SourceOrigin& sourceOrigin, const String& filename)
    11051107{
    11061108    String str = stringFromUTF(utf8);
    1107     return makeSource(str, SourceOrigin { filename }, filename);
     1109    return makeSource(str, sourceOrigin, filename);
    11081110}
    11091111
     
    12781280    }
    12791281
     1282    static JSInternalPromise* moduleLoaderImportModule(JSGlobalObject*, ExecState*, JSModuleLoader*, JSString*, const SourceOrigin&);
    12801283    static JSInternalPromise* moduleLoaderResolve(JSGlobalObject*, ExecState*, JSModuleLoader*, JSValue, JSValue, JSValue);
    12811284    static JSInternalPromise* moduleLoaderFetch(JSGlobalObject*, ExecState*, JSModuleLoader*, JSValue, JSValue);
     
    12891292    nullptr,
    12901293    &shouldInterruptScriptBeforeTimeout,
     1294    &moduleLoaderImportModule,
    12911295    &moduleLoaderResolve,
    12921296    &moduleLoaderFetch,
     
    14211425}
    14221426
     1427static String absolutePath(const String& fileName)
     1428{
     1429    auto directoryName = currentWorkingDirectory();
     1430    if (!directoryName)
     1431        return fileName;
     1432    return resolvePath(directoryName.value(), ModuleName(fileName.impl()));
     1433}
     1434
     1435JSInternalPromise* GlobalObject::moduleLoaderImportModule(JSGlobalObject*, ExecState* exec, JSModuleLoader* moduleLoader, JSString* moduleName, const SourceOrigin& sourceOrigin)
     1436{
     1437    auto* function = jsCast<JSObject*>(moduleLoader->get(exec, exec->propertyNames().builtinNames().importModulePublicName()));
     1438    CallData callData;
     1439    auto callType = JSC::getCallData(function, callData);
     1440    ASSERT(callType != CallType::None);
     1441
     1442    MarkedArgumentBuffer arguments;
     1443    arguments.append(moduleName);
     1444    arguments.append(jsString(exec, sourceOrigin.string()));
     1445    arguments.append(jsUndefined());
     1446
     1447    return jsCast<JSInternalPromise*>(call(exec, function, callType, callData, moduleLoader, arguments));
     1448}
     1449
    14231450JSInternalPromise* GlobalObject::moduleLoaderResolve(JSGlobalObject* globalObject, ExecState* exec, JSModuleLoader*, JSValue keyValue, JSValue referrerValue, JSValue)
    14241451{
     
    19251952    StopWatch stopWatch;
    19261953    stopWatch.start();
    1927     evaluate(globalObject->globalExec(), jscSource(script, fileName), JSValue(), exception);
     1954    evaluate(globalObject->globalExec(), jscSource(script, SourceOrigin { absolutePath(fileName) }, fileName), JSValue(), exception);
    19281955    stopWatch.stop();
    19291956
     
    19772004   
    19782005    NakedPtr<Exception> evaluationException;
    1979     JSValue result = evaluate(globalObject->globalExec(), jscSource(script, fileName), JSValue(), evaluationException);
     2006    JSValue result = evaluate(globalObject->globalExec(), jscSource(script, SourceOrigin { absolutePath(fileName) }, fileName), JSValue(), evaluationException);
    19802007    if (evaluationException)
    19812008        throwException(exec, scope, evaluationException);
     
    20482075
    20492076    JSValue syntaxException;
    2050     bool validSyntax = checkSyntax(globalObject->globalExec(), jscSource(script, fileName), &syntaxException);
     2077    bool validSyntax = checkSyntax(globalObject->globalExec(), jscSource(script, SourceOrigin { absolutePath(fileName) }, fileName), &syntaxException);
    20512078    stopWatch.stop();
    20522079
     
    29102937        if (isModule) {
    29112938            if (!promise)
    2912                 promise = loadAndEvaluateModule(globalObject->globalExec(), jscSource(scriptBuffer, fileName));
     2939                promise = loadAndEvaluateModule(globalObject->globalExec(), jscSource(scriptBuffer, SourceOrigin { absolutePath(fileName) }, fileName));
    29132940            scope.clearException();
    29142941
     
    29272954        } else {
    29282955            NakedPtr<Exception> evaluationException;
    2929             JSValue returnValue = evaluate(globalObject->globalExec(), jscSource(scriptBuffer, fileName), JSValue(), evaluationException);
     2956            JSValue returnValue = evaluate(globalObject->globalExec(), jscSource(scriptBuffer, SourceOrigin { absolutePath(fileName) }, fileName), JSValue(), evaluationException);
    29302957            ASSERT(!scope.exception());
    29312958            if (evaluationException)
     
    30003027
    30013028        NakedPtr<Exception> evaluationException;
    3002         JSValue returnValue = evaluate(globalObject->globalExec(), jscSource(line, sourceOrigin.string()), JSValue(), evaluationException);
     3029        JSValue returnValue = evaluate(globalObject->globalExec(), jscSource(line, sourceOrigin, sourceOrigin.string()), JSValue(), evaluationException);
    30033030#endif
    30043031        if (evaluationException)
  • trunk/Source/JavaScriptCore/parser/ASTBuilder.h

    r208885 r210522  
    179179        return new (m_parserArena) SuperNode(location);
    180180    }
     181    ExpressionNode* createImportExpr(const JSTokenLocation& location, ExpressionNode* expr, const JSTextPosition& start, const JSTextPosition& divot, const JSTextPosition& end)
     182    {
     183        auto* node = new (m_parserArena) ImportNode(location, expr);
     184        setExceptionLocation(node, start, divot, end);
     185        return node;
     186    }
    181187    ExpressionNode* createNewTargetExpr(const JSTokenLocation location)
    182188    {
  • trunk/Source/JavaScriptCore/parser/NodeConstructors.h

    r206525 r210522  
    168168    }
    169169
     170    inline ImportNode::ImportNode(const JSTokenLocation& location, ExpressionNode* expr)
     171        : ExpressionNode(location)
     172        , m_expr(expr)
     173    {
     174    }
     175
    170176    inline NewTargetNode::NewTargetNode(const JSTokenLocation& location)
    171177        : ExpressionNode(location)
  • trunk/Source/JavaScriptCore/parser/Nodes.h

    r209871 r210522  
    187187        virtual bool isSpreadExpression() const { return false; }
    188188        virtual bool isSuperNode() const { return false; }
     189        virtual bool isImportNode() const { return false; }
    189190        virtual bool isNewTarget() const { return false; }
    190191        virtual bool isBytecodeIntrinsicNode() const { return false; }
     
    569570        bool isSuperNode() const override { return true; }
    570571        RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) override;
     572    };
     573
     574    class ImportNode : public ExpressionNode, public ThrowableExpressionData {
     575    public:
     576        ImportNode(const JSTokenLocation&, ExpressionNode*);
     577
     578    private:
     579        bool isImportNode() const override { return true; }
     580        RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) override;
     581
     582        ExpressionNode* m_expr;
    571583    };
    572584
  • trunk/Source/JavaScriptCore/parser/Parser.cpp

    r210151 r210522  
    43444344
    43454345    bool baseIsSuper = match(SUPER);
    4346     semanticFailIfTrue(baseIsSuper && newCount, "Cannot use new with super");
     4346    bool baseIsImport = match(IMPORT);
     4347    semanticFailIfTrue((baseIsSuper || baseIsImport) && newCount, "Cannot use new with ", getToken());
    43474348
    43484349    bool baseIsNewTarget = false;
     
    43844385            }
    43854386        }
     4387    } else if (baseIsImport) {
     4388        JSTextPosition expressionEnd = lastTokenEndPosition();
     4389        next();
     4390        consumeOrFail(OPENPAREN, "import call expects exactly one argument");
     4391        TreeExpression expr = parseAssignmentExpression(context);
     4392        failIfFalse(expr, "Cannot parse expression");
     4393        consumeOrFail(CLOSEPAREN, "import call expects exactly one argument");
     4394        return context.createImportExpr(location, expr, expressionStart, expressionEnd, lastTokenEndPosition());
    43864395    } else if (!baseIsNewTarget) {
    43874396        const bool isAsync = match(ASYNC);
  • trunk/Source/JavaScriptCore/parser/SyntaxChecker.h

    r208885 r210522  
    7272        ResolveEvalExpr, ResolveExpr, IntegerExpr, DoubleExpr, StringExpr,
    7373        ThisExpr, NullExpr, BoolExpr, RegExpExpr, ObjectLiteralExpr,
    74         FunctionExpr, ClassExpr, SuperExpr, BracketExpr, DotExpr, CallExpr,
     74        FunctionExpr, ClassExpr, SuperExpr, ImportExpr, BracketExpr, DotExpr, CallExpr,
    7575        NewExpr, PreExpr, PostExpr, UnaryExpr, BinaryExpr,
    7676        ConditionalExpr, AssignmentExpr, TypeofExpr, NewTargetExpr,
     
    157157    ExpressionType createUnaryPlus(const JSTokenLocation&, ExpressionType) { return UnaryExpr; }
    158158    ExpressionType createVoid(const JSTokenLocation&, ExpressionType) { return UnaryExpr; }
     159    ExpressionType createImportExpr(const JSTokenLocation&, ExpressionType, int, int, int) { return ImportExpr; }
    159160    ExpressionType createThisExpr(const JSTokenLocation&) { return ThisExpr; }
    160161    ExpressionType createSuperExpr(const JSTokenLocation&) { return SuperExpr; }
  • trunk/Source/JavaScriptCore/runtime/JSGlobalObject.cpp

    r210518 r210522  
    257257    nullptr,
    258258    nullptr,
     259    nullptr,
    259260    nullptr
    260261};
     
    733734
    734735    JSFunction* privateFuncGetTemplateObject = JSFunction::create(vm, this, 0, String(), getTemplateObject);
     736    JSFunction* privateFuncImportModule = JSFunction::create(vm, this, 0, String(), globalFuncImportModule);
    735737    JSFunction* privateFuncTypedArrayLength = JSFunction::create(vm, this, 0, String(), typedArrayViewPrivateFuncLength);
    736738    JSFunction* privateFuncTypedArrayGetOriginalConstructor = JSFunction::create(vm, this, 0, String(), typedArrayViewPrivateFuncGetOriginalConstructor);
     
    786788        GlobalPropertyInfo(vm.propertyNames->builtinNames().ownEnumerablePropertyKeysPrivateName(), JSFunction::create(vm, this, 0, String(), ownEnumerablePropertyKeys), DontEnum | DontDelete | ReadOnly),
    787789        GlobalPropertyInfo(vm.propertyNames->builtinNames().getTemplateObjectPrivateName(), privateFuncGetTemplateObject, DontEnum | DontDelete | ReadOnly),
     790        GlobalPropertyInfo(vm.propertyNames->builtinNames().importModulePrivateName(), privateFuncImportModule, DontEnum | DontDelete | ReadOnly),
    788791        GlobalPropertyInfo(vm.propertyNames->builtinNames().enqueueJobPrivateName(), JSFunction::create(vm, this, 0, String(), enqueueJob), DontEnum | DontDelete | ReadOnly),
    789792        GlobalPropertyInfo(vm.propertyNames->builtinNames().ErrorPrivateName(), m_errorConstructor.get(), DontEnum | DontDelete | ReadOnly),
  • trunk/Source/JavaScriptCore/runtime/JSGlobalObject.h

    r210518 r210522  
    185185    ShouldInterruptScriptBeforeTimeoutPtr shouldInterruptScriptBeforeTimeout;
    186186
     187    typedef JSInternalPromise* (*ModuleLoaderImportModulePtr)(JSGlobalObject*, ExecState*, JSModuleLoader*, JSString*, const SourceOrigin&);
     188    ModuleLoaderImportModulePtr moduleLoaderImportModule;
     189
    187190    typedef JSInternalPromise* (*ModuleLoaderResolvePtr)(JSGlobalObject*, ExecState*, JSModuleLoader*, JSValue, JSValue, JSValue);
    188191    ModuleLoaderResolvePtr moduleLoaderResolve;
  • trunk/Source/JavaScriptCore/runtime/JSGlobalObjectFunctions.cpp

    r210149 r210522  
    2828#include "CallFrame.h"
    2929#include "EvalExecutable.h"
     30#include "Exception.h"
    3031#include "IndirectEvalExecutable.h"
    3132#include "Interpreter.h"
    3233#include "JSFunction.h"
    3334#include "JSGlobalObject.h"
     35#include "JSInternalPromise.h"
     36#include "JSModuleLoader.h"
     37#include "JSPromiseDeferred.h"
    3438#include "JSString.h"
    3539#include "JSStringBuilder.h"
     
    926930}
    927931
     932EncodedJSValue JSC_HOST_CALL globalFuncImportModule(ExecState* exec)
     933{
     934    VM& vm = exec->vm();
     935    auto catchScope = DECLARE_CATCH_SCOPE(vm);
     936
     937    auto* globalObject = exec->lexicalGlobalObject();
     938
     939    auto* promise = JSPromiseDeferred::create(exec, globalObject);
     940    RETURN_IF_EXCEPTION(catchScope, { });
     941
     942    auto sourceOrigin = exec->callerSourceOrigin();
     943    if (sourceOrigin.isNull()) {
     944        promise->reject(exec, createError(exec, ASCIILiteral("Could not resolve the module specifier.")));
     945        return JSValue::encode(promise->promise());
     946    }
     947
     948    RELEASE_ASSERT(exec->argumentCount() == 1);
     949    auto* specifier = exec->uncheckedArgument(0).toString(exec);
     950    if (Exception* exception = catchScope.exception()) {
     951        catchScope.clearException();
     952        promise->reject(exec, exception);
     953        return JSValue::encode(promise->promise());
     954    }
     955
     956    auto* internalPromise = globalObject->moduleLoader()->importModule(exec, specifier, sourceOrigin);
     957    if (Exception* exception = catchScope.exception()) {
     958        catchScope.clearException();
     959        promise->reject(exec, exception);
     960        return JSValue::encode(promise->promise());
     961    }
     962    promise->resolve(exec, internalPromise);
     963
     964    return JSValue::encode(promise->promise());
     965}
     966
    928967} // namespace JSC
  • trunk/Source/JavaScriptCore/runtime/JSGlobalObjectFunctions.h

    r206525 r210522  
    5151EncodedJSValue JSC_HOST_CALL globalFuncProtoSetter(ExecState*);
    5252EncodedJSValue JSC_HOST_CALL globalFuncBuiltinLog(ExecState*);
     53EncodedJSValue JSC_HOST_CALL globalFuncImportModule(ExecState*);
    5354
    5455static const double mantissaOverflowLowerBound = 9007199254740992.0;
  • trunk/Source/JavaScriptCore/runtime/JSModuleLoader.cpp

    r209801 r210522  
    135135}
    136136
     137JSInternalPromise* JSModuleLoader::importModule(ExecState* exec, JSString* moduleName, const SourceOrigin& referrer)
     138{
     139    if (Options::dumpModuleLoadingState())
     140        dataLog("Loader [import] ", printableModuleKey(exec, moduleName), "\n");
     141
     142    auto* globalObject = exec->lexicalGlobalObject();
     143    VM& vm = globalObject->vm();
     144    auto scope = DECLARE_CATCH_SCOPE(vm);
     145
     146    if (globalObject->globalObjectMethodTable()->moduleLoaderImportModule)
     147        return globalObject->globalObjectMethodTable()->moduleLoaderImportModule(globalObject, exec, this, moduleName, referrer);
     148
     149    auto* deferred = JSInternalPromiseDeferred::create(exec, globalObject);
     150    auto moduleNameString = moduleName->value(exec);
     151    if (UNLIKELY(scope.exception())) {
     152        JSValue exception = scope.exception()->value();
     153        scope.clearException();
     154        deferred->reject(exec, exception);
     155        return deferred->promise();
     156    }
     157    deferred->reject(exec, createError(exec, makeString("Could not import the module '", moduleNameString, "'.")));
     158    return deferred->promise();
     159}
     160
    137161JSInternalPromise* JSModuleLoader::resolve(ExecState* exec, JSValue name, JSValue referrer, JSValue initiator)
    138162{
     
    198222}
    199223
     224JSModuleNamespaceObject* JSModuleLoader::getModuleNamespaceObject(ExecState* exec, JSValue moduleRecordValue)
     225{
     226    VM& vm = exec->vm();
     227    auto scope = DECLARE_THROW_SCOPE(vm);
     228
     229    auto* moduleRecord = jsDynamicCast<AbstractModuleRecord*>(moduleRecordValue);
     230    if (!moduleRecord) {
     231        throwTypeError(exec, scope);
     232        return nullptr;
     233    }
     234
     235    scope.release();
     236    return moduleRecord->getModuleNamespace(exec);
     237}
     238
    200239} // namespace JSC
  • trunk/Source/JavaScriptCore/runtime/JSModuleLoader.h

    r209500 r210522  
    3232
    3333class JSInternalPromise;
     34class JSModuleNamespaceObject;
    3435
    3536class JSModuleLoader : public JSNonFinalObject {
     
    6869
    6970    // Platform dependent hooked APIs.
     71    JSInternalPromise* importModule(ExecState*, JSString* moduleName, const SourceOrigin& referrer);
    7072    JSInternalPromise* resolve(ExecState*, JSValue name, JSValue referrer, JSValue initiator);
    7173    JSInternalPromise* fetch(ExecState*, JSValue key, JSValue initiator);
     
    7577    JSValue evaluate(ExecState*, JSValue key, JSValue moduleRecord, JSValue initiator);
    7678
     79    // Utility functions.
     80    JSModuleNamespaceObject* getModuleNamespaceObject(ExecState*, JSValue moduleRecord);
     81
    7782protected:
    7883    void finishCreation(ExecState*, VM&, JSGlobalObject*);
  • trunk/Source/JavaScriptCore/runtime/ModuleLoaderPrototype.cpp

    r210149 r210522  
    3838#include "JSModuleEnvironment.h"
    3939#include "JSModuleLoader.h"
     40#include "JSModuleNamespaceObject.h"
    4041#include "JSModuleRecord.h"
    4142#include "ModuleAnalyzer.h"
     
    5354static EncodedJSValue JSC_HOST_CALL moduleLoaderPrototypeFetch(ExecState*);
    5455static EncodedJSValue JSC_HOST_CALL moduleLoaderPrototypeInstantiate(ExecState*);
     56static EncodedJSValue JSC_HOST_CALL moduleLoaderPrototypeGetModuleNamespaceObject(ExecState*);
    5557
    5658}
     
    8688    loadModule                     JSBuiltin                                           DontEnum|Function 3
    8789    linkAndEvaluateModule          JSBuiltin                                           DontEnum|Function 2
     90    importModule                   JSBuiltin                                           DontEnum|Function 3
     91    getModuleNamespaceObject       moduleLoaderPrototypeGetModuleNamespaceObject       DontEnum|Function 1
    8892    parseModule                    moduleLoaderPrototypeParseModule                    DontEnum|Function 2
    8993    requestedModules               moduleLoaderPrototypeRequestedModules               DontEnum|Function 1
     
    212216}
    213217
     218EncodedJSValue JSC_HOST_CALL moduleLoaderPrototypeGetModuleNamespaceObject(ExecState* exec)
     219{
     220    VM& vm = exec->vm();
     221    auto scope = DECLARE_THROW_SCOPE(vm);
     222
     223    auto* loader = jsDynamicCast<JSModuleLoader*>(exec->thisValue());
     224    if (!loader)
     225        return JSValue::encode(jsUndefined());
     226    auto* moduleNamespaceObject = loader->getModuleNamespaceObject(exec, exec->argument(0));
     227    RETURN_IF_EXCEPTION(scope, encodedJSValue());
     228    return JSValue::encode(moduleNamespaceObject);
     229}
     230
    214231// ------------------- Additional Hook Functions ---------------------------
    215232
  • trunk/Source/WebCore/ChangeLog

    r210514 r210522  
     12017-01-09  Yusuke Suzuki  <utatane.tea@gmail.com>
     2
     3        [JSC] Prototype dynamic-import
     4        https://bugs.webkit.org/show_bug.cgi?id=165724
     5
     6        Reviewed by Saam Barati.
     7
     8        We do not set a handler for import for now.
     9        So dynamic import feature is only enabled in the JSC shell right now.
     10
     11        * bindings/js/JSDOMWindowBase.cpp:
     12        * bindings/js/JSWorkerGlobalScopeBase.cpp:
     13
    1142017-01-09  Youenn Fablet  <youennf@gmail.com>
    215
  • trunk/Source/WebCore/bindings/js/JSDOMWindowBase.cpp

    r209683 r210522  
    6565    &queueTaskToEventLoop,
    6666    &shouldInterruptScriptBeforeTimeout,
     67    nullptr,
    6768    &moduleLoaderResolve,
    6869    &moduleLoaderFetch,
  • trunk/Source/WebCore/bindings/js/JSWorkerGlobalScopeBase.cpp

    r209897 r210522  
    5454    &queueTaskToEventLoop,
    5555    &shouldInterruptScriptBeforeTimeout,
     56    nullptr,
    5657    nullptr,
    5758    nullptr,
Note: See TracChangeset for help on using the changeset viewer.