mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-17 07:15:46 +00:00
Bug 1401577 - Optimize object flag accessors on native objects. r=anba
This commit is contained in:
parent
af29d63449
commit
810244a62c
@ -1680,7 +1680,7 @@ CanAttachDenseElementHole(JSObject* obj, bool ownProp)
|
||||
// because we would have to lookup a property on the prototype instead.
|
||||
do {
|
||||
// The first two checks are also relevant to the receiver object.
|
||||
if (obj->isIndexed())
|
||||
if (obj->isNative() && obj->as<NativeObject>().isIndexed())
|
||||
return false;
|
||||
|
||||
if (ClassCanHaveExtraProperties(obj->getClass()))
|
||||
@ -3149,7 +3149,7 @@ CanAttachAddElement(JSObject* obj, bool isInit)
|
||||
// or that such properties can't appear without a shape change.
|
||||
do {
|
||||
// The first two checks are also relevant to the receiver object.
|
||||
if (obj->isIndexed())
|
||||
if (obj->isNative() && obj->as<NativeObject>().isIndexed())
|
||||
return false;
|
||||
|
||||
const Class* clasp = obj->getClass();
|
||||
|
@ -531,7 +531,8 @@ SetArrayElement(JSContext* cx, HandleObject obj, uint64_t index, HandleValue v)
|
||||
static bool
|
||||
DeleteArrayElement(JSContext* cx, HandleObject obj, uint64_t index, ObjectOpResult& result)
|
||||
{
|
||||
if (obj->is<ArrayObject>() && !obj->isIndexed() &&
|
||||
if (obj->is<ArrayObject>() &&
|
||||
!obj->as<NativeObject>().isIndexed() &&
|
||||
!obj->as<NativeObject>().denseElementsAreFrozen())
|
||||
{
|
||||
ArrayObject* aobj = &obj->as<ArrayObject>();
|
||||
@ -579,7 +580,8 @@ DeletePropertyOrThrow(JSContext* cx, HandleObject obj, uint64_t index)
|
||||
static bool
|
||||
DeletePropertiesOrThrow(JSContext* cx, HandleObject obj, uint64_t len, uint64_t finalLength)
|
||||
{
|
||||
if (obj->is<ArrayObject>() && !obj->isIndexed() &&
|
||||
if (obj->is<ArrayObject>() &&
|
||||
!obj->as<NativeObject>().isIndexed() &&
|
||||
!obj->as<NativeObject>().denseElementsAreFrozen())
|
||||
{
|
||||
if (len <= UINT32_MAX) {
|
||||
@ -988,10 +990,16 @@ array_addProperty(JSContext* cx, HandleObject obj, HandleId id, HandleValue v)
|
||||
static inline bool
|
||||
ObjectMayHaveExtraIndexedOwnProperties(JSObject* obj)
|
||||
{
|
||||
return (!obj->isNative() && !obj->is<UnboxedArrayObject>()) ||
|
||||
obj->isIndexed() ||
|
||||
obj->is<TypedArrayObject>() ||
|
||||
ClassMayResolveId(*obj->runtimeFromAnyThread()->commonNames,
|
||||
if (!obj->isNative())
|
||||
return !obj->is<UnboxedArrayObject>();
|
||||
|
||||
if (obj->as<NativeObject>().isIndexed())
|
||||
return true;
|
||||
|
||||
if (obj->is<TypedArrayObject>())
|
||||
return true;
|
||||
|
||||
return ClassMayResolveId(*obj->runtimeFromAnyThread()->commonNames,
|
||||
obj->getClass(), INT_TO_JSID(0), obj);
|
||||
}
|
||||
|
||||
@ -3138,8 +3146,8 @@ GetIndexedPropertiesInRange(JSContext* cx, HandleObject obj, uint64_t begin, uin
|
||||
}
|
||||
|
||||
// Append typed array elements.
|
||||
if (pobj->is<TypedArrayObject>()) {
|
||||
uint32_t len = pobj->as<TypedArrayObject>().length();
|
||||
if (nativeObj->is<TypedArrayObject>()) {
|
||||
uint32_t len = nativeObj->as<TypedArrayObject>().length();
|
||||
for (uint32_t i = begin; i < len && i < end; i++) {
|
||||
if (!indexes.append(i))
|
||||
return false;
|
||||
@ -3147,8 +3155,8 @@ GetIndexedPropertiesInRange(JSContext* cx, HandleObject obj, uint64_t begin, uin
|
||||
}
|
||||
|
||||
// Append sparse elements.
|
||||
if (pobj->isIndexed()) {
|
||||
Shape::Range<NoGC> r(pobj->as<NativeObject>().lastProperty());
|
||||
if (nativeObj->isIndexed()) {
|
||||
Shape::Range<NoGC> r(nativeObj->lastProperty());
|
||||
for (; !r.empty(); r.popFront()) {
|
||||
Shape& shape = r.front();
|
||||
jsid id = shape.propid();
|
||||
@ -3278,7 +3286,7 @@ ArraySliceOrdinary(JSContext* cx, HandleObject obj, uint64_t begin, uint64_t end
|
||||
}
|
||||
}
|
||||
|
||||
if (obj->isNative() && obj->isIndexed() && count > 1000) {
|
||||
if (obj->isNative() && obj->as<NativeObject>().isIndexed() && count > 1000) {
|
||||
if (!SliceSparse(cx, obj, begin, end, narr))
|
||||
return false;
|
||||
} else {
|
||||
|
@ -1161,7 +1161,7 @@ GetScriptArrayObjectElements(JSContext* cx, HandleObject obj, MutableHandle<GCVe
|
||||
{
|
||||
MOZ_ASSERT(!obj->isSingleton());
|
||||
MOZ_ASSERT(obj->is<ArrayObject>() || obj->is<UnboxedArrayObject>());
|
||||
MOZ_ASSERT(!obj->isIndexed());
|
||||
MOZ_ASSERT_IF(obj->isNative(), !obj->as<NativeObject>().isIndexed());
|
||||
|
||||
size_t length = GetAnyBoxedOrUnboxedArrayLength(obj);
|
||||
if (!values.appendN(MagicValue(JS_ELEMENTS_HOLE), length))
|
||||
@ -3586,7 +3586,6 @@ JSObject::dump(js::GenericPrinter& out) const
|
||||
out.put("flags:");
|
||||
if (obj->isDelegate()) out.put(" delegate");
|
||||
if (!obj->is<ProxyObject>() && !obj->nonProxyIsExtensible()) out.put(" not_extensible");
|
||||
if (obj->isIndexed()) out.put(" indexed");
|
||||
if (obj->maybeHasInterestingSymbolProperty()) out.put(" maybe_has_interesting_symbol");
|
||||
if (obj->isBoundFunction()) out.put(" bound_function");
|
||||
if (obj->isQualifiedVarObj()) out.put(" varobj");
|
||||
@ -3595,8 +3594,6 @@ JSObject::dump(js::GenericPrinter& out) const
|
||||
if (obj->isIteratedSingleton()) out.put(" iterated_singleton");
|
||||
if (obj->isNewGroupUnknown()) out.put(" new_type_unknown");
|
||||
if (obj->hasUncacheableProto()) out.put(" has_uncacheable_proto");
|
||||
if (obj->hadElementsAccess()) out.put(" had_elements_access");
|
||||
if (obj->wasNewScriptCleared()) out.put(" new_script_cleared");
|
||||
if (obj->hasStaticPrototype() && obj->staticPrototypeIsImmutable())
|
||||
out.put(" immutable_prototype");
|
||||
|
||||
@ -3606,6 +3603,12 @@ JSObject::dump(js::GenericPrinter& out) const
|
||||
out.put(" inDictionaryMode");
|
||||
if (nobj->hasShapeTable())
|
||||
out.put(" hasShapeTable");
|
||||
if (nobj->hadElementsAccess())
|
||||
out.put(" had_elements_access");
|
||||
if (nobj->isIndexed())
|
||||
out.put(" indexed");
|
||||
if (nobj->wasNewScriptCleared())
|
||||
out.put(" new_script_cleared");
|
||||
}
|
||||
out.putChar('\n');
|
||||
|
||||
|
@ -235,21 +235,6 @@ class JSObject : public js::gc::Cell
|
||||
return setFlags(cx, obj, js::BaseShape::UNCACHEABLE_PROTO, GENERATE_SHAPE);
|
||||
}
|
||||
|
||||
/*
|
||||
* Whether SETLELEM was used to access this object. See also the comment near
|
||||
* PropertyTree::MAX_HEIGHT.
|
||||
*/
|
||||
inline bool hadElementsAccess() const;
|
||||
static bool setHadElementsAccess(JSContext* cx, JS::HandleObject obj) {
|
||||
return setFlags(cx, obj, js::BaseShape::HAD_ELEMENTS_ACCESS);
|
||||
}
|
||||
|
||||
/*
|
||||
* Whether there may be indexed properties on this object, excluding any in
|
||||
* the object's elements.
|
||||
*/
|
||||
inline bool isIndexed() const;
|
||||
|
||||
/*
|
||||
* Whether there may be "interesting symbol" properties on this object. An
|
||||
* interesting symbol is a symbol for which symbol->isInterestingSymbol()
|
||||
@ -413,12 +398,6 @@ class JSObject : public js::gc::Cell
|
||||
inline bool isNewGroupUnknown() const;
|
||||
static bool setNewGroupUnknown(JSContext* cx, const js::Class* clasp, JS::HandleObject obj);
|
||||
|
||||
// Mark an object as having its 'new' script information cleared.
|
||||
inline bool wasNewScriptCleared() const;
|
||||
static bool setNewScriptCleared(JSContext* cx, JS::HandleObject obj) {
|
||||
return setFlags(cx, obj, js::BaseShape::NEW_SCRIPT_CLEARED);
|
||||
}
|
||||
|
||||
/* Set a new prototype for an object with a singleton type. */
|
||||
static bool splicePrototype(JSContext* cx, js::HandleObject obj, const js::Class* clasp,
|
||||
js::Handle<js::TaggedProto> proto);
|
||||
|
@ -468,18 +468,6 @@ JSObject::hasUncacheableProto() const
|
||||
return hasAllFlags(js::BaseShape::UNCACHEABLE_PROTO);
|
||||
}
|
||||
|
||||
inline bool
|
||||
JSObject::hadElementsAccess() const
|
||||
{
|
||||
return hasAllFlags(js::BaseShape::HAD_ELEMENTS_ACCESS);
|
||||
}
|
||||
|
||||
inline bool
|
||||
JSObject::isIndexed() const
|
||||
{
|
||||
return hasAllFlags(js::BaseShape::INDEXED);
|
||||
}
|
||||
|
||||
MOZ_ALWAYS_INLINE bool
|
||||
JSObject::maybeHasInterestingSymbolProperty() const
|
||||
{
|
||||
@ -494,7 +482,7 @@ JSObject::maybeHasInterestingSymbolProperty() const
|
||||
return true;
|
||||
}
|
||||
|
||||
return nobj->hasAllFlags(js::BaseShape::HAS_INTERESTING_SYMBOL);
|
||||
return nobj->hasInterestingSymbol();
|
||||
}
|
||||
|
||||
inline bool
|
||||
@ -516,12 +504,6 @@ JSObject::isNewGroupUnknown() const
|
||||
return hasAllFlags(js::BaseShape::NEW_GROUP_UNKNOWN);
|
||||
}
|
||||
|
||||
inline bool
|
||||
JSObject::wasNewScriptCleared() const
|
||||
{
|
||||
return hasAllFlags(js::BaseShape::NEW_SCRIPT_CLEARED);
|
||||
}
|
||||
|
||||
namespace js {
|
||||
|
||||
static MOZ_ALWAYS_INLINE bool
|
||||
|
@ -505,7 +505,7 @@ JA(JSContext* cx, HandleObject obj, StringifyContext* scx)
|
||||
"all its initially-dense elements were sparsified "
|
||||
"and the object is indexed");
|
||||
} else {
|
||||
MOZ_ASSERT(obj->isIndexed());
|
||||
MOZ_ASSERT(nativeObj->isIndexed());
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
@ -1630,10 +1630,10 @@ SetObjectElementOperation(JSContext* cx, HandleObject obj, HandleId id, HandleVa
|
||||
if (obj->isNative() &&
|
||||
JSID_IS_ATOM(id) &&
|
||||
!obj->as<NativeObject>().inDictionaryMode() &&
|
||||
!obj->hadElementsAccess() &&
|
||||
!obj->as<NativeObject>().hadElementsAccess() &&
|
||||
obj->as<NativeObject>().slotSpan() > PropertyTree::MAX_HEIGHT_WITH_ELEMENTS_ACCESS / 3)
|
||||
{
|
||||
if (!JSObject::setHadElementsAccess(cx, obj))
|
||||
if (!NativeObject::setHadElementsAccess(cx, obj.as<NativeObject>()))
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -720,6 +720,53 @@ class NativeObject : public ShapedObject
|
||||
return slot - numFixedSlots();
|
||||
}
|
||||
|
||||
/*
|
||||
* The methods below shadow methods on JSObject and are more efficient for
|
||||
* known-native objects.
|
||||
*/
|
||||
bool hasAllFlags(js::BaseShape::Flag flags) const {
|
||||
MOZ_ASSERT(flags);
|
||||
return shape_->hasAllObjectFlags(flags);
|
||||
}
|
||||
bool watched() const {
|
||||
return hasAllFlags(js::BaseShape::WATCHED);
|
||||
}
|
||||
bool nonProxyIsExtensible() const {
|
||||
return !hasAllFlags(js::BaseShape::NOT_EXTENSIBLE);
|
||||
}
|
||||
|
||||
/*
|
||||
* Whether there may be indexed properties on this object, excluding any in
|
||||
* the object's elements.
|
||||
*/
|
||||
bool isIndexed() const {
|
||||
return hasAllFlags(js::BaseShape::INDEXED);
|
||||
}
|
||||
|
||||
static bool setHadElementsAccess(JSContext* cx, HandleNativeObject obj) {
|
||||
return setFlags(cx, obj, js::BaseShape::HAD_ELEMENTS_ACCESS);
|
||||
}
|
||||
|
||||
/*
|
||||
* Whether SETLELEM was used to access this object. See also the comment near
|
||||
* PropertyTree::MAX_HEIGHT.
|
||||
*/
|
||||
bool hadElementsAccess() const {
|
||||
return hasAllFlags(js::BaseShape::HAD_ELEMENTS_ACCESS);
|
||||
}
|
||||
|
||||
// Mark an object as having its 'new' script information cleared.
|
||||
bool wasNewScriptCleared() const {
|
||||
return hasAllFlags(js::BaseShape::NEW_SCRIPT_CLEARED);
|
||||
}
|
||||
static bool setNewScriptCleared(JSContext* cx, HandleNativeObject obj) {
|
||||
return setFlags(cx, obj, js::BaseShape::NEW_SCRIPT_CLEARED);
|
||||
}
|
||||
|
||||
bool hasInterestingSymbol() const {
|
||||
return hasAllFlags(js::BaseShape::HAS_INTERESTING_SYMBOL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Grow or shrink slots immediately before changing the slot span.
|
||||
* The number of allocated slots is not stored explicitly, and changes to
|
||||
|
@ -320,7 +320,7 @@ JSObject::makeLazyGroup(JSContext* cx, HandleObject obj)
|
||||
if (obj->isIteratedSingleton())
|
||||
initialFlags |= OBJECT_FLAG_ITERATED;
|
||||
|
||||
if (obj->isIndexed())
|
||||
if (obj->isNative() && obj->as<NativeObject>().isIndexed())
|
||||
initialFlags |= OBJECT_FLAG_SPARSE_INDEXES;
|
||||
|
||||
if (obj->is<ArrayObject>() && obj->as<ArrayObject>().length() > INT32_MAX)
|
||||
@ -497,7 +497,7 @@ ObjectGroup::defaultNewGroup(JSContext* cx, const Class* clasp,
|
||||
|
||||
// If we have previously cleared the 'new' script information for this
|
||||
// function, don't try to construct another one.
|
||||
if (associated && associated->wasNewScriptCleared())
|
||||
if (associated && associated->as<JSFunction>().wasNewScriptCleared())
|
||||
associated = nullptr;
|
||||
|
||||
} else {
|
||||
|
@ -3044,7 +3044,7 @@ ObjectGroup::clearNewScript(JSContext* cx, ObjectGroup* replacement /* = nullptr
|
||||
// Mark the constructing function as having its 'new' script cleared, so we
|
||||
// will not try to construct another one later.
|
||||
RootedFunction fun(cx, newScript->function());
|
||||
if (!JSObject::setNewScriptCleared(cx, fun))
|
||||
if (!NativeObject::setNewScriptCleared(cx, fun))
|
||||
cx->recoverFromOutOfMemory();
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user