Bug 1834711 - Set background finalized flag for dead object proxes created after nuking all CCWs r=jandem

The background finalized flag wasn't getting set in the second overload of
NewDeadProxyObject. The patch makes the first overload of this function more
generic so it can accept non-proxy arguments and uses it in all cases.

The testcase also results in dead object proxies being returned from rewrap()
in RemapDeadWrapper which previously cased an assertion. I added an early
return for this case - do you think that's OK?

Differential Revision: https://phabricator.services.mozilla.com/D179576
This commit is contained in:
Jon Coppeard 2023-06-06 08:37:02 +00:00
Родитель b8fe0dda5f
Коммит 5432788739
6 изменённых файлов: 24 добавлений и 50 удалений

Просмотреть файл

@ -562,7 +562,7 @@ void js::RemapDeadWrapper(JSContext* cx, HandleObject wobj,
}
if (!wobj->is<WrapperObject>()) {
MOZ_ASSERT(js::IsDOMRemoteProxyObject(wobj));
MOZ_ASSERT(js::IsDOMRemoteProxyObject(wobj) || IsDeadProxyObject(wobj));
return;
}

Просмотреть файл

@ -11,6 +11,8 @@
#include "vm/JSFunction.h" // XXXefaust Bug 1064662
#include "vm/ProxyObject.h"
#include "vm/JSObject-inl.h"
using namespace js;
const DeadObjectProxy DeadObjectProxy::singleton;
@ -125,28 +127,26 @@ bool js::IsDeadProxyObject(const JSObject* obj) {
return IsDerivedProxyObject(obj, &DeadObjectProxy::singleton);
}
Value js::DeadProxyTargetValue(ProxyObject* obj) {
Value js::DeadProxyTargetValue(JSObject* obj) {
// When nuking scripted proxies, isCallable and isConstructor values for
// the proxy needs to be preserved. So does background-finalization status.
int32_t flags = 0;
if (obj->handler()->isCallable(obj)) {
if (obj->isCallable()) {
flags |= DeadObjectProxyIsCallable;
}
if (obj->handler()->isConstructor(obj)) {
if (obj->isConstructor()) {
flags |= DeadObjectProxyIsConstructor;
}
if (obj->handler()->finalizeInBackground(obj->private_())) {
if (obj->isBackgroundFinalized()) {
flags |= DeadObjectProxyIsBackgroundFinalized;
}
return Int32Value(flags);
}
JSObject* js::NewDeadProxyObject(JSContext* cx, JSObject* origObj) {
MOZ_ASSERT_IF(origObj, origObj->is<ProxyObject>());
RootedValue target(cx);
if (origObj && origObj->is<ProxyObject>()) {
target = DeadProxyTargetValue(&origObj->as<ProxyObject>());
if (origObj) {
target = DeadProxyTargetValue(origObj);
} else {
target = Int32Value(DeadObjectProxyIsBackgroundFinalized);
}
@ -154,18 +154,3 @@ JSObject* js::NewDeadProxyObject(JSContext* cx, JSObject* origObj) {
return NewProxyObject(cx, &DeadObjectProxy::singleton, target, nullptr,
ProxyOptions());
}
JSObject* js::NewDeadProxyObject(JSContext* cx, IsCallableFlag isCallable,
IsConstructorFlag isConstructor) {
int32_t flags = 0;
if (isCallable == IsCallableFlag::True) {
flags |= DeadObjectProxyIsCallable;
}
if (isConstructor == IsConstructorFlag::True) {
flags |= DeadObjectProxyIsConstructor;
}
RootedValue target(cx, Int32Value(flags));
return NewProxyObject(cx, &DeadObjectProxy::singleton, target, nullptr,
ProxyOptions());
}

Просмотреть файл

@ -91,16 +91,10 @@ class DeadObjectProxy : public BaseProxyHandler {
bool IsDeadProxyObject(const JSObject* obj);
JS::Value DeadProxyTargetValue(ProxyObject* obj);
JS::Value DeadProxyTargetValue(JSObject* obj);
JSObject* NewDeadProxyObject(JSContext* cx, JSObject* origObj = nullptr);
enum class IsCallableFlag : bool { False, True };
enum class IsConstructorFlag : bool { False, True };
JSObject* NewDeadProxyObject(JSContext* cx, IsCallableFlag isCallable,
IsConstructorFlag isConstructor);
} /* namespace js */
#endif /* proxy_DeadObjectProxy_h */

Просмотреть файл

@ -231,8 +231,7 @@ bool Compartment::getNonWrapperObjectForCurrentCompartment(
// Disallow creating new wrappers if we nuked the object's realm or the
// current compartment.
if (!AllowNewWrapper(this, obj)) {
obj.set(NewDeadProxyObject(cx, IsCallableFlag(obj->isCallable()),
IsConstructorFlag(obj->isConstructor())));
obj.set(NewDeadProxyObject(cx, obj));
return !!obj;
}

Просмотреть файл

@ -26,6 +26,7 @@
#include "builtin/String.h"
#include "builtin/Symbol.h"
#include "builtin/WeakSetObject.h"
#include "gc/AllocKind.h"
#include "gc/GC.h"
#include "js/CharacterEncoding.h"
#include "js/friend/DumpFunctions.h" // js::DumpObject
@ -1189,21 +1190,6 @@ bool ProxyObject::fixupAfterSwap(JSContext* cx,
return true;
}
#ifdef DEBUG
static bool IsBackgroundFinalizedWhenTenured(JSObject* obj) {
if (obj->isTenured()) {
return gc::IsBackgroundFinalized(obj->asTenured().getAllocKind());
}
if (obj->is<ProxyObject>()) {
return gc::IsBackgroundFinalized(
obj->as<ProxyObject>().allocKindForTenure());
}
return js::gc::CanUseBackgroundAllocKind(obj->getClass());
}
#endif
static gc::AllocKind SwappableObjectAllocKind(JSObject* obj) {
MOZ_ASSERT(ObjectMayBeSwapped(obj));
@ -1222,8 +1208,7 @@ static gc::AllocKind SwappableObjectAllocKind(JSObject* obj) {
void JSObject::swap(JSContext* cx, HandleObject a, HandleObject b,
AutoEnterOOMUnsafeRegion& oomUnsafe) {
// Ensure swap doesn't cause a finalizer to be run at the wrong time.
MOZ_ASSERT(IsBackgroundFinalizedWhenTenured(a) ==
IsBackgroundFinalizedWhenTenured(b));
MOZ_ASSERT(a->isBackgroundFinalized() == b->isBackgroundFinalized());
MOZ_ASSERT(a->compartment() == b->compartment());
@ -3273,6 +3258,15 @@ JS_PUBLIC_API void js::DumpBacktrace(JSContext* cx) {
/* * */
bool JSObject::isBackgroundFinalized() const {
if (isTenured()) {
return js::gc::IsBackgroundFinalized(asTenured().getAllocKind());
}
js::Nursery& nursery = runtimeFromMainThread()->gc.nursery();
return js::gc::IsBackgroundFinalized(allocKindForTenure(nursery));
}
js::gc::AllocKind JSObject::allocKindForTenure(
const js::Nursery& nursery) const {
using namespace js::gc;

Просмотреть файл

@ -434,6 +434,8 @@ class JSObject
MOZ_ALWAYS_INLINE JSNative callHook() const;
MOZ_ALWAYS_INLINE JSNative constructHook() const;
bool isBackgroundFinalized() const;
MOZ_ALWAYS_INLINE void finalize(JS::GCContext* gcx);
public: