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()) {
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1216,8 +1216,12 @@ static Maybe<ModuleScope::ParserData*> NewModuleScopeData(
|
|||
}
|
||||
|
||||
ModuleScope::ParserData* bindings = nullptr;
|
||||
uint32_t numBindings =
|
||||
imports.length() + vars.length() + lets.length() + consts.length();
|
||||
uint32_t numBindings = imports.length() + vars.length() + lets.length() +
|
||||
consts.length()
|
||||
#ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT
|
||||
+ usings.length()
|
||||
#endif
|
||||
;
|
||||
|
||||
if (numBindings > 0) {
|
||||
bindings = NewEmptyBindingData<ModuleScope>(fc, alloc, numBindings);
|
||||
|
|
@ -1229,7 +1233,12 @@ static Maybe<ModuleScope::ParserData*> NewModuleScopeData(
|
|||
InitializeBindingData(bindings, numBindings, imports,
|
||||
&ParserModuleScopeSlotInfo::varStart, vars,
|
||||
&ParserModuleScopeSlotInfo::letStart, lets,
|
||||
&ParserModuleScopeSlotInfo::constStart, consts);
|
||||
&ParserModuleScopeSlotInfo::constStart, consts
|
||||
#ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT
|
||||
,
|
||||
&ParserModuleScopeSlotInfo::usingStart, usings
|
||||
#endif
|
||||
);
|
||||
}
|
||||
|
||||
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());
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT
|
||||
env->initSlot(ModuleEnvironmentObject::DISPOSABLE_OBJECTS_SLOT,
|
||||
UndefinedValue());
|
||||
#endif
|
||||
|
||||
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 */
|
||||
ModuleEnvironmentObject* ModuleEnvironmentObject::createSynthetic(
|
||||
JSContext* cx, Handle<ModuleObject*> module) {
|
||||
|
|
@ -957,18 +998,8 @@ bool LexicalEnvironmentObject::isExtensible() const {
|
|||
#ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT
|
||||
bool LexicalEnvironmentObject::addDisposableObject(JSContext* cx,
|
||||
JS::Handle<JS::Value> val) {
|
||||
Value slotData = getReservedSlot(DISPOSABLE_OBJECTS_SLOT);
|
||||
ListObject* disposablesList = nullptr;
|
||||
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);
|
||||
Rooted<LexicalEnvironmentObject*> env(cx, this);
|
||||
return addDisposableObjectHelper(env, DISPOSABLE_OBJECTS_SLOT, cx, val);
|
||||
}
|
||||
|
||||
Value LexicalEnvironmentObject::getDisposables() {
|
||||
|
|
|
|||
|
|
@ -618,6 +618,10 @@ class VarEnvironmentObject : public EnvironmentObject {
|
|||
class ModuleEnvironmentObject : public EnvironmentObject {
|
||||
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 JSClassOps classOps_;
|
||||
|
||||
|
|
@ -626,7 +630,12 @@ class ModuleEnvironmentObject : public EnvironmentObject {
|
|||
|
||||
static const JSClass class_;
|
||||
|
||||
#ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT
|
||||
static constexpr uint32_t RESERVED_SLOTS = 3;
|
||||
#else
|
||||
static constexpr uint32_t RESERVED_SLOTS = 2;
|
||||
#endif
|
||||
|
||||
static constexpr ObjectFlags OBJECT_FLAGS = {ObjectFlag::NotExtensible,
|
||||
ObjectFlag::QualifiedVarObj};
|
||||
|
||||
|
|
@ -655,6 +664,18 @@ class ModuleEnvironmentObject : public EnvironmentObject {
|
|||
|
||||
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:
|
||||
static bool lookupProperty(JSContext* cx, HandleObject obj, HandleId id,
|
||||
MutableHandleObject objp, PropertyResult* propp);
|
||||
|
|
|
|||
|
|
@ -1639,11 +1639,15 @@ void js::ReportInNotObjectError(JSContext* cx, HandleValue lref,
|
|||
#ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT
|
||||
bool js::DisposeDisposablesOnScopeLeave(JSContext* cx,
|
||||
JS::Handle<JSObject*> env) {
|
||||
if (!env->is<LexicalEnvironmentObject>()) {
|
||||
if (!env->is<LexicalEnvironmentObject>() &&
|
||||
!env->is<ModuleEnvironmentObject>()) {
|
||||
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());
|
||||
|
||||
|
|
@ -1698,7 +1702,11 @@ bool js::DisposeDisposablesOnScopeLeave(JSContext* cx,
|
|||
|
||||
// Step 3. Set disposeCapability.[[DisposableResourceStack]] to
|
||||
// a new empty List.
|
||||
env->as<LexicalEnvironmentObject>().clearDisposables();
|
||||
if (env->is<LexicalEnvironmentObject>()) {
|
||||
env->as<LexicalEnvironmentObject>().clearDisposables();
|
||||
} else {
|
||||
env->as<ModuleEnvironmentObject>().clearDisposables();
|
||||
}
|
||||
|
||||
// 4. Return ? completion.
|
||||
if (hadError) {
|
||||
|
|
@ -2069,8 +2077,14 @@ bool MOZ_NEVER_INLINE JS_HAZ_JSNATIVE_CALLER js::Interpret(JSContext* cx,
|
|||
? UndefinedValue()
|
||||
: REGS.sp[-1]);
|
||||
|
||||
if (!env->as<LexicalEnvironmentObject>().addDisposableObject(cx, val)) {
|
||||
goto error;
|
||||
if (env->is<LexicalEnvironmentObject>()) {
|
||||
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)
|
||||
|
|
|
|||
Loading…
Reference in a new issue