зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1696861 part 6 - Rename Delegate flag to IsUsedAsPrototype. r=tcampbell
Differential Revision: https://phabricator.services.mozilla.com/D107421
This commit is contained in:
Родитель
b5e10bfb9d
Коммит
0ddf1b7480
|
@ -151,7 +151,7 @@ bool InterpretObjLiteralObj(JSContext* cx, HandlePlainObject obj,
|
|||
}
|
||||
|
||||
if (kind == PropertySetKind::UniqueNames) {
|
||||
if (!AddDataPropertyNonDelegate(cx, obj, propId, propVal)) {
|
||||
if (!AddDataPropertyNonPrototype(cx, obj, propId, propVal)) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
|
|
|
@ -8048,7 +8048,7 @@ void GCRuntime::mergeRealms(Realm* source, Realm* target) {
|
|||
if (GlobalObject::isOffThreadPrototypePlaceholder(obj)) {
|
||||
JSObject* targetProto =
|
||||
global->getPrototypeForOffThreadPlaceholder(obj);
|
||||
MOZ_ASSERT(targetProto->isDelegate());
|
||||
MOZ_ASSERT(targetProto->isUsedAsPrototype());
|
||||
baseShape->setProtoForMergeRealms(TaggedProto(targetProto));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,8 +17,8 @@ prettyprinters.clear_module_printers(__name__)
|
|||
class JSObjectTypeCache(object):
|
||||
def __init__(self, value, cache):
|
||||
object_flag = gdb.lookup_type("js::ObjectFlag")
|
||||
self.objectflag_Delegate = prettyprinters.enum_value(
|
||||
object_flag, "js::ObjectFlag::Delegate"
|
||||
self.objectflag_IsUsedAsPrototype = prettyprinters.enum_value(
|
||||
object_flag, "js::ObjectFlag::IsUsedAsPrototype"
|
||||
)
|
||||
self.func_ptr_type = gdb.lookup_type("JSFunction").pointer()
|
||||
self.class_NON_NATIVE = gdb.parse_and_eval("JSClass::NON_NATIVE")
|
||||
|
@ -60,7 +60,7 @@ class JSObjectPtrOrRef(prettyprinters.Pointer):
|
|||
return "[object {}]".format(class_name)
|
||||
else:
|
||||
flags = shape["objectFlags_"]["flags_"]
|
||||
is_delegate = bool(flags & self.otc.objectflag_Delegate)
|
||||
used_as_prototype = bool(flags & self.otc.objectflag_IsUsedAsPrototype)
|
||||
name = None
|
||||
if class_name == "Function":
|
||||
function = self.value
|
||||
|
@ -73,7 +73,7 @@ class JSObjectPtrOrRef(prettyprinters.Pointer):
|
|||
return "[object {}{}]{}".format(
|
||||
class_name,
|
||||
" " + name if name else "",
|
||||
" delegate" if is_delegate else "",
|
||||
" used_as_prototype" if used_as_prototype else "",
|
||||
)
|
||||
|
||||
|
||||
|
|
|
@ -13,7 +13,7 @@ run_fragment("JSObject.simple")
|
|||
|
||||
assert_pretty("glob", "(JSObject *) [object global]")
|
||||
assert_pretty("plain", "(JSObject *) [object Object]")
|
||||
assert_pretty("objectProto", "(JSObject *) [object Object] delegate")
|
||||
assert_pretty("objectProto", "(JSObject *) [object Object] used_as_prototype")
|
||||
assert_pretty("func", '(JSObject *) [object Function "dys"]')
|
||||
assert_pretty("anon", "(JSObject *) [object Function <unnamed>]")
|
||||
assert_pretty("funcPtr", '(JSFunction *) [object Function "formFollows"]')
|
||||
|
|
|
@ -645,7 +645,7 @@ static void TestMatchingProxyReceiver(CacheIRWriter& writer, ProxyObject* obj,
|
|||
static bool ProtoChainSupportsTeleporting(JSObject* obj, JSObject* holder) {
|
||||
// The receiver should already have been handled since its checks are always
|
||||
// required.
|
||||
MOZ_ASSERT(obj->isDelegate());
|
||||
MOZ_ASSERT(obj->isUsedAsPrototype());
|
||||
|
||||
// Prototype chain must have cacheable prototypes to ensure the cached
|
||||
// holder is the current holder.
|
||||
|
@ -714,7 +714,7 @@ static void GeneratePrototypeGuards(CacheIRWriter& writer, JSObject* obj,
|
|||
// Receiver guards (see TestMatchingReceiver) ensure the receiver's proto is
|
||||
// unchanged so peel off the receiver.
|
||||
JSObject* pobj = obj->staticPrototype();
|
||||
MOZ_ASSERT(pobj->isDelegate());
|
||||
MOZ_ASSERT(pobj->isUsedAsPrototype());
|
||||
|
||||
// If teleporting is supported for this prototype chain, we are done.
|
||||
if (ProtoChainSupportsTeleporting(pobj, holder)) {
|
||||
|
|
|
@ -1013,9 +1013,9 @@ static bool EnsureConstructor(JSContext* cx, Handle<GlobalObject*> global,
|
|||
return false;
|
||||
}
|
||||
|
||||
// Mark the prototype as delegate here because we can't GC in mergeRealms.
|
||||
// Set the used-as-prototype flag here because we can't GC in mergeRealms.
|
||||
RootedObject proto(cx, &global->getPrototype(key).toObject());
|
||||
return JSObject::setDelegate(cx, proto);
|
||||
return JSObject::setIsUsedAsPrototype(cx, proto);
|
||||
}
|
||||
|
||||
// Initialize all classes potentially created during parsing for use in parser
|
||||
|
|
|
@ -235,10 +235,6 @@ inline bool JSObject::isBoundFunction() const {
|
|||
return is<JSFunction>() && as<JSFunction>().isBoundFunction();
|
||||
}
|
||||
|
||||
inline bool JSObject::isDelegate() const {
|
||||
return hasFlag(js::ObjectFlag::Delegate);
|
||||
}
|
||||
|
||||
inline bool JSObject::hasUncacheableProto() const {
|
||||
return hasFlag(js::ObjectFlag::UncacheableProto);
|
||||
}
|
||||
|
|
|
@ -1523,9 +1523,9 @@ void JSObject::swap(JSContext* cx, HandleObject a, HandleObject b,
|
|||
// teleporting optimizations.
|
||||
//
|
||||
// See: ReshapeForProtoMutation, ReshapeForShadowedProp
|
||||
MOZ_ASSERT_IF(a->is<NativeObject>() && a->isDelegate(),
|
||||
MOZ_ASSERT_IF(a->is<NativeObject>() && a->isUsedAsPrototype(),
|
||||
a->taggedProto() == TaggedProto());
|
||||
MOZ_ASSERT_IF(b->is<NativeObject>() && b->isDelegate(),
|
||||
MOZ_ASSERT_IF(b->is<NativeObject>() && b->isUsedAsPrototype(),
|
||||
b->taggedProto() == TaggedProto());
|
||||
|
||||
bool aIsProxyWithInlineValues =
|
||||
|
@ -1751,12 +1751,12 @@ static bool ReshapeForProtoMutation(JSContext* cx, HandleObject obj) {
|
|||
//
|
||||
// There are two cases:
|
||||
//
|
||||
// (1) The object is not marked Delegate. This is the common case. Because
|
||||
// shape implies proto, we rely on the caller changing the object's shape.
|
||||
// The JIT guards on this object's shape or prototype so there's nothing
|
||||
// we have to do here for objects on the proto chain.
|
||||
// (1) The object is not marked IsUsedAsPrototype. This is the common case.
|
||||
// Because shape implies proto, we rely on the caller changing the
|
||||
// object's shape. The JIT guards on this object's shape or prototype so
|
||||
// there's nothing we have to do here for objects on the proto chain.
|
||||
//
|
||||
// (2) The object is marked Delegate. This implies the object may be
|
||||
// (2) The object is marked IsUsedAsPrototype. This implies the object may be
|
||||
// participating in shape teleporting. To invalidate JIT ICs depending on
|
||||
// the proto chain being unchanged, set the UncacheableProto shape flag
|
||||
// for this object and objects on its proto chain.
|
||||
|
@ -1771,7 +1771,7 @@ static bool ReshapeForProtoMutation(JSContext* cx, HandleObject obj) {
|
|||
// - GeneratePrototypeGuards
|
||||
// - GeneratePrototypeHoleGuards
|
||||
|
||||
if (!obj->isDelegate()) {
|
||||
if (!obj->isUsedAsPrototype()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1799,7 +1799,7 @@ static bool SetProto(JSContext* cx, HandleObject obj,
|
|||
|
||||
if (proto.isObject()) {
|
||||
RootedObject protoObj(cx, proto.toObject());
|
||||
if (!JSObject::setDelegate(cx, protoObj)) {
|
||||
if (!JSObject::setIsUsedAsPrototype(cx, protoObj)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -3209,15 +3209,27 @@ void JSObject::dump(js::GenericPrinter& out) const {
|
|||
out.printf(" shape %p\n", shape);
|
||||
|
||||
out.put(" flags:");
|
||||
if (obj->isDelegate()) out.put(" delegate");
|
||||
if (!obj->is<ProxyObject>() && !obj->nonProxyIsExtensible())
|
||||
if (obj->isUsedAsPrototype()) {
|
||||
out.put(" used_as_prototype");
|
||||
}
|
||||
if (!obj->is<ProxyObject>() && !obj->nonProxyIsExtensible()) {
|
||||
out.put(" not_extensible");
|
||||
if (obj->maybeHasInterestingSymbolProperty())
|
||||
}
|
||||
if (obj->maybeHasInterestingSymbolProperty()) {
|
||||
out.put(" maybe_has_interesting_symbol");
|
||||
if (obj->isBoundFunction()) out.put(" bound_function");
|
||||
if (obj->isQualifiedVarObj()) out.put(" varobj");
|
||||
if (obj->isUnqualifiedVarObj()) out.put(" unqualified_varobj");
|
||||
if (obj->hasUncacheableProto()) out.put(" has_uncacheable_proto");
|
||||
}
|
||||
if (obj->isBoundFunction()) {
|
||||
out.put(" bound_function");
|
||||
}
|
||||
if (obj->isQualifiedVarObj()) {
|
||||
out.put(" varobj");
|
||||
}
|
||||
if (obj->isUnqualifiedVarObj()) {
|
||||
out.put(" unqualified_varobj");
|
||||
}
|
||||
if (obj->hasUncacheableProto()) {
|
||||
out.put(" has_uncacheable_proto");
|
||||
}
|
||||
if (obj->hasStaticPrototype() && obj->staticPrototypeIsImmutable()) {
|
||||
out.put(" immutable_prototype");
|
||||
}
|
||||
|
|
|
@ -162,12 +162,22 @@ class JSObject
|
|||
static bool setProtoUnchecked(JSContext* cx, JS::HandleObject obj,
|
||||
js::Handle<js::TaggedProto> proto);
|
||||
|
||||
// An object is a delegate if it is (or was) another object's prototype.
|
||||
// Optimization heuristics will make use of this flag.
|
||||
// An object is marked IsUsedAsPrototype if it is (or was) another object's
|
||||
// prototype. Optimization heuristics will make use of this flag.
|
||||
//
|
||||
// This flag is only relevant for static prototypes. Proxy traps can return
|
||||
// objects without this flag set.
|
||||
//
|
||||
// NOTE: it's important to call setIsUsedAsPrototype *after* initializing the
|
||||
// object's properties, because that avoids unnecessary shadowing checks and
|
||||
// reshaping.
|
||||
//
|
||||
// See: ReshapeForProtoMutation, ReshapeForShadowedProp
|
||||
inline bool isDelegate() const;
|
||||
static bool setDelegate(JSContext* cx, JS::HandleObject obj) {
|
||||
return setFlag(cx, obj, js::ObjectFlag::Delegate, GENERATE_SHAPE);
|
||||
bool isUsedAsPrototype() const {
|
||||
return hasFlag(js::ObjectFlag::IsUsedAsPrototype);
|
||||
}
|
||||
static bool setIsUsedAsPrototype(JSContext* cx, JS::HandleObject obj) {
|
||||
return setFlag(cx, obj, js::ObjectFlag::IsUsedAsPrototype, GENERATE_SHAPE);
|
||||
}
|
||||
|
||||
inline bool isBoundFunction() const;
|
||||
|
@ -202,12 +212,13 @@ class JSObject
|
|||
// exist on the scope chain) are kept.
|
||||
inline bool isUnqualifiedVarObj() const;
|
||||
|
||||
// An object with an "uncacheable proto" is a Delegate object that either had
|
||||
// An object with an "uncacheable proto" is a prototype object that either had
|
||||
// its own proto mutated or it was on the proto chain of an object that had
|
||||
// its proto mutated. This is used to opt-out of the shape teleporting
|
||||
// optimization. See: ReshapeForProtoMutation, ProtoChainSupportsTeleporting.
|
||||
inline bool hasUncacheableProto() const;
|
||||
static bool setUncacheableProto(JSContext* cx, JS::HandleObject obj) {
|
||||
MOZ_ASSERT(obj->isUsedAsPrototype());
|
||||
MOZ_ASSERT(obj->hasStaticPrototype(),
|
||||
"uncacheability as a concept is only applicable to static "
|
||||
"(not dynamically-computed) prototypes");
|
||||
|
|
|
@ -853,11 +853,11 @@ inline bool IsPackedArray(JSObject* obj) {
|
|||
return true;
|
||||
}
|
||||
|
||||
MOZ_ALWAYS_INLINE bool AddDataPropertyNonDelegate(JSContext* cx,
|
||||
HandlePlainObject obj,
|
||||
HandleId id, HandleValue v) {
|
||||
MOZ_ALWAYS_INLINE bool AddDataPropertyNonPrototype(JSContext* cx,
|
||||
HandlePlainObject obj,
|
||||
HandleId id, HandleValue v) {
|
||||
MOZ_ASSERT(!JSID_IS_INT(id));
|
||||
MOZ_ASSERT(!obj->isDelegate());
|
||||
MOZ_ASSERT(!obj->isUsedAsPrototype());
|
||||
|
||||
// If we know this is a new property we can call addProperty instead of
|
||||
// the slower putProperty.
|
||||
|
|
|
@ -1223,7 +1223,7 @@ static bool WouldDefinePastNonwritableLength(ArrayObject* arr, uint32_t index) {
|
|||
|
||||
static bool ReshapeForShadowedPropSlow(JSContext* cx, HandleNativeObject obj,
|
||||
HandleId id) {
|
||||
MOZ_ASSERT(obj->isDelegate());
|
||||
MOZ_ASSERT(obj->isUsedAsPrototype());
|
||||
|
||||
// Lookups on integer ids cannot be cached through prototypes.
|
||||
if (JSID_IS_INT(id)) {
|
||||
|
@ -1257,7 +1257,7 @@ static MOZ_ALWAYS_INLINE bool ReshapeForShadowedProp(JSContext* cx,
|
|||
// See also the 'Shape Teleporting Optimization' comment in jit/CacheIR.cpp.
|
||||
|
||||
// Inlined fast path for non-prototype/non-native objects.
|
||||
if (!obj->isDelegate() || !obj->is<NativeObject>()) {
|
||||
if (!obj->isUsedAsPrototype() || !obj->is<NativeObject>()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -2767,7 +2767,7 @@ bool js::CopyDataPropertiesNative(JSContext* cx, HandlePlainObject target,
|
|||
Handle<PlainObject*> excludedItems,
|
||||
bool* optimized) {
|
||||
MOZ_ASSERT(
|
||||
!target->isDelegate(),
|
||||
!target->isUsedAsPrototype(),
|
||||
"CopyDataPropertiesNative should only be called during object literal "
|
||||
"construction"
|
||||
"which precludes that |target| is the prototype of any other object");
|
||||
|
@ -2837,7 +2837,7 @@ bool js::CopyDataPropertiesNative(JSContext* cx, HandlePlainObject target,
|
|||
MOZ_ASSERT(!target->contains(cx, key),
|
||||
"didn't expect to find an existing property");
|
||||
|
||||
if (!AddDataPropertyNonDelegate(cx, target, key, value)) {
|
||||
if (!AddDataPropertyNonPrototype(cx, target, key, value)) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
|
|
|
@ -56,7 +56,7 @@ bool GlobalObject::splicePrototype(JSContext* cx, Handle<GlobalObject*> global,
|
|||
|
||||
if (proto.isObject()) {
|
||||
RootedObject protoObj(cx, proto.toObject());
|
||||
if (!JSObject::setDelegate(cx, protoObj)) {
|
||||
if (!JSObject::setIsUsedAsPrototype(cx, protoObj)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1390,7 +1390,7 @@ bool JSObject::setFlag(JSContext* cx, HandleObject obj, ObjectFlag flag,
|
|||
bool JSObject::setProtoUnchecked(JSContext* cx, HandleObject obj,
|
||||
Handle<TaggedProto> proto) {
|
||||
MOZ_ASSERT(cx->compartment() == obj->compartment());
|
||||
MOZ_ASSERT_IF(proto.isObject(), proto.toObject()->isDelegate());
|
||||
MOZ_ASSERT_IF(proto.isObject(), proto.toObject()->isUsedAsPrototype());
|
||||
|
||||
if (obj->shape()->proto() == proto) {
|
||||
return true;
|
||||
|
@ -1469,7 +1469,7 @@ inline BaseShape::BaseShape(const StackBaseShape& base)
|
|||
|
||||
MOZ_ASSERT_IF(proto().isObject(),
|
||||
compartment() == proto().toObject()->compartment());
|
||||
MOZ_ASSERT_IF(proto().isObject(), proto().toObject()->isDelegate());
|
||||
MOZ_ASSERT_IF(proto().isObject(), proto().toObject()->isUsedAsPrototype());
|
||||
|
||||
// Windows may not appear on prototype chains.
|
||||
MOZ_ASSERT_IF(proto().isObject(), !IsWindow(proto().toObject()));
|
||||
|
@ -1985,9 +1985,9 @@ Shape* EmptyShape::getInitialShape(JSContext* cx, const JSClass* clasp,
|
|||
MOZ_ASSERT_IF(proto.isObject(),
|
||||
cx->isInsideCurrentCompartment(proto.toObject()));
|
||||
|
||||
if (proto.isObject() && !proto.toObject()->isDelegate()) {
|
||||
if (proto.isObject() && !proto.toObject()->isUsedAsPrototype()) {
|
||||
RootedObject protoObj(cx, proto.toObject());
|
||||
if (!JSObject::setDelegate(cx, protoObj)) {
|
||||
if (!JSObject::setIsUsedAsPrototype(cx, protoObj)) {
|
||||
return nullptr;
|
||||
}
|
||||
proto = TaggedProto(protoObj);
|
||||
|
|
|
@ -646,7 +646,7 @@ struct StackBaseShape;
|
|||
// If you add a new flag here, please add appropriate code to JSObject::dump to
|
||||
// dump it as part of the object representation.
|
||||
enum class ObjectFlag : uint16_t {
|
||||
Delegate = 1 << 0,
|
||||
IsUsedAsPrototype = 1 << 0,
|
||||
NotExtensible = 1 << 1,
|
||||
Indexed = 1 << 2,
|
||||
HasInterestingSymbol = 1 << 3,
|
||||
|
|
Загрузка…
Ссылка в новой задаче