Backed out 15 changesets (bug 1519100) for wpt leaks CLOSED TREE

Backed out changeset 7302ebdbaa35 (bug 1519100)
Backed out changeset 5b89081f0f08 (bug 1519100)
Backed out changeset ee02050e3c97 (bug 1519100)
Backed out changeset 47cf4bde107e (bug 1519100)
Backed out changeset bfd96f55a3bd (bug 1519100)
Backed out changeset c9afefd66eb7 (bug 1519100)
Backed out changeset 90b61247d071 (bug 1519100)
Backed out changeset e0250e4cba61 (bug 1519100)
Backed out changeset 5f90543431cb (bug 1519100)
Backed out changeset d7f3440addc7 (bug 1519100)
Backed out changeset 10194540aff0 (bug 1519100)
Backed out changeset 880873b815a4 (bug 1519100)
Backed out changeset d99f0109da7a (bug 1519100)
Backed out changeset c723f6b16b67 (bug 1519100)
Backed out changeset da24af409d92 (bug 1519100)
This commit is contained in:
Bogdan Tara 2020-12-02 21:14:35 +02:00
parent 10b26e1c74
commit c1b7803fbd
335 changed files with 654 additions and 2498 deletions

View File

@ -174,8 +174,7 @@ nsresult nsJSUtils::ModuleInstantiate(JSContext* aCx,
}
nsresult nsJSUtils::ModuleEvaluate(JSContext* aCx,
JS::Handle<JSObject*> aModule,
JS::MutableHandle<JS::Value> aResult) {
JS::Handle<JSObject*> aModule) {
AUTO_PROFILER_LABEL("nsJSUtils::ModuleEvaluate", JS);
MOZ_ASSERT(aCx == nsContentUtils::GetCurrentJSContext());
@ -185,7 +184,7 @@ nsresult nsJSUtils::ModuleEvaluate(JSContext* aCx,
NS_ENSURE_TRUE(xpc::Scriptability::Get(aModule).Allowed(), NS_OK);
if (!JS::ModuleEvaluate(aCx, aModule, aResult)) {
if (!JS::ModuleEvaluate(aCx, aModule)) {
return NS_ERROR_FAILURE;
}

View File

@ -80,21 +80,7 @@ class nsJSUtils {
static nsresult ModuleInstantiate(JSContext* aCx,
JS::Handle<JSObject*> aModule);
/*
* Wrapper for JSAPI ModuleEvaluate function.
*
* @param JSContext aCx
* The JSContext where this is executed.
* @param JS::Handle<JSObject*> aModule
* The module to be evaluated.
* @param JS::Handle<Value*> aResult
* If Top level await is enabled:
* The evaluation promise returned from evaluating the module.
* Otherwise:
* Undefined
*/
static nsresult ModuleEvaluate(JSContext* aCx, JS::Handle<JSObject*> aModule,
JS::MutableHandle<JS::Value> aResult);
static nsresult ModuleEvaluate(JSContext* aCx, JS::Handle<JSObject*> aModule);
// Returns false if an exception got thrown on aCx. Passing a null
// aElement is allowed; that wil produce an empty aScopeChain.

View File

@ -16,7 +16,6 @@
#include "jsfriendapi.h"
#include "js/Array.h" // JS::GetArrayLength
#include "js/CompilationAndEvaluation.h"
#include "js/ContextOptions.h" // JS::ContextOptionsRef
#include "js/friend/ErrorMessages.h" // js::GetErrorMessage, JSMSG_*
#include "js/MemoryFunctions.h"
#include "js/Modules.h" // JS::FinishDynamicModuleImport, JS::{G,S}etModuleResolveHook, JS::Get{ModulePrivate,ModuleScript,RequestedModule{s,Specifier,SourcePos}}, JS::SetModule{DynamicImport,Metadata}Hook
@ -220,7 +219,7 @@ ScriptLoader::~ScriptLoader() {
for (ScriptLoadRequest* req = mDynamicImportRequests.getFirst(); req;
req = req->getNext()) {
FinishDynamicImportAndReject(req->AsModuleRequest(), NS_ERROR_ABORT);
FinishDynamicImport(req->AsModuleRequest(), NS_ERROR_ABORT);
}
for (ScriptLoadRequest* req =
@ -1053,30 +1052,20 @@ void ScriptLoader::StartDynamicImport(ModuleLoadRequest* aRequest) {
nsresult rv = StartLoad(aRequest);
if (NS_FAILED(rv)) {
FinishDynamicImportAndReject(aRequest, rv);
FinishDynamicImport(aRequest, rv);
}
}
void ScriptLoader::FinishDynamicImportAndReject(ModuleLoadRequest* aRequest,
nsresult aResult) {
void ScriptLoader::FinishDynamicImport(ModuleLoadRequest* aRequest,
nsresult aResult) {
AutoJSAPI jsapi;
MOZ_ASSERT(NS_FAILED(aResult));
MOZ_ALWAYS_TRUE(jsapi.Init(aRequest->mDynamicPromise));
if (!JS::ContextOptionsRef(jsapi.cx()).topLevelAwait()) {
// This is used so that Top Level Await functionality can be turned off
// entirely. It will be removed in bug#1676612.
FinishDynamicImport_NoTLA(jsapi.cx(), aRequest, aResult);
} else {
// Path for when Top Level Await is enabled.
FinishDynamicImport(jsapi.cx(), aRequest, aResult, nullptr);
}
FinishDynamicImport(jsapi.cx(), aRequest, aResult);
}
// This is used so that Top Level Await functionality can be turned off
// entirely. It will be removed in bug#1676612.
void ScriptLoader::FinishDynamicImport_NoTLA(JSContext* aCx,
ModuleLoadRequest* aRequest,
nsresult aResult) {
void ScriptLoader::FinishDynamicImport(JSContext* aCx,
ModuleLoadRequest* aRequest,
nsresult aResult) {
LOG(("ScriptLoadRequest (%p): Finish dynamic import %x %d", aRequest,
unsigned(aResult), JS_IsExceptionPending(aCx)));
@ -1100,42 +1089,8 @@ void ScriptLoader::FinishDynamicImport_NoTLA(JSContext* aCx,
JS::Rooted<JSString*> specifier(aCx, aRequest->mDynamicSpecifier);
JS::Rooted<JSObject*> promise(aCx, aRequest->mDynamicPromise);
JS::FinishDynamicModuleImport_NoTLA(aCx, status, referencingScript, specifier,
promise);
// FinishDynamicModuleImport clears any pending exception.
MOZ_ASSERT(!JS_IsExceptionPending(aCx));
aRequest->ClearDynamicImport();
}
void ScriptLoader::FinishDynamicImport(
JSContext* aCx, ModuleLoadRequest* aRequest, nsresult aResult,
JS::Handle<JSObject*> aEvaluationPromise) {
// If aResult is a failed result, we don't have an EvaluationPromise. If it
// succeeded, evaluationPromise may still be null, but in this case it will
// be handled by rejecting the dynamic module import promise in the JSAPI.
MOZ_ASSERT_IF(NS_FAILED(aResult), !aEvaluationPromise);
LOG(("ScriptLoadRequest (%p): Finish dynamic import %x %d", aRequest,
unsigned(aResult), JS_IsExceptionPending(aCx)));
// Complete the dynamic import, report failures indicated by aResult or as a
// pending exception on the context.
if (NS_FAILED(aResult) &&
aResult != NS_SUCCESS_DOM_SCRIPT_EVALUATION_THREW_UNCATCHABLE) {
MOZ_ASSERT(!JS_IsExceptionPending(aCx));
JS_ReportErrorNumberUC(aCx, js::GetErrorMessage, nullptr,
JSMSG_DYNAMIC_IMPORT_FAILED);
}
JS::Rooted<JS::Value> referencingScript(aCx,
aRequest->mDynamicReferencingPrivate);
JS::Rooted<JSString*> specifier(aCx, aRequest->mDynamicSpecifier);
JS::Rooted<JSObject*> promise(aCx, aRequest->mDynamicPromise);
JS::FinishDynamicModuleImport(aCx, aEvaluationPromise, referencingScript,
specifier, promise);
JS::FinishDynamicModuleImport(aCx, status, referencingScript, specifier,
promise);
// FinishDynamicModuleImport clears any pending exception.
MOZ_ASSERT(!JS_IsExceptionPending(aCx));
@ -2687,7 +2642,7 @@ void ScriptLoader::ProcessDynamicImport(ModuleLoadRequest* aRequest) {
}
if (NS_FAILED(rv)) {
FinishDynamicImportAndReject(aRequest, rv);
FinishDynamicImport(aRequest, rv);
}
}
@ -2981,30 +2936,12 @@ nsresult ScriptLoader::EvaluateScript(ScriptLoadRequest* aRequest) {
LOG(("ScriptLoadRequest (%p): module has error to rethrow",
aRequest));
JS::Rooted<JS::Value> error(cx, moduleScript->ErrorToRethrow());
if (!JS::ContextOptionsRef(cx).topLevelAwait()) {
JS_SetPendingException(cx, error);
// For a dynamic import, the promise is rejected. Otherwise an error
// is either reported by AutoEntryScript.
if (request->IsDynamicImport()) {
FinishDynamicImport_NoTLA(cx, request, NS_OK);
}
} else {
ErrorResult err;
RefPtr<Promise> aPromise = Promise::Create(globalObject, err);
if (NS_WARN_IF(err.Failed())) {
return err.StealNSResult();
}
aPromise->MaybeReject(error);
JS::Rooted<JSObject*> aEvaluationPromise(cx, aPromise->PromiseObj());
if (request->IsDynamicImport()) {
FinishDynamicImport(cx, request, NS_OK, aEvaluationPromise);
} else {
if (!JS::ThrowOnModuleEvaluationFailure(cx, aEvaluationPromise)) {
LOG(("ScriptLoadRequest (%p): evaluation failed", aRequest));
// For a dynamic import, the promise is rejected. Otherwise an
// error is either reported by AutoEntryScript.
}
}
JS_SetPendingException(cx, error);
// For a dynamic import, the promise is rejected. Otherwise an error is
// either reported by AutoEntryScript.
if (request->IsDynamicImport()) {
FinishDynamicImport(cx, request, NS_OK);
}
return NS_OK;
}
@ -3017,10 +2954,7 @@ nsresult ScriptLoader::EvaluateScript(ScriptLoadRequest* aRequest) {
TRACE_FOR_TEST(aRequest->GetScriptElement(),
"scriptloader_evaluate_module");
JS::Rooted<JS::Value> rval(cx);
rv = nsJSUtils::ModuleEvaluate(cx, module, &rval);
rv = nsJSUtils::ModuleEvaluate(cx, module);
MOZ_ASSERT(NS_FAILED(rv) == aes.HasException());
if (NS_FAILED(rv)) {
@ -3030,25 +2964,8 @@ nsresult ScriptLoader::EvaluateScript(ScriptLoadRequest* aRequest) {
rv = NS_OK;
}
if (!JS::ContextOptionsRef(cx).topLevelAwait()) {
if (request->IsDynamicImport()) {
FinishDynamicImport_NoTLA(cx, request, rv);
}
} else {
// Path for when Top Level Await is enabled
JS::Rooted<JSObject*> aEvaluationPromise(cx, &rval.toObject());
if (request->IsDynamicImport()) {
FinishDynamicImport(cx, request, rv, aEvaluationPromise);
} else {
// If this is not a dynamic import, and if the promise is rejected,
// the value is unwrapped from the promise value.
if (!JS::ThrowOnModuleEvaluationFailure(cx, aEvaluationPromise)) {
LOG(("ScriptLoadRequest (%p): evaluation failed", aRequest));
// For a dynamic import, the promise is rejected. Otherwise an
// error is either reported by AutoEntryScript.
rv = NS_OK;
}
}
if (request->IsDynamicImport()) {
FinishDynamicImport(cx, request, rv);
}
TRACE_FOR_TEST_NONE(aRequest->GetScriptElement(),
@ -3863,7 +3780,7 @@ void ScriptLoader::HandleLoadError(ScriptLoadRequest* aRequest,
// FinishDynamicImport must happen exactly once for each dynamic import
// request. If the load is aborted we do it when we remove the request
// from mDynamicImportRequests.
FinishDynamicImportAndReject(modReq, aResult);
FinishDynamicImport(modReq, aResult);
}
} else {
MOZ_ASSERT(!modReq->IsTopLevel());
@ -4111,7 +4028,7 @@ void ScriptLoader::ParsingComplete(bool aTerminated) {
// FinishDynamicImport must happen exactly once for each dynamic import
// request. If the load is aborted we do it when we remove the request
// from mDynamicImportRequests.
FinishDynamicImportAndReject(req->AsModuleRequest(), NS_ERROR_ABORT);
FinishDynamicImport(req->AsModuleRequest(), NS_ERROR_ABORT);
}
mDynamicImportRequests.Clear();

View File

@ -411,60 +411,9 @@ class ScriptLoader final : public nsISupports {
JS::MutableHandle<JSObject*> aModuleOut);
void StartDynamicImport(ModuleLoadRequest* aRequest);
/**
* Shorthand Wrapper for JSAPI FinishDynamicImport function for the reject
* case where we do not have `aEvaluationPromise`. As there is no evaluation
* Promise, JS::FinishDynamicImport will always reject.
*
* @param aRequest
* The module load request for the dynamic module.
* @param aResult
* The result of running ModuleEvaluate -- If this is successful, then
* we can await the associated EvaluationPromise.
*/
void FinishDynamicImportAndReject(ModuleLoadRequest* aRequest,
nsresult aResult);
/**
* Wrapper for JSAPI FinishDynamicImport function. Takes an optional argument
* `aEvaluationPromise` which, if null, exits early.
*
* This is the non-tla version, which works with modules which return
* completion records.
*
* @param aCX
* The JSContext for the module.
* @param aRequest
* The module load request for the dynamic module.
* @param aResult
* The result of running ModuleEvaluate
*/
void FinishDynamicImport_NoTLA(JSContext* aCx, ModuleLoadRequest* aRequest,
nsresult aResult);
/**
* Wrapper for JSAPI FinishDynamicImport function. Takes an optional argument
* `aEvaluationPromise` which, if null, exits early.
*
* This is the Top Level Await version, which works with modules which return
* promises.
*
* @param aCX
* The JSContext for the module.
* @param aRequest
* The module load request for the dynamic module.
* @param aResult
* The result of running ModuleEvaluate -- If this is successful, then
* we can await the associated EvaluationPromise.
* @param aEvaluationPromise
* The evaluation promise returned from evaluating the module. If this
* is null, JS::FinishDynamicImport will reject the dynamic import
* module promise.
*/
void FinishDynamicImport(ModuleLoadRequest* aRequest, nsresult aResult);
void FinishDynamicImport(JSContext* aCx, ModuleLoadRequest* aRequest,
nsresult aResult,
JS::Handle<JSObject*> aEvaluationPromise);
nsresult aResult);
/*
* Get the currently active script. This is used as the initiating script when

View File

@ -297,8 +297,7 @@ void LoadContextOptions(const char* aPrefName, void* /* aClosure */) {
.setPrivateClassFields(
GetWorkerPref<bool>("experimental.private_fields"_ns))
.setPrivateClassMethods(
GetWorkerPref<bool>("experimental.private_methods"_ns))
.setTopLevelAwait(GetWorkerPref<bool>("experimental.top_level_await"_ns));
GetWorkerPref<bool>("experimental.private_methods"_ns));
nsCOMPtr<nsIXULRuntime> xr = do_GetService("@mozilla.org/xre/runtime;1");
if (xr) {

View File

@ -405,8 +405,7 @@ void ExecutionRunnable::RunOnWorkletThread() {
// https://html.spec.whatwg.org/multipage/webappapis.html#run-a-module-script
// without /rethrow errors/ and so unhandled exceptions do not cause the
// promise to be rejected.
JS::Rooted<JS::Value> ignored(cx);
JS::ModuleEvaluate(cx, module, &ignored);
JS::ModuleEvaluate(cx, module);
// All done.
mResult = NS_OK;

View File

@ -132,7 +132,6 @@ class JS_PUBLIC_API TransitiveCompileOptions {
bool nonSyntacticScope = false;
bool privateClassFields = false;
bool privateClassMethods = false;
bool topLevelAwait = false;
// True if transcoding to XDR should use Stencil instead of JSScripts.
bool useStencilXDR = false;

View File

@ -46,8 +46,7 @@ class JS_PUBLIC_API ContextOptions {
#endif
fuzzing_(false),
privateClassFields_(false),
privateClassMethods_(false),
topLevelAwait_(false) {
privateClassMethods_(false) {
}
bool asmJS() const { return asmJS_; }
@ -159,12 +158,6 @@ class JS_PUBLIC_API ContextOptions {
return *this;
}
bool topLevelAwait() const { return topLevelAwait_; }
ContextOptions& setTopLevelAwait(bool enabled) {
topLevelAwait_ = enabled;
return *this;
}
// Override to allow disabling the eval restriction security checks for
// this context.
bool disableEvalSecurityChecks() const { return disableEvalSecurityChecks_; }
@ -275,7 +268,6 @@ class JS_PUBLIC_API ContextOptions {
bool fuzzing_ : 1;
bool privateClassFields_ : 1;
bool privateClassMethods_ : 1;
bool topLevelAwait_ : 1;
};
JS_PUBLIC_API ContextOptions& ContextOptionsRef(JSContext* cx);

View File

@ -90,24 +90,10 @@ enum class DynamicImportStatus { Failed = 0, Ok };
/**
* This must be called after a dynamic import operation is complete.
*
* If |evaluationPromise| is rejected, the rejection reason will be used to
* complete the user's promise.
*/
extern JS_PUBLIC_API bool FinishDynamicModuleImport(
JSContext* cx, Handle<JSObject*> evaluationPromise,
Handle<Value> referencingPrivate, Handle<JSString*> specifier,
Handle<JSObject*> promise);
/**
* This must be called after a dynamic import operation is complete.
*
* This is used so that Top Level Await functionality can be turned off
* entirely. It will be removed in bug#1676612.
*
* If |status| is Failed, any pending exception on the context will be used to
* complete the user's promise.
*/
extern JS_PUBLIC_API bool FinishDynamicModuleImport_NoTLA(
extern JS_PUBLIC_API bool FinishDynamicModuleImport(
JSContext* cx, DynamicImportStatus status, Handle<Value> referencingPrivate,
Handle<JSString*> specifier, Handle<JSObject*> promise);
@ -151,32 +137,16 @@ extern JS_PUBLIC_API bool ModuleInstantiate(JSContext* cx,
Handle<JSObject*> moduleRecord);
/*
* Perform the ModuleEvaluate operation on the given source text module record
* and returns a bool. A result value is returned in result and is either
* undefined (and ignored) or a promise (if Top Level Await is enabled).
* Perform the ModuleEvaluate operation on the given source text module record.
*
* If this module has already been evaluated, it returns the evaluation
* promise. Otherwise, it transitively evaluates all dependences of this module
* and then evaluates this module.
* This does nothing if this module has already been evaluated. Otherwise, it
* transitively evaluates all dependences of this module and then evaluates this
* module.
*
* ModuleInstantiate must have completed prior to calling this.
*/
extern JS_PUBLIC_API bool ModuleEvaluate(JSContext* cx,
Handle<JSObject*> moduleRecord,
MutableHandleValue rval);
/*
* If a module evaluation fails, unwrap the resulting evaluation promise
* and rethrow.
*
* This does nothing if this module succeeds in evaluation. Otherwise, it
* takes the reason for the module throwing, unwraps it and throws it as a
* regular error rather than as an uncaught promise.
*
* ModuleEvaluate must have completed prior to calling this.
*/
extern JS_PUBLIC_API bool ThrowOnModuleEvaluationFailure(
JSContext* cx, Handle<JSObject*> evaluationPromise);
Handle<JSObject*> moduleRecord);
/*
* Get a list of the module specifiers used by a source text module

View File

@ -211,7 +211,6 @@ MSG_DEF(JSMSG_AS_AFTER_IMPORT_STAR, 0, JSEXN_SYNTAXERR, "missing keyword 'as'
MSG_DEF(JSMSG_AS_AFTER_RESERVED_WORD, 1, JSEXN_SYNTAXERR, "missing keyword 'as' after reserved word '{0}'")
MSG_DEF(JSMSG_AWAIT_IN_PARAMETER, 0, JSEXN_SYNTAXERR, "await expression can't be used in parameter")
MSG_DEF(JSMSG_AWAIT_OUTSIDE_ASYNC, 0, JSEXN_SYNTAXERR, "await is only valid in async functions and async generators")
MSG_DEF(JSMSG_TOP_LEVEL_AWAIT_NOT_SUPPORTED, 0, JSEXN_SYNTAXERR, "top level await is not currently supported")
MSG_DEF(JSMSG_BAD_ARROW_ARGS, 0, JSEXN_SYNTAXERR, "invalid arrow-function arguments (parentheses around the arrow-function may help)")
MSG_DEF(JSMSG_BAD_BINDING, 1, JSEXN_SYNTAXERR, "redefining {0} is deprecated")
MSG_DEF(JSMSG_BAD_COALESCE_MIXING, 0, JSEXN_SYNTAXERR, "cannot use `??` unparenthesized within `||` and `&&` expressions")

View File

@ -575,8 +575,6 @@ function ModuleEvaluate()
if (!IsObject(this) || !IsModule(this))
return callFunction(CallModuleMethodIfWrapped, this, "ModuleEvaluate");
const isTopLevelAwaitEnabled = IsTopLevelAwaitEnabled();
// Step 2
let module = this;
@ -588,37 +586,12 @@ function ModuleEvaluate()
ThrowInternalError(JSMSG_BAD_MODULE_STATUS);
}
let capability = undefined;
if (isTopLevelAwaitEnabled) {
// Top-level Await Step 4
if (module.status === MODULE_STATUS_EVALUATED) {
module = GetAsyncCycleRoot(module);
}
// Top-level Await Step 5
if (module.topLevelCapability) {
return module.topLevelCapability;
}
capability = CreateTopLevelCapability(module);
}
// Step 4
let stack = [];
// Steps 5-6
try {
InnerModuleEvaluation(module, stack, 0);
if (isTopLevelAwaitEnabled) {
if (!module.asyncEvaluating) {
ModuleTopLevelCapabilityResolve(module);
}
// Steps 7-8
assert(module.status === MODULE_STATUS_EVALUATED,
"Bad module status after successful evaluation");
assert(stack.length === 0,
"Stack should be empty after successful evaluation");
}
} catch (error) {
for (let i = 0; i < stack.length; i++) {
let m = stack[i];
@ -634,23 +607,23 @@ function ModuleEvaluate()
assert(module.status === MODULE_STATUS_EVALUATED_ERROR,
"Bad module status after failed evaluation");
if (isTopLevelAwaitEnabled) {
ModuleTopLevelCapabilityReject(module, error);
} else {
throw error;
}
throw error;
}
// Steps 7-8
assert(module.status === MODULE_STATUS_EVALUATED,
"Bad module status after successful evaluation");
assert(stack.length === 0,
"Stack should be empty after successful evaluation");
// Step 9
return capability;
return undefined;
}
// https://tc39.es/ecma262/#sec-innermoduleevaluation
// ES2020 15.2.1.16.2.1 InnerModuleEvaluation
function InnerModuleEvaluation(module, stack, index)
{
const isTopLevelAwaitEnabled = IsTopLevelAwaitEnabled();
// Step 1
// TODO: Support module records other than Cyclic Module Records.
@ -675,11 +648,6 @@ function InnerModuleEvaluation(module, stack, index)
// Steps 6-8
UnsafeSetReservedSlot(module, MODULE_OBJECT_DFS_INDEX_SLOT, index);
UnsafeSetReservedSlot(module, MODULE_OBJECT_DFS_ANCESTOR_INDEX_SLOT, index);
if (isTopLevelAwaitEnabled) {
UnsafeSetReservedSlot(module, MODULE_OBJECT_PENDING_ASYNC_DEPENDENCIES_SLOT, 0);
}
index++;
// Step 9
@ -709,41 +677,11 @@ function InnerModuleEvaluation(module, stack, index)
UnsafeSetReservedSlot(module, MODULE_OBJECT_DFS_ANCESTOR_INDEX_SLOT,
std_Math_min(module.dfsAncestorIndex,
requiredModule.dfsAncestorIndex));
} else {
if (isTopLevelAwaitEnabled) {
requiredModule = GetAsyncCycleRoot(requiredModule);
assert(requiredModule.status === MODULE_STATUS_EVALUATED,
`Bad module status in InnerModuleEvaluation: ${requiredModule.status}`);
if (requiredModule.evaluationError) {
throw GetModuleEvaluationError(module);
}
}
}
if (isTopLevelAwaitEnabled) {
if (requiredModule.asyncEvaluating) {
UnsafeSetReservedSlot(module,
MODULE_OBJECT_PENDING_ASYNC_DEPENDENCIES_SLOT,
module.pendingAsyncDependencies + 1);
AppendAsyncParentModule(requiredModule, module);
}
}
}
if (isTopLevelAwaitEnabled) {
if (module.pendingAsyncDependencies > 0) {
UnsafeSetReservedSlot(module, MODULE_OBJECT_ASYNC_EVALUATING_SLOT, true);
} else {
if (module.async) {
ExecuteAsyncModule(module);
} else {
// Step 11
ExecuteModule(module);
}
}
} else {
// Step 11
ExecuteModule(module);
}
// Step 11
ExecuteModule(module);
// Step 12
assert(CountArrayValues(stack, module) === 1,
@ -765,17 +703,3 @@ function InnerModuleEvaluation(module, stack, index)
// Step 15
return index;
}
// https://tc39.es/proposal-top-level-await/#sec-execute-async-module
function ExecuteAsyncModule(module) {
// Steps 1-3.
assert(module.status == MODULE_STATUS_EVALUATING ||
module.status == MODULE_STATUS_EVALUATED, "bad status for async module");
assert(module.async, "module is not async");
UnsafeSetReservedSlot(module, MODULE_OBJECT_ASYNC_EVALUATING_SLOT, true);
// Step 4-11 done in AsyncAwait opcode
ExecuteModule(module);
}

View File

@ -29,10 +29,8 @@
#include "vm/SelfHosting.h"
#include "vm/SharedStencil.h" // js::GCThingIndex
#include "builtin/HandlerFunction-inl.h" // js::ExtraValueFromHandler, js::NewHandler{,WithExtraValue}, js::TargetFromHandler
#include "vm/JSObject-inl.h"
#include "vm/JSScript-inl.h"
#include "vm/List-inl.h"
#include "vm/NativeObject-inl.h"
using namespace js;
@ -837,15 +835,6 @@ void ModuleObject::initFunctionDeclarations(
*functionDeclarations() = std::move(decls);
}
bool ModuleObject::initAsyncSlots(JSContext* cx, bool isAsync,
HandleObject asyncParentModulesList) {
initReservedSlot(AsyncSlot, BooleanValue(isAsync));
initReservedSlot(AsyncEvaluatingSlot, BooleanValue(false));
initReservedSlot(AsyncParentModulesSlot,
ObjectValue(*asyncParentModulesList));
return true;
}
void ModuleObject::initScriptSlots(HandleScript script) {
MOZ_ASSERT(script);
initReservedSlot(ScriptSlot, PrivateGCThingValue(script));
@ -970,77 +959,10 @@ ModuleStatus ModuleObject::status() const {
return status;
}
bool ModuleObject::isAsync() const {
return getReservedSlot(AsyncSlot).toBoolean();
}
bool ModuleObject::isAsyncEvaluating() const {
return getReservedSlot(AsyncEvaluatingSlot).toBoolean();
}
void ModuleObject::setAsyncEvaluating(bool isEvaluating) {
return setReservedSlot(AsyncEvaluatingSlot, BooleanValue(isEvaluating));
}
uint32_t ModuleObject::dfsIndex() const {
return getReservedSlot(DFSIndexSlot).toInt32();
}
uint32_t ModuleObject::dfsAncestorIndex() const {
return getReservedSlot(DFSAncestorIndexSlot).toInt32();
}
JSObject* ModuleObject::topLevelCapability() const {
return &getReservedSlot(TopLevelCapabilitySlot).toObject();
}
PromiseObject* ModuleObject::createTopLevelCapability(
JSContext* cx, HandleModuleObject module) {
MOZ_ASSERT(module->getReservedSlot(TopLevelCapabilitySlot).isUndefined());
Rooted<PromiseObject*> resultPromise(cx, CreatePromiseObjectForAsync(cx));
if (!resultPromise) {
return nullptr;
}
module->setInitialTopLevelCapability(resultPromise);
return resultPromise;
}
void ModuleObject::setInitialTopLevelCapability(HandleObject promiseObj) {
initReservedSlot(TopLevelCapabilitySlot, ObjectValue(*promiseObj));
}
inline ListObject* ModuleObject::asyncParentModules() const {
return &getReservedSlot(AsyncParentModulesSlot).toObject().as<ListObject>();
}
bool ModuleObject::appendAsyncParentModule(JSContext* cx,
HandleModuleObject self,
HandleModuleObject parent) {
Rooted<Value> parentValue(cx, ObjectValue(*parent));
return self->asyncParentModules()->append(cx, parentValue);
}
uint32_t ModuleObject::pendingAsyncDependencies() const {
return getReservedSlot(PendingAsyncDependenciesSlot).toInt32();
}
void ModuleObject::setPendingAsyncDependencies(uint32_t newValue) {
return setReservedSlot(PendingAsyncDependenciesSlot, NumberValue(newValue));
}
bool ModuleObject::hasTopLevelCapability() const {
return !getReservedSlot(TopLevelCapabilitySlot).isUndefined();
}
bool ModuleObject::hadEvaluationError() const {
return status() == MODULE_STATUS_EVALUATED_ERROR;
}
void ModuleObject::setEvaluationError(HandleValue newValue) {
setReservedSlot(StatusSlot, Int32Value(MODULE_STATUS_EVALUATED_ERROR));
return setReservedSlot(EvaluationErrorSlot, newValue);
}
Value ModuleObject::evaluationError() const {
MOZ_ASSERT(hadEvaluationError());
return getReservedSlot(EvaluationErrorSlot);
@ -1123,8 +1045,7 @@ bool ModuleObject::instantiateFunctionDeclarations(JSContext* cx,
bool ModuleObject::execute(JSContext* cx, HandleModuleObject self,
MutableHandleValue rval) {
#ifdef DEBUG
MOZ_ASSERT(self->status() == MODULE_STATUS_EVALUATING ||
self->status() == MODULE_STATUS_EVALUATED);
MOZ_ASSERT(self->status() == MODULE_STATUS_EVALUATING);
if (!AssertFrozen(cx, self)) {
return false;
}
@ -1183,25 +1104,22 @@ bool ModuleObject::createEnvironment(JSContext* cx, HandleModuleObject self) {
}
static bool InvokeSelfHostedMethod(JSContext* cx, HandleModuleObject self,
HandlePropertyName name,
MutableHandleValue rval) {
HandlePropertyName name) {
RootedValue thisv(cx, ObjectValue(*self));
FixedInvokeArgs<0> args(cx);
return CallSelfHostedFunction(cx, name, thisv, args, rval);
RootedValue ignored(cx);
return CallSelfHostedFunction(cx, name, thisv, args, &ignored);
}
/* static */
bool ModuleObject::Instantiate(JSContext* cx, HandleModuleObject self) {
RootedValue ignored(cx);
return InvokeSelfHostedMethod(cx, self, cx->names().ModuleInstantiate,
&ignored);
return InvokeSelfHostedMethod(cx, self, cx->names().ModuleInstantiate);
}
/* static */
bool ModuleObject::Evaluate(JSContext* cx, HandleModuleObject self,
MutableHandleValue rval) {
return InvokeSelfHostedMethod(cx, self, cx->names().ModuleEvaluate, rval);
bool ModuleObject::Evaluate(JSContext* cx, HandleModuleObject self) {
return InvokeSelfHostedMethod(cx, self, cx->names().ModuleEvaluate);
}
/* static */
@ -1231,14 +1149,6 @@ DEFINE_GETTER_FUNCTIONS(ModuleObject, indirectExportEntries,
DEFINE_GETTER_FUNCTIONS(ModuleObject, starExportEntries, StarExportEntriesSlot)
DEFINE_GETTER_FUNCTIONS(ModuleObject, dfsIndex, DFSIndexSlot)
DEFINE_GETTER_FUNCTIONS(ModuleObject, dfsAncestorIndex, DFSAncestorIndexSlot)
DEFINE_GETTER_FUNCTIONS(ModuleObject, async, AsyncSlot)
DEFINE_GETTER_FUNCTIONS(ModuleObject, topLevelCapability,
TopLevelCapabilitySlot)
DEFINE_GETTER_FUNCTIONS(ModuleObject, asyncEvaluating, AsyncEvaluatingSlot)
DEFINE_GETTER_FUNCTIONS(ModuleObject, asyncParentModules,
AsyncParentModulesSlot)
DEFINE_GETTER_FUNCTIONS(ModuleObject, pendingAsyncDependencies,
PendingAsyncDependenciesSlot)
/* static */
bool GlobalObject::initModuleProto(JSContext* cx,
@ -1255,12 +1165,6 @@ bool GlobalObject::initModuleProto(JSContext* cx,
JS_PSG("starExportEntries", ModuleObject_starExportEntriesGetter, 0),
JS_PSG("dfsIndex", ModuleObject_dfsIndexGetter, 0),
JS_PSG("dfsAncestorIndex", ModuleObject_dfsAncestorIndexGetter, 0),
JS_PSG("async", ModuleObject_asyncGetter, 0),
JS_PSG("topLevelCapability", ModuleObject_topLevelCapabilityGetter, 0),
JS_PSG("asyncEvaluating", ModuleObject_asyncEvaluatingGetter, 0),
JS_PSG("asyncParentModules", ModuleObject_asyncParentModulesGetter, 0),
JS_PSG("pendingAsyncDependencies",
ModuleObject_pendingAsyncDependenciesGetter, 0),
JS_PS_END};
static const JSFunctionSpec protoFunctions[] = {
@ -1308,10 +1212,6 @@ bool ModuleBuilder::noteFunctionDeclaration(JSContext* cx, uint32_t funIndex) {
return true;
}
void ModuleBuilder::noteAsync(frontend::StencilModuleMetadata& metadata) {
metadata.isAsync = true;
}
bool ModuleBuilder::buildTables(frontend::StencilModuleMetadata& metadata) {
// https://tc39.es/ecma262/#sec-parsemodule
// 15.2.1.17.1 ParseModule, Steps 4-11.
@ -1506,15 +1406,6 @@ bool frontend::StencilModuleMetadata::initModule(
}
module->initFunctionDeclarations(std::move(functionDeclsCopy));
Rooted<ListObject*> asyncParentModulesList(cx, ListObject::create(cx));
if (!asyncParentModulesList) {
return false;
}
if (!module->initAsyncSlots(cx, isAsync, asyncParentModulesList)) {
return false;
}
module->initImportExportData(
requestedModulesObject, importEntriesObject, localExportEntriesObject,
indirectExportEntriesObject, starExportEntriesObject);
@ -1940,193 +1831,6 @@ JSObject* js::CallModuleResolveHook(JSContext* cx,
return result;
}
// https://tc39.es/proposal-top-level-await/#sec-getasynccycleroot
ModuleObject* js::GetAsyncCycleRoot(ModuleObject* module) {
// Step 1.
MOZ_ASSERT(module->status() == MODULE_STATUS_EVALUATED);
// Step 2.
if (module->asyncParentModules()->empty()) {
return module;
}
// Step 3.
ModuleObject* currentModule = module;
while (currentModule->dfsIndex() > currentModule->dfsAncestorIndex()) {
MOZ_ASSERT(!currentModule->asyncParentModules()->empty());
ModuleObject* nextCycleModule = &currentModule->asyncParentModules()
->get(0)
.toObject()
.as<ModuleObject>();
MOZ_ASSERT(nextCycleModule->dfsAncestorIndex() <=
currentModule->dfsAncestorIndex());
currentModule = nextCycleModule;
}
// Step 4.
MOZ_ASSERT(currentModule->dfsIndex() == currentModule->dfsAncestorIndex());
// Step 5.
return currentModule;
}
bool js::AsyncModuleExecutionFulfilledHandler(JSContext* cx, unsigned argc,
Value* vp) {
CallArgs args = CallArgsFromVp(argc, vp);
JSFunction& func = args.callee().as<JSFunction>();
Rooted<ModuleObject*> module(
cx, &func.getExtendedSlot(FunctionExtended::MODULE_SLOT)
.toObject()
.as<ModuleObject>());
AsyncModuleExecutionFulfilled(cx, module);
args.rval().setUndefined();
return true;
}
bool js::AsyncModuleExecutionRejectedHandler(JSContext* cx, unsigned argc,
Value* vp) {
CallArgs args = CallArgsFromVp(argc, vp);
JSFunction& func = args.callee().as<JSFunction>();
Rooted<ModuleObject*> module(
cx, &func.getExtendedSlot(FunctionExtended::MODULE_SLOT)
.toObject()
.as<ModuleObject>());
AsyncModuleExecutionRejected(cx, module, args.get(0));
args.rval().setUndefined();
return true;
}
// Top Level Await
// https://tc39.es/proposal-top-level-await/#sec-asyncmodulexecutionfulfilled
void js::AsyncModuleExecutionFulfilled(JSContext* cx,
HandleModuleObject module) {
// Step 1.
MOZ_ASSERT(module->status() == MODULE_STATUS_EVALUATED);
// Step 2.
if (!module->isAsyncEvaluating()) {
MOZ_ASSERT(module->hadEvaluationError());
return;
}
// Step 3.
MOZ_ASSERT(!module->hadEvaluationError());
// Step 4.
module->setAsyncEvaluating(false);
// Step 5.
uint32_t length = module->asyncParentModules()->length();
Rooted<ModuleObject*> m(cx);
Rooted<ModuleObject*> cycleRoot(cx);
RootedValue result(cx);
for (uint32_t i = 0; i < length; i++) {
m = &module->asyncParentModules()->get(i).toObject().as<ModuleObject>();
if (module->dfsIndex() != module->dfsAncestorIndex()) {
MOZ_ASSERT(m->dfsAncestorIndex() <= module->dfsAncestorIndex());
}
m->setPendingAsyncDependencies(m->pendingAsyncDependencies() - 1);
if (m->pendingAsyncDependencies() == 0 && !m->hadEvaluationError()) {
MOZ_ASSERT(m->isAsyncEvaluating());
cycleRoot = GetAsyncCycleRoot(m);
if (cycleRoot->hadEvaluationError()) {
return;
}
if (m->isAsync()) {
// Steps for ExecuteAsyncModule
MOZ_ASSERT(m->status() == MODULE_STATUS_EVALUATING ||
m->status() == MODULE_STATUS_EVALUATED);
MOZ_ASSERT(m->isAsync());
MOZ_ASSERT(m->isAsyncEvaluating());
ModuleObject::execute(cx, m, &result);
} else {
if (ModuleObject::execute(cx, m, &result)) {
AsyncModuleExecutionFulfilled(cx, m);
} else {
AsyncModuleExecutionRejected(cx, m, result);
}
}
}
}
// Step 6.
if (module->hasTopLevelCapability()) {
MOZ_ASSERT(module->dfsIndex() == module->dfsAncestorIndex());
ModuleObject::topLevelCapabilityResolve(cx, module);
}
// Return undefined.
}
// https://tc39.es/proposal-top-level-await/#sec-asyncmodulexecutionrejected
void js::AsyncModuleExecutionRejected(JSContext* cx, HandleModuleObject module,
HandleValue error) {
// Step 1.
MOZ_ASSERT(module->status() == MODULE_STATUS_EVALUATED);
// Step 2.
if (!module->isAsyncEvaluating()) {
MOZ_ASSERT(module->hadEvaluationError());
return;
}
// Step 3.
MOZ_ASSERT(!module->hadEvaluationError());
// Step 4.
module->setEvaluationError(error);
// Step 5.
module->setAsyncEvaluating(false);
// Step 6.
uint32_t length = module->asyncParentModules()->length();
Rooted<ModuleObject*> parent(cx);
for (uint32_t i = 0; i < length; i++) {
parent =
&module->asyncParentModules()->get(i).toObject().as<ModuleObject>();
if (module->dfsIndex() != module->dfsAncestorIndex()) {
MOZ_ASSERT(parent->dfsAncestorIndex() == module->dfsAncestorIndex());
}
AsyncModuleExecutionRejected(cx, parent, error);
}
// Step 7.
if (module->hasTopLevelCapability()) {
MOZ_ASSERT(module->dfsIndex() == module->dfsAncestorIndex());
ModuleObject::topLevelCapabilityReject(cx, module, error);
}
// Return undefined.
}
bool ModuleObject::topLevelCapabilityResolve(JSContext* cx,
HandleModuleObject module) {
RootedValue rval(cx);
Rooted<PromiseObject*> promise(
cx, &module->topLevelCapability()->as<PromiseObject>());
return AsyncFunctionReturned(cx, promise, rval);
}
bool ModuleObject::topLevelCapabilityReject(JSContext* cx,
HandleModuleObject module,
HandleValue error) {
Rooted<PromiseObject*> promise(
cx, &module->topLevelCapability()->as<PromiseObject>());
if (!AsyncFunctionThrown(cx, promise, error)) {
return false;
}
MOZ_ASSERT(promise->state() == JS::PromiseState::Rejected);
return true;
}
JSObject* js::StartDynamicModuleImport(JSContext* cx, HandleScript script,
HandleValue specifierArg) {
RootedObject promiseConstructor(cx, JS::GetPromiseConstructor(cx));
@ -2183,141 +1887,11 @@ JSObject* js::StartDynamicModuleImport(JSContext* cx, HandleScript script,
return promise;
}
static bool OnRootModuleRejected(JSContext* cx, unsigned argc, Value* vp) {
CallArgs args = CallArgsFromVp(argc, vp);
HandleValue error = args.get(0);
js::ReportExceptionClosure reportExn(error);
PrepareScriptEnvironmentAndInvoke(cx, cx->global(), reportExn);
args.rval().setUndefined();
return true;
};
bool js::OnModuleEvaluationFailure(JSContext* cx,
HandleObject evaluationPromise) {
if (evaluationPromise == nullptr) {
return false;
}
RootedFunction onRejected(
cx, NewHandler(cx, OnRootModuleRejected, evaluationPromise));
if (!onRejected) {
return false;
}
return JS::AddPromiseReactions(cx, evaluationPromise, nullptr, onRejected);
}
// Adjustment for Top-level await;
// See: https://github.com/tc39/proposal-dynamic-import/pull/71/files
static bool OnResolvedDynamicModule(JSContext* cx, unsigned argc, Value* vp) {
CallArgs args = CallArgsFromVp(argc, vp);
MOZ_ASSERT(args.get(0).isUndefined());
// This is a hack to allow us to have the 2 extra variables needed
// for FinishDynamicModuleImport in the resolve callback.
Rooted<ListObject*> resolvedModuleParams(cx,
ExtraFromHandler<ListObject>(args));
MOZ_ASSERT(resolvedModuleParams->length() == 2);
RootedValue referencingPrivate(cx, resolvedModuleParams->get(0));
RootedString specifier(cx, resolvedModuleParams->get(1).toString());
Rooted<PromiseObject*> promise(cx, TargetFromHandler<PromiseObject>(args));
auto releasePrivate = mozilla::MakeScopeExit(
[&] { cx->runtime()->releaseScriptPrivate(referencingPrivate); });
RootedObject result(cx,
CallModuleResolveHook(cx, referencingPrivate, specifier));
if (!result) {
return RejectPromiseWithPendingError(cx, promise);
}
RootedModuleObject module(cx, &result->as<ModuleObject>());
if (module->status() != MODULE_STATUS_EVALUATED) {
JS_ReportErrorASCII(
cx, "Unevaluated or errored module returned by module resolve hook");
return RejectPromiseWithPendingError(cx, promise);
}
MOZ_ASSERT(module->topLevelCapability()->as<PromiseObject>().state() ==
JS::PromiseState::Fulfilled);
RootedObject ns(cx, ModuleObject::GetOrCreateModuleNamespace(cx, module));
if (!ns) {
return RejectPromiseWithPendingError(cx, promise);
}
args.rval().setUndefined();
RootedValue value(cx, ObjectValue(*ns));
return PromiseObject::resolve(cx, promise, value);
};
static bool OnRejectedDynamicModule(JSContext* cx, unsigned argc, Value* vp) {
CallArgs args = CallArgsFromVp(argc, vp);
HandleValue error = args.get(0);
RootedValue referencingPrivate(cx, ExtraValueFromHandler(args));
Rooted<PromiseObject*> promise(cx, TargetFromHandler<PromiseObject>(args));
auto releasePrivate = mozilla::MakeScopeExit(
[&] { cx->runtime()->releaseScriptPrivate(referencingPrivate); });
args.rval().setUndefined();
return PromiseObject::reject(cx, promise, error);
};
bool js::FinishDynamicModuleImport(JSContext* cx,
HandleObject evaluationPromise,
JS::DynamicImportStatus status,
HandleValue referencingPrivate,
HandleString specifier,
HandleObject promiseArg) {
// If we do not have an evaluation promise for the module, we can assume that
// evaluation has failed or been interrupted -- we can reject the dynamic
// module.
if (!evaluationPromise) {
auto releasePrivate = mozilla::MakeScopeExit(
[&] { cx->runtime()->releaseScriptPrivate(referencingPrivate); });
Handle<PromiseObject*> promise = promiseArg.as<PromiseObject>();
return RejectPromiseWithPendingError(cx, promise);
}
Rooted<ListObject*> resolutionArgs(cx, ListObject::create(cx));
if (!resolutionArgs->append(cx, referencingPrivate)) {
return false;
}
Rooted<Value> stringValue(cx, StringValue(specifier));
if (!resolutionArgs->append(cx, stringValue)) {
return false;
}
Rooted<Value> resolutionArgsValue(cx, ObjectValue(*resolutionArgs));
RootedFunction onResolved(
cx, NewHandlerWithExtraValue(cx, OnResolvedDynamicModule, promiseArg,
resolutionArgsValue));
if (!onResolved) {
return false;
}
RootedFunction onRejected(
cx, NewHandlerWithExtraValue(cx, OnRejectedDynamicModule, promiseArg,
referencingPrivate));
if (!onRejected) {
return false;
}
return JS::AddPromiseReactionsIgnoringUnhandledRejection(
cx, evaluationPromise, onResolved, onRejected);
}
bool js::FinishDynamicModuleImport_NoTLA(JSContext* cx,
JS::DynamicImportStatus status,
HandleValue referencingPrivate,
HandleString specifier,
HandleObject promiseArg) {
MOZ_ASSERT_IF(cx->isExceptionPending(),
status == JS::DynamicImportStatus::Failed);
@ -2633,23 +2207,6 @@ XDRResult js::XDRModuleObject(XDRState<mode>* xdr,
starExportEntries);
}
/* isAsync Slot */
uint8_t isAsyncModule = 0;
if (mode == XDR_ENCODE) {
isAsyncModule = module->isAsync() ? 1 : 0;
}
MOZ_TRY(xdr->codeUint8(&isAsyncModule));
if (mode == XDR_DECODE) {
Rooted<ListObject*> asyncParentModulesList(cx, ListObject::create(cx));
if (!asyncParentModulesList) {
return xdr->fail(JS::TranscodeResult_Throw);
}
module->initAsyncSlots(cx, isAsyncModule == 1, asyncParentModulesList);
}
modp.set(module);
return Ok();
}

View File

@ -19,9 +19,7 @@
#include "js/Modules.h"
#include "js/UniquePtr.h"
#include "vm/JSAtom.h"
#include "vm/List.h"
#include "vm/NativeObject.h"
#include "vm/PromiseObject.h" // js::PromiseObject
#include "vm/ProxyObject.h"
namespace js {
@ -250,11 +248,6 @@ class ModuleObject : public NativeObject {
FunctionDeclarationsSlot,
DFSIndexSlot,
DFSAncestorIndexSlot,
AsyncSlot,
AsyncEvaluatingSlot,
TopLevelCapabilitySlot,
AsyncParentModulesSlot,
PendingAsyncDependenciesSlot,
SlotCount
};
@ -268,14 +261,6 @@ class ModuleObject : public NativeObject {
"DFSIndexSlot must match self-hosting define");
static_assert(DFSAncestorIndexSlot == MODULE_OBJECT_DFS_ANCESTOR_INDEX_SLOT,
"DFSAncestorIndexSlot must match self-hosting define");
static_assert(AsyncEvaluatingSlot == MODULE_OBJECT_ASYNC_EVALUATING_SLOT,
"AsyncEvaluatingSlot must match self-hosting define");
static_assert(TopLevelCapabilitySlot ==
MODULE_OBJECT_TOP_LEVEL_CAPABILITY_SLOT,
"topLevelCapabilitySlot must match self-hosting define");
static_assert(PendingAsyncDependenciesSlot ==
MODULE_OBJECT_PENDING_ASYNC_DEPENDENCIES_SLOT,
"PendingAsyncDependenciesSlot must match self-hosting define");
static const JSClass class_;
@ -308,8 +293,6 @@ class ModuleObject : public NativeObject {
ModuleEnvironmentObject* environment() const;
ModuleNamespaceObject* namespace_();
ModuleStatus status() const;
uint32_t dfsIndex() const;
uint32_t dfsAncestorIndex() const;
bool hadEvaluationError() const;
Value evaluationError() const;
JSObject* metaObject() const;
@ -321,33 +304,8 @@ class ModuleObject : public NativeObject {
ArrayObject& starExportEntries() const;
IndirectBindingMap& importBindings();
static PromiseObject* createTopLevelCapability(JSContext* cx,
HandleModuleObject module);
bool isAsync() const;
void setAsync(bool isAsync);
bool isAsyncEvaluating() const;
void setAsyncEvaluating(bool isEvaluating);
void setEvaluationError(HandleValue newValue);
void setPendingAsyncDependencies(uint32_t newValue);
void setInitialTopLevelCapability(HandleObject promiseObj);
bool hasTopLevelCapability() const;
JSObject* topLevelCapability() const;
ListObject* asyncParentModules() const;
uint32_t pendingAsyncDependencies() const;
static bool appendAsyncParentModule(JSContext* cx, HandleModuleObject self,
HandleModuleObject parent);
static bool topLevelCapabilityResolve(JSContext* cx,
HandleModuleObject module);
static bool topLevelCapabilityReject(JSContext* cx, HandleModuleObject module,
HandleValue error);
static bool Instantiate(JSContext* cx, HandleModuleObject self);
// Start evaluating the module. If TLA is enabled, rval will be a promise
static bool Evaluate(JSContext* cx, HandleModuleObject self,
MutableHandleValue rval);
static bool Evaluate(JSContext* cx, HandleModuleObject self);
static ModuleNamespaceObject* GetOrCreateModuleNamespace(
JSContext* cx, HandleModuleObject self);
@ -372,9 +330,6 @@ class ModuleObject : public NativeObject {
frontend::FunctionDeclarationVector* functionDeclarations();
void initFunctionDeclarations(frontend::FunctionDeclarationVector&& decls);
bool initAsyncSlots(JSContext* cx, bool isAsync,
HandleObject asyncParentModulesList);
private:
static const JSClassOps classOps_;
@ -389,41 +344,13 @@ JSObject* GetOrCreateModuleMetaObject(JSContext* cx, HandleObject module);
JSObject* CallModuleResolveHook(JSContext* cx, HandleValue referencingPrivate,
HandleString specifier);
// https://tc39.es/proposal-top-level-await/#sec-getasynccycleroot
ModuleObject* GetAsyncCycleRoot(ModuleObject* module);
// https://tc39.es/proposal-top-level-await/#sec-asyncmodulexecutionfulfilled
void AsyncModuleExecutionFulfilled(JSContext* cx, HandleModuleObject module);
// https://tc39.es/proposal-top-level-await/#sec-asyncmodulexecutionrejected
void AsyncModuleExecutionRejected(JSContext* cx, HandleModuleObject module,
HandleValue error);
// https://tc39.es/proposal-top-level-await/#sec-asyncmodulexecutionfulfilled
bool AsyncModuleExecutionFulfilledHandler(JSContext* cx, unsigned argc,
Value* vp);
// https://tc39.es/proposal-top-level-await/#sec-asyncmodulexecutionrejected
bool AsyncModuleExecutionRejectedHandler(JSContext* cx, unsigned argc,
Value* vp);
JSObject* StartDynamicModuleImport(JSContext* cx, HandleScript script,
HandleValue specifier);
bool OnModuleEvaluationFailure(JSContext* cx, HandleObject evaluationPromise);
bool FinishDynamicModuleImport(JSContext* cx, HandleObject evaluationPromise,
bool FinishDynamicModuleImport(JSContext* cx, JS::DynamicImportStatus status,
HandleValue referencingPrivate,
HandleString specifier, HandleObject promise);
// This is used so that Top Level Await functionality can be turned off
// entirely. It will be removed in bug#1676612.
bool FinishDynamicModuleImport_NoTLA(JSContext* cx,
JS::DynamicImportStatus status,
HandleValue referencingPrivate,
HandleString specifier,
HandleObject promise);
template <XDRMode mode>
XDRResult XDRModuleObject(XDRState<mode>* xdr, MutableHandleModuleObject modp);

View File

@ -5702,13 +5702,7 @@ static MOZ_MUST_USE bool IsTopMostAsyncFunctionCall(JSContext* cx) {
if (iter.done()) {
return false;
}
if (!iter.isFunctionFrame() && iter.isModuleFrame()) {
// The iterator is not a function frame, it is a module frame.
// Ignore this optimization for now.
return true;
}
MOZ_ASSERT(iter.isFunctionFrame());
MOZ_ASSERT(iter.calleeTemplate()->isAsync());
#ifdef DEBUG

View File

@ -110,9 +110,6 @@
#define MODULE_OBJECT_EVALUATION_ERROR_SLOT 4
#define MODULE_OBJECT_DFS_INDEX_SLOT 14
#define MODULE_OBJECT_DFS_ANCESTOR_INDEX_SLOT 15
#define MODULE_OBJECT_ASYNC_EVALUATING_SLOT 17
#define MODULE_OBJECT_TOP_LEVEL_CAPABILITY_SLOT 18
#define MODULE_OBJECT_PENDING_ASYNC_DEPENDENCIES_SLOT 20
// rev b012019fea18f29737a67c36911340a3e25bfc63
// 15.2.1.16 Cyclic Module Records

View File

@ -29,7 +29,7 @@
#include "vm/PromiseObject.h" // js::PromiseObject, js::PromiseResolvedWithUndefined
#include "vm/SelfHosting.h"
#include "builtin/HandlerFunction-inl.h" // js::NewHandler
#include "builtin/streams/HandlerFunction-inl.h" // js::NewHandler
#include "builtin/streams/ReadableStreamReader-inl.h" // js::Unwrap{ReaderFromStream{,NoThrow},StreamFromReader}
#include "vm/Compartment-inl.h"
#include "vm/List-inl.h" // js::ListObject, js::StoreNewListInFixedSlot
@ -421,7 +421,7 @@ static MOZ_MUST_USE PromiseObject* ReadableByteStreamControllerPullSteps(
MOZ_RELEASE_ASSERT(unwrappedStream->mode() ==
JS::ReadableStreamMode::ExternalSource);
#if 0 // disable user-defined byte streams
#if 0 // disable user-defined byte streams
if (unwrappedStream->mode() == JS::ReadableStreamMode::ExternalSource)
#endif // user-defined byte streams
{
@ -448,7 +448,7 @@ static MOZ_MUST_USE PromiseObject* ReadableByteStreamControllerPullSteps(
queueTotalSize = queueTotalSize - bytesWritten;
}
#if 0 // disable user-defined byte streams
#if 0 // disable user-defined byte streams
else {
// Step 3.b: Let entry be the first element of this.[[queue]].
// Step 3.c: Remove entry from this.[[queue]], shifting all other

View File

@ -186,12 +186,6 @@ static bool GetRealmConfiguration(JSContext* cx, unsigned argc, Value* vp) {
return false;
}
bool topLevelAwait = cx->options().topLevelAwait();
if (!JS_SetProperty(cx, info, "topLevelAwait",
topLevelAwait ? TrueHandleValue : FalseHandleValue)) {
return false;
}
bool offThreadParseGlobal = js::UseOffThreadParseGlobal();
if (!JS_SetProperty(
cx, info, "offThreadParseGlobal",
@ -5542,7 +5536,7 @@ static bool GetTimeZone(JSContext* cx, unsigned argc, Value* vp) {
return tzname[local.tm_isdst > 0];
# endif /* HAVE_TM_ZONE_TM_GMTOFF */
}
#endif /* _WIN32 */
#endif /* _WIN32 */
return nullptr;
};

View File

@ -5,12 +5,12 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/*
* Handler for operations that act on a target object, and possibly upon
* Stream handler for operations that act on a target object, and possibly upon
* an extra value.
*/
#ifndef builtin_HandlerFunction_inl_h
#define builtin_HandlerFunction_inl_h
#ifndef builtin_streams_HandlerFunction_inl_h
#define builtin_streams_HandlerFunction_inl_h
#include "mozilla/Attributes.h" // MOZ_MUST_USE
@ -33,10 +33,11 @@ namespace js {
// Handler functions are extended functions, that close over a target object and
// (optionally) over an extra object, storing those objects in the function's
// extended slots.
constexpr size_t HandlerFunctionSlot_Target = 0;
constexpr size_t HandlerFunctionSlot_Extra = 1;
constexpr size_t StreamHandlerFunctionSlot_Target = 0;
constexpr size_t StreamHandlerFunctionSlot_Extra = 1;
static_assert(HandlerFunctionSlot_Extra < FunctionExtended::NUM_EXTENDED_SLOTS,
static_assert(StreamHandlerFunctionSlot_Extra <
FunctionExtended::NUM_EXTENDED_SLOTS,
"handler function slots shouldn't exceed available extended "
"slots");
@ -51,7 +52,7 @@ inline MOZ_MUST_USE JSFunction* NewHandler(JSContext* cx, Native handler,
if (!handlerFun) {
return nullptr;
}
handlerFun->setExtendedSlot(HandlerFunctionSlot_Target,
handlerFun->setExtendedSlot(StreamHandlerFunctionSlot_Target,
JS::ObjectValue(*target));
return handlerFun;
}
@ -62,7 +63,7 @@ inline MOZ_MUST_USE JSFunction* NewHandlerWithExtra(
cx->check(extra);
JSFunction* handlerFun = NewHandler(cx, handler, target);
if (handlerFun) {
handlerFun->setExtendedSlot(HandlerFunctionSlot_Extra,
handlerFun->setExtendedSlot(StreamHandlerFunctionSlot_Extra,
JS::ObjectValue(*extra));
}
return handlerFun;
@ -74,7 +75,7 @@ inline MOZ_MUST_USE JSFunction* NewHandlerWithExtraValue(
cx->check(extra);
JSFunction* handlerFun = NewHandler(cx, handler, target);
if (handlerFun) {
handlerFun->setExtendedSlot(HandlerFunctionSlot_Extra, extra);
handlerFun->setExtendedSlot(StreamHandlerFunctionSlot_Extra, extra);
}
return handlerFun;
}
@ -86,7 +87,9 @@ inline MOZ_MUST_USE JSFunction* NewHandlerWithExtraValue(
template <class T>
inline MOZ_MUST_USE T* TargetFromHandler(const JS::CallArgs& args) {
JSFunction& func = args.callee().as<JSFunction>();
return &func.getExtendedSlot(HandlerFunctionSlot_Target).toObject().as<T>();
return &func.getExtendedSlot(StreamHandlerFunctionSlot_Target)
.toObject()
.as<T>();
}
/**
@ -95,7 +98,7 @@ inline MOZ_MUST_USE T* TargetFromHandler(const JS::CallArgs& args) {
*/
inline MOZ_MUST_USE JS::Value ExtraValueFromHandler(const JS::CallArgs& args) {
JSFunction& func = args.callee().as<JSFunction>();
return func.getExtendedSlot(HandlerFunctionSlot_Extra);
return func.getExtendedSlot(StreamHandlerFunctionSlot_Extra);
}
/**
@ -110,4 +113,4 @@ inline MOZ_MUST_USE T* ExtraFromHandler(const JS::CallArgs& args) {
} // namespace js
#endif // builtin_HandlerFunction_inl_h
#endif // builtin_streams_HandlerFunction_inl_h

View File

@ -31,7 +31,7 @@
#include "vm/PromiseObject.h" // js::PromiseObject
#include "vm/Runtime.h" // JSRuntime
#include "builtin/HandlerFunction-inl.h" // js::ExtraValueFromHandler, js::NewHandler{,WithExtraValue}, js::TargetFromHandler
#include "builtin/streams/HandlerFunction-inl.h" // js::ExtraValueFromHandler, js::NewHandler{,WithExtraValue}, js::TargetFromHandler
#include "builtin/streams/ReadableStreamReader-inl.h" // js::UnwrapReaderFromStream, js::UnwrapStreamFromReader
#include "builtin/streams/WritableStream-inl.h" // js::UnwrapWriterFromStream
#include "builtin/streams/WritableStreamDefaultWriter-inl.h" // js::UnwrapStreamFromWriter

View File

@ -34,7 +34,7 @@
#include "vm/PromiseObject.h" // js::PromiseObject, js::PromiseResolvedWithUndefined
#include "vm/SelfHosting.h"
#include "builtin/HandlerFunction-inl.h" // js::TargetFromHandler
#include "builtin/streams/HandlerFunction-inl.h" // js::TargetFromHandler
#include "builtin/streams/MiscellaneousOperations-inl.h" // js::PromiseCall
#include "builtin/streams/ReadableStreamReader-inl.h" // js::UnwrapReaderFromStream
#include "vm/Compartment-inl.h" // JS::Compartment::wrap, js::UnwrapAnd{DowncastObject,TypeCheckThis}

View File

@ -34,7 +34,7 @@
#include "vm/Runtime.h" // JSAtomState
#include "vm/SavedFrame.h" // js::SavedFrame
#include "builtin/HandlerFunction-inl.h" // js::NewHandler
#include "builtin/streams/HandlerFunction-inl.h" // js::NewHandler
#include "builtin/streams/MiscellaneousOperations-inl.h" // js::PromiseCall
#include "vm/Compartment-inl.h" // JS::Compartment::wrap, js::UnwrapCalleeSlot
#include "vm/JSContext-inl.h" // JSContext::check

View File

@ -29,7 +29,7 @@
#include "vm/ObjectOperations.h" // js::GetProperty
#include "vm/PromiseObject.h" // js::PromiseObject, js::PromiseResolvedWithUndefined
#include "builtin/HandlerFunction-inl.h" // js::NewHandler, js::TargetFromHandler
#include "builtin/streams/HandlerFunction-inl.h" // js::NewHandler, js::TargetFromHandler
#include "builtin/streams/MiscellaneousOperations-inl.h" // js::ResolveUnwrappedPromiseWithValue
#include "builtin/streams/ReadableStreamReader-inl.h" // js::UnwrapReaderFromStream
#include "vm/Compartment-inl.h" // JS::Compartment::wrap, js::Unwrap{Callee,Internal}Slot

View File

@ -29,7 +29,7 @@
#include "vm/PromiseObject.h" // js::PromiseObject, js::PromiseResolvedWithUndefined
#include "vm/Runtime.h" // JSAtomState
#include "builtin/HandlerFunction-inl.h" // js::TargetFromHandler
#include "builtin/streams/HandlerFunction-inl.h" // js::TargetFromHandler
#include "builtin/streams/MiscellaneousOperations-inl.h" // js::PromiseCall
#include "builtin/streams/QueueWithSizes-inl.h" // js::PeekQueueValue
#include "vm/Compartment-inl.h" // JS::Compartment::wrap

View File

@ -30,8 +30,8 @@
#include "vm/List.h" // js::ListObject
#include "vm/PromiseObject.h" // js::PromiseObject, js::PromiseResolvedWithUndefined
#include "builtin/HandlerFunction-inl.h" // js::NewHandler, js::TargetFromHandler
#include "builtin/Promise-inl.h" // js::SetSettledPromiseIsHandled
#include "builtin/Promise-inl.h" // js::SetSettledPromiseIsHandled
#include "builtin/streams/HandlerFunction-inl.h" // js::NewHandler, js::TargetFromHandler
#include "builtin/streams/MiscellaneousOperations-inl.h" // js::ResolveUnwrappedPromiseWithUndefined, js::RejectUnwrappedPromiseWithError
#include "builtin/streams/WritableStream-inl.h" // js::UnwrapWriterFromStream
#include "builtin/streams/WritableStreamDefaultWriter-inl.h" // js::WritableStreamDefaultWriter::closedPromise

View File

@ -1,198 +0,0 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
* vim: set ts=8 sts=2 et sw=2 tw=80:
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "frontend/AsyncEmitter.h"
#include "mozilla/Assertions.h" // MOZ_ASSERT
#include "frontend/BytecodeEmitter.h" // BytecodeEmitter
#include "frontend/NameOpEmitter.h" // NameOpEmitter
#include "vm/AsyncFunctionResolveKind.h" // AsyncFunctionResolveKind
#include "vm/Opcodes.h" // JSOp
using namespace js;
using namespace js::frontend;
bool AsyncEmitter::prepareForParamsWithExpression() {
MOZ_ASSERT(state_ == State::Start);
#ifdef DEBUG
state_ = State::Parameters;
#endif
rejectTryCatch_.emplace(bce_, TryEmitter::Kind::TryCatch,
TryEmitter::ControlKind::NonSyntactic);
return rejectTryCatch_->emitTry();
}
bool AsyncEmitter::prepareForParamsWithoutExpression() {
MOZ_ASSERT(state_ == State::Start);
#ifdef DEBUG
state_ = State::Parameters;
#endif
return true;
}
bool AsyncEmitter::emitParamsEpilogue() {
MOZ_ASSERT(state_ == State::Parameters);
if (rejectTryCatch_) {
// If we get here, we need to reset the TryEmitter. Parameters can't reuse
// the reject try-catch block from the function body, because the body
// may have pushed an additional var-environment. This messes up scope
// resolution for the |.generator| variable, because we'd need different
// hops to reach |.generator| depending on whether the error was thrown
// from the parameters or the function body.
if (!emitRejectCatch()) {
return false;
}
}
#ifdef DEBUG
state_ = State::PostParams;
#endif
return true;
}
bool AsyncEmitter::prepareForModule() {
// Unlike functions, modules do not have params that we need to worry about.
// Instead, this code is for setting up the required generator that will be
// used for top level await. Before we can start using top-level await in
// modules, we need to emit a
// |.generator| which we can use to pause and resume execution.
MOZ_ASSERT(state_ == State::Start);
MOZ_ASSERT(
bce_->lookupName(bce_->cx->parserNames().dotGenerator).hasKnownSlot());
NameOpEmitter noe(bce_, bce_->cx->parserNames().dotGenerator,
NameOpEmitter::Kind::Initialize);
if (!noe.prepareForRhs()) {
// [stack]
return false;
}
if (!bce_->emit1(JSOp::Generator)) {
// [stack] GEN
return false;
}
if (!noe.emitAssignment()) {
// [stack] GEN
return false;
}
if (!bce_->emit1(JSOp::Pop)) {
// [stack]
return false;
}
#ifdef DEBUG
state_ = State::ModulePrologue;
#endif
return true;
}
bool AsyncEmitter::prepareForBody() {
MOZ_ASSERT(state_ == State::PostParams || state_ == State::ModulePrologue);
rejectTryCatch_.emplace(bce_, TryEmitter::Kind::TryCatch,
TryEmitter::ControlKind::NonSyntactic);
#ifdef DEBUG
state_ = State::Body;
#endif
return rejectTryCatch_->emitTry();
}
bool AsyncEmitter::emitEnd() {
#ifdef DEBUG
MOZ_ASSERT(state_ == State::Body);
#endif
if (!emitFinalYield()) {
return false;
}
if (!emitRejectCatch()) {
return false;
}
#ifdef DEBUG
state_ = State::End;
#endif
return true;
}
bool AsyncEmitter::emitFinalYield() {
if (!bce_->emit1(JSOp::Undefined)) {
// [stack] UNDEF
return false;
}
if (!bce_->emitGetDotGeneratorInInnermostScope()) {
// [stack] UNDEF GEN
return false;
}
if (!bce_->emit2(JSOp::AsyncResolve,
uint8_t(AsyncFunctionResolveKind::Fulfill))) {
// [stack] PROMISE
return false;
}
if (!bce_->emit1(JSOp::SetRval)) {
// [stack]
return false;
}
if (!bce_->emitGetDotGeneratorInInnermostScope()) {
// [stack] GEN
return false;
}
if (!bce_->emitYieldOp(JSOp::FinalYieldRval)) {
// [stack]
return false;
}
return true;
}
bool AsyncEmitter::emitRejectCatch() {
if (!rejectTryCatch_->emitCatch()) {
// [stack] EXC
return false;
}
if (!bce_->emitGetDotGeneratorInInnermostScope()) {
// [stack] EXC GEN
return false;
}
if (!bce_->emit2(JSOp::AsyncResolve,
uint8_t(AsyncFunctionResolveKind::Reject))) {
// [stack] PROMISE
return false;
}
if (!bce_->emit1(JSOp::SetRval)) {
// [stack]
return false;
}
if (!bce_->emitGetDotGeneratorInInnermostScope()) {
// [stack] GEN
return false;
}
if (!bce_->emitYieldOp(JSOp::FinalYieldRval)) {
// [stack]
return false;
}
if (!rejectTryCatch_->emitEnd()) {
return false;
}
rejectTryCatch_.reset();
return true;
}

View File

@ -1,163 +0,0 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
* vim: set ts=8 sts=2 et sw=2 tw=80:
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef frontend_AsyncEmitter_h
#define frontend_AsyncEmitter_h
#include "mozilla/Attributes.h" // MOZ_STACK_CLASS, MOZ_MUST_USE
#include "frontend/TryEmitter.h" // TryEmitter
namespace js {
namespace frontend {
struct BytecodeEmitter;
// Class for emitting Bytecode associated with the AsyncFunctionGenerator.
//
// Usage:
//
// For an async function, the params have to be handled separately,
// because the body may have pushed an additional var environment, changing
// the number of hops required to reach the |.generator| variable. In order
// to handle this, we can't reuse the same TryCatch emitter.
//
// Simple case - For a function without expression parameters:
// `async function f(<params>) {<body>}`,
// AsyncEmitter ae(this);
//
// ae.prepareForParamsWithoutExpression();
// // Emit Params.
// ...
// ae.paramsEpilogue(); // We need to emit the epilogue before the extra
// VarScope emitExtraBodyVarScope();
//
// // Emit new scope
// ae.prepareForBody();
//
// // Emit body of the Function.
//
// ae.emitEnd();
//
// Complex case - For a function with expression parameters:
// `async function f(<expression>) {<body>}`,
// AsyncEmitter ae(this);
//
// ae.prepareForParamsWithExpression();
//
// // Emit Params.
// ...
// ae.paramsEpilogue(); // We need to emit the epilogue before the extra
// // VarScope
// emitExtraBodyVarScope();
//
// // Emit new scope
// ae.prepareForBody();
//
// // Emit body of the Function.
// ...
// ae.emitEnd();
//
//
// Async Module case - For a module with `await` in the top level:
// AsyncEmitter ae(this);
// ae.prepareForModule(); // prepareForModule is used to setup the generator
// // for the async module.
// switchToMain();
// ...
//
// // Emit new scope
// ae.prepareForBody();
//
// // Emit body of the Script.
//
// ae.emitEnd();
//
class MOZ_STACK_CLASS AsyncEmitter {
private:
BytecodeEmitter* bce_;
// try-catch block for async function parameter and body.
mozilla::Maybe<TryEmitter> rejectTryCatch_;
#ifdef DEBUG
// The state of this emitter.
//
// +-------+
// | Start |-+
// +-------+ |
// |
// +----------+
// |
// | [Parameters with Expression]
// | prepareForParamsWithExpression +------------+
// +-------------------------------------| Parameters |-->+
// | +------------+ |
// | |
// | [Parameters Without Expression] |
// | prepareForParamsWithoutExpression +------------+ |
// +-------------------------------------| Parameters |-->+
// | +------------+ |
// | [Modules] |
// | prepareForModule +----------------+ |
// +-------------------->| ModulePrologue |--+ |
// +----------------+ | |
// | |
// | |
// +-----------------------------------------+ |
// | |
// | |
// V +------------+ paramsEpilogue |
// +<--------------------| PostParams |<------------------+
// | +------------+
// |
// | [Script body]
// | prepareForBody +---------+
// +-------------------->| Body |--------+
// +---------+ | <emit script body>
// +----------------------------------------+
// |
// | emitEnd +-----+
// +--------------------->| End |
// +-----+
enum class State {
// The initial state.
Start,
Parameters,
ModulePrologue,
PostParams,
Body,
End,
};
State state_ = State::Start;
#endif
MOZ_MUST_USE bool emitRejectCatch();
MOZ_MUST_USE bool emitFinalYield();
public:
explicit AsyncEmitter(BytecodeEmitter* bce) : bce_(bce){};
MOZ_MUST_USE bool prepareForParamsWithoutExpression();
MOZ_MUST_USE bool prepareForParamsWithExpression();
MOZ_MUST_USE bool prepareForModule();
MOZ_MUST_USE bool emitParamsEpilogue();
MOZ_MUST_USE bool prepareForBody();
MOZ_MUST_USE bool emitEnd();
};
} /* namespace frontend */
} /* namespace js */
#endif /* frontend_AsyncEmitter_h */

View File

@ -184,14 +184,13 @@ Maybe<NameLocation> BytecodeEmitter::locationOfNameBoundInScope(
return innermostEmitterScope()->locationBoundInScope(name, target);
}
template <typename T>
Maybe<NameLocation> BytecodeEmitter::locationOfNameBoundInScopeType(
Maybe<NameLocation> BytecodeEmitter::locationOfNameBoundInFunctionScope(
const ParserAtom* name, EmitterScope* source) {
EmitterScope* aScope = source;
while (!aScope->scope(this).is<T>()) {
aScope = aScope->enclosingInFrame();
EmitterScope* funScope = source;
while (!funScope->scope(this).is<FunctionScope>()) {
funScope = funScope->enclosingInFrame();
}
return source->locationBoundInScope(name, aScope);
return source->locationBoundInScope(name, funScope);
}
bool BytecodeEmitter::markStepBreakpoint() {
@ -2465,7 +2464,6 @@ bool BytecodeEmitter::emitScript(ParseNode* body) {
TDZCheckCache tdzCache(this);
EmitterScope emitterScope(this);
Maybe<AsyncEmitter> topLevelAwait;
if (sc->isGlobalContext()) {
if (!emitterScope.enterGlobal(this, sc->asGlobalContext())) {
return false;
@ -2479,9 +2477,6 @@ bool BytecodeEmitter::emitScript(ParseNode* body) {
if (!emitterScope.enterModule(this, sc->asModuleContext())) {
return false;
}
if (sc->asModuleContext()->isAsync()) {
topLevelAwait.emplace(this);
}
}
setFunctionBodyEndPos(body->pn_pos.end);
@ -2529,24 +2524,12 @@ bool BytecodeEmitter::emitScript(ParseNode* body) {
if (!emitDeclarationInstantiation(body)) {
return false;
}
if (topLevelAwait) {
if (!topLevelAwait->prepareForModule()) {
return false;
}
}
if (!switchToMain()) {
return false;
}
if (topLevelAwait) {
if (!topLevelAwait->prepareForBody()) {
return false;
}
}
if (!emitTree(body)) {
// [stack]
return false;
}
@ -2554,13 +2537,6 @@ bool BytecodeEmitter::emitScript(ParseNode* body) {
return false;
}
}
if (topLevelAwait) {
if (!topLevelAwait->emitEnd()) {
return false;
}
}
if (!markSimpleBreakpoint()) {
return false;
}
@ -2909,11 +2885,8 @@ bool BytecodeEmitter::emitIteratorNext(
const Maybe<uint32_t>& callSourceCoordOffset,
IteratorKind iterKind /* = IteratorKind::Sync */,
bool allowSelfHosted /* = false */) {
// TODO: migrate Module code to cpp, to avoid having the extra check here.
MOZ_ASSERT(allowSelfHosted || emitterMode != BytecodeEmitter::SelfHosting ||
(sc->isModuleContext() && sc->asModuleContext()->isAsync()),
".next() iteration is prohibited in non-module self-hosted code "
"because it"
MOZ_ASSERT(allowSelfHosted || emitterMode != BytecodeEmitter::SelfHosting,
".next() iteration is prohibited in self-hosted code because it "
"can run user-modifiable iteration code");
// [stack] ... NEXT ITER
@ -5494,9 +5467,9 @@ bool BytecodeEmitter::emitForOf(ForNode* forOfLoop,
unsigned iflags = forOfLoop->iflags();
IteratorKind iterKind =
(iflags & JSITER_FORAWAITOF) ? IteratorKind::Async : IteratorKind::Sync;
MOZ_ASSERT_IF(iterKind == IteratorKind::Async, sc->isSuspendableContext());
MOZ_ASSERT_IF(iterKind == IteratorKind::Async, sc->asFunctionBox());
MOZ_ASSERT_IF(iterKind == IteratorKind::Async,
sc->asSuspendableContext()->isAsync());
sc->asFunctionBox()->isAsync());
ParseNode* forHeadExpr = forOfHead->kid3();
@ -6062,8 +6035,7 @@ bool BytecodeEmitter::emitReturn(UnaryNode* returnNode) {
return false;
}
if (sc->asSuspendableContext()->isAsync() &&
sc->asSuspendableContext()->isGenerator()) {
if (sc->asFunctionBox()->isAsync() && sc->asFunctionBox()->isGenerator()) {
if (!emitAwaitInInnermostScope()) {
return false;
}
@ -6129,7 +6101,7 @@ bool BytecodeEmitter::emitReturn(UnaryNode* returnNode) {
if (needsFinalYield) {
// We know that .generator is on the function scope, as we just exited
// all nested scopes.
NameLocation loc = *locationOfNameBoundInScopeType<FunctionScope>(
NameLocation loc = *locationOfNameBoundInFunctionScope(
cx->parserNames().dotGenerator, varEmitterScope);
// Resolve the return value before emitting the final yield.
@ -6179,13 +6151,7 @@ bool BytecodeEmitter::emitReturn(UnaryNode* returnNode) {
}
bool BytecodeEmitter::emitGetDotGeneratorInScope(EmitterScope& currentScope) {
if (!sc->isFunction() && sc->isModuleContext() &&
sc->asModuleContext()->isAsync()) {
NameLocation loc = *locationOfNameBoundInScopeType<ModuleScope>(
cx->parserNames().dotGenerator, &currentScope);
return emitGetNameAtLocation(cx->parserNames().dotGenerator, loc);
}
NameLocation loc = *locationOfNameBoundInScopeType<FunctionScope>(
NameLocation loc = *locationOfNameBoundInFunctionScope(
cx->parserNames().dotGenerator, &currentScope);
return emitGetNameAtLocation(cx->parserNames().dotGenerator, loc);
}
@ -6236,7 +6202,7 @@ bool BytecodeEmitter::emitYield(UnaryNode* yieldNode) {
}
// 25.5.3.7 AsyncGeneratorYield step 5.
if (sc->asSuspendableContext()->isAsync()) {
if (sc->asFunctionBox()->isAsync()) {
MOZ_ASSERT(!needsIteratorResult);
if (!emitAwaitInInnermostScope()) {
// [stack] RESULT
@ -6273,7 +6239,7 @@ bool BytecodeEmitter::emitYield(UnaryNode* yieldNode) {
}
bool BytecodeEmitter::emitAwaitInInnermostScope(UnaryNode* awaitNode) {
MOZ_ASSERT(sc->isSuspendableContext());
MOZ_ASSERT(sc->isFunctionBox());
MOZ_ASSERT(awaitNode->isKind(ParseNodeKind::AwaitExpr));
if (!emitTree(awaitNode->kid())) {
@ -6299,7 +6265,7 @@ bool BytecodeEmitter::emitAwaitInScope(EmitterScope& currentScope) {
return false;
}
if (sc->asSuspendableContext()->needsPromiseResult()) {
if (sc->asFunctionBox()->needsPromiseResult()) {
if (!emitGetDotGeneratorInScope(currentScope)) {
// [stack] VALUE GENERATOR
return false;
@ -6336,14 +6302,13 @@ bool BytecodeEmitter::emitAwaitInScope(EmitterScope& currentScope) {
// 14.4.14 Runtime Semantics: Evaluation
// YieldExpression : yield* AssignmentExpression
bool BytecodeEmitter::emitYieldStar(ParseNode* iter) {
MOZ_ASSERT(sc->isSuspendableContext());
MOZ_ASSERT(sc->asSuspendableContext()->isGenerator());
MOZ_ASSERT(sc->isFunctionBox());
MOZ_ASSERT(sc->asFunctionBox()->isGenerator());
// Step 1.
IteratorKind iterKind = sc->asSuspendableContext()->isAsync()
? IteratorKind::Async
: IteratorKind::Sync;
bool needsIteratorResult = sc->asSuspendableContext()->needsIteratorResult();
IteratorKind iterKind =
sc->asFunctionBox()->isAsync() ? IteratorKind::Async : IteratorKind::Sync;
bool needsIteratorResult = sc->asFunctionBox()->needsIteratorResult();
// Steps 2-5.
if (!emitTree(iter)) {

View File

@ -220,18 +220,14 @@ struct MOZ_STACK_CLASS BytecodeEmitter {
mozilla::Maybe<NameLocation> locationOfNameBoundInScope(
const ParserAtom* name, EmitterScope* target);
// Get the location of a name known to be bound in a given scope,
// starting at the source scope.
template <typename T>
mozilla::Maybe<NameLocation> locationOfNameBoundInScopeType(
const ParserAtom* name, EmitterScope* source);
// Get the location of a name known to be bound in the function scope,
// starting at the source scope.
mozilla::Maybe<NameLocation> locationOfNameBoundInFunctionScope(
const ParserAtom* name, EmitterScope* source);
mozilla::Maybe<NameLocation> locationOfNameBoundInFunctionScope(
const ParserAtom* name) {
return locationOfNameBoundInScopeType<FunctionScope>(
name, innermostEmitterScope());
return locationOfNameBoundInFunctionScope(name, innermostEmitterScope());
}
void setVarEmitterScope(EmitterScope* emitterScope) {

View File

@ -10,7 +10,6 @@
#include "mozilla/Unused.h"
#include "builtin/ModuleObject.h" // ModuleObject
#include "frontend/AsyncEmitter.h" // AsyncEmitter
#include "frontend/BytecodeEmitter.h" // BytecodeEmitter
#include "frontend/FunctionSyntaxKind.h" // FunctionSyntaxKind
#include "frontend/ModuleSharedContext.h" // ModuleSharedContext
@ -356,10 +355,6 @@ bool FunctionScriptEmitter::prepareForParameters() {
}
}
if (funbox_->needsPromiseResult()) {
asyncEmitter_.emplace(bce_);
}
if (bodyEnd_) {
bce_->setFunctionBodyEndPos(*bodyEnd_);
}
@ -401,15 +396,14 @@ bool FunctionScriptEmitter::prepareForParameters() {
}
}
if (funbox_->needsPromiseResult()) {
if (funbox_->hasParameterExprs) {
if (!asyncEmitter_->prepareForParamsWithExpression()) {
return false;
}
} else {
if (!asyncEmitter_->prepareForParamsWithoutExpression()) {
return false;
}
// Parameters can't reuse the reject try-catch block from the function body,
// because the body may have pushed an additional var-environment. This
// messes up scope resolution for the |.generator| variable, because we'd
// need different hops to reach |.generator| depending on whether the error
// was thrown from the parameters or the function body.
if (funbox_->hasParameterExprs && funbox_->needsPromiseResult()) {
if (!emitAsyncFunctionRejectPrologue()) {
return false;
}
}
@ -424,8 +418,8 @@ bool FunctionScriptEmitter::prepareForBody() {
// [stack]
if (funbox_->needsPromiseResult()) {
if (!asyncEmitter_->emitParamsEpilogue()) {
if (rejectTryCatch_) {
if (!emitAsyncFunctionRejectEpilogue()) {
return false;
}
}
@ -436,7 +430,7 @@ bool FunctionScriptEmitter::prepareForBody() {
}
if (funbox_->needsPromiseResult()) {
if (!asyncEmitter_->prepareForBody()) {
if (!emitAsyncFunctionRejectPrologue()) {
return false;
}
}
@ -456,6 +450,47 @@ bool FunctionScriptEmitter::prepareForBody() {
return true;
}
bool FunctionScriptEmitter::emitAsyncFunctionRejectPrologue() {
rejectTryCatch_.emplace(bce_, TryEmitter::Kind::TryCatch,
TryEmitter::ControlKind::NonSyntactic);
return rejectTryCatch_->emitTry();
}
bool FunctionScriptEmitter::emitAsyncFunctionRejectEpilogue() {
if (!rejectTryCatch_->emitCatch()) {
// [stack] EXC
return false;
}
if (!bce_->emitGetDotGeneratorInInnermostScope()) {
// [stack] EXC GEN
return false;
}
if (!bce_->emit2(JSOp::AsyncResolve,
uint8_t(AsyncFunctionResolveKind::Reject))) {
// [stack] PROMISE
return false;
}
if (!bce_->emit1(JSOp::SetRval)) {
// [stack]
return false;
}
if (!bce_->emitGetDotGeneratorInInnermostScope()) {
// [stack] GEN
return false;
}
if (!bce_->emitYieldOp(JSOp::FinalYieldRval)) {
// [stack]
return false;
}
if (!rejectTryCatch_->emitEnd()) {
return false;
}
rejectTryCatch_.reset();
return true;
}
bool FunctionScriptEmitter::emitExtraBodyVarScope() {
// [stack]
@ -524,73 +559,58 @@ bool FunctionScriptEmitter::emitExtraBodyVarScope() {
bool FunctionScriptEmitter::emitEndBody() {
MOZ_ASSERT(state_ == State::Body);
// [stack]
if (funbox_->needsFinalYield()) {
// If we fall off the end of a generator, do a final yield.
if (funbox_->needsIteratorResult()) {
MOZ_ASSERT(!funbox_->needsPromiseResult());
// Emit final yield bytecode for generators, for example:
// function gen * () { ... }
bool needsIteratorResult = funbox_->needsIteratorResult();
if (needsIteratorResult) {
if (!bce_->emitPrepareIteratorResult()) {
// [stack] RESULT
return false;
}
}
if (!bce_->emit1(JSOp::Undefined)) {
// [stack] RESULT? UNDEF
return false;
}
if (!bce_->emit1(JSOp::Undefined)) {
// [stack] RESULT? UNDEF
return false;
}
if (needsIteratorResult) {
if (!bce_->emitFinishIteratorResult(true)) {
// [stack] RESULT
return false;
}
}
if (!bce_->emit1(JSOp::SetRval)) {
// [stack]
return false;
}
if (funbox_->needsPromiseResult()) {
if (!bce_->emitGetDotGeneratorInInnermostScope()) {
// [stack] GEN
// [stack] RVAL GEN
return false;
}
// No need to check for finally blocks, etc as in EmitReturn.
if (!bce_->emitYieldOp(JSOp::FinalYieldRval)) {
// [stack]
return false;
}
} else if (funbox_->needsPromiseResult()) {
// Emit final yield bytecode for async functions, for example:
// async function deferred() { ... }
if (!asyncEmitter_->emitEnd()) {
return false;
}
} else {
// Emit final yield bytecode for async generators, for example:
// async function asyncgen * () { ... }
if (!bce_->emit1(JSOp::Undefined)) {
// [stack] RESULT? UNDEF
if (!bce_->emit2(JSOp::AsyncResolve,
uint8_t(AsyncFunctionResolveKind::Fulfill))) {
// [stack] PROMISE
return false;
}
}
if (!bce_->emit1(JSOp::SetRval)) {
// [stack]
return false;
}
if (!bce_->emit1(JSOp::SetRval)) {
// [stack]
return false;
}
if (!bce_->emitGetDotGeneratorInInnermostScope()) {
// [stack] GEN
return false;
}
if (!bce_->emitGetDotGeneratorInInnermostScope()) {
// [stack] GEN
return false;
}
// No need to check for finally blocks, etc as in EmitReturn.
if (!bce_->emitYieldOp(JSOp::FinalYieldRval)) {
// [stack]
return false;
}
// No need to check for finally blocks, etc as in EmitReturn.
if (!bce_->emitYieldOp(JSOp::FinalYieldRval)) {
// [stack]
return false;
}
} else {
// Non-generator functions just return |undefined|. The
@ -617,6 +637,12 @@ bool FunctionScriptEmitter::emitEndBody() {
}
}
if (rejectTryCatch_) {
if (!emitAsyncFunctionRejectEpilogue()) {
return false;
}
}
if (extraBodyVarEmitterScope_) {
if (!extraBodyVarEmitterScope_->leave(bce_)) {
return false;

View File

@ -11,12 +11,12 @@
#include <stdint.h> // uint16_t, uint32_t
#include "frontend/AsyncEmitter.h" // AsyncEmitter
#include "frontend/DefaultEmitter.h" // DefaultEmitter
#include "frontend/EmitterScope.h" // EmitterScope
#include "frontend/FunctionSyntaxKind.h" // FunctionSyntaxKind
#include "frontend/SharedContext.h" // FunctionBox, TopLevelFunction
#include "frontend/TDZCheckCache.h" // TDZCheckCache
#include "frontend/TryEmitter.h" // TryEmitter
#include "gc/Rooting.h" // JS::Rooted, JS::Handle
#include "vm/BytecodeUtil.h" // JSOp
#include "vm/JSAtom.h" // JSAtom
@ -185,7 +185,7 @@ class MOZ_STACK_CLASS FunctionScriptEmitter {
mozilla::Maybe<TDZCheckCache> tdzCache_;
// try-catch block for async function parameter and body.
mozilla::Maybe<AsyncEmitter> asyncEmitter_;
mozilla::Maybe<TryEmitter> rejectTryCatch_;
// See the comment for constructor.
mozilla::Maybe<uint32_t> paramStart_;
@ -254,6 +254,11 @@ class MOZ_STACK_CLASS FunctionScriptEmitter {
private:
MOZ_MUST_USE bool emitExtraBodyVarScope();
// Async functions have implicit try-catch blocks to convert exceptions
// into promise rejections.
MOZ_MUST_USE bool emitAsyncFunctionRejectPrologue();
MOZ_MUST_USE bool emitAsyncFunctionRejectEpilogue();
};
// Class for emitting function parameters.
@ -316,7 +321,7 @@ class MOZ_STACK_CLASS FunctionParamsEmitter {
// | |
// +------------+ |
// | |
// | [single binding, without default] |
// | [single binding, wihtout default] |
// | emitSimple |
// +--------------------------------------------------------->+
// | ^

View File

@ -14,7 +14,6 @@
#include "frontend/SharedContext.h" // js::frontend::SharedContext
#include "js/RootingAPI.h" // JS::Handle, JS::Rooted
#include "vm/Scope.h" // js::{Module,}Scope
#include "vm/StencilEnums.h" // ImmutableScriptFlagsEnum
namespace js {
@ -24,7 +23,7 @@ namespace frontend {
struct CompilationInfo;
class MOZ_STACK_CLASS ModuleSharedContext : public SuspendableContext {
class MOZ_STACK_CLASS ModuleSharedContext : public SharedContext {
public:
ParserModuleScopeData* bindings;
ModuleBuilder& builder;

View File

@ -701,21 +701,6 @@ bool ParseContext::declareDotGeneratorName() {
return true;
}
bool ParseContext::declareTopLevelDotGeneratorName() {
// Provide a .generator binding on the module scope for compatibility with
// generator code, which expect to find it on the CallObject for normal
// generators.
MOZ_ASSERT(
sc()->isModuleContext(),
"Tried to declare top level dot generator in a non-module context.");
ParseContext::Scope& modScope = varScope();
const ParserName* dotGenerator = sc()->cx_->parserNames().dotGenerator;
AddDeclaredNamePtr p = modScope.lookupDeclaredNameForAdd(dotGenerator);
return p ||
modScope.addDeclaredName(this, p, dotGenerator, DeclarationKind::Var,
DeclaredNameInfo::npos);
}
} // namespace frontend
} // namespace js

View File

@ -11,7 +11,6 @@
#include "frontend/BytecodeCompiler.h"
#include "frontend/CompilationInfo.h"
#include "frontend/ErrorReporter.h"
#include "frontend/ModuleSharedContext.h"
#include "frontend/NameAnalysisTypes.h" // DeclaredNameInfo
#include "frontend/NameCollections.h"
#include "frontend/SharedContext.h"
@ -478,27 +477,6 @@ class ParseContext : public Nestable<ParseContext> {
// be at top level.
bool atTopLevel() { return atBodyLevel() && sc_->isTopLevelContext(); }
bool atModuleTopLevel() {
// True if we are at the topmost level of an entire module.
//
// For example, this is used to determine if an await statement should
// mark a module as an async module during parsing.
//
// Example module:
// import x from "y";
//
// await x.foo(); // mark as Top level await.
//
// if (cond) {
// await x.bar(); // mark as Top level await.
// }
//
// async function z() {
// await x.baz(); // do not mark as Top level await.
// }
return sc_->isModuleContext() && sc_->isTopLevelContext();
}
void setSuperScopeNeedsHomeObject() {
MOZ_ASSERT(sc_->allowSuperProperty());
superScopeNeedsHomeObject_ = true;
@ -521,8 +499,7 @@ class ParseContext : public Nestable<ParseContext> {
}
bool isAsync() const {
return sc_->isSuspendableContext() &&
sc_->asSuspendableContext()->isAsync();
return sc_->isFunctionBox() && sc_->asFunctionBox()->isAsync();
}
bool isGeneratorOrAsync() const { return isGenerator() || isAsync(); }
@ -566,7 +543,6 @@ class ParseContext : public Nestable<ParseContext> {
bool declareFunctionArgumentsObject(const UsedNameTracker& usedNames,
bool canSkipLazyClosedOverBindings);
bool declareDotGeneratorName();
bool declareTopLevelDotGeneratorName();
private:
MOZ_MUST_USE bool isVarRedeclaredInInnermostScope(

View File

@ -1733,16 +1733,6 @@ ModuleNode* Parser<FullParseHandler, Unit>::moduleBody(
MOZ_ASSERT(stmtList->isKind(ParseNodeKind::StatementList));
moduleNode->setBody(&stmtList->as<ListNode>());
if (pc_->isAsync()) {
if (!noteUsedName(cx_->parserNames().dotGenerator)) {
return null();
}
if (!pc_->declareTopLevelDotGeneratorName()) {
return null();
}
}
TokenKind tt;
if (!tokenStream.getToken(&tt, TokenStream::SlashIsRegExp)) {
return null();
@ -1752,12 +1742,6 @@ ModuleNode* Parser<FullParseHandler, Unit>::moduleBody(
return null();
}
// Set the module to async if an await keyword was found at the top level.
if (pc_->isAsync()) {
pc_->sc()->asModuleContext()->builder.noteAsync(
this->compilationInfo_.stencil.moduleMetadata);
}
// Generate the Import/Export tables and store in CompilationInfo.
if (!modulesc->builder.buildTables(
this->compilationInfo_.stencil.moduleMetadata)) {
@ -6276,18 +6260,12 @@ typename ParseHandler::Node GeneralParser<ParseHandler, Unit>::forStatement(
IteratorKind iterKind = IteratorKind::Sync;
unsigned iflags = 0;
if (pc_->isAsync() || pc_->sc()->isModuleContext()) {
if (pc_->isAsync()) {
bool matched;
if (!tokenStream.matchToken(&matched, TokenKind::Await)) {
return null();
}
// If we come across a top level await here, mark the module as async.
if (matched && pc_->sc()->isModuleContext() && !pc_->isAsync()) {
pc_->sc()->asModuleContext()->setIsAsync();
MOZ_ASSERT(pc_->isAsync());
}
if (matched) {
iflags |= JSITER_FORAWAITOF;
iterKind = IteratorKind::Async;
@ -8284,19 +8262,6 @@ typename ParseHandler::Node GeneralParser<ParseHandler, Unit>::statement(
}
default: {
// If we encounter an await in a module, and the module is not marked
// as async, mark the module as async.
if (tt == TokenKind::Await && !pc_->isAsync()) {
if (pc_->atModuleTopLevel()) {
if (!options().topLevelAwait) {
error(JSMSG_TOP_LEVEL_AWAIT_NOT_SUPPORTED);
return null();
}
pc_->sc()->asModuleContext()->setIsAsync();
MOZ_ASSERT(pc_->isAsync());
}
}
// Avoid getting next token with SlashIsDiv.
if (tt == TokenKind::Await && pc_->isAsync()) {
return expressionStatement(yieldHandling);
@ -8541,19 +8506,6 @@ GeneralParser<ParseHandler, Unit>::statementListItem(
}
default: {
// If we encounter an await in a module, and the module is not marked
// as async, mark the module as async.
if (tt == TokenKind::Await && !pc_->isAsync()) {
if (pc_->atModuleTopLevel()) {
if (!options().topLevelAwait) {
error(JSMSG_TOP_LEVEL_AWAIT_NOT_SUPPORTED);
return null();
}
pc_->sc()->asModuleContext()->setIsAsync();
MOZ_ASSERT(pc_->isAsync());
}
}
// Avoid getting next token with SlashIsDiv.
if (tt == TokenKind::Await && pc_->isAsync()) {
return expressionStatement(yieldHandling);
@ -9562,16 +9514,6 @@ typename ParseHandler::Node GeneralParser<ParseHandler, Unit>::unaryExpr(
}
case TokenKind::Await: {
// If we encounter an await in a module, mark it as async.
if (!pc_->isAsync() && pc_->sc()->isModule()) {
if (!options().topLevelAwait) {
error(JSMSG_TOP_LEVEL_AWAIT_NOT_SUPPORTED);
return null();
}
pc_->sc()->asModuleContext()->setIsAsync();
MOZ_ASSERT(pc_->isAsync());
}
if (pc_->isAsync()) {
if (inParametersOfAsyncFunction()) {
error(JSMSG_AWAIT_IN_PARAMETER);

View File

@ -708,7 +708,6 @@ class MOZ_STACK_CLASS GeneralParser : public PerHandlerParser<ParseHandler> {
using Base::hasValidSimpleStrictParameterNames;
using Base::isUnexpectedEOF_;
using Base::nameIsArgumentsOrEval;
using Base::newDotGeneratorName;
using Base::newFunction;
using Base::newFunctionBox;
using Base::newName;
@ -751,7 +750,6 @@ class MOZ_STACK_CLASS GeneralParser : public PerHandlerParser<ParseHandler> {
using Base::anyChars;
using Base::cx_;
using Base::handler_;
using Base::noteUsedName;
using Base::pc_;
using Base::usedNames_;
@ -760,11 +758,13 @@ class MOZ_STACK_CLASS GeneralParser : public PerHandlerParser<ParseHandler> {
using Base::finishFunction;
using Base::identifierReference;
using Base::leaveInnerFunction;
using Base::newDotGeneratorName;
using Base::newInternalDotName;
using Base::newThisName;
using Base::nextTokenContinuesLetDeclaration;
using Base::noSubstitutionTaggedTemplate;
using Base::noteDestructuredPositionalFormalParameter;
using Base::noteUsedName;
using Base::prefixAccessorName;
using Base::privateNameReference;
using Base::processExport;
@ -1648,7 +1648,6 @@ class MOZ_STACK_CLASS Parser<FullParseHandler, Unit> final
using Base::newName;
using Base::newVarScopeData;
using Base::noteDeclaredName;
using Base::noteUsedName;
using Base::null;
using Base::propagateFreeNamesAndMarkClosedOverBindings;
using Base::statementList;

View File

@ -224,24 +224,12 @@ EvalSharedContext::EvalSharedContext(JSContext* cx,
inWith_ = compilationState.scopeContext.inWith;
}
SuspendableContext::SuspendableContext(JSContext* cx, Kind kind,
CompilationInfo& compilationInfo,
Directives directives,
SourceExtent extent, bool isGenerator,
bool isAsync)
: SharedContext(cx, kind, compilationInfo, directives, extent) {
setFlag(ImmutableFlags::IsGenerator, isGenerator);
setFlag(ImmutableFlags::IsAsync, isAsync);
}
FunctionBox::FunctionBox(JSContext* cx, SourceExtent extent,
CompilationInfo& compilationInfo,
Directives directives, GeneratorKind generatorKind,
FunctionAsyncKind asyncKind, const ParserAtom* atom,
FunctionFlags flags, FunctionIndex index)
: SuspendableContext(cx, Kind::FunctionBox, compilationInfo, directives,
extent, generatorKind == GeneratorKind::Generator,
asyncKind == FunctionAsyncKind::AsyncFunction),
: SharedContext(cx, Kind::FunctionBox, compilationInfo, directives, extent),
atom_(atom),
funcDataIndex_(index),
flags_(FunctionFlags::clearMutableflags(flags)),
@ -253,7 +241,12 @@ FunctionBox::FunctionBox(JSContext* cx, SourceExtent extent,
hasDestructuringArgs(false),
hasDuplicateParameters(false),
hasExprBody_(false),
isFunctionFieldCopiedToStencil(false) {}
isFunctionFieldCopiedToStencil(false) {
setFlag(ImmutableFlags::IsGenerator,
generatorKind == GeneratorKind::Generator);
setFlag(ImmutableFlags::IsAsync,
asyncKind == FunctionAsyncKind::AsyncFunction);
}
void FunctionBox::initFromLazyFunction(JSFunction* fun) {
BaseScript* lazy = fun->baseScript();
@ -386,9 +379,8 @@ ModuleSharedContext::ModuleSharedContext(JSContext* cx,
CompilationInfo& compilationInfo,
ModuleBuilder& builder,
SourceExtent extent)
: SuspendableContext(cx, Kind::Module, compilationInfo, Directives(true),
extent, /* isGenerator = */ false,
/* isAsync = */ false),
: SharedContext(cx, Kind::Module, compilationInfo, Directives(true),
extent),
bindings(nullptr),
builder(builder) {
thisBinding_ = ThisBinding::Module;

View File

@ -108,7 +108,6 @@ enum class ThisBinding : uint8_t {
class GlobalSharedContext;
class EvalSharedContext;
class ModuleSharedContext;
class SuspendableContext;
using ParserBindingName = AbstractBindingName<const ParserAtom>;
using ParserBindingIter = AbstractBindingIter<const ParserAtom>;
@ -231,8 +230,6 @@ class SharedContext {
inline FunctionBox* asFunctionBox();
bool isModuleContext() const { return isModule(); }
inline ModuleSharedContext* asModuleContext();
bool isSuspendableContext() const { return isFunction() || isModule(); }
inline SuspendableContext* asSuspendableContext();
bool isGlobalContext() const {
return !(isFunction() || isModule() || isForEval());
}
@ -319,23 +316,7 @@ inline EvalSharedContext* SharedContext::asEvalContext() {
enum class HasHeritage { No, Yes };
class SuspendableContext : public SharedContext {
public:
SuspendableContext(JSContext* cx, Kind kind, CompilationInfo& compilationInfo,
Directives directives, SourceExtent extent,
bool isGenerator, bool isAsync);
IMMUTABLE_FLAG_GETTER_SETTER(isAsync, IsAsync)
IMMUTABLE_FLAG_GETTER_SETTER(isGenerator, IsGenerator)
bool needsFinalYield() const { return isGenerator() || isAsync(); }
bool needsDotGeneratorName() const { return isGenerator() || isAsync(); }
bool needsClearSlotsOnExit() const { return isGenerator() || isAsync(); }
bool needsIteratorResult() const { return isGenerator() && !isAsync(); }
bool needsPromiseResult() const { return isAsync() && !isGenerator(); }
};
class FunctionBox : public SuspendableContext {
class FunctionBox : public SharedContext {
friend struct GCThingList;
// If this FunctionBox refers to a lazy child of the function being
@ -701,11 +682,6 @@ inline FunctionBox* SharedContext::asFunctionBox() {
return static_cast<FunctionBox*>(this);
}
inline SuspendableContext* SharedContext::asSuspendableContext() {
MOZ_ASSERT(isSuspendableContext());
return static_cast<SuspendableContext*>(this);
}
} // namespace frontend
} // namespace js

View File

@ -1260,8 +1260,6 @@ void StencilModuleMetadata::dumpFields(js::JSONPrinter& json,
json.value("FunctionIndex(%zu)", size_t(index));
}
json.endList();
json.boolProperty("isAsync", isAsync);
}
static void DumpImmutableScriptFlags(js::JSONPrinter& json,

View File

@ -402,8 +402,6 @@ class StencilModuleMetadata {
EntryVector indirectExportEntries;
EntryVector starExportEntries;
FunctionDeclarationVector functionDecls;
// Set to true if the module has a top-level await keyword.
bool isAsync = false;
StencilModuleMetadata() = default;

View File

@ -574,19 +574,6 @@ static XDRResult XDRStencilModuleMetadata(XDRState<mode>* xdr,
}
}
uint8_t isAsync = 0;
if (mode == XDR_ENCODE) {
if (stencil.isAsync) {
isAsync = stencil.isAsync ? 1 : 0;
}
}
MOZ_TRY(xdr->codeUint8(&isAsync));
if (mode == XDR_DECODE) {
stencil.isAsync = isAsync == 1;
}
return Ok();
}

View File

@ -25,7 +25,6 @@ if CONFIG["JS_ENABLE_SMOOSH"]:
UNIFIED_SOURCES += [
"AbstractScopePtr.cpp",
"AsyncEmitter.cpp",
"BytecodeCompiler.cpp",
"BytecodeControlStructures.cpp",
"BytecodeEmitter.cpp",

View File

@ -1,2 +1,2 @@
// |jit-test| module --enable-top-level-await;
// |jit-test| module
eval("1");

View File

@ -8,11 +8,7 @@ let c = registerModule("c", parseModule(`import "a";`));
b.declarationInstantiation();
c.declarationInstantiation();
(async () => {
let count = 0;
try { await b.evaluation() } catch (e) { count++; }
try { await c.evaluation() } catch (e) { count++; }
assertEq(count, 2);
})();
drainJobQueue();
let count = 0;
try { b.evaluation() } catch (e) { count++; }
try { c.evaluation() } catch (e) { count++; }
assertEq(count, 2);

View File

@ -1,4 +1,3 @@
// |jit-test| --enable-top-level-await;
"use strict";
load(libdir + "asserts.js");
@ -14,18 +13,6 @@ let b = registerModule('b', parseModule(`
`));
a.declarationInstantiation();
a.evaluation()
.then(r => {
// We should not reach here, as we expect an error to be thrown.
assertEq(false, true);
})
.catch(e => assertEq(e instanceof UniqueError, true));
assertThrowsInstanceOf(() => a.evaluation(), UniqueError);
b.declarationInstantiation();
b.evaluation()
.then(r => {
// We should not reach here, as we expect an error to be thrown.
assertEq(false, true);
})
.catch(e => assertEq(e instanceof UniqueError, true));
drainJobQueue();
assertThrowsInstanceOf(() => b.evaluation(), UniqueError);

View File

@ -1,4 +1,3 @@
// |jit-test| --enable-top-level-await;
dbgGlobal = newGlobal({newCompartment: true});
dbg = new dbgGlobal.Debugger;
dbg.addDebuggee(this);
@ -10,20 +9,16 @@ function f() {
function execModule(source) {
m = parseModule(source);
m.declarationInstantiation();
return m.evaluation();
m.evaluation();
}
execModule("f();").then(() => {
gc();
execModule("f();");
gc();
execModule("throw 'foo'")
.then(r => {
// We should not reach here.
assertEq(false, true);
})
.catch(e => {
assertEq(e, 'foo');
});
})
drainJobQueue();
let caught;
try {
execModule("throw 'foo'");
} catch (e) {
caught = e;
}
assertEq(caught, 'foo');

View File

@ -1,3 +1,3 @@
// |jit-test| --more-compartments;
// |jit-test| --more-compartments
fullcompartmentchecks(true);
newGlobal().eval(`import("javascript:")`).catch(() => {});

View File

@ -2,11 +2,11 @@
class MyError {}
async function assertThrowsMyError(f)
function assertThrowsMyError(f)
{
let caught = false;
try {
await f();
f();
} catch (e) {
caught = true;
assertEq(e.constructor, MyError);
@ -29,5 +29,3 @@ let b = registerModule('b', parseModule(`
`));
b.declarationInstantiation();
assertThrowsMyError(() => b.evaluation(b));
drainJobQueue();

View File

@ -1,4 +1,3 @@
// |jit-test| --enable-top-level-await;
// Test importing module namespaces
"use strict";
@ -91,14 +90,7 @@ let d = registerModule('d',
parseModule("export let d = 2; import * as ns from 'c'; let c = ns.c;"));
c.declarationInstantiation();
d.declarationInstantiation();
c.evaluation()
.then(r => {
// We expect the evaluation to throw, so we should not reach this.
assertEq(false, true)
})
.catch(e => {
assertEq(e instanceof ReferenceError, true)
});
assertThrowsInstanceOf(() => c.evaluation(), ReferenceError);
// Test cyclic namespace import.
let e = registerModule('e',
@ -111,4 +103,3 @@ e.evaluation();
f.evaluation();
assertEq(e.namespace.f(), 2);
assertEq(f.namespace.e(), 1);
drainJobQueue();

View File

@ -1,46 +1,34 @@
// |jit-test| --enable-top-level-await;
// Exercise ModuleEvaluation() concrete method.
load(libdir + "asserts.js");
async function parseAndEvaluate(source) {
function parseAndEvaluate(source) {
let m = parseModule(source);
m.declarationInstantiation();
await m.evaluation();
m.evaluation();
return m;
}
// Check the evaluation of an empty module succeeds.
(async () => {
await parseAndEvaluate("");
})();
parseAndEvaluate("");
(async () => {
// Check that evaluation returns evaluation promise,
// and promise is always the same.
let m = parseModule("1");
m.declarationInstantiation();
assertEq(typeof m.evaluation(), "object");
assertEq(m.evaluation() instanceof Promise, true);
assertEq(m.evaluation(), m.evaluation());
await m.evaluation();
})();
// Check evaluation returns evaluation result the first time, then undefined.
let m = parseModule("1");
m.declarationInstantiation();
assertEq(m.evaluation(), undefined);
assertEq(typeof m.evaluation(), "undefined");
(async () => {
// Check top level variables are initialized by evaluation.
let m = parseModule("export var x = 2 + 2;");
assertEq(typeof getModuleEnvironmentValue(m, "x"), "undefined");
m.declarationInstantiation();
await m.evaluation();
assertEq(getModuleEnvironmentValue(m, "x"), 4);
})();
// Check top level variables are initialized by evaluation.
m = parseModule("export var x = 2 + 2;");
assertEq(typeof getModuleEnvironmentValue(m, "x"), "undefined");
m.declarationInstantiation();
m.evaluation();
assertEq(getModuleEnvironmentValue(m, "x"), 4);
(async () => {
let m = parseModule("export let x = 2 * 3;");
m.declarationInstantiation();
await m.evaluation();
assertEq(getModuleEnvironmentValue(m, "x"), 6);
})();
m = parseModule("export let x = 2 * 3;");
m.declarationInstantiation();
m.evaluation();
assertEq(getModuleEnvironmentValue(m, "x"), 6);
// Set up a module to import from.
let a = registerModule('a',
@ -49,77 +37,62 @@ let a = registerModule('a',
export default 2;
export function f(x) { return x + 1; }`));
(async () => {
// Check we can evaluate top level definitions.
await parseAndEvaluate("var foo = 1;");
await parseAndEvaluate("let foo = 1;");
await parseAndEvaluate("const foo = 1");
await parseAndEvaluate("function foo() {}");
await parseAndEvaluate("class foo { constructor() {} }");
// Check we can evaluate top level definitions.
parseAndEvaluate("var foo = 1;");
parseAndEvaluate("let foo = 1;");
parseAndEvaluate("const foo = 1");
parseAndEvaluate("function foo() {}");
parseAndEvaluate("class foo { constructor() {} }");
// Check we can evaluate all module-related syntax.
await parseAndEvaluate("export var foo = 1;");
await parseAndEvaluate("export let foo = 1;");
await parseAndEvaluate("export const foo = 1;");
await parseAndEvaluate("var x = 1; export { x };");
await parseAndEvaluate("export default 1");
await parseAndEvaluate("export default function() {};");
await parseAndEvaluate("export default function foo() {};");
await parseAndEvaluate("import a from 'a';");
await parseAndEvaluate("import { x } from 'a';");
await parseAndEvaluate("import * as ns from 'a';");
await parseAndEvaluate("export * from 'a'");
await parseAndEvaluate("export default class { constructor() {} };");
await parseAndEvaluate("export default class foo { constructor() {} };");
})();
// Check we can evaluate all module-related syntax.
parseAndEvaluate("export var foo = 1;");
parseAndEvaluate("export let foo = 1;");
parseAndEvaluate("export const foo = 1;");
parseAndEvaluate("var x = 1; export { x };");
parseAndEvaluate("export default 1");
parseAndEvaluate("export default function() {};");
parseAndEvaluate("export default function foo() {};");
parseAndEvaluate("import a from 'a';");
parseAndEvaluate("import { x } from 'a';");
parseAndEvaluate("import * as ns from 'a';");
parseAndEvaluate("export * from 'a'");
parseAndEvaluate("export default class { constructor() {} };");
parseAndEvaluate("export default class foo { constructor() {} };");
(async () => {
// Test default import
let m = parseModule("import a from 'a'; export { a };")
m.declarationInstantiation();
await m.evaluation()
assertEq(getModuleEnvironmentValue(m, "a"), 2);
})();
// Test default import
m = parseModule("import a from 'a'; export { a };")
m.declarationInstantiation();
m.evaluation()
assertEq(getModuleEnvironmentValue(m, "a"), 2);
(async () => {
// Test named import
let m = parseModule("import { x as y } from 'a'; export { y };")
m.declarationInstantiation();
await m.evaluation();
assertEq(getModuleEnvironmentValue(m, "y"), 1);
})();
// Test named import
m = parseModule("import { x as y } from 'a'; export { y };")
m.declarationInstantiation();
m.evaluation();
assertEq(getModuleEnvironmentValue(m, "y"), 1);
(async () => {
// Call exported function
let m = parseModule("import { f } from 'a'; export let x = f(3);")
m.declarationInstantiation();
await m.evaluation();
assertEq(getModuleEnvironmentValue(m, "x"), 4);
})();
// Call exported function
m = parseModule("import { f } from 'a'; export let x = f(3);")
m.declarationInstantiation();
m.evaluation();
assertEq(getModuleEnvironmentValue(m, "x"), 4);
(async () => {
// Test importing an indirect export
registerModule('b', parseModule("export { x as z } from 'a';"));
let m = await parseAndEvaluate("import { z } from 'b'; export { z }");
assertEq(getModuleEnvironmentValue(m, "z"), 1);
})();
// Test importing an indirect export
registerModule('b', parseModule("export { x as z } from 'a';"));
m = parseAndEvaluate("import { z } from 'b'; export { z }");
assertEq(getModuleEnvironmentValue(m, "z"), 1);
(async () => {
// Test cyclic dependencies
registerModule('c1', parseModule("export var x = 1; export {y} from 'c2'"));
registerModule('c2', parseModule("export var y = 2; export {x} from 'c1'"));
let m = await parseAndEvaluate(`import { x as x1, y as y1 } from 'c1';
import { x as x2, y as y2 } from 'c2';
export let z = [x1, y1, x2, y2]`);
assertDeepEq(getModuleEnvironmentValue(m, "z"), [1, 2, 1, 2]);
})();
// Test cyclic dependencies
registerModule('c1', parseModule("export var x = 1; export {y} from 'c2'"));
registerModule('c2', parseModule("export var y = 2; export {x} from 'c1'"));
m = parseAndEvaluate(`import { x as x1, y as y1 } from 'c1';
import { x as x2, y as y2 } from 'c2';
export let z = [x1, y1, x2, y2]`),
assertDeepEq(getModuleEnvironmentValue(m, "z"), [1, 2, 1, 2]);
(async () => {
// Import access in functions
let m = await parseModule("import { x } from 'a'; function f() { return x; }")
m.declarationInstantiation();
m.evaluation();
let f = getModuleEnvironmentValue(m, "f");
assertEq(f(), 1);
})();
drainJobQueue();
// Import access in functions
m = parseModule("import { x } from 'a'; function f() { return x; }")
m.declarationInstantiation();
m.evaluation();
let f = getModuleEnvironmentValue(m, "f");
assertEq(f(), 1);

View File

@ -1,4 +1,3 @@
// |jit-test| --enable-top-level-await;
// Test 'this' is undefined in modules.
function parseAndEvaluate(source) {
@ -7,19 +6,10 @@ function parseAndEvaluate(source) {
return m.evaluation();
}
parseAndEvaluate("this")
.then(value => assertEq(typeof(value), "undefined"))
.catch(error => {
// We shouldn't throw in this case.
assertEq(false, true)
});
assertEq(typeof(parseAndEvaluate("this")), "undefined");
let m = parseModule("export function getThis() { return this; }");
m.declarationInstantiation();
m.evaluation()
.then(() => {
let f = getModuleEnvironmentValue(m, "getThis");
assertEq(typeof(f()), "undefined");
});
drainJobQueue();
m.evaluation();
let f = getModuleEnvironmentValue(m, "getThis");
assertEq(typeof(f()), "undefined");

View File

@ -1,93 +1,81 @@
// |jit-test| --enable-top-level-await;
load(libdir + "asserts.js");
async function parseAndEvaluate(source) {
function parseAndEvaluate(source) {
let og = parseModule(source);
let bc = codeModule(og);
let m = decodeModule(bc);
m.declarationInstantiation();
await m.evaluation();
m.evaluation();
return m;
}
(async () => {
// Check the evaluation of an empty module succeeds.
await parseAndEvaluate("");
})();
// Check the evaluation of an empty module succeeds.
parseAndEvaluate("");
(async () => {
// Check that evaluation returns evaluation promise,
// and promise is always the same.
let og = parseModule("1");
let bc = codeModule(og);
let m = decodeModule(bc);
m.declarationInstantiation();
assertEq(typeof m.evaluation(), "object");
assertEq(m.evaluation() instanceof Promise, true);
assertEq(m.evaluation(), m.evaluation());
})();
// Check evaluation returns evaluation result the first time, then undefined.
let og = parseModule("1");
let bc = codeModule(og);
let m = decodeModule(bc);
m.declarationInstantiation();
assertEq(m.evaluation(), undefined);
assertEq(typeof m.evaluation(), "undefined");
(async () => {
// Check top level variables are initialized by evaluation.
let og = parseModule("export var x = 2 + 2;");
let bc = codeModule(og);
let m = decodeModule(bc);
assertEq(typeof getModuleEnvironmentValue(m, "x"), "undefined");
m.declarationInstantiation();
await m.evaluation();
assertEq(getModuleEnvironmentValue(m, "x"), 4);
})();
// Check top level variables are initialized by evaluation.
og = parseModule("export var x = 2 + 2;");
bc = codeModule(og);
m = decodeModule(bc);
assertEq(typeof getModuleEnvironmentValue(m, "x"), "undefined");
m.declarationInstantiation();
m.evaluation();
assertEq(getModuleEnvironmentValue(m, "x"), 4);
(async () => {
let m = await parseAndEvaluate("export let x = 2 * 3;");
assertEq(getModuleEnvironmentValue(m, "x"), 6);
m = parseAndEvaluate("export let x = 2 * 3;");
assertEq(getModuleEnvironmentValue(m, "x"), 6);
// Set up a module to import from.
let og = parseModule(`var x = 1;
export { x };
export default 2;
export function f(x) { return x + 1; }`);
let bc = codeModule(og);
let a = registerModule('a', decodeModule(bc));
// Set up a module to import from.
og = parseModule(`var x = 1;
export { x };
export default 2;
export function f(x) { return x + 1; }`);
bc = codeModule(og);
a = registerModule('a', decodeModule(bc));
// Check we can evaluate top level definitions.
await parseAndEvaluate("var foo = 1;");
await parseAndEvaluate("let foo = 1;");
await parseAndEvaluate("const foo = 1");
await parseAndEvaluate("function foo() {}");
await parseAndEvaluate("class foo { constructor() {} }");
// Check we can evaluate top level definitions.
parseAndEvaluate("var foo = 1;");
parseAndEvaluate("let foo = 1;");
parseAndEvaluate("const foo = 1");
parseAndEvaluate("function foo() {}");
parseAndEvaluate("class foo { constructor() {} }");
// Check we can evaluate all module-related syntax.
await parseAndEvaluate("export var foo = 1;");
await parseAndEvaluate("export let foo = 1;");
await parseAndEvaluate("export const foo = 1;");
await parseAndEvaluate("var x = 1; export { x };");
await parseAndEvaluate("export default 1");
await parseAndEvaluate("export default function() {};");
await parseAndEvaluate("export default function foo() {};");
await parseAndEvaluate("import a from 'a';");
await parseAndEvaluate("import { x } from 'a';");
await parseAndEvaluate("import * as ns from 'a';");
await parseAndEvaluate("export * from 'a'");
await parseAndEvaluate("export default class { constructor() {} };");
await parseAndEvaluate("export default class foo { constructor() {} };");
// Check we can evaluate all module-related syntax.
parseAndEvaluate("export var foo = 1;");
parseAndEvaluate("export let foo = 1;");
parseAndEvaluate("export const foo = 1;");
parseAndEvaluate("var x = 1; export { x };");
parseAndEvaluate("export default 1");
parseAndEvaluate("export default function() {};");
parseAndEvaluate("export default function foo() {};");
parseAndEvaluate("import a from 'a';");
parseAndEvaluate("import { x } from 'a';");
parseAndEvaluate("import * as ns from 'a';");
parseAndEvaluate("export * from 'a'");
parseAndEvaluate("export default class { constructor() {} };");
parseAndEvaluate("export default class foo { constructor() {} };");
// Test default import
m = await parseAndEvaluate("import a from 'a'; export { a };")
assertEq(getModuleEnvironmentValue(m, "a"), 2);
// Test default import
m = parseAndEvaluate("import a from 'a'; export { a };")
assertEq(getModuleEnvironmentValue(m, "a"), 2);
// Test named import
m = await parseAndEvaluate("import { x as y } from 'a'; export { y };")
assertEq(getModuleEnvironmentValue(m, "y"), 1);
// Test named import
m = parseAndEvaluate("import { x as y } from 'a'; export { y };")
assertEq(getModuleEnvironmentValue(m, "y"), 1);
// Call exported function
m = await parseAndEvaluate("import { f } from 'a'; export let x = f(3);")
assertEq(getModuleEnvironmentValue(m, "x"), 4);
// Call exported function
m = parseAndEvaluate("import { f } from 'a'; export let x = f(3);")
assertEq(getModuleEnvironmentValue(m, "x"), 4);
// Import access in functions
m = await parseAndEvaluate("import { x } from 'a'; function f() { return x; }")
let f = getModuleEnvironmentValue(m, "f");
assertEq(f(), 1);
})();
drainJobQueue();
// Import access in functions
m = parseAndEvaluate("import { x } from 'a'; function f() { return x; }")
let f = getModuleEnvironmentValue(m, "f");
assertEq(f(), 1);

View File

@ -362,9 +362,7 @@ class BaselineFrame {
bool isGlobalFrame() const { return script()->isGlobalCode(); }
bool isModuleFrame() const { return script()->isModule(); }
bool isEvalFrame() const { return script()->isForEval(); }
bool isFunctionFrame() const {
return CalleeTokenIsFunction(calleeToken()) && !isModuleFrame();
}
bool isFunctionFrame() const { return CalleeTokenIsFunction(calleeToken()); }
bool isDebuggerEvalFrame() const { return false; }
JitFrameLayout* framePrefix() const {

View File

@ -523,7 +523,7 @@ JS_PUBLIC_API JSErrorInterceptor* JS_GetErrorInterceptorCallback(
JSRuntime* rt) {
#if defined(NIGHTLY_BUILD)
return rt->errorInterception.interceptor;
#else // !NIGHTLY_BUILD
#else // !NIGHTLY_BUILD
return nullptr;
#endif // defined(NIGHTLY_BUILD)
}
@ -3461,7 +3461,6 @@ void JS::TransitiveCompileOptions::copyPODTransitiveOptions(
nonSyntacticScope = rhs.nonSyntacticScope;
privateClassFields = rhs.privateClassFields;
privateClassMethods = rhs.privateClassMethods;
topLevelAwait = rhs.topLevelAwait;
useStencilXDR = rhs.useStencilXDR;
useOffThreadParseGlobal = rhs.useOffThreadParseGlobal;
};
@ -3557,7 +3556,6 @@ JS::CompileOptions::CompileOptions(JSContext* cx)
cx->options().throwOnAsmJSValidationFailure();
privateClassFields = cx->options().privateClassFields();
privateClassMethods = cx->options().privateClassMethods();
topLevelAwait = cx->options().topLevelAwait();
useStencilXDR = !UseOffThreadParseGlobal();
useOffThreadParseGlobal = UseOffThreadParseGlobal();

View File

@ -89,20 +89,7 @@ bool ModuleLoader::ImportModuleDynamically(JSContext* cx,
}
bool ModuleLoader::loadRootModule(JSContext* cx, HandleString path) {
RootedValue rval(cx);
if (!loadAndExecute(cx, path, &rval)) {
return false;
}
if (cx->options().topLevelAwait()) {
RootedObject evaluationPromise(cx, &rval.toObject());
if (evaluationPromise == nullptr) {
return false;
}
return JS::ThrowOnModuleEvaluationFailure(cx, evaluationPromise);
}
return true;
return loadAndExecute(cx, path);
}
bool ModuleLoader::registerTestModule(JSContext* cx, HandleString specifier,
@ -120,18 +107,13 @@ bool ModuleLoader::registerTestModule(JSContext* cx, HandleString specifier,
return addModuleToRegistry(cx, path, module);
}
bool ModuleLoader::loadAndExecute(JSContext* cx, HandleString path,
MutableHandleValue rval) {
bool ModuleLoader::loadAndExecute(JSContext* cx, HandleString path) {
RootedObject module(cx, loadAndParse(cx, path));
if (!module) {
return false;
}
if (!JS::ModuleInstantiate(cx, module)) {
return false;
}
return JS::ModuleEvaluate(cx, module, rval);
return JS::ModuleInstantiate(cx, module) && JS::ModuleEvaluate(cx, module);
}
JSObject* ModuleLoader::resolveImportedModule(
@ -244,31 +226,23 @@ bool ModuleLoader::doDynamicImport(JSContext* cx,
JS::HandleObject promise) {
// Exceptions during dynamic import are handled by calling
// FinishDynamicModuleImport with a pending exception on the context.
RootedValue rval(cx);
bool ok = tryDynamicImport(cx, referencingPrivate, specifier, promise, &rval);
if (cx->options().topLevelAwait()) {
JSObject* evaluationObject = ok ? &rval.toObject() : nullptr;
RootedObject evaluationPromise(cx, evaluationObject);
return JS::FinishDynamicModuleImport(
cx, evaluationPromise, referencingPrivate, specifier, promise);
}
bool ok = tryDynamicImport(cx, referencingPrivate, specifier, promise);
JS::DynamicImportStatus status =
ok ? JS::DynamicImportStatus::Ok : JS::DynamicImportStatus::Failed;
return JS::FinishDynamicModuleImport_NoTLA(cx, status, referencingPrivate,
specifier, promise);
return JS::FinishDynamicModuleImport(cx, status, referencingPrivate,
specifier, promise);
}
bool ModuleLoader::tryDynamicImport(JSContext* cx,
JS::HandleValue referencingPrivate,
JS::HandleString specifier,
JS::HandleObject promise,
JS::MutableHandleValue rval) {
JS::HandleObject promise) {
RootedLinearString path(cx, resolve(cx, specifier, referencingPrivate));
if (!path) {
return false;
}
return loadAndExecute(cx, path, rval);
return loadAndExecute(cx, path);
}
JSLinearString* ModuleLoader::resolve(JSContext* cx, HandleString nameArg,

View File

@ -39,7 +39,7 @@ class ModuleLoader {
static bool DynamicImportDelayRejected(JSContext* cx, unsigned argc,
Value* vp);
bool loadAndExecute(JSContext* cx, HandleString path, MutableHandleValue);
bool loadAndExecute(JSContext* cx, HandleString path);
JSObject* resolveImportedModule(JSContext* cx, HandleValue referencingPrivate,
HandleString specifier);
bool populateImportMeta(JSContext* cx, HandleValue privateValue,
@ -49,8 +49,7 @@ class ModuleLoader {
bool doDynamicImport(JSContext* cx, HandleValue referencingPrivate,
HandleString specifier, HandleObject promise);
bool tryDynamicImport(JSContext* cx, HandleValue referencingPrivate,
HandleString specifier, HandleObject promise,
MutableHandleValue rval);
HandleString specifier, HandleObject promise);
JSObject* loadAndParse(JSContext* cx, HandleString path);
bool lookupModuleInRegistry(JSContext* cx, HandleString path,
MutableHandleObject moduleOut);

View File

@ -531,7 +531,6 @@ bool shell::enablePropertyErrorMessageFix = false;
bool shell::enableIteratorHelpers = false;
bool shell::enablePrivateClassFields = false;
bool shell::enablePrivateClassMethods = false;
bool shell::enableTopLevelAwait = false;
bool shell::useOffThreadParseGlobal = true;
#ifdef JS_GC_ZEAL
uint32_t shell::gZealBits = 0;
@ -10420,7 +10419,6 @@ static bool SetContextOptions(JSContext* cx, const OptionParser& op) {
enablePrivateClassFields = op.getBoolOption("enable-private-fields") ||
op.getBoolOption("enable-private-methods");
enablePrivateClassMethods = op.getBoolOption("enable-private-methods");
enableTopLevelAwait = op.getBoolOption("enable-top-level-await");
useOffThreadParseGlobal = !op.getBoolOption("no-off-thread-parse-global");
JS::ContextOptionsRef(cx)
@ -10452,8 +10450,7 @@ static bool SetContextOptions(JSContext* cx, const OptionParser& op) {
.setAsyncStack(enableAsyncStacks)
.setAsyncStackCaptureDebuggeeOnly(enableAsyncStackCaptureDebuggeeOnly)
.setPrivateClassFields(enablePrivateClassFields)
.setPrivateClassMethods(enablePrivateClassMethods)
.setTopLevelAwait(enableTopLevelAwait);
.setPrivateClassMethods(enablePrivateClassMethods);
JS::SetUseOffThreadParseGlobal(useOffThreadParseGlobal);
@ -11315,8 +11312,6 @@ int main(int argc, char** argv, char** envp) {
"Enable private class fields") ||
!op.addBoolOption('\0', "enable-private-methods",
"Enable private class methods") ||
!op.addBoolOption('\0', "enable-top-level-await",
"Enable top-level await") ||
!op.addBoolOption('\0', "no-off-thread-parse-global",
"Do not use parseGlobal in off-thread compilation and "
"instead instantiate stencil in main-thread") ||

View File

@ -140,7 +140,6 @@ extern bool useOffThreadParseGlobal;
extern bool enableIteratorHelpers;
extern bool enablePrivateClassFields;
extern bool enablePrivateClassMethods;
extern bool enableTopLevelAwait;
#ifdef JS_GC_ZEAL
extern uint32_t gZealBits;
extern uint32_t gZealFrequency;

View File

@ -25,6 +25,7 @@ UNSUPPORTED_FEATURES = set(
"regexp-match-indices",
"Intl.DateTimeFormat-quarter",
"Intl.Segmenter",
"top-level-await",
"Atomics.waitAsync",
"legacy-regexp",
"TypedArray.prototype.item",
@ -50,7 +51,6 @@ SHELL_OPTIONS = {
"class-static-fields-private": "--enable-private-fields",
"class-methods-private": "--enable-private-methods",
"class-static-methods-private": "--enable-private-methods",
"top-level-await": "--enable-top-level-await",
}

View File

@ -1,4 +1,4 @@
// |reftest| shell-option(--enable-top-level-await) skip-if(!xulRuntime.shell) module async -- requires shell-options
// |reftest| skip module async -- top-level-await is not supported
// Copyright 2019 Leo Balter. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.

View File

@ -1,4 +1,4 @@
// |reftest| shell-option(--enable-top-level-await) skip-if(!xulRuntime.shell) module async -- requires shell-options
// |reftest| skip module async -- top-level-await is not supported
// Copyright 2019 Leo Balter. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.

View File

@ -1,4 +1,4 @@
// |reftest| shell-option(--enable-top-level-await) skip-if(!xulRuntime.shell) module async -- requires shell-options
// |reftest| skip module async -- top-level-await is not supported
// Copyright 2019 Leo Balter. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.

View File

@ -1,4 +1,4 @@
// |reftest| shell-option(--enable-top-level-await) skip-if(!xulRuntime.shell) error:TypeError module -- requires shell-options
// |reftest| skip error:TypeError module -- top-level-await is not supported
// Copyright (C) 2019 Leo Balter. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.

View File

@ -1,4 +1,4 @@
// |reftest| shell-option(--enable-top-level-await) skip-if(!xulRuntime.shell) module async -- requires shell-options
// |reftest| skip module async -- top-level-await is not supported
// Copyright (C) 2019 Leo Balter. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.

View File

@ -1,4 +1,4 @@
// |reftest| shell-option(--enable-top-level-await) skip-if(!xulRuntime.shell) module async -- requires shell-options
// |reftest| skip module async -- top-level-await is not supported
// Copyright (C) 2019 Leo Balter. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.

View File

@ -1,4 +1,4 @@
// |reftest| shell-option(--enable-top-level-await) skip-if(!xulRuntime.shell) module async -- requires shell-options
// |reftest| skip module async -- top-level-await is not supported
// Copyright (C) 2019 Leo Balter. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.

View File

@ -1,4 +1,4 @@
// |reftest| shell-option(--enable-top-level-await) skip-if(!xulRuntime.shell) module async -- requires shell-options
// |reftest| skip module async -- top-level-await is not supported
// Copyright (C) 2019 Leo Balter. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.

View File

@ -1,4 +1,4 @@
// |reftest| shell-option(--enable-top-level-await) skip-if(!xulRuntime.shell) module async -- requires shell-options
// |reftest| skip module async -- top-level-await is not supported
// Copyright (C) 2019 Leo Balter. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.

View File

@ -1,4 +1,4 @@
// |reftest| shell-option(--enable-top-level-await) skip-if(!xulRuntime.shell) module async -- requires shell-options
// |reftest| skip module async -- top-level-await is not supported
// Copyright (C) 2019 Leo Balter. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.

View File

@ -1,4 +1,4 @@
// |reftest| shell-option(--enable-top-level-await) skip-if(!xulRuntime.shell) module async -- requires shell-options
// |reftest| skip module async -- top-level-await is not supported
// Copyright (C) 2019 Leo Balter. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.

View File

@ -1,4 +1,4 @@
// |reftest| shell-option(--enable-top-level-await) skip-if(!xulRuntime.shell) module async -- requires shell-options
// |reftest| skip module async -- top-level-await is not supported
// Copyright (C) 2019 Leo Balter. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.

View File

@ -1,4 +1,4 @@
// |reftest| shell-option(--enable-top-level-await) skip-if(!xulRuntime.shell) module async -- requires shell-options
// |reftest| skip module async -- top-level-await is not supported
// Copyright (C) 2019 Leo Balter. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.

View File

@ -1,4 +1,4 @@
// |reftest| shell-option(--enable-top-level-await) skip-if(!xulRuntime.shell) module async -- requires shell-options
// |reftest| skip module async -- top-level-await is not supported
// Copyright (C) 2019 Leo Balter. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.

View File

@ -1,4 +1,4 @@
// |reftest| shell-option(--enable-top-level-await) skip-if(!xulRuntime.shell) error:SyntaxError module -- requires shell-options
// |reftest| skip error:SyntaxError module -- top-level-await is not supported
// Copyright 2019 Leo Balter. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.

View File

@ -1,4 +1,4 @@
// |reftest| shell-option(--enable-top-level-await) skip-if(!xulRuntime.shell) module async -- requires shell-options
// |reftest| skip module async -- top-level-await is not supported
// Copyright (C) 2019 Leo Balter. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.

View File

@ -1,4 +1,4 @@
// |reftest| shell-option(--enable-top-level-await) skip-if(!xulRuntime.shell) module async -- requires shell-options
// |reftest| skip module async -- top-level-await is not supported
// Copyright (C) 2019 Leo Balter. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.

View File

@ -1,4 +1,4 @@
// |reftest| shell-option(--enable-top-level-await) skip-if(!xulRuntime.shell) error:TypeError module -- requires shell-options
// |reftest| skip error:TypeError module -- top-level-await is not supported
// Copyright (C) 2019 Leo Balter. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.

View File

@ -1,4 +1,4 @@
// |reftest| shell-option(--enable-top-level-await) skip-if(!xulRuntime.shell) error:RangeError module -- requires shell-options
// |reftest| skip error:RangeError module -- top-level-await is not supported
// Copyright (C) 2019 Leo Balter. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.

View File

@ -1,4 +1,4 @@
// |reftest| shell-option(--enable-top-level-await) skip-if(!xulRuntime.shell) error:TypeError module -- requires shell-options
// |reftest| skip error:TypeError module -- top-level-await is not supported
// Copyright (C) 2019 Leo Balter. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.

View File

@ -1,4 +1,4 @@
// |reftest| shell-option(--enable-top-level-await) skip-if(!xulRuntime.shell) module async -- requires shell-options
// |reftest| skip module async -- top-level-await is not supported
// Copyright (C) 2019 Leo Balter. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.

View File

@ -1,4 +1,4 @@
// |reftest| shell-option(--enable-top-level-await) skip-if(!xulRuntime.shell) module async -- requires shell-options
// |reftest| skip module async -- top-level-await is not supported
// Copyright (C) 2019 Leo Balter. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.

View File

@ -1,4 +1,4 @@
// |reftest| shell-option(--enable-top-level-await) skip-if(!xulRuntime.shell) module async -- requires shell-options
// |reftest| skip module async -- top-level-await is not supported
// Copyright (C) 2019 Leo Balter. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.

View File

@ -1,4 +1,4 @@
// |reftest| shell-option(--enable-top-level-await) skip-if(!xulRuntime.shell) module async -- requires shell-options
// |reftest| skip module async -- top-level-await is not supported
// Copyright (C) 2019 Leo Balter. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.

View File

@ -1,4 +1,4 @@
// |reftest| shell-option(--enable-top-level-await) skip-if(!xulRuntime.shell) module async -- requires shell-options
// |reftest| skip module async -- top-level-await is not supported
// Copyright (C) 2020 Rick Waldron. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.

View File

@ -1,4 +1,4 @@
// |reftest| shell-option(--enable-top-level-await) skip-if(!xulRuntime.shell) -- requires shell-options
// |reftest| skip -- top-level-await is not supported
// Copyright (C) 2020 Rick Waldron. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.

View File

@ -1,4 +1,4 @@
// |reftest| shell-option(--enable-top-level-await) skip-if(!xulRuntime.shell) error:SyntaxError module -- requires shell-options
// |reftest| skip error:SyntaxError module -- top-level-await is not supported
// Copyright (C) 2020 Rick Waldron. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.

View File

@ -1,4 +1,4 @@
// |reftest| shell-option(--enable-top-level-await) skip-if(!xulRuntime.shell) error:SyntaxError module -- requires shell-options
// |reftest| skip error:SyntaxError module -- top-level-await is not supported
// Copyright 2019 Leo Balter. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.

View File

@ -1,4 +1,4 @@
// |reftest| shell-option(--enable-top-level-await) skip-if(!xulRuntime.shell) module -- requires shell-options
// |reftest| skip module -- top-level-await is not supported
// Copyright (C) 2019 Leo Balter. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.

View File

@ -1,4 +1,4 @@
// |reftest| shell-option(--enable-top-level-await) skip-if(!xulRuntime.shell) module -- requires shell-options
// |reftest| skip module -- top-level-await is not supported
// This file was procedurally generated from the following sources:
// - src/top-level-await/await-expr-array-literal.case
// - src/top-level-await/syntax/block.template

View File

@ -1,4 +1,4 @@
// |reftest| shell-option(--enable-top-level-await) skip-if(!xulRuntime.shell) module -- requires shell-options
// |reftest| skip module -- top-level-await is not supported
// This file was procedurally generated from the following sources:
// - src/top-level-await/await-expr-func-expression.case
// - src/top-level-await/syntax/block.template

View File

@ -1,4 +1,4 @@
// |reftest| shell-option(--enable-top-level-await) skip-if(!xulRuntime.shell) module -- requires shell-options
// |reftest| skip module -- top-level-await is not supported
// This file was procedurally generated from the following sources:
// - src/top-level-await/await-expr-identifier.case
// - src/top-level-await/syntax/block.template

View File

@ -1,4 +1,4 @@
// |reftest| shell-option(--enable-top-level-await) skip-if(!xulRuntime.shell) module -- requires shell-options
// |reftest| skip module -- top-level-await is not supported
// This file was procedurally generated from the following sources:
// - src/top-level-await/await-expr-literal-number.case
// - src/top-level-await/syntax/block.template

View File

@ -1,4 +1,4 @@
// |reftest| shell-option(--enable-top-level-await) skip-if(!xulRuntime.shell) module -- requires shell-options
// |reftest| skip module -- top-level-await is not supported
// This file was procedurally generated from the following sources:
// - src/top-level-await/await-expr-literal-string.case
// - src/top-level-await/syntax/block.template

View File

@ -1,4 +1,4 @@
// |reftest| shell-option(--enable-top-level-await) skip-if(!xulRuntime.shell) module -- requires shell-options
// |reftest| skip module -- top-level-await is not supported
// This file was procedurally generated from the following sources:
// - src/top-level-await/await-expr-nested.case
// - src/top-level-await/syntax/block.template

View File

@ -1,4 +1,4 @@
// |reftest| shell-option(--enable-top-level-await) skip-if(!xulRuntime.shell) module -- requires shell-options
// |reftest| skip module -- top-level-await is not supported
// This file was procedurally generated from the following sources:
// - src/top-level-await/await-expr-new-expr.case
// - src/top-level-await/syntax/block.template

View File

@ -1,4 +1,4 @@
// |reftest| shell-option(--enable-top-level-await) skip-if(!xulRuntime.shell) module -- requires shell-options
// |reftest| skip module -- top-level-await is not supported
// This file was procedurally generated from the following sources:
// - src/top-level-await/await-expr-null.case
// - src/top-level-await/syntax/block.template

View File

@ -1,4 +1,4 @@
// |reftest| shell-option(--enable-top-level-await) skip-if(!xulRuntime.shell) module -- requires shell-options
// |reftest| skip module -- top-level-await is not supported
// This file was procedurally generated from the following sources:
// - src/top-level-await/await-expr-obj-literal.case
// - src/top-level-await/syntax/block.template

View File

@ -1,4 +1,4 @@
// |reftest| shell-option(--enable-top-level-await) skip-if(!xulRuntime.shell) module -- requires shell-options
// |reftest| skip module -- top-level-await is not supported
// This file was procedurally generated from the following sources:
// - src/top-level-await/await-expr-regexp.case
// - src/top-level-await/syntax/block.template

View File

@ -1,4 +1,4 @@
// |reftest| shell-option(--enable-top-level-await) skip-if(!xulRuntime.shell) module -- requires shell-options
// |reftest| skip module -- top-level-await is not supported
// This file was procedurally generated from the following sources:
// - src/top-level-await/await-expr-template-literal.case
// - src/top-level-await/syntax/block.template

View File

@ -1,4 +1,4 @@
// |reftest| shell-option(--enable-top-level-await) skip-if(!xulRuntime.shell) module -- requires shell-options
// |reftest| skip module -- top-level-await is not supported
// This file was procedurally generated from the following sources:
// - src/top-level-await/await-expr-this.case
// - src/top-level-await/syntax/block.template

View File

@ -1,4 +1,4 @@
// |reftest| shell-option(--enable-top-level-await) skip-if(!xulRuntime.shell) module -- requires shell-options
// |reftest| skip module -- top-level-await is not supported
// Copyright (C) 2019 Leo Balter. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.

Some files were not shown because too many files have changed in this diff Show More