Bug 1694040 - Use JSObject::is<ProxyObject> in more places. r=jandem

Also replace JSClass::isProxy with isProxyObject and clarify that the flag
indicates primarily that the JSObject is of type js::ProxyObject.

In DOM binding code, prefer checks for NativeObject rather than !ProxyObject
where that is what we really meant.

Differential Revision: https://phabricator.services.mozilla.com/D105884
This commit is contained in:
Ted Campbell 2021-02-22 13:12:29 +00:00
parent 4f0b11e2f5
commit bf2062a7c7
19 changed files with 54 additions and 44 deletions

View File

@ -1144,14 +1144,15 @@ bool TryPreserveWrapper(JS::Handle<JSObject*> obj) {
// The addProperty hook for WebIDL classes does wrapper preservation, and
// nothing else, so call it, if present.
const DOMJSClass* domClass = GetDOMClass(obj);
const JSClass* clasp = domClass->ToJSClass();
JSAddPropertyOp addProperty = clasp->getAddProperty();
const JSClass* clasp = JS::GetClass(obj);
const DOMJSClass* domClass = GetDOMClass(clasp);
// We expect all proxies to be nsISupports.
MOZ_RELEASE_ASSERT(!clasp->isProxy(),
MOZ_RELEASE_ASSERT(clasp->isNativeObject(),
"Should not call addProperty for proxies.");
JSAddPropertyOp addProperty = clasp->getAddProperty();
if (!addProperty) {
return true;
}
@ -1172,10 +1173,11 @@ bool HasReleasedWrapper(JS::Handle<JSObject*> obj) {
if (nsISupports* native = UnwrapDOMObjectToISupports(obj)) {
CallQueryInterface(native, &cache);
} else {
const DOMJSClass* domClass = GetDOMClass(obj);
const JSClass* clasp = JS::GetClass(obj);
const DOMJSClass* domClass = GetDOMClass(clasp);
// We expect all proxies to be nsISupports.
MOZ_RELEASE_ASSERT(!domClass->ToJSClass()->isProxy(),
MOZ_RELEASE_ASSERT(clasp->isNativeObject(),
"Should not call getWrapperCache for proxies.");
WrapperCacheGetter getter = domClass->mWrapperCacheGetter;

View File

@ -94,7 +94,7 @@ inline bool IsDOMClass(const JSClass* clasp) {
// Return true if the JSClass is used for non-proxy DOM objects.
inline bool IsNonProxyDOMClass(const JSClass* clasp) {
return IsDOMClass(clasp) && !clasp->isProxy();
return IsDOMClass(clasp) && clasp->isNativeObject();
}
// Returns true if the JSClass is used for DOM interface and interface

View File

@ -163,8 +163,7 @@ class ShadowingDOMProxyHandler : public DOMProxyHandler {
};
inline bool IsDOMProxy(JSObject* obj) {
const JSClass* clasp = JS::GetClass(obj);
return clasp->isProxy() &&
return js::IsProxy(obj) &&
js::GetProxyHandler(obj)->family() == &DOMProxyHandler::family;
}

View File

@ -790,7 +790,19 @@ struct alignas(js::gc::JSClassAlignBytes) JSClass {
*/
static const uint32_t NON_NATIVE = JSCLASS_INTERNAL_FLAG2;
// A JSObject created from a JSClass extends from one of:
// - js::NativeObject
// - js::ProxyObject
//
// While it is possible to introduce new families of objects, it is strongly
// discouraged. The JITs would be entirely unable to optimize them and testing
// coverage is low. The existing NativeObject and ProxyObject are extremely
// flexible and are able to represent the entire Gecko embedding requirements.
//
// NOTE: Internal to SpiderMonkey, there is an experimental js::TypedObject
// object family for future WASM features.
bool isNativeObject() const { return !(flags & NON_NATIVE); }
bool isProxyObject() const { return flags & JSCLASS_IS_PROXY; }
bool hasPrivate() const { return !!(flags & JSCLASS_HAS_PRIVATE); }
@ -799,14 +811,12 @@ struct alignas(js::gc::JSClassAlignBytes) JSClass {
bool isJSFunction() const { return this == js::FunctionClassPtr; }
bool nonProxyCallable() const {
MOZ_ASSERT(!isProxy());
MOZ_ASSERT(!isProxyObject());
return isJSFunction() || getCall();
}
bool isGlobal() const { return flags & JSCLASS_IS_GLOBAL; }
bool isProxy() const { return flags & JSCLASS_IS_PROXY; }
bool isDOMClass() const { return flags & JSCLASS_IS_DOMJSCLASS; }
bool shouldDelayMetadataBuilder() const {

View File

@ -371,7 +371,7 @@ class JS_FRIEND_API BaseProxyHandler {
extern JS_FRIEND_DATA const JSClass ProxyClass;
inline bool IsProxy(const JSObject* obj) {
return JS::GetClass(obj)->isProxy();
return JS::GetClass(obj)->isProxyObject();
}
namespace detail {

View File

@ -546,7 +546,7 @@ static MOZ_ALWAYS_INLINE JSString* GetBuiltinTagFast(JSObject* obj,
const JSClass* clasp,
JSContext* cx) {
MOZ_ASSERT(clasp == obj->getClass());
MOZ_ASSERT(!clasp->isProxy());
MOZ_ASSERT(!clasp->isProxyObject());
// Optimize the non-proxy case to bypass GetBuiltinClass.
if (clasp == &PlainObject::class_) {
@ -674,7 +674,7 @@ bool js::obj_toString(JSContext* cx, unsigned argc, Value* vp) {
// When |obj| is a non-proxy object, compute |builtinTag| only when needed.
RootedString builtinTag(cx);
const JSClass* clasp = obj->getClass();
if (MOZ_UNLIKELY(clasp->isProxy())) {
if (MOZ_UNLIKELY(clasp->isProxyObject())) {
builtinTag = GetBuiltinTagSlow(cx, obj);
if (!builtinTag) {
return false;

View File

@ -826,7 +826,7 @@ bool CDataArrayProxyHandler::set(JSContext* cx, HandleObject proxy, HandleId id,
}
static JSObject* MaybeUnwrapArrayWrapper(JSObject* obj) {
if (IsProxy(obj) &&
if (obj->is<ProxyObject>() &&
obj->as<ProxyObject>().handler() == &CDataArrayProxyHandler::singleton) {
return obj->as<ProxyObject>().target();
}

View File

@ -411,8 +411,8 @@ JSObject* js::Nursery::allocateObject(JSContext* cx, size_t size,
MOZ_ASSERT(size >= sizeof(RelocationOverlay));
// Sanity check the finalizer.
MOZ_ASSERT_IF(clasp->hasFinalize(),
CanNurseryAllocateFinalizedClass(clasp) || clasp->isProxy());
MOZ_ASSERT_IF(clasp->hasFinalize(), CanNurseryAllocateFinalizedClass(clasp) ||
clasp->isProxyObject());
auto* obj = reinterpret_cast<JSObject*>(
allocateCell(cx->zone(), size, JS::TraceKind::Object));

View File

@ -36,7 +36,8 @@ static inline AllocKind GetGCObjectKind(const JSClass* clasp) {
return AllocKind::FUNCTION;
}
MOZ_ASSERT(!clasp->isProxy(), "Proxies should use GetProxyGCObjectKind");
MOZ_ASSERT(!clasp->isProxyObject(),
"Proxies should use GetProxyGCObjectKind");
uint32_t nslots = JSCLASS_RESERVED_SLOTS(clasp);
if (clasp->flags & JSCLASS_HAS_PRIVATE) {

View File

@ -1005,7 +1005,7 @@ static bool CanAttachDOMCall(JSContext* cx, JSJitInfo::OpType type,
return false;
}
if (type != JSJitInfo::Method && clasp->isProxy()) {
if (type != JSJitInfo::Method && clasp->isProxyObject()) {
return false;
}
@ -1319,7 +1319,7 @@ static bool GetXrayExpandoShapeWrapper(JSContext* cx, HandleObject xray,
AttachDecision GetPropIRGenerator::tryAttachXrayCrossCompartmentWrapper(
HandleObject obj, ObjOperandId objId, HandleId id,
ValOperandId receiverId) {
if (!IsProxy(obj)) {
if (!obj->is<ProxyObject>()) {
return AttachDecision::NoAction;
}
@ -1357,7 +1357,7 @@ AttachDecision GetPropIRGenerator::tryAttachXrayCrossCompartmentWrapper(
cx_->clearPendingException();
return AttachDecision::NoAction;
}
if (!holder || !IsProxy(holder) ||
if (!holder || !holder->is<ProxyObject>() ||
!info->isCrossCompartmentXray(GetProxyHandler(holder))) {
return AttachDecision::NoAction;
}
@ -5809,7 +5809,7 @@ AttachDecision CallIRGenerator::tryAttachHasClass(HandleFunction callee,
MOZ_ASSERT(args_[0].isObject());
// Only optimize when the object isn't a proxy.
if (isPossiblyWrapped && IsProxy(&args_[0].toObject())) {
if (isPossiblyWrapped && args_[0].toObject().is<ProxyObject>()) {
return AttachDecision::NoAction;
}

View File

@ -5223,7 +5223,7 @@ MDefinition* MGuardIsNotProxy::foldsTo(TempAllocator& alloc) {
return this;
}
MOZ_ASSERT(!GetObjectKnownJSClass(object())->isProxy());
MOZ_ASSERT(!GetObjectKnownJSClass(object())->isProxyObject());
AssertKnownClass(alloc, this, object());
return object();
}

View File

@ -64,7 +64,7 @@ MCall* WarpBuilderShared::makeCall(CallInfo& callInfo, bool needsThisCheck,
if (clasp->isNativeObject()) {
objKind = DOMObjectKind::Native;
} else {
MOZ_ASSERT(clasp->isProxy());
MOZ_ASSERT(clasp->isProxyObject());
objKind = DOMObjectKind::Proxy;
}
}

View File

@ -432,7 +432,7 @@ bool js::GetObjectProto(JSContext* cx, JS::Handle<JSObject*> obj,
JS::MutableHandle<JSObject*> proto) {
cx->check(obj);
if (IsProxy(obj)) {
if (obj->is<ProxyObject>()) {
return JS_GetPrototype(cx, obj, proto);
}
@ -453,7 +453,7 @@ JS_FRIEND_API bool js::GetRealmOriginalEval(JSContext* cx,
void JS::detail::SetReservedSlotWithBarrier(JSObject* obj, size_t slot,
const Value& value) {
if (IsProxy(obj)) {
if (obj->is<ProxyObject>()) {
obj->as<ProxyObject>().setReservedSlot(slot, value);
} else {
obj->as<NativeObject>().setSlot(slot, value);

View File

@ -236,7 +236,7 @@ inline bool JSObject::hasAllFlags(js::BaseShape::Flag flags) const {
}
inline bool JSObject::nonProxyIsExtensible() const {
MOZ_ASSERT(!uninlinedIsProxy());
MOZ_ASSERT(!uninlinedIsProxyObject());
// [[Extensible]] for ordinary non-proxy objects is an object flag.
return !hasAllFlags(js::BaseShape::NOT_EXTENSIBLE);

View File

@ -1467,7 +1467,7 @@ bool js::ObjectMayBeSwapped(const JSObject* obj) {
// WindowProxy, Wrapper, DeadProxyObject, DOMProxy, and DOMClass (non-global)
// types may be swapped. It is hard to detect DOMProxy from shell, so target
// proxies in general.
return clasp->isProxy() || clasp->isDOMClass();
return clasp->isProxyObject() || clasp->isDOMClass();
}
[[nodiscard]] static bool CopyProxyValuesBeforeSwap(
@ -1500,7 +1500,7 @@ bool js::ObjectMayBeSwapped(const JSObject* obj) {
bool ProxyObject::initExternalValueArrayAfterSwap(
JSContext* cx, const HandleValueVector values) {
MOZ_ASSERT(getClass()->isProxy());
MOZ_ASSERT(getClass()->isProxyObject());
size_t nreserved = numReservedSlots();
@ -3322,7 +3322,7 @@ bool JSObject::hasSameRealmAs(JSContext* cx) const {
return nonCCWRealm() == cx->realm();
}
bool JSObject::uninlinedIsProxy() const { return is<ProxyObject>(); }
bool JSObject::uninlinedIsProxyObject() const { return is<ProxyObject>(); }
bool JSObject::uninlinedNonProxyIsExtensible() const {
return nonProxyIsExtensible();
@ -3637,7 +3637,7 @@ js::gc::AllocKind JSObject::allocKindForTenure(
}
// Proxies that are CrossCompartmentWrappers may be nursery allocated.
if (IsProxy(this)) {
if (is<ProxyObject>()) {
return as<ProxyObject>().allocKindForTenure();
}
@ -3924,7 +3924,7 @@ void JSObject::debugCheckNewObject(ObjectGroup* group, Shape* shape,
JSCLASS_FOREGROUND_FINALIZE | JSCLASS_BACKGROUND_FINALIZE;
uint32_t flags = clasp->flags;
uint32_t finalizeFlags = flags & FinalizeMask;
if (clasp->hasFinalize() && !clasp->isProxy()) {
if (clasp->hasFinalize() && !clasp->isProxyObject()) {
MOZ_ASSERT(finalizeFlags == JSCLASS_FOREGROUND_FINALIZE ||
finalizeFlags == JSCLASS_BACKGROUND_FINALIZE);
MOZ_ASSERT((finalizeFlags == JSCLASS_BACKGROUND_FINALIZE) ==
@ -3936,7 +3936,7 @@ void JSObject::debugCheckNewObject(ObjectGroup* group, Shape* shape,
MOZ_ASSERT_IF(clasp->hasFinalize(),
heap == gc::TenuredHeap ||
CanNurseryAllocateFinalizedClass(clasp) ||
clasp->isProxy());
clasp->isProxyObject());
MOZ_ASSERT(!group->realm()->hasObjectPendingMetadata());
@ -3944,7 +3944,7 @@ void JSObject::debugCheckNewObject(ObjectGroup* group, Shape* shape,
// slotSpan are always 0. Note that proxy classes can have reserved slots
// but they're also not included in numFixedSlots/slotSpan.
if (!clasp->isNativeObject()) {
MOZ_ASSERT_IF(!clasp->isProxy(), JSCLASS_RESERVED_SLOTS(clasp) == 0);
MOZ_ASSERT_IF(!clasp->isProxyObject(), JSCLASS_RESERVED_SLOTS(clasp) == 0);
MOZ_ASSERT(!clasp->hasPrivate());
MOZ_ASSERT_IF(shape, shape->numFixedSlots() == 0);
MOZ_ASSERT_IF(shape, shape->slotSpan() == 0);

View File

@ -299,7 +299,7 @@ class JSObject
js::TaggedProto taggedProto() const { return group()->proto(); }
bool uninlinedIsProxy() const;
bool uninlinedIsProxyObject() const;
JSObject* staticPrototype() const {
MOZ_ASSERT(hasStaticPrototype());
@ -319,7 +319,7 @@ class JSObject
// the wrapper/wrappee [[Prototype]]s consistent.)
bool hasDynamicPrototype() const {
bool dynamic = taggedProto().isDynamic();
MOZ_ASSERT_IF(dynamic, uninlinedIsProxy());
MOZ_ASSERT_IF(dynamic, uninlinedIsProxyObject());
return dynamic;
}

View File

@ -20,7 +20,7 @@ using namespace js;
static gc::AllocKind GetProxyGCObjectKind(const JSClass* clasp,
const BaseProxyHandler* handler,
const Value& priv) {
MOZ_ASSERT(clasp->isProxy());
MOZ_ASSERT(clasp->isProxyObject());
uint32_t nreserved = JSCLASS_RESERVED_SLOTS(clasp);
@ -73,7 +73,7 @@ ProxyObject* ProxyObject::New(JSContext* cx, const BaseProxyHandler* handler,
Rooted<TaggedProto> proto(cx, proto_);
MOZ_ASSERT(!clasp->isNativeObject());
MOZ_ASSERT(clasp->isProxy());
MOZ_ASSERT(clasp->isProxyObject());
MOZ_ASSERT(isValidProxyClass(clasp));
MOZ_ASSERT(clasp->shouldDelayMetadataBuilder());
MOZ_ASSERT_IF(proto.isObject(),

View File

@ -122,7 +122,7 @@ class ProxyObject : public JSObject {
// Proxy classes are not allowed to have call or construct hooks directly.
// Their callability is instead decided by handler()->isCallable().
return clasp->isProxy() && clasp->isTrace(ProxyObject::trace) &&
return clasp->isProxyObject() && clasp->isTrace(ProxyObject::trace) &&
!clasp->getCall() && !clasp->getConstruct();
}
@ -138,8 +138,6 @@ class ProxyObject : public JSObject {
void nuke();
};
inline bool IsProxyClass(const JSClass* clasp) { return clasp->isProxy(); }
bool IsDerivedProxyObject(const JSObject* obj,
const js::BaseProxyHandler* handler);

View File

@ -117,7 +117,7 @@
MOZ_ALWAYS_INLINE size_t JSSLOT_FREE(const JSClass* clasp) {
// Proxy classes have reserved slots, but proxies manage their own slot
// layout.
MOZ_ASSERT(!clasp->isProxy());
MOZ_ASSERT(!clasp->isProxyObject());
return JSCLASS_RESERVED_SLOTS(clasp);
}
@ -1284,7 +1284,7 @@ class Shape : public gc::CellWithTenuredGCPointer<gc::TenuredCell, BaseShape> {
// Proxy classes have reserved slots, but proxies manage their own slot
// layout. This means all non-native object shapes have nfixed == 0 and
// slotSpan == 0.
uint32_t free = clasp->isProxy() ? 0 : JSSLOT_FREE(clasp);
uint32_t free = clasp->isProxyObject() ? 0 : JSSLOT_FREE(clasp);
return hasMissingSlot() ? free : std::max(free, maybeSlot() + 1);
}