mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-16 23:05:42 +00:00
Bug 1723085 part 2 - Optimize getting/setting reserved slots inside the JS engine. r=jonco
After removing private slots, we can optimize gets/sets of reserved slots by relying on the fact that fixed slots are used for them (up to the maximum number of fixed slots). This means we no longer need to read obj->shape->numFixedSlots when getting/setting reserved slots and can optimize a slot access with constant index (the common case) to a single memory load/store. Unfortunately doing the same for the JS::GetReservedSlot and JS::SetReservedSlot APIs is more complicated because these can also be used for proxies and swappable DOM objects. Differential Revision: https://phabricator.services.mozilla.com/D121356
This commit is contained in:
parent
d6bd2be0c6
commit
16e64b6d3f
@ -2075,13 +2075,19 @@ JS_PUBLIC_API void JS_SetAllNonReservedSlotsToUndefined(JS::HandleObject obj) {
|
||||
|
||||
JS_PUBLIC_API void JS_SetReservedSlot(JSObject* obj, uint32_t index,
|
||||
const Value& value) {
|
||||
obj->as<NativeObject>().setReservedSlot(index, value);
|
||||
// Note: we don't use setReservedSlot so that this also works on swappable DOM
|
||||
// objects. See NativeObject::getReservedSlotRef comment.
|
||||
MOZ_ASSERT(index < JSCLASS_RESERVED_SLOTS(obj->getClass()));
|
||||
obj->as<NativeObject>().setSlot(index, value);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API void JS_InitReservedSlot(JSObject* obj, uint32_t index, void* ptr,
|
||||
size_t nbytes, JS::MemoryUse use) {
|
||||
InitReservedSlot(&obj->as<NativeObject>(), index, ptr, nbytes,
|
||||
js::MemoryUse(use));
|
||||
// Note: we don't use InitReservedSlot so that this also works on swappable
|
||||
// DOM objects. See NativeObject::getReservedSlotRef comment.
|
||||
MOZ_ASSERT(index < JSCLASS_RESERVED_SLOTS(obj->getClass()));
|
||||
AddCellMemory(obj, nbytes, js::MemoryUse(use));
|
||||
obj->as<NativeObject>().initSlot(index, PrivateValue(ptr));
|
||||
}
|
||||
|
||||
JS_PUBLIC_API bool JS::IsMapObject(JSContext* cx, JS::HandleObject obj,
|
||||
|
@ -446,6 +446,8 @@ void JS::detail::SetReservedSlotWithBarrier(JSObject* obj, size_t slot,
|
||||
if (obj->is<ProxyObject>()) {
|
||||
obj->as<ProxyObject>().setReservedSlot(slot, value);
|
||||
} else {
|
||||
// Note: we don't use setReservedSlot so that this also works on swappable
|
||||
// DOM objects. See NativeObject::getReservedSlotRef comment.
|
||||
obj->as<NativeObject>().setSlot(slot, value);
|
||||
}
|
||||
}
|
||||
|
@ -1123,20 +1123,42 @@ class NativeObject : public JSObject {
|
||||
|
||||
inline void shiftDenseElementsUnchecked(uint32_t count);
|
||||
|
||||
// Like getSlotRef, but optimized for reserved slots. This relies on the fact
|
||||
// that the first reserved slots (up to MAX_FIXED_SLOTS) are always stored in
|
||||
// fixed slots. This lets the compiler optimize away the branch below when
|
||||
// |index| is a constant (after inlining).
|
||||
//
|
||||
// Note: objects that may be swapped have less predictable slot layouts
|
||||
// because they could have been swapped with an object with fewer fixed slots.
|
||||
// Fortunately, the only native objects that can be swapped are DOM objects
|
||||
// and these shouldn't end up here (asserted below).
|
||||
MOZ_ALWAYS_INLINE HeapSlot& getReservedSlotRef(uint32_t index) {
|
||||
MOZ_ASSERT(index < JSSLOT_FREE(getClass()));
|
||||
MOZ_ASSERT(slotIsFixed(index) == (index < MAX_FIXED_SLOTS));
|
||||
MOZ_ASSERT(!ObjectMayBeSwapped(this));
|
||||
return index < MAX_FIXED_SLOTS ? fixedSlots()[index]
|
||||
: slots_[index - MAX_FIXED_SLOTS];
|
||||
}
|
||||
MOZ_ALWAYS_INLINE const HeapSlot& getReservedSlotRef(uint32_t index) const {
|
||||
MOZ_ASSERT(index < JSSLOT_FREE(getClass()));
|
||||
MOZ_ASSERT(slotIsFixed(index) == (index < MAX_FIXED_SLOTS));
|
||||
MOZ_ASSERT(!ObjectMayBeSwapped(this));
|
||||
return index < MAX_FIXED_SLOTS ? fixedSlots()[index]
|
||||
: slots_[index - MAX_FIXED_SLOTS];
|
||||
}
|
||||
|
||||
public:
|
||||
MOZ_ALWAYS_INLINE const Value& getReservedSlot(uint32_t index) const {
|
||||
MOZ_ASSERT(index < JSSLOT_FREE(getClass()));
|
||||
return getSlot(index);
|
||||
return getReservedSlotRef(index);
|
||||
}
|
||||
|
||||
MOZ_ALWAYS_INLINE void initReservedSlot(uint32_t index, const Value& v) {
|
||||
MOZ_ASSERT(index < JSSLOT_FREE(getClass()));
|
||||
initSlot(index, v);
|
||||
MOZ_ASSERT(getReservedSlot(index).isUndefined());
|
||||
checkStoredValue(v);
|
||||
getReservedSlotRef(index).init(this, HeapSlot::Slot, index, v);
|
||||
}
|
||||
|
||||
MOZ_ALWAYS_INLINE void setReservedSlot(uint32_t index, const Value& v) {
|
||||
MOZ_ASSERT(index < JSSLOT_FREE(getClass()));
|
||||
setSlot(index, v);
|
||||
checkStoredValue(v);
|
||||
getReservedSlotRef(index).set(this, HeapSlot::Slot, index, v);
|
||||
}
|
||||
|
||||
// For slots which are known to always be fixed, due to the way they are
|
||||
@ -1482,11 +1504,11 @@ class NativeObject : public JSObject {
|
||||
gc::Cell* cell) {
|
||||
MOZ_ASSERT(slot < JSCLASS_RESERVED_SLOTS(getClass()));
|
||||
MOZ_ASSERT(cell);
|
||||
getSlotAddress(slot)->unbarrieredSet(PrivateValue(cell));
|
||||
getReservedSlotRef(slot).unbarrieredSet(PrivateValue(cell));
|
||||
}
|
||||
void clearReservedSlotGCThingAsPrivate(uint32_t slot) {
|
||||
MOZ_ASSERT(slot < JSCLASS_RESERVED_SLOTS(getClass()));
|
||||
HeapSlot* pslot = getSlotAddress(slot);
|
||||
HeapSlot* pslot = &getReservedSlotRef(slot);
|
||||
if (!pslot->isUndefined()) {
|
||||
privatePreWriteBarrier(pslot);
|
||||
pslot->unbarrieredSet(UndefinedValue());
|
||||
|
Loading…
Reference in New Issue
Block a user