зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1804253 part 4 - Optimize checks for native objects and proxies. r=jonco
This saves two dereferences by looking at the shape instead of the class. Differential Revision: https://phabricator.services.mozilla.com/D164214
This commit is contained in:
Родитель
326592ff60
Коммит
2031ad337d
|
@ -381,7 +381,7 @@ class JS_PUBLIC_API BaseProxyHandler {
|
|||
extern JS_PUBLIC_DATA const JSClass ProxyClass;
|
||||
|
||||
inline bool IsProxy(const JSObject* obj) {
|
||||
return JS::GetClass(obj)->isProxyObject();
|
||||
return reinterpret_cast<const JS::shadow::Object*>(obj)->shape->isProxy();
|
||||
}
|
||||
|
||||
namespace detail {
|
||||
|
|
|
@ -35,8 +35,27 @@ class Shape {
|
|||
shadow::BaseShape* base;
|
||||
uint32_t immutableFlags;
|
||||
|
||||
enum class Kind : uint8_t {
|
||||
// SharedShape or DictionaryShape for NativeObject.
|
||||
// (Only) these two kinds must have the low bit set, to allow for fast
|
||||
// is-native checking.
|
||||
Shared = 1,
|
||||
Dictionary = 3,
|
||||
// ProxyShape for ProxyObject.
|
||||
Proxy = 0,
|
||||
// WasmGCShape for WasmGCObject.
|
||||
WasmGC = 2,
|
||||
};
|
||||
|
||||
static constexpr uint32_t KIND_SHIFT = 4;
|
||||
static constexpr uint32_t KIND_MASK = 0b11;
|
||||
|
||||
static constexpr uint32_t FIXED_SLOTS_SHIFT = 6;
|
||||
static constexpr uint32_t FIXED_SLOTS_MASK = 0x1f << FIXED_SLOTS_SHIFT;
|
||||
|
||||
bool isProxy() const {
|
||||
return Kind((immutableFlags >> KIND_SHIFT) & KIND_MASK) == Kind::Proxy;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace shadow
|
||||
|
|
|
@ -724,8 +724,13 @@ void MacroAssembler::branchTestClassIsProxy(bool proxy, Register clasp,
|
|||
|
||||
void MacroAssembler::branchTestObjectIsProxy(bool proxy, Register object,
|
||||
Register scratch, Label* label) {
|
||||
loadObjClassUnsafe(object, scratch);
|
||||
branchTestClassIsProxy(proxy, scratch, label);
|
||||
constexpr uint32_t ShiftedMask = (Shape::kindMask() << Shape::kindShift());
|
||||
static_assert(uint32_t(Shape::Kind::Proxy) == 0,
|
||||
"branchTest32 below depends on proxy kind being 0");
|
||||
loadPtr(Address(object, JSObject::offsetOfShape()), scratch);
|
||||
branchTest32(proxy ? Assembler::Zero : Assembler::NonZero,
|
||||
Address(scratch, Shape::offsetOfImmutableFlags()),
|
||||
Imm32(ShiftedMask), label);
|
||||
}
|
||||
|
||||
void MacroAssembler::branchTestProxyHandlerFamily(Condition cond,
|
||||
|
@ -735,8 +740,7 @@ void MacroAssembler::branchTestProxyHandlerFamily(Condition cond,
|
|||
Label* label) {
|
||||
#ifdef DEBUG
|
||||
Label ok;
|
||||
loadObjClassUnsafe(proxy, scratch);
|
||||
branchTestClassIsProxy(true, scratch, &ok);
|
||||
branchTestObjectIsProxy(true, proxy, scratch, &ok);
|
||||
assumeUnreachable("Expected ProxyObject in branchTestProxyHandlerFamily");
|
||||
bind(&ok);
|
||||
#endif
|
||||
|
|
|
@ -4139,9 +4139,10 @@ void MacroAssembler::branchTestObjCompartment(
|
|||
|
||||
void MacroAssembler::branchIfNonNativeObj(Register obj, Register scratch,
|
||||
Label* label) {
|
||||
loadObjClassUnsafe(obj, scratch);
|
||||
branchTest32(Assembler::NonZero, Address(scratch, JSClass::offsetOfFlags()),
|
||||
Imm32(JSClass::NON_NATIVE), label);
|
||||
loadPtr(Address(obj, JSObject::offsetOfShape()), scratch);
|
||||
branchTest32(Assembler::Zero,
|
||||
Address(scratch, Shape::offsetOfImmutableFlags()),
|
||||
Imm32(Shape::isNativeBit()), label);
|
||||
}
|
||||
|
||||
void MacroAssembler::branchIfObjectNotExtensible(Register obj, Register scratch,
|
||||
|
|
|
@ -1747,7 +1747,7 @@ extern bool GetNameBoundInEnvironment(JSContext* cx, HandleObject env,
|
|||
|
||||
template <>
|
||||
inline bool JSObject::is<js::NativeObject>() const {
|
||||
return getClass()->isNativeObject();
|
||||
return shape()->isNative();
|
||||
}
|
||||
|
||||
namespace js {
|
||||
|
|
|
@ -275,15 +275,7 @@ class Shape : public gc::CellWithTenuredGCPointer<gc::TenuredCell, BaseShape> {
|
|||
// Base shape, stored in the cell header.
|
||||
BaseShape* base() const { return headerPtr(); }
|
||||
|
||||
enum class Kind : uint8_t {
|
||||
// SharedShape or DictionaryShape for NativeObject.
|
||||
Shared,
|
||||
Dictionary,
|
||||
// ProxyShape for ProxyObject.
|
||||
Proxy,
|
||||
// WasmGCShape for WasmGCObject.
|
||||
WasmGC,
|
||||
};
|
||||
using Kind = JS::shadow::Shape::Kind;
|
||||
|
||||
protected:
|
||||
// Flags that are not modified after the Shape is created. Off-thread Ion
|
||||
|
@ -295,9 +287,10 @@ class Shape : public gc::CellWithTenuredGCPointer<gc::TenuredCell, BaseShape> {
|
|||
// no properties).
|
||||
MAP_LENGTH_MASK = BitMask(4),
|
||||
|
||||
// The Shape Kind.
|
||||
// The Shape Kind. The NativeObject kinds have the low bit set.
|
||||
KIND_SHIFT = 4,
|
||||
KIND_MASK = 0b11,
|
||||
IS_NATIVE_BIT = 0x1 << KIND_SHIFT,
|
||||
|
||||
// Number of fixed slots in objects with this shape.
|
||||
// FIXED_SLOTS_MAX is the biggest count of fixed slots a Shape can store.
|
||||
|
@ -372,6 +365,7 @@ class Shape : public gc::CellWithTenuredGCPointer<gc::TenuredCell, BaseShape> {
|
|||
objectFlags_(objectFlags) {
|
||||
MOZ_ASSERT(base);
|
||||
MOZ_ASSERT(this->kind() == kind, "kind must fit in KIND_MASK");
|
||||
MOZ_ASSERT(isNative() == base->clasp()->isNativeObject());
|
||||
}
|
||||
|
||||
Shape(const Shape& other) = delete;
|
||||
|
@ -379,7 +373,11 @@ class Shape : public gc::CellWithTenuredGCPointer<gc::TenuredCell, BaseShape> {
|
|||
public:
|
||||
Kind kind() const { return Kind((immutableFlags >> KIND_SHIFT) & KIND_MASK); }
|
||||
|
||||
bool isNative() const { return isShared() || isDictionary(); }
|
||||
bool isNative() const {
|
||||
// Note: this is equivalent to `isShared() || isDictionary()`.
|
||||
return immutableFlags & IS_NATIVE_BIT;
|
||||
}
|
||||
|
||||
bool isShared() const { return kind() == Kind::Shared; }
|
||||
bool isDictionary() const { return kind() == Kind::Dictionary; }
|
||||
bool isProxy() const { return kind() == Kind::Proxy; }
|
||||
|
@ -416,6 +414,10 @@ class Shape : public gc::CellWithTenuredGCPointer<gc::TenuredCell, BaseShape> {
|
|||
return offsetof(Shape, immutableFlags);
|
||||
}
|
||||
|
||||
static constexpr uint32_t kindShift() { return KIND_SHIFT; }
|
||||
static constexpr uint32_t kindMask() { return KIND_MASK; }
|
||||
static constexpr uint32_t isNativeBit() { return IS_NATIVE_BIT; }
|
||||
|
||||
static constexpr size_t offsetOfCachePtr() { return offsetof(Shape, cache_); }
|
||||
|
||||
private:
|
||||
|
@ -423,6 +425,8 @@ class Shape : public gc::CellWithTenuredGCPointer<gc::TenuredCell, BaseShape> {
|
|||
static_assert(offsetOfBaseShape() == offsetof(JS::shadow::Shape, base));
|
||||
static_assert(offsetof(Shape, immutableFlags) ==
|
||||
offsetof(JS::shadow::Shape, immutableFlags));
|
||||
static_assert(KIND_SHIFT == JS::shadow::Shape::KIND_SHIFT);
|
||||
static_assert(KIND_MASK == JS::shadow::Shape::KIND_MASK);
|
||||
static_assert(FIXED_SLOTS_SHIFT == JS::shadow::Shape::FIXED_SLOTS_SHIFT);
|
||||
static_assert(FIXED_SLOTS_MASK == JS::shadow::Shape::FIXED_SLOTS_MASK);
|
||||
// Sanity check Shape size is what we expect.
|
||||
|
|
Загрузка…
Ссылка в новой задаче