Revert "Bug 1844878 - Eliminate redundant addProperty calls for wrapper preservation r=smaug,jandem" for causing multiple failures
This reverts commit 2c63c9b4d8.
This commit is contained in:
committed by
chorotan@mozilla.com
parent
afe59fc849
commit
afe3a7ad62
@@ -1290,6 +1290,9 @@ bool TryPreserveWrapper(JS::Handle<JSObject*> obj) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// The addProperty hook for WebIDL classes does wrapper preservation, and
|
||||
// nothing else, so call it, if present.
|
||||
|
||||
const JSClass* clasp = JS::GetClass(obj);
|
||||
const DOMJSClass* domClass = GetDOMClass(clasp);
|
||||
|
||||
@@ -1297,23 +1300,17 @@ bool TryPreserveWrapper(JS::Handle<JSObject*> obj) {
|
||||
MOZ_RELEASE_ASSERT(clasp->isNativeObject(),
|
||||
"Should not call addProperty for proxies.");
|
||||
|
||||
if (!clasp->preservesWrapper()) {
|
||||
JSAddPropertyOp addProperty = clasp->getAddProperty();
|
||||
if (!addProperty) {
|
||||
return true;
|
||||
}
|
||||
|
||||
WrapperCacheGetter getter = domClass->mWrapperCacheGetter;
|
||||
MOZ_RELEASE_ASSERT(getter);
|
||||
// The class should have an addProperty hook iff it is a CC participant.
|
||||
MOZ_RELEASE_ASSERT(domClass->mParticipant);
|
||||
|
||||
nsWrapperCache* cache = getter(obj);
|
||||
// We obviously can't preserve if we're not initialized, we don't want
|
||||
// to preserve if we don't have a wrapper or if the object is in the
|
||||
// process of being finalized.
|
||||
if (cache && cache->GetWrapperPreserveColor()) {
|
||||
cache->PreserveWrapper(
|
||||
cache, reinterpret_cast<nsScriptObjectTracer*>(domClass->mParticipant));
|
||||
}
|
||||
|
||||
return true;
|
||||
JS::Rooted<jsid> dummyId(RootingCx());
|
||||
JS::Rooted<JS::Value> dummyValue(RootingCx());
|
||||
return addProperty(nullptr, obj, dummyId, dummyValue);
|
||||
}
|
||||
|
||||
bool HasReleasedWrapper(JS::Handle<JSObject*> obj) {
|
||||
@@ -2443,7 +2440,6 @@ void UpdateReflectorGlobal(JSContext* aCx, JS::Handle<JSObject*> aObjArg,
|
||||
// propertyHolder. Otherwise, an object with |foo.x === foo| will
|
||||
// crash when JS_CopyOwnPropertiesAndPrivateFields tries to call wrap() on
|
||||
// foo.x.
|
||||
static_assert(DOM_OBJECT_SLOT == JS_OBJECT_WRAPPER_SLOT);
|
||||
JS::SetReservedSlot(newobj, DOM_OBJECT_SLOT,
|
||||
JS::GetReservedSlot(aObj, DOM_OBJECT_SLOT));
|
||||
JS::SetReservedSlot(aObj, DOM_OBJECT_SLOT, JS::PrivateValue(nullptr));
|
||||
|
||||
@@ -1029,22 +1029,55 @@ using ToWrapperCacheHelper = std::conditional_t<
|
||||
CastableToWrapperCache<CastableToWrapperCacheHelper::OffsetOf<T>()>,
|
||||
NeedsQIToWrapperCache>;
|
||||
|
||||
template <class Base>
|
||||
class NativeTypeHelpersBase_nsISupports : public Base {
|
||||
public:
|
||||
static bool AddProperty(JSContext* cx, JS::Handle<JSObject*> aObj,
|
||||
JS::Handle<jsid>, JS::Handle<JS::Value>) {
|
||||
nsISupports* self =
|
||||
UnwrapPossiblyNotInitializedDOMObject<nsISupports>(aObj);
|
||||
// We obviously can't preserve if we're not initialized.
|
||||
if (self) {
|
||||
nsWrapperCache* cache = Base::GetWrapperCache(self);
|
||||
// We don't want to preserve if we don't have a wrapper.
|
||||
if (cache->GetWrapperPreserveColor()) {
|
||||
cache->PreserveWrapper(self);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
template <class T,
|
||||
bool CastableToWrapperCache = std::is_base_of_v<nsWrapperCache, T>>
|
||||
class NativeTypeHelpers_nsISupports;
|
||||
|
||||
template <class T>
|
||||
class NativeTypeHelpers_nsISupports<T, true>
|
||||
: public CastableToWrapperCache<
|
||||
CastableToWrapperCacheHelper::OffsetOf<T>()> {};
|
||||
: public NativeTypeHelpersBase_nsISupports<
|
||||
CastableToWrapperCache<CastableToWrapperCacheHelper::OffsetOf<T>()>> {
|
||||
};
|
||||
|
||||
template <class T>
|
||||
class NativeTypeHelpers_nsISupports<T, false> : public NeedsQIToWrapperCache {};
|
||||
class NativeTypeHelpers_nsISupports<T, false>
|
||||
: public NativeTypeHelpersBase_nsISupports<NeedsQIToWrapperCache> {};
|
||||
|
||||
template <class T>
|
||||
class NativeTypeHelpers_Other
|
||||
: public CastableToWrapperCache<
|
||||
CastableToWrapperCacheHelper::OffsetOf<T>()> {};
|
||||
CastableToWrapperCacheHelper::OffsetOf<T>()> {
|
||||
public:
|
||||
static bool AddProperty(JSContext* cx, JS::Handle<JSObject*> aObj,
|
||||
JS::Handle<jsid>, JS::Handle<JS::Value>) {
|
||||
T* self = UnwrapPossiblyNotInitializedDOMObject<T>(aObj);
|
||||
// We obviously can't preserve if we're not initialized, and we don't want
|
||||
// to preserve if we don't have a wrapper.
|
||||
if (self && self->GetWrapperPreserveColor()) {
|
||||
self->PreserveWrapper(self, NS_CYCLE_COLLECTION_PARTICIPANT(T));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
using NativeTypeHelpers = std::conditional_t<std::is_base_of_v<nsISupports, T>,
|
||||
|
||||
@@ -251,9 +251,9 @@ def idlTypeNeedsCallContext(type, descriptor=None, allowTreatNonCallableAsNull=F
|
||||
|
||||
|
||||
# TryPreserveWrapper uses the addProperty hook to preserve the wrapper of
|
||||
# non-nsISupports cycle collected objects, so if wantsPreservedWrapper is changed
|
||||
# non-nsISupports cycle collected objects, so if wantsAddProperty is changed
|
||||
# to not cover that case then TryPreserveWrapper will need to be changed.
|
||||
def wantsPreservedWrapper(desc):
|
||||
def wantsAddProperty(desc):
|
||||
return desc.concrete and desc.wrapperCache and not desc.isGlobal()
|
||||
|
||||
|
||||
@@ -697,9 +697,6 @@ class CGDOMJSClass(CGThing):
|
||||
)
|
||||
classFlags += " | JSCLASS_SKIP_NURSERY_FINALIZE"
|
||||
|
||||
if wantsPreservedWrapper(self.descriptor):
|
||||
classFlags += " | JSCLASS_PRESERVES_WRAPPER"
|
||||
|
||||
if self.descriptor.interface.getExtendedAttribute("NeedResolve"):
|
||||
resolveHook = RESOLVE_HOOK_NAME
|
||||
mayResolveHook = MAY_RESOLVE_HOOK_NAME
|
||||
@@ -716,7 +713,7 @@ class CGDOMJSClass(CGThing):
|
||||
return fill(
|
||||
"""
|
||||
static const JSClassOps sClassOps = {
|
||||
nullptr, /* addProperty */
|
||||
${addProperty}, /* addProperty */
|
||||
nullptr, /* delProperty */
|
||||
nullptr, /* enumerate */
|
||||
${newEnumerate}, /* newEnumerate */
|
||||
@@ -745,6 +742,11 @@ class CGDOMJSClass(CGThing):
|
||||
""",
|
||||
name=self.descriptor.interface.getClassName(),
|
||||
flags=classFlags,
|
||||
addProperty=(
|
||||
"NativeTypeHelpers<%s>::AddProperty" % self.descriptor.nativeType
|
||||
if wantsAddProperty(self.descriptor)
|
||||
else "nullptr"
|
||||
),
|
||||
newEnumerate=newEnumerateHook,
|
||||
resolve=resolveHook,
|
||||
mayResolve=mayResolveHook,
|
||||
@@ -2038,6 +2040,40 @@ class CGAbstractClassHook(CGAbstractStaticMethod):
|
||||
assert False # Override me!
|
||||
|
||||
|
||||
class CGAddPropertyHook(CGAbstractClassHook):
|
||||
"""
|
||||
A hook for addProperty, used to preserve our wrapper from GC.
|
||||
"""
|
||||
|
||||
def __init__(self, descriptor):
|
||||
args = [
|
||||
Argument("JSContext*", "cx"),
|
||||
Argument("JS::Handle<JSObject*>", "obj"),
|
||||
Argument("JS::Handle<jsid>", "id"),
|
||||
Argument("JS::Handle<JS::Value>", "val"),
|
||||
]
|
||||
CGAbstractClassHook.__init__(
|
||||
self, descriptor, ADDPROPERTY_HOOK_NAME, "bool", args
|
||||
)
|
||||
|
||||
def generate_code(self):
|
||||
assert self.descriptor.wrapperCache
|
||||
# This hook is also called by TryPreserveWrapper on non-nsISupports
|
||||
# cycle collected objects, so if addProperty is ever changed to do
|
||||
# anything more or less than preserve the wrapper, TryPreserveWrapper
|
||||
# will need to be changed.
|
||||
return dedent(
|
||||
"""
|
||||
// We don't want to preserve if we don't have a wrapper, and we
|
||||
// obviously can't preserve if we're not initialized.
|
||||
if (self && self->GetWrapperPreserveColor()) {
|
||||
PreserveWrapper(self);
|
||||
}
|
||||
return true;
|
||||
"""
|
||||
)
|
||||
|
||||
|
||||
class CGGetWrapperCacheHook(CGAbstractClassHook):
|
||||
"""
|
||||
A hook for GetWrapperCache, used by HasReleasedWrapper to get the
|
||||
|
||||
@@ -489,11 +489,7 @@ static constexpr const js::ObjectOps* JS_NULL_OBJECT_OPS = nullptr;
|
||||
|
||||
// Classes, objects, and properties.
|
||||
|
||||
// Must call a callback when the first property is added to an object of this
|
||||
// class. If this is set, the object must store a pointer at
|
||||
// JS_OBJECT_WRAPPER_SLOT to the C++ wrapper as a PrivateValue or
|
||||
// UndefinedValue() if the object does not have a wrapper.
|
||||
static const uint32_t JSCLASS_PRESERVES_WRAPPER = 1 << 0;
|
||||
// (1 << 0 is unused)
|
||||
|
||||
// Class's initialization code will call `SetNewObjectMetadata` itself.
|
||||
static const uint32_t JSCLASS_DELAY_METADATA_BUILDER = 1 << 1;
|
||||
@@ -597,9 +593,6 @@ static constexpr uint32_t JSCLASS_HAS_CACHED_PROTO(JSProtoKey key) {
|
||||
return uint32_t(key) << JSCLASS_CACHED_PROTO_SHIFT;
|
||||
}
|
||||
|
||||
// See JSCLASS_PRESERVES_WRAPPER.
|
||||
static constexpr size_t JS_OBJECT_WRAPPER_SLOT = 0;
|
||||
|
||||
struct MOZ_STATIC_CLASS JSClassOps {
|
||||
/* Function pointer members (may be null). */
|
||||
JSAddPropertyOp addProperty;
|
||||
@@ -713,8 +706,6 @@ struct alignas(js::gc::JSClassAlignBytes) JSClass {
|
||||
|
||||
bool slot0IsISupports() const { return flags & JSCLASS_SLOT0_IS_NSISUPPORTS; }
|
||||
|
||||
bool preservesWrapper() const { return flags & JSCLASS_PRESERVES_WRAPPER; }
|
||||
|
||||
static size_t offsetOfFlags() { return offsetof(JSClass, flags); }
|
||||
|
||||
// Internal / friend API accessors:
|
||||
|
||||
@@ -4963,8 +4963,7 @@ static bool CanAttachAddElement(NativeObject* obj, bool isInit,
|
||||
const JSClass* clasp = obj->getClass();
|
||||
if (clasp != &ArrayObject::class_ &&
|
||||
(clasp->getAddProperty() || clasp->getResolve() ||
|
||||
clasp->getOpsLookupProperty() || clasp->getOpsSetProperty() ||
|
||||
obj->hasUnpreservedWrapper())) {
|
||||
clasp->getOpsLookupProperty() || clasp->getOpsSetProperty())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -5736,10 +5735,7 @@ AttachDecision SetPropIRGenerator::tryAttachAddSlotStub(
|
||||
DebugOnly<uint32_t> index;
|
||||
MOZ_ASSERT_IF(obj->is<ArrayObject>(), !IdIsIndex(id, &index));
|
||||
bool mustCallAddPropertyHook =
|
||||
!obj->is<ArrayObject>() &&
|
||||
(obj->getClass()->getAddProperty() ||
|
||||
(obj->getClass()->preservesWrapper() &&
|
||||
!oldShape->hasObjectFlag(ObjectFlag::HasPreservedWrapper)));
|
||||
obj->getClass()->getAddProperty() && !obj->is<ArrayObject>();
|
||||
|
||||
if (mustCallAddPropertyHook) {
|
||||
writer.addSlotAndCallAddPropHook(objId, rhsValId, newShape);
|
||||
|
||||
@@ -11312,11 +11312,11 @@ static const JSClassOps FakeDOMObjectClassOps = {
|
||||
nullptr,
|
||||
};
|
||||
|
||||
static const JSClass dom_class = {
|
||||
"FakeDOMObject",
|
||||
JSCLASS_IS_DOMJSCLASS | JSCLASS_HAS_RESERVED_SLOTS(2) |
|
||||
JSCLASS_BACKGROUND_FINALIZE | JSCLASS_PRESERVES_WRAPPER,
|
||||
&FakeDOMObjectClassOps};
|
||||
static const JSClass dom_class = {"FakeDOMObject",
|
||||
JSCLASS_IS_DOMJSCLASS |
|
||||
JSCLASS_HAS_RESERVED_SLOTS(2) |
|
||||
JSCLASS_BACKGROUND_FINALIZE,
|
||||
&FakeDOMObjectClassOps};
|
||||
|
||||
static const JSClass* GetDomClass() { return &dom_class; }
|
||||
|
||||
|
||||
@@ -550,10 +550,7 @@ inline bool IsConstructor(const Value& v) {
|
||||
}
|
||||
|
||||
static inline bool MaybePreserveDOMWrapper(JSContext* cx, HandleObject obj) {
|
||||
if (!obj->getClass()->preservesWrapper()) {
|
||||
return true;
|
||||
}
|
||||
if (JS::GetReservedSlot(obj, JS_OBJECT_WRAPPER_SLOT).isUndefined()) {
|
||||
if (!obj->getClass()->isDOMClass()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -895,7 +895,6 @@ MOZ_ALWAYS_INLINE bool AddDataPropertyToPlainObject(
|
||||
obj->initSlot(*resultSlot, v);
|
||||
|
||||
MOZ_ASSERT(!obj->getClass()->getAddProperty());
|
||||
MOZ_ASSERT(!obj->getClass()->preservesWrapper());
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -1182,10 +1182,6 @@ static MOZ_ALWAYS_INLINE bool CallAddPropertyHook(JSContext* cx,
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (MOZ_UNLIKELY(obj->hasUnpreservedWrapper())) {
|
||||
MaybePreserveDOMWrapper(cx, obj);
|
||||
return JSObject::setFlag(cx, obj, ObjectFlag::HasPreservedWrapper);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1210,11 +1206,6 @@ static MOZ_ALWAYS_INLINE bool CallAddPropertyHookDense(
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (MOZ_UNLIKELY(obj->hasUnpreservedWrapper())) {
|
||||
MaybePreserveDOMWrapper(cx, obj);
|
||||
return JSObject::setFlag(cx, obj, ObjectFlag::HasPreservedWrapper);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1431,6 +1422,7 @@ static MOZ_ALWAYS_INLINE bool AddDataProperty(JSContext* cx,
|
||||
|
||||
bool js::AddSlotAndCallAddPropHook(JSContext* cx, Handle<NativeObject*> obj,
|
||||
HandleValue v, Handle<Shape*> newShape) {
|
||||
MOZ_ASSERT(obj->getClass()->getAddProperty());
|
||||
MOZ_ASSERT(newShape->asShared().lastProperty().isDataProperty());
|
||||
|
||||
RootedId id(cx, newShape->asShared().lastProperty().key());
|
||||
|
||||
@@ -1730,11 +1730,6 @@ class NativeObject : public JSObject {
|
||||
/* isFixedSlot = */ false);
|
||||
}
|
||||
|
||||
bool hasUnpreservedWrapper() const {
|
||||
return getClass()->preservesWrapper() &&
|
||||
!shape()->hasObjectFlag(ObjectFlag::HasPreservedWrapper);
|
||||
}
|
||||
|
||||
/* JIT Accessors */
|
||||
static size_t offsetOfElements() { return offsetof(NativeObject, elements_); }
|
||||
static size_t offsetOfFixedElements() {
|
||||
|
||||
@@ -86,9 +86,6 @@ enum class ObjectFlag : uint16_t {
|
||||
// with it, and thus we must trap on changes to said property.
|
||||
HasFuseProperty = 1 << 14,
|
||||
|
||||
// If set, we have already called the preserveWrapper hook for this object.
|
||||
// This should only be set if `obj->getClass()->preservesWrapper()` is true.
|
||||
HasPreservedWrapper = 1 << 15,
|
||||
};
|
||||
|
||||
using ObjectFlags = EnumFlags<ObjectFlag>;
|
||||
|
||||
Reference in New Issue
Block a user