[ES6] Add more fine-grained APIs and additional hooks to control module loader from...
authorutatane.tea@gmail.com <utatane.tea@gmail.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 17 Sep 2015 22:26:18 +0000 (22:26 +0000)
committerutatane.tea@gmail.com <utatane.tea@gmail.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 17 Sep 2015 22:26:18 +0000 (22:26 +0000)
https://bugs.webkit.org/show_bug.cgi?id=149129

Reviewed by Saam Barati.

No behavior change.

Source/JavaScriptCore:

Module tag `<script type="module>` will be executed asynchronously.
But we would like to fetch the resources before when the postTask-ed task is performed.
So instead of 1 API that fetch, instantiate and execute the module,
we need 2 fine-grained APIs.

1. Fetch and initialize a module, but not execute it yet.
2. Link and execute a module specified by the key (this will be invoked asynchronously).

And to instrument the script execution (like reporting the execution time of the module to
the inspector), we need a hook to inject code around an execution of a module body.

* builtins/ModuleLoaderObject.js:
(moduleEvaluation):
(loadAndEvaluateModule):
(loadModule):
(linkAndEvaluateModule):
* jsc.cpp:
(functionLoadModule):
(runWithScripts):
* runtime/Completion.cpp:
(JSC::identifierToJSValue):
(JSC::createSymbolForEntryPointModule):
(JSC::rejectPromise):
(JSC::loadAndEvaluateModule):
(JSC::loadModule):
(JSC::linkAndEvaluateModule):
(JSC::evaluateModule): Deleted.
* runtime/Completion.h:
* runtime/JSGlobalObject.cpp:
* runtime/JSGlobalObject.h:
* runtime/JSModuleRecord.cpp:
(JSC::JSModuleRecord::evaluate):
(JSC::JSModuleRecord::execute): Deleted.
* runtime/JSModuleRecord.h:
* runtime/ModuleLoaderObject.cpp:
(JSC::ModuleLoaderObject::loadAndEvaluateModule):
(JSC::ModuleLoaderObject::linkAndEvaluateModule):
(JSC::ModuleLoaderObject::evaluate):
(JSC::moduleLoaderObjectEvaluate):
* runtime/ModuleLoaderObject.h:

Source/WebCore:

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

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

14 files changed:
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/builtins/ModuleLoaderObject.js
Source/JavaScriptCore/jsc.cpp
Source/JavaScriptCore/runtime/Completion.cpp
Source/JavaScriptCore/runtime/Completion.h
Source/JavaScriptCore/runtime/JSGlobalObject.cpp
Source/JavaScriptCore/runtime/JSGlobalObject.h
Source/JavaScriptCore/runtime/JSModuleRecord.cpp
Source/JavaScriptCore/runtime/JSModuleRecord.h
Source/JavaScriptCore/runtime/ModuleLoaderObject.cpp
Source/JavaScriptCore/runtime/ModuleLoaderObject.h
Source/WebCore/ChangeLog
Source/WebCore/bindings/js/JSDOMWindowBase.cpp
Source/WebCore/bindings/js/JSWorkerGlobalScopeBase.cpp

index 69fcbf8..842aae2 100644 (file)
@@ -1,3 +1,53 @@
+2015-09-17  Yusuke Suzuki  <utatane.tea@gmail.com>
+
+        [ES6] Add more fine-grained APIs and additional hooks to control module loader from WebCore
+        https://bugs.webkit.org/show_bug.cgi?id=149129
+
+        Reviewed by Saam Barati.
+
+        No behavior change.
+
+        Module tag `<script type="module>` will be executed asynchronously.
+        But we would like to fetch the resources before when the postTask-ed task is performed.
+        So instead of 1 API that fetch, instantiate and execute the module,
+        we need 2 fine-grained APIs.
+
+        1. Fetch and initialize a module, but not execute it yet.
+        2. Link and execute a module specified by the key (this will be invoked asynchronously).
+
+        And to instrument the script execution (like reporting the execution time of the module to
+        the inspector), we need a hook to inject code around an execution of a module body.
+
+        * builtins/ModuleLoaderObject.js:
+        (moduleEvaluation):
+        (loadAndEvaluateModule):
+        (loadModule):
+        (linkAndEvaluateModule):
+        * jsc.cpp:
+        (functionLoadModule):
+        (runWithScripts):
+        * runtime/Completion.cpp:
+        (JSC::identifierToJSValue):
+        (JSC::createSymbolForEntryPointModule):
+        (JSC::rejectPromise):
+        (JSC::loadAndEvaluateModule):
+        (JSC::loadModule):
+        (JSC::linkAndEvaluateModule):
+        (JSC::evaluateModule): Deleted.
+        * runtime/Completion.h:
+        * runtime/JSGlobalObject.cpp:
+        * runtime/JSGlobalObject.h:
+        * runtime/JSModuleRecord.cpp:
+        (JSC::JSModuleRecord::evaluate):
+        (JSC::JSModuleRecord::execute): Deleted.
+        * runtime/JSModuleRecord.h:
+        * runtime/ModuleLoaderObject.cpp:
+        (JSC::ModuleLoaderObject::loadAndEvaluateModule):
+        (JSC::ModuleLoaderObject::linkAndEvaluateModule):
+        (JSC::ModuleLoaderObject::evaluate):
+        (JSC::moduleLoaderObjectEvaluate):
+        * runtime/ModuleLoaderObject.h:
+
 2015-09-17  Saam barati  <sbarati@apple.com>
 
         Implement try/catch in the DFG.
index 16062e6..c5ce317 100644 (file)
@@ -483,22 +483,10 @@ function moduleEvaluation(moduleRecord)
         var requiredModuleRecord = pair.value;
         this.moduleEvaluation(requiredModuleRecord);
     }
-    this.evaluate(moduleRecord);
+    this.evaluate(entry.key, moduleRecord);
 }
 
-function loadModule(moduleName, referrer)
-{
-    "use strict";
-
-    var loader = this;
-    // 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).then(function (key) {
-        return loader.requestReady(key);
-    });
-}
+// APIs to control the module loader.
 
 function provide(key, stage, value)
 {
@@ -535,3 +523,40 @@ function provide(key, stage, value)
 
     throw new @TypeError("Requested module is already ready to be executed.");
 }
+
+function loadAndEvaluateModule(moduleName, referrer)
+{
+    "use strict";
+
+    var loader = this;
+    // 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).then(function (key) {
+        return loader.requestReady(key);
+    });
+}
+
+function loadModule(moduleName, referrer)
+{
+    "use strict";
+
+    var loader = this;
+    // 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).then(function (key) {
+        return loader.requestInstantiateAll(key);
+    }).then(function (entry) {
+        return entry.key;
+    });
+}
+
+function linkAndEvaluateModule(key)
+{
+    "use strict";
+
+    return this.requestReady(key);
+}
index af8ae15..1f23ca1 100644 (file)
@@ -707,7 +707,7 @@ protected:
 };
 
 const ClassInfo GlobalObject::s_info = { "global", &JSGlobalObject::s_info, nullptr, CREATE_METHOD_TABLE(GlobalObject) };
-const GlobalObjectMethodTable GlobalObject::s_globalObjectMethodTable = { &allowsAccessFrom, &supportsProfiling, &supportsRichSourceInfo, &shouldInterruptScript, &javaScriptRuntimeFlags, 0, &shouldInterruptScriptBeforeTimeout, &moduleLoaderResolve, &moduleLoaderFetch, nullptr, nullptr };
+const GlobalObjectMethodTable GlobalObject::s_globalObjectMethodTable = { &allowsAccessFrom, &supportsProfiling, &supportsRichSourceInfo, &shouldInterruptScript, &javaScriptRuntimeFlags, 0, &shouldInterruptScriptBeforeTimeout, &moduleLoaderResolve, &moduleLoaderFetch, nullptr, nullptr, nullptr };
 
 
 GlobalObject::GlobalObject(VM& vm, Structure* structure)
@@ -1466,7 +1466,7 @@ EncodedJSValue JSC_HOST_CALL functionLoadModule(ExecState* exec)
     if (!fetchScriptFromLocalFileSystem(fileName, script))
         return JSValue::encode(exec->vm().throwException(exec, createError(exec, ASCIILiteral("Could not open file."))));
 
-    JSInternalPromise* promise = evaluateModule(exec, fileName);
+    JSInternalPromise* promise = loadAndEvaluateModule(exec, fileName);
     if (exec->hadException())
         return JSValue::encode(jsUndefined());
 
@@ -1639,7 +1639,7 @@ static bool runWithScripts(GlobalObject* globalObject, const Vector<Script>& scr
         if (scripts[i].isFile) {
             fileName = scripts[i].argument;
             if (module)
-                promise = evaluateModule(globalObject->globalExec(), fileName);
+                promise = loadAndEvaluateModule(globalObject->globalExec(), fileName);
             else {
                 if (!fetchScriptFromLocalFileSystem(fileName, scriptBuffer))
                     return false; // fail early so we can catch missing files
@@ -1655,7 +1655,7 @@ static bool runWithScripts(GlobalObject* globalObject, const Vector<Script>& scr
 
         if (module) {
             if (!promise)
-                promise = evaluateModule(globalObject->globalExec(), jscSource(scriptBuffer, fileName));
+                promise = loadAndEvaluateModule(globalObject->globalExec(), jscSource(scriptBuffer, fileName));
             globalObject->globalExec()->clearException();
             promise->then(globalObject->globalExec(), nullptr, errorHandler);
             globalObject->vm().drainMicrotasks();
index b5f623a..a632c48 100644 (file)
@@ -113,63 +113,112 @@ JSValue evaluate(ExecState* exec, const SourceCode& source, JSValue thisValue, N
     return result;
 }
 
-static JSInternalPromise* evaluateModule(const JSLockHolder&, ExecState* exec, JSGlobalObject* globalObject, JSValue moduleName, JSValue referrer)
+static JSValue identifierToJSValue(VM& vm, const Identifier& identifier)
 {
-    return globalObject->moduleLoader()->loadModule(exec, moduleName, referrer);
+    if (identifier.isSymbol())
+        return Symbol::create(vm, static_cast<SymbolImpl&>(*identifier.impl()));
+    return jsString(&vm, identifier.impl());
+}
+
+static Symbol* createSymbolForEntryPointModule(VM& vm)
+{
+    // Generate the unique key for the source-provided module.
+    PrivateName privateName(PrivateName::Description, "EntryPointModule");
+    return Symbol::create(vm, *privateName.uid());
 }
 
-static JSInternalPromise* evaluateModule(const JSLockHolder& lock, ExecState* exec, JSGlobalObject* globalObject, const Identifier& moduleName)
+static JSInternalPromise* rejectPromise(ExecState* exec, JSGlobalObject* globalObject)
 {
-    JSValue moduleNameValue;
-    if (moduleName.isSymbol())
-        moduleNameValue = Symbol::create(exec->vm(), static_cast<SymbolImpl&>(*moduleName.impl()));
-    else
-        moduleNameValue = jsString(&exec->vm(), moduleName.impl());
+    ASSERT(exec->hadException());
+    JSValue exception = exec->exception()->value();
+    exec->clearException();
+    JSInternalPromiseDeferred* deferred = JSInternalPromiseDeferred::create(exec, globalObject);
+    deferred->reject(exec, exception);
+    return deferred->promise();
+}
+
+static JSInternalPromise* loadAndEvaluateModule(const JSLockHolder&, ExecState* exec, JSGlobalObject* globalObject, JSValue moduleName, JSValue referrer)
+{
+    return globalObject->moduleLoader()->loadAndEvaluateModule(exec, moduleName, referrer);
+}
 
-    return evaluateModule(lock, exec, globalObject, moduleNameValue, jsUndefined());
+static JSInternalPromise* loadAndEvaluateModule(const JSLockHolder& lock, ExecState* exec, JSGlobalObject* globalObject, const Identifier& moduleName)
+{
+    return loadAndEvaluateModule(lock, exec, globalObject, identifierToJSValue(exec->vm(), moduleName), jsUndefined());
 }
 
-JSInternalPromise* evaluateModule(ExecState* exec, const SourceCode& source)
+JSInternalPromise* loadAndEvaluateModule(ExecState* exec, const String& moduleName)
 {
     JSLockHolder lock(exec);
     RELEASE_ASSERT(exec->vm().atomicStringTable() == wtfThreadData().atomicStringTable());
     RELEASE_ASSERT(!exec->vm().isCollectorBusy());
 
-    JSGlobalObject* globalObject = exec->vmEntryGlobalObject();
+    return loadAndEvaluateModule(lock, exec, exec->vmEntryGlobalObject(), Identifier::fromString(exec, moduleName));
+}
 
-    // Generate the unique key for the source-provided module.
-    PrivateName privateName(PrivateName::Description, "EntryPointModule");
-    Symbol* key = Symbol::create(exec->vm(), *privateName.uid());
+JSInternalPromise* loadAndEvaluateModule(ExecState* exec, const SourceCode& source)
+{
+    JSLockHolder lock(exec);
+    RELEASE_ASSERT(exec->vm().atomicStringTable() == wtfThreadData().atomicStringTable());
+    RELEASE_ASSERT(!exec->vm().isCollectorBusy());
+
+    Symbol* key = createSymbolForEntryPointModule(exec->vm());
+
+    JSGlobalObject* globalObject = exec->vmEntryGlobalObject();
 
     // Insert the given source code to the ModuleLoader registry as the fetched registry entry.
     globalObject->moduleLoader()->provide(exec, key, ModuleLoaderObject::Status::Fetch, source.toString());
-    if (exec->hadException()) {
-        JSValue exception = exec->exception()->value();
-        exec->clearException();
-        JSInternalPromiseDeferred* deferred = JSInternalPromiseDeferred::create(exec, globalObject);
-        deferred->reject(exec, exception);
-        return deferred->promise();
-    }
+    if (exec->hadException())
+        return rejectPromise(exec, globalObject);
+
+    return loadAndEvaluateModule(lock, exec, globalObject, key, jsUndefined());
+}
+
+static JSInternalPromise* loadModule(const JSLockHolder&, ExecState* exec, JSGlobalObject* globalObject, JSValue moduleName, JSValue referrer)
+{
+    return globalObject->moduleLoader()->loadModule(exec, moduleName, referrer);
+}
 
-    return evaluateModule(lock, exec, globalObject, key, jsUndefined());
+static JSInternalPromise* loadModule(const JSLockHolder& lock, ExecState* exec, JSGlobalObject* globalObject, const Identifier& moduleName)
+{
+    return loadModule(lock, exec, globalObject, identifierToJSValue(exec->vm(), moduleName), jsUndefined());
 }
 
-JSInternalPromise* evaluateModule(ExecState* exec, const Identifier& moduleName)
+JSInternalPromise* loadModule(ExecState* exec, const String& moduleName)
 {
     JSLockHolder lock(exec);
     RELEASE_ASSERT(exec->vm().atomicStringTable() == wtfThreadData().atomicStringTable());
     RELEASE_ASSERT(!exec->vm().isCollectorBusy());
 
-    return evaluateModule(lock, exec, exec->vmEntryGlobalObject(), moduleName);
+    return loadModule(lock, exec, exec->vmEntryGlobalObject(), Identifier::fromString(exec, moduleName));
 }
 
-JSInternalPromise* evaluateModule(ExecState* exec, const String& moduleName)
+JSInternalPromise* loadModule(ExecState* exec, const SourceCode& source)
 {
     JSLockHolder lock(exec);
     RELEASE_ASSERT(exec->vm().atomicStringTable() == wtfThreadData().atomicStringTable());
     RELEASE_ASSERT(!exec->vm().isCollectorBusy());
 
-    return evaluateModule(lock, exec, exec->vmEntryGlobalObject(), Identifier::fromString(exec, moduleName));
+    Symbol* key = createSymbolForEntryPointModule(exec->vm());
+
+    JSGlobalObject* globalObject = exec->vmEntryGlobalObject();
+
+    // Insert the given source code to the ModuleLoader registry as the fetched registry entry.
+    globalObject->moduleLoader()->provide(exec, key, ModuleLoaderObject::Status::Fetch, source.toString());
+    if (exec->hadException())
+        return rejectPromise(exec, globalObject);
+
+    return loadModule(lock, exec, globalObject, key, jsUndefined());
+}
+
+JSInternalPromise* linkAndEvaluateModule(ExecState* exec, const Identifier& moduleKey)
+{
+    JSLockHolder lock(exec);
+    RELEASE_ASSERT(exec->vm().atomicStringTable() == wtfThreadData().atomicStringTable());
+    RELEASE_ASSERT(!exec->vm().isCollectorBusy());
+
+    JSGlobalObject* globalObject = exec->vmEntryGlobalObject();
+    return globalObject->moduleLoader()->linkAndEvaluateModule(exec, identifierToJSValue(exec->vm(), moduleKey));
 }
 
 } // namespace JSC
index cb091ff..24d78f1 100644 (file)
@@ -45,9 +45,17 @@ inline JSValue evaluate(ExecState* exec, const SourceCode& sourceCode, JSValue t
     NakedPtr<Exception> unused;
     return evaluate(exec, sourceCode, thisValue, unused);
 }
-JS_EXPORT_PRIVATE JSInternalPromise* evaluateModule(ExecState*, const SourceCode&);
-JS_EXPORT_PRIVATE JSInternalPromise* evaluateModule(ExecState*, const Identifier& moduleName);
-JS_EXPORT_PRIVATE JSInternalPromise* evaluateModule(ExecState*, const String& moduleName);
+
+// Load the module source and evaluate it.
+JS_EXPORT_PRIVATE JSInternalPromise* loadAndEvaluateModule(ExecState*, const String& moduleName);
+JS_EXPORT_PRIVATE JSInternalPromise* loadAndEvaluateModule(ExecState*, const SourceCode&);
+
+// Fetch the module source, and instantiate the module record.
+JS_EXPORT_PRIVATE JSInternalPromise* loadModule(ExecState*, const String& moduleName);
+JS_EXPORT_PRIVATE JSInternalPromise* loadModule(ExecState*, const SourceCode&);
+
+// Link and evaluate the already linked module.
+JS_EXPORT_PRIVATE JSInternalPromise* linkAndEvaluateModule(ExecState*, const Identifier& moduleKey);
 
 } // namespace JSC
 
index 545a134..c9ec9d9 100644 (file)
@@ -168,7 +168,7 @@ namespace JSC {
 
 const ClassInfo JSGlobalObject::s_info = { "GlobalObject", &Base::s_info, &globalObjectTable, CREATE_METHOD_TABLE(JSGlobalObject) };
 
-const GlobalObjectMethodTable JSGlobalObject::s_globalObjectMethodTable = { &allowsAccessFrom, &supportsProfiling, &supportsRichSourceInfo, &shouldInterruptScript, &javaScriptRuntimeFlags, nullptr, &shouldInterruptScriptBeforeTimeout, nullptr, nullptr, nullptr, nullptr };
+const GlobalObjectMethodTable JSGlobalObject::s_globalObjectMethodTable = { &allowsAccessFrom, &supportsProfiling, &supportsRichSourceInfo, &shouldInterruptScript, &javaScriptRuntimeFlags, nullptr, &shouldInterruptScriptBeforeTimeout, nullptr, nullptr, nullptr, nullptr, nullptr };
 
 /* Source for JSGlobalObject.lut.h
 @begin globalObjectTable
index 1df6da2..21085d6 100644 (file)
@@ -170,6 +170,9 @@ struct GlobalObjectMethodTable {
 
     typedef JSInternalPromise* (*ModuleLoaderInstantiatePtr)(JSGlobalObject*, ExecState*, JSValue, JSValue);
     ModuleLoaderInstantiatePtr moduleLoaderInstantiate;
+
+    typedef JSValue (*ModuleLoaderEvaluatePtr)(JSGlobalObject*, ExecState*, JSValue, JSValue);
+    ModuleLoaderEvaluatePtr moduleLoaderEvaluate;
 };
 
 class JSGlobalObject : public JSSegmentedVariableObject {
index 843c94e..1cc4937 100644 (file)
@@ -844,7 +844,7 @@ void JSModuleRecord::instantiateDeclarations(ExecState* exec, ModuleProgramExecu
     m_moduleEnvironment.set(vm, this, moduleEnvironment);
 }
 
-JSValue JSModuleRecord::execute(ExecState* exec)
+JSValue JSModuleRecord::evaluate(ExecState* exec)
 {
     if (!m_moduleProgramExecutable)
         return jsUndefined();
index 30de7f5..b82a9e1 100644 (file)
@@ -123,7 +123,7 @@ public:
     }
 
     void link(ExecState*);
-    JSValue execute(ExecState*);
+    JS_EXPORT_PRIVATE JSValue evaluate(ExecState*);
 
     ModuleProgramExecutable* moduleProgramExecutable() const { return m_moduleProgramExecutable.get(); }
 
index 6e6f9f9..eb80b8e 100644 (file)
@@ -85,8 +85,10 @@ const ClassInfo ModuleLoaderObject::s_info = { "ModuleLoader", &Base::s_info, &m
     moduleDeclarationInstantiation moduleLoaderObjectModuleDeclarationInstantiation DontEnum|Function 2
     moduleEvaluation               moduleLoaderObjectModuleEvaluation               DontEnum|Function 2
     evaluate                       moduleLoaderObjectEvaluate                       DontEnum|Function 2
-    loadModule                     moduleLoaderObjectLoadModule                     DontEnum|Function 2
     provide                        moduleLoaderObjectProvide                        DontEnum|Function 3
+    loadAndEvaluateModule          moduleLoaderObjectLoadAndEvaluateModule          DontEnum|Function 2
+    loadModule                     moduleLoaderObjectLoadModule                     DontEnum|Function 2
+    linkAndEvaluateModule          moduleLoaderObjectLinkAndEvaluateModule          DontEnum|Function 1
     parseModule                    moduleLoaderObjectParseModule                    DontEnum|Function 2
     requestedModules               moduleLoaderObjectRequestedModules               DontEnum|Function 1
     resolve                        moduleLoaderObjectResolve                        DontEnum|Function 1
@@ -146,6 +148,20 @@ JSValue ModuleLoaderObject::provide(ExecState* exec, JSValue key, Status status,
     return call(exec, function, callType, callData, this, arguments);
 }
 
+JSInternalPromise* ModuleLoaderObject::loadAndEvaluateModule(ExecState* exec, JSValue moduleName, JSValue referrer)
+{
+    JSObject* function = jsCast<JSObject*>(get(exec, exec->propertyNames().builtinNames().loadAndEvaluateModulePublicName()));
+    CallData callData;
+    CallType callType = JSC::getCallData(function, callData);
+    ASSERT(callType != CallTypeNone);
+
+    MarkedArgumentBuffer arguments;
+    arguments.append(moduleName);
+    arguments.append(referrer);
+
+    return jsCast<JSInternalPromise*>(call(exec, function, callType, callData, this, arguments));
+}
+
 JSInternalPromise* ModuleLoaderObject::loadModule(ExecState* exec, JSValue moduleName, JSValue referrer)
 {
     JSObject* function = jsCast<JSObject*>(get(exec, exec->propertyNames().builtinNames().loadModulePublicName()));
@@ -160,6 +176,19 @@ JSInternalPromise* ModuleLoaderObject::loadModule(ExecState* exec, JSValue modul
     return jsCast<JSInternalPromise*>(call(exec, function, callType, callData, this, arguments));
 }
 
+JSInternalPromise* ModuleLoaderObject::linkAndEvaluateModule(ExecState* exec, JSValue moduleKey)
+{
+    JSObject* function = jsCast<JSObject*>(get(exec, exec->propertyNames().builtinNames().linkAndEvaluateModulePublicName()));
+    CallData callData;
+    CallType callType = JSC::getCallData(function, callData);
+    ASSERT(callType != CallTypeNone);
+
+    MarkedArgumentBuffer arguments;
+    arguments.append(moduleKey);
+
+    return jsCast<JSInternalPromise*>(call(exec, function, callType, callData, this, arguments));
+}
+
 JSInternalPromise* ModuleLoaderObject::resolve(ExecState* exec, JSValue name, JSValue referrer)
 {
     if (Options::dumpModuleLoadingState())
@@ -219,6 +248,21 @@ JSInternalPromise* ModuleLoaderObject::instantiate(ExecState* exec, JSValue key,
     return deferred->promise();
 }
 
+JSValue ModuleLoaderObject::evaluate(ExecState* exec, JSValue key, JSValue moduleRecordValue)
+{
+    if (Options::dumpModuleLoadingState())
+        dataLog("Loader [evaluate] ", printableModuleKey(exec, key), "\n");
+
+    JSGlobalObject* globalObject = exec->lexicalGlobalObject();
+    if (globalObject->globalObjectMethodTable()->moduleLoaderEvaluate)
+        return globalObject->globalObjectMethodTable()->moduleLoaderEvaluate(globalObject, exec, key, moduleRecordValue);
+
+    JSModuleRecord* moduleRecord = jsDynamicCast<JSModuleRecord*>(moduleRecordValue);
+    if (!moduleRecord)
+        return jsUndefined();
+    return moduleRecord->evaluate(exec);
+}
+
 EncodedJSValue JSC_HOST_CALL moduleLoaderObjectParseModule(ExecState* exec)
 {
     VM& vm = exec->vm();
@@ -281,18 +325,6 @@ EncodedJSValue JSC_HOST_CALL moduleLoaderObjectModuleDeclarationInstantiation(Ex
     return JSValue::encode(jsUndefined());
 }
 
-EncodedJSValue JSC_HOST_CALL moduleLoaderObjectEvaluate(ExecState* exec)
-{
-    JSModuleRecord* moduleRecord = jsDynamicCast<JSModuleRecord*>(exec->argument(0));
-    if (!moduleRecord)
-        return JSValue::encode(jsUndefined());
-
-    if (Options::dumpModuleLoadingState())
-        dataLog("Loader [evaluate] ", moduleRecord->moduleKey(), "\n");
-
-    return JSValue::encode(moduleRecord->execute(exec));
-}
-
 // ------------------------------ Hook Functions ---------------------------
 
 EncodedJSValue JSC_HOST_CALL moduleLoaderObjectResolve(ExecState* exec)
@@ -346,4 +378,17 @@ EncodedJSValue JSC_HOST_CALL moduleLoaderObjectInstantiate(ExecState* exec)
     return JSValue::encode(loader->instantiate(exec, exec->argument(0), exec->argument(1)));
 }
 
+// ------------------- Additional Hook Functions ---------------------------
+
+EncodedJSValue JSC_HOST_CALL moduleLoaderObjectEvaluate(ExecState* exec)
+{
+    // To instrument and retrieve the errors raised from the module execution,
+    // we inserted the hook point here.
+
+    ModuleLoaderObject* loader = jsDynamicCast<ModuleLoaderObject*>(exec->thisValue());
+    if (!loader)
+        return JSValue::encode(jsUndefined());
+    return JSValue::encode(loader->evaluate(exec, exec->argument(0), exec->argument(1)));
+}
+
 } // namespace JSC
index 12cfe56..becaf10 100644 (file)
@@ -64,7 +64,9 @@ public:
 
     // APIs to control the module loader.
     JSValue provide(ExecState*, JSValue key, Status, const String&);
+    JSInternalPromise* loadAndEvaluateModule(ExecState*, JSValue moduleName, JSValue referrer);
     JSInternalPromise* loadModule(ExecState*, JSValue moduleName, JSValue referrer);
+    JSInternalPromise* linkAndEvaluateModule(ExecState*, JSValue moduleKey);
 
     // Platform dependent hooked APIs.
     JSInternalPromise* resolve(ExecState*, JSValue name, JSValue referrer);
@@ -72,6 +74,9 @@ public:
     JSInternalPromise* translate(ExecState*, JSValue key, JSValue payload);
     JSInternalPromise* instantiate(ExecState*, JSValue key, JSValue source);
 
+    // Additional platform dependent hooked APIs.
+    JSValue evaluate(ExecState*, JSValue key, JSValue moduleRecord);
+
     static bool getOwnPropertySlot(JSObject*, ExecState*, PropertyName, PropertySlot&);
 
 protected:
index b9263c6..f80cc1f 100644 (file)
@@ -1,3 +1,15 @@
+2015-09-17  Yusuke Suzuki  <utatane.tea@gmail.com>
+
+        [ES6] Add more fine-grained APIs and additional hooks to control module loader from WebCore
+        https://bugs.webkit.org/show_bug.cgi?id=149129
+
+        Reviewed by Saam Barati.
+
+        No behavior change.
+
+        * bindings/js/JSDOMWindowBase.cpp:
+        * bindings/js/JSWorkerGlobalScopeBase.cpp:
+
 2015-09-17  Alex Christensen  <achristensen@webkit.org>
 
         Switch AppleWin build to use CMake
index d4f001d..79b740b 100644 (file)
@@ -56,7 +56,7 @@ static bool shouldAllowAccessFrom(const JSGlobalObject* thisObject, ExecState* e
 
 const ClassInfo JSDOMWindowBase::s_info = { "Window", &JSDOMGlobalObject::s_info, 0, CREATE_METHOD_TABLE(JSDOMWindowBase) };
 
-const GlobalObjectMethodTable JSDOMWindowBase::s_globalObjectMethodTable = { &shouldAllowAccessFrom, &supportsProfiling, &supportsRichSourceInfo, &shouldInterruptScript, &javaScriptRuntimeFlags, &queueTaskToEventLoop, &shouldInterruptScriptBeforeTimeout, nullptr, nullptr, nullptr, nullptr };
+const GlobalObjectMethodTable JSDOMWindowBase::s_globalObjectMethodTable = { &shouldAllowAccessFrom, &supportsProfiling, &supportsRichSourceInfo, &shouldInterruptScript, &javaScriptRuntimeFlags, &queueTaskToEventLoop, &shouldInterruptScriptBeforeTimeout, nullptr, nullptr, nullptr, nullptr, nullptr };
 
 JSDOMWindowBase::JSDOMWindowBase(VM& vm, Structure* structure, PassRefPtr<DOMWindow> window, JSDOMWindowShell* shell)
     : JSDOMGlobalObject(vm, structure, &shell->world(), &s_globalObjectMethodTable)
index 5044bc1..acd617e 100644 (file)
@@ -43,7 +43,7 @@ namespace WebCore {
 
 const ClassInfo JSWorkerGlobalScopeBase::s_info = { "WorkerGlobalScope", &JSDOMGlobalObject::s_info, 0, CREATE_METHOD_TABLE(JSWorkerGlobalScopeBase) };
 
-const GlobalObjectMethodTable JSWorkerGlobalScopeBase::s_globalObjectMethodTable = { &allowsAccessFrom, &supportsProfiling, &supportsRichSourceInfo, &shouldInterruptScript, &javaScriptRuntimeFlags, &queueTaskToEventLoop, &shouldInterruptScriptBeforeTimeout, nullptr, nullptr, nullptr, nullptr };
+const GlobalObjectMethodTable JSWorkerGlobalScopeBase::s_globalObjectMethodTable = { &allowsAccessFrom, &supportsProfiling, &supportsRichSourceInfo, &shouldInterruptScript, &javaScriptRuntimeFlags, &queueTaskToEventLoop, &shouldInterruptScriptBeforeTimeout, nullptr, nullptr, nullptr, nullptr, nullptr };
 
 JSWorkerGlobalScopeBase::JSWorkerGlobalScopeBase(JSC::VM& vm, JSC::Structure* structure, PassRefPtr<WorkerGlobalScope> impl)
     : JSDOMGlobalObject(vm, structure, &normalWorld(vm), &s_globalObjectMethodTable)