forked from mirrors/gecko-dev
Bug 1900276 - Implement bytecode to handle using syntax in module context. r=arai
Differential Revision: https://phabricator.services.mozilla.com/D212400
This commit is contained in:
parent
de089f1a73
commit
175cb7f2fa
7 changed files with 143 additions and 20 deletions
|
|
@ -2467,6 +2467,14 @@ bool BytecodeEmitter::emitScript(ParseNode* body) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT
|
||||||
|
if (emitterScope.hasDisposables()) {
|
||||||
|
if (!emit1(JSOp::DisposeDisposables)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
if (!markSimpleBreakpoint()) {
|
if (!markSimpleBreakpoint()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1216,8 +1216,12 @@ static Maybe<ModuleScope::ParserData*> NewModuleScopeData(
|
||||||
}
|
}
|
||||||
|
|
||||||
ModuleScope::ParserData* bindings = nullptr;
|
ModuleScope::ParserData* bindings = nullptr;
|
||||||
uint32_t numBindings =
|
uint32_t numBindings = imports.length() + vars.length() + lets.length() +
|
||||||
imports.length() + vars.length() + lets.length() + consts.length();
|
consts.length()
|
||||||
|
#ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT
|
||||||
|
+ usings.length()
|
||||||
|
#endif
|
||||||
|
;
|
||||||
|
|
||||||
if (numBindings > 0) {
|
if (numBindings > 0) {
|
||||||
bindings = NewEmptyBindingData<ModuleScope>(fc, alloc, numBindings);
|
bindings = NewEmptyBindingData<ModuleScope>(fc, alloc, numBindings);
|
||||||
|
|
@ -1229,7 +1233,12 @@ static Maybe<ModuleScope::ParserData*> NewModuleScopeData(
|
||||||
InitializeBindingData(bindings, numBindings, imports,
|
InitializeBindingData(bindings, numBindings, imports,
|
||||||
&ParserModuleScopeSlotInfo::varStart, vars,
|
&ParserModuleScopeSlotInfo::varStart, vars,
|
||||||
&ParserModuleScopeSlotInfo::letStart, lets,
|
&ParserModuleScopeSlotInfo::letStart, lets,
|
||||||
&ParserModuleScopeSlotInfo::constStart, consts);
|
&ParserModuleScopeSlotInfo::constStart, consts
|
||||||
|
#ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT
|
||||||
|
,
|
||||||
|
&ParserModuleScopeSlotInfo::usingStart, usings
|
||||||
|
#endif
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return Some(bindings);
|
return Some(bindings);
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,24 @@
|
||||||
|
// |jit-test| skip-if: !getBuildConfiguration("explicit-resource-management")
|
||||||
|
|
||||||
|
load(libdir + "asserts.js");
|
||||||
|
|
||||||
|
globalThis.callOrder = [];
|
||||||
|
|
||||||
|
const m = parseModule(`
|
||||||
|
using x = {
|
||||||
|
[Symbol.dispose]() {
|
||||||
|
globalThis.callOrder.push("x");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
using y = {
|
||||||
|
[Symbol.dispose]() {
|
||||||
|
globalThis.callOrder.push("y");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`);
|
||||||
|
|
||||||
|
moduleLink(m);
|
||||||
|
moduleEvaluate(m);
|
||||||
|
|
||||||
|
assertArrayEq(globalThis.callOrder, ["y", "x"]);
|
||||||
|
|
@ -0,0 +1,16 @@
|
||||||
|
// |jit-test| skip-if: !getBuildConfiguration("explicit-resource-management")
|
||||||
|
|
||||||
|
globalThis.called = false;
|
||||||
|
|
||||||
|
const m = parseModule(`
|
||||||
|
using x = {
|
||||||
|
[Symbol.dispose]() {
|
||||||
|
globalThis.called = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`);
|
||||||
|
|
||||||
|
moduleLink(m);
|
||||||
|
moduleEvaluate(m);
|
||||||
|
|
||||||
|
assertEq(globalThis.called, true);
|
||||||
|
|
@ -414,9 +414,50 @@ ModuleEnvironmentObject* ModuleEnvironmentObject::create(
|
||||||
MOZ_ASSERT(!env->inDictionaryMode());
|
MOZ_ASSERT(!env->inDictionaryMode());
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT
|
||||||
|
env->initSlot(ModuleEnvironmentObject::DISPOSABLE_OBJECTS_SLOT,
|
||||||
|
UndefinedValue());
|
||||||
|
#endif
|
||||||
|
|
||||||
return env;
|
return env;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT
|
||||||
|
// TODO: at the time of unflagging ENABLE_EXPLICIT_RESOURCE_MANAGEMENT
|
||||||
|
// consider having a common base class for LexicalEnvironmentObject and
|
||||||
|
// ModuleEnvironmentObject containing all the common code.
|
||||||
|
static bool addDisposableObjectHelper(JS::Handle<EnvironmentObject*> env,
|
||||||
|
uint32_t slot, JSContext* cx,
|
||||||
|
JS::Handle<JS::Value> val) {
|
||||||
|
Value slotData = env->getReservedSlot(slot);
|
||||||
|
ListObject* disposablesList = nullptr;
|
||||||
|
if (slotData.isUndefined()) {
|
||||||
|
disposablesList = ListObject::create(cx);
|
||||||
|
if (!disposablesList) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
env->setReservedSlot(slot, ObjectValue(*disposablesList));
|
||||||
|
} else {
|
||||||
|
disposablesList = &slotData.toObject().as<ListObject>();
|
||||||
|
}
|
||||||
|
return disposablesList->append(cx, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ModuleEnvironmentObject::addDisposableObject(JSContext* cx,
|
||||||
|
JS::Handle<JS::Value> val) {
|
||||||
|
Rooted<ModuleEnvironmentObject*> env(cx, this);
|
||||||
|
return addDisposableObjectHelper(env, DISPOSABLE_OBJECTS_SLOT, cx, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
Value ModuleEnvironmentObject::getDisposables() {
|
||||||
|
return getReservedSlot(DISPOSABLE_OBJECTS_SLOT);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ModuleEnvironmentObject::clearDisposables() {
|
||||||
|
setReservedSlot(DISPOSABLE_OBJECTS_SLOT, UndefinedValue());
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/* static */
|
/* static */
|
||||||
ModuleEnvironmentObject* ModuleEnvironmentObject::createSynthetic(
|
ModuleEnvironmentObject* ModuleEnvironmentObject::createSynthetic(
|
||||||
JSContext* cx, Handle<ModuleObject*> module) {
|
JSContext* cx, Handle<ModuleObject*> module) {
|
||||||
|
|
@ -957,18 +998,8 @@ bool LexicalEnvironmentObject::isExtensible() const {
|
||||||
#ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT
|
#ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT
|
||||||
bool LexicalEnvironmentObject::addDisposableObject(JSContext* cx,
|
bool LexicalEnvironmentObject::addDisposableObject(JSContext* cx,
|
||||||
JS::Handle<JS::Value> val) {
|
JS::Handle<JS::Value> val) {
|
||||||
Value slotData = getReservedSlot(DISPOSABLE_OBJECTS_SLOT);
|
Rooted<LexicalEnvironmentObject*> env(cx, this);
|
||||||
ListObject* disposablesList = nullptr;
|
return addDisposableObjectHelper(env, DISPOSABLE_OBJECTS_SLOT, cx, val);
|
||||||
if (slotData.isUndefined()) {
|
|
||||||
disposablesList = ListObject::create(cx);
|
|
||||||
if (!disposablesList) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
setReservedSlot(DISPOSABLE_OBJECTS_SLOT, ObjectValue(*disposablesList));
|
|
||||||
} else {
|
|
||||||
disposablesList = &slotData.toObject().as<ListObject>();
|
|
||||||
}
|
|
||||||
return disposablesList->append(cx, val);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Value LexicalEnvironmentObject::getDisposables() {
|
Value LexicalEnvironmentObject::getDisposables() {
|
||||||
|
|
|
||||||
|
|
@ -618,6 +618,10 @@ class VarEnvironmentObject : public EnvironmentObject {
|
||||||
class ModuleEnvironmentObject : public EnvironmentObject {
|
class ModuleEnvironmentObject : public EnvironmentObject {
|
||||||
static constexpr uint32_t MODULE_SLOT = 1;
|
static constexpr uint32_t MODULE_SLOT = 1;
|
||||||
|
|
||||||
|
#ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT
|
||||||
|
static constexpr uint32_t DISPOSABLE_OBJECTS_SLOT = 2;
|
||||||
|
#endif
|
||||||
|
|
||||||
static const ObjectOps objectOps_;
|
static const ObjectOps objectOps_;
|
||||||
static const JSClassOps classOps_;
|
static const JSClassOps classOps_;
|
||||||
|
|
||||||
|
|
@ -626,7 +630,12 @@ class ModuleEnvironmentObject : public EnvironmentObject {
|
||||||
|
|
||||||
static const JSClass class_;
|
static const JSClass class_;
|
||||||
|
|
||||||
|
#ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT
|
||||||
|
static constexpr uint32_t RESERVED_SLOTS = 3;
|
||||||
|
#else
|
||||||
static constexpr uint32_t RESERVED_SLOTS = 2;
|
static constexpr uint32_t RESERVED_SLOTS = 2;
|
||||||
|
#endif
|
||||||
|
|
||||||
static constexpr ObjectFlags OBJECT_FLAGS = {ObjectFlag::NotExtensible,
|
static constexpr ObjectFlags OBJECT_FLAGS = {ObjectFlag::NotExtensible,
|
||||||
ObjectFlag::QualifiedVarObj};
|
ObjectFlag::QualifiedVarObj};
|
||||||
|
|
||||||
|
|
@ -655,6 +664,18 @@ class ModuleEnvironmentObject : public EnvironmentObject {
|
||||||
|
|
||||||
uint32_t firstSyntheticValueSlot() { return RESERVED_SLOTS; }
|
uint32_t firstSyntheticValueSlot() { return RESERVED_SLOTS; }
|
||||||
|
|
||||||
|
#ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT
|
||||||
|
bool addDisposableObject(JSContext* cx, JS::Handle<JS::Value> val);
|
||||||
|
|
||||||
|
// Used to get the Disposable objects within the
|
||||||
|
// lexical scope, it returns a ListObject* if there
|
||||||
|
// is a non empty list of Disposables, else
|
||||||
|
// UndefinedValue.
|
||||||
|
Value getDisposables();
|
||||||
|
|
||||||
|
void clearDisposables();
|
||||||
|
#endif
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static bool lookupProperty(JSContext* cx, HandleObject obj, HandleId id,
|
static bool lookupProperty(JSContext* cx, HandleObject obj, HandleId id,
|
||||||
MutableHandleObject objp, PropertyResult* propp);
|
MutableHandleObject objp, PropertyResult* propp);
|
||||||
|
|
|
||||||
|
|
@ -1639,11 +1639,15 @@ void js::ReportInNotObjectError(JSContext* cx, HandleValue lref,
|
||||||
#ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT
|
#ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT
|
||||||
bool js::DisposeDisposablesOnScopeLeave(JSContext* cx,
|
bool js::DisposeDisposablesOnScopeLeave(JSContext* cx,
|
||||||
JS::Handle<JSObject*> env) {
|
JS::Handle<JSObject*> env) {
|
||||||
if (!env->is<LexicalEnvironmentObject>()) {
|
if (!env->is<LexicalEnvironmentObject>() &&
|
||||||
|
!env->is<ModuleEnvironmentObject>()) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
Value maybeDisposables = env->as<LexicalEnvironmentObject>().getDisposables();
|
Value maybeDisposables =
|
||||||
|
env->is<LexicalEnvironmentObject>()
|
||||||
|
? env->as<LexicalEnvironmentObject>().getDisposables()
|
||||||
|
: env->as<ModuleEnvironmentObject>().getDisposables();
|
||||||
|
|
||||||
MOZ_ASSERT(maybeDisposables.isObject() || maybeDisposables.isUndefined());
|
MOZ_ASSERT(maybeDisposables.isObject() || maybeDisposables.isUndefined());
|
||||||
|
|
||||||
|
|
@ -1698,7 +1702,11 @@ bool js::DisposeDisposablesOnScopeLeave(JSContext* cx,
|
||||||
|
|
||||||
// Step 3. Set disposeCapability.[[DisposableResourceStack]] to
|
// Step 3. Set disposeCapability.[[DisposableResourceStack]] to
|
||||||
// a new empty List.
|
// a new empty List.
|
||||||
env->as<LexicalEnvironmentObject>().clearDisposables();
|
if (env->is<LexicalEnvironmentObject>()) {
|
||||||
|
env->as<LexicalEnvironmentObject>().clearDisposables();
|
||||||
|
} else {
|
||||||
|
env->as<ModuleEnvironmentObject>().clearDisposables();
|
||||||
|
}
|
||||||
|
|
||||||
// 4. Return ? completion.
|
// 4. Return ? completion.
|
||||||
if (hadError) {
|
if (hadError) {
|
||||||
|
|
@ -2069,8 +2077,14 @@ bool MOZ_NEVER_INLINE JS_HAZ_JSNATIVE_CALLER js::Interpret(JSContext* cx,
|
||||||
? UndefinedValue()
|
? UndefinedValue()
|
||||||
: REGS.sp[-1]);
|
: REGS.sp[-1]);
|
||||||
|
|
||||||
if (!env->as<LexicalEnvironmentObject>().addDisposableObject(cx, val)) {
|
if (env->is<LexicalEnvironmentObject>()) {
|
||||||
goto error;
|
if (!env->as<LexicalEnvironmentObject>().addDisposableObject(cx, val)) {
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
} else if (env->is<ModuleEnvironmentObject>()) {
|
||||||
|
if (!env->as<ModuleEnvironmentObject>().addDisposableObject(cx, val)) {
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
END_CASE(AddDisposable)
|
END_CASE(AddDisposable)
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue