mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 948445 - use different caching schemes for ProtoAndIfaceArray depending on the global kind; r=bz
This commit is contained in:
parent
dfd53166ec
commit
bfa7382195
@ -1134,7 +1134,8 @@ ResolvePrototypeOrConstructor(JSContext* cx, JS::Handle<JSObject*> wrapper,
|
||||
{
|
||||
JSAutoCompartment ac(cx, global);
|
||||
ProtoAndIfaceArray& protoAndIfaceArray = *GetProtoAndIfaceArray(global);
|
||||
JSObject* protoOrIface = protoAndIfaceArray[protoAndIfaceArrayIndex];
|
||||
JSObject* protoOrIface =
|
||||
protoAndIfaceArray.EntrySlotIfExists(protoAndIfaceArrayIndex);
|
||||
if (!protoOrIface) {
|
||||
return false;
|
||||
}
|
||||
|
@ -293,29 +293,190 @@ static_assert((size_t)constructors::id::_ID_Start ==
|
||||
"Overlapping or discontiguous indexes.");
|
||||
const size_t kProtoAndIfaceCacheCount = constructors::id::_ID_Count;
|
||||
|
||||
class ProtoAndIfaceArray : public Array<JS::Heap<JSObject*>, kProtoAndIfaceCacheCount>
|
||||
class ProtoAndIfaceArray
|
||||
{
|
||||
// The caching strategy we use depends on what sort of global we're dealing
|
||||
// with. For a window-like global, we want everything to be as fast as
|
||||
// possible, so we use a flat array, indexed by prototype/constructor ID.
|
||||
// For everything else (e.g. globals for JSMs), space is more important than
|
||||
// speed, so we use a two-level lookup table.
|
||||
|
||||
class ArrayCache : public Array<JS::Heap<JSObject*>, kProtoAndIfaceCacheCount>
|
||||
{
|
||||
public:
|
||||
JSObject* EntrySlotIfExists(size_t i) {
|
||||
return (*this)[i];
|
||||
}
|
||||
|
||||
JS::Heap<JSObject*>& EntrySlotOrCreate(size_t i) {
|
||||
return (*this)[i];
|
||||
}
|
||||
|
||||
JS::Heap<JSObject*>& EntrySlotMustExist(size_t i) {
|
||||
MOZ_ASSERT((*this)[i]);
|
||||
return (*this)[i];
|
||||
}
|
||||
|
||||
void Trace(JSTracer* aTracer) {
|
||||
for (size_t i = 0; i < ArrayLength(*this); ++i) {
|
||||
if ((*this)[i]) {
|
||||
JS_CallHeapObjectTracer(aTracer, &(*this)[i], "protoAndIfaceArray[i]");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) {
|
||||
return aMallocSizeOf(this);
|
||||
}
|
||||
};
|
||||
|
||||
class PageTableCache
|
||||
{
|
||||
public:
|
||||
PageTableCache() {
|
||||
memset(&mPages, 0, sizeof(mPages));
|
||||
}
|
||||
|
||||
~PageTableCache() {
|
||||
for (size_t i = 0; i < ArrayLength(mPages); ++i) {
|
||||
delete mPages[i];
|
||||
}
|
||||
}
|
||||
|
||||
JSObject* EntrySlotIfExists(size_t i) {
|
||||
MOZ_ASSERT(i < kProtoAndIfaceCacheCount);
|
||||
size_t pageIndex = i / kPageSize;
|
||||
size_t leafIndex = i % kPageSize;
|
||||
Page* p = mPages[pageIndex];
|
||||
if (!p) {
|
||||
return nullptr;
|
||||
}
|
||||
return (*p)[leafIndex];
|
||||
}
|
||||
|
||||
JS::Heap<JSObject*>& EntrySlotOrCreate(size_t i) {
|
||||
MOZ_ASSERT(i < kProtoAndIfaceCacheCount);
|
||||
size_t pageIndex = i / kPageSize;
|
||||
size_t leafIndex = i % kPageSize;
|
||||
Page* p = mPages[pageIndex];
|
||||
if (!p) {
|
||||
p = new Page;
|
||||
mPages[pageIndex] = p;
|
||||
}
|
||||
return (*p)[leafIndex];
|
||||
}
|
||||
|
||||
JS::Heap<JSObject*>& EntrySlotMustExist(size_t i) {
|
||||
MOZ_ASSERT(i < kProtoAndIfaceCacheCount);
|
||||
size_t pageIndex = i / kPageSize;
|
||||
size_t leafIndex = i % kPageSize;
|
||||
Page* p = mPages[pageIndex];
|
||||
MOZ_ASSERT(p);
|
||||
return (*p)[leafIndex];
|
||||
}
|
||||
|
||||
void Trace(JSTracer* trc) {
|
||||
for (size_t i = 0; i < ArrayLength(mPages); ++i) {
|
||||
Page* p = mPages[i];
|
||||
if (p) {
|
||||
for (size_t j = 0; j < ArrayLength(*p); ++j) {
|
||||
if ((*p)[j]) {
|
||||
JS_CallHeapObjectTracer(trc, &(*p)[j], "protoAndIfaceArray[i]");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) {
|
||||
size_t n = aMallocSizeOf(this);
|
||||
for (size_t i = 0; i < ArrayLength(mPages); ++i) {
|
||||
n += aMallocSizeOf(mPages[i]);
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
private:
|
||||
static const size_t kPageSize = 16;
|
||||
typedef Array<JS::Heap<JSObject*>, kPageSize> Page;
|
||||
static const size_t kNPages = kProtoAndIfaceCacheCount / kPageSize +
|
||||
size_t(bool(kProtoAndIfaceCacheCount % kPageSize));
|
||||
Array<Page*, kNPages> mPages;
|
||||
};
|
||||
|
||||
public:
|
||||
ProtoAndIfaceArray() {
|
||||
enum Kind {
|
||||
WindowLike,
|
||||
NonWindowLike
|
||||
};
|
||||
|
||||
ProtoAndIfaceArray(Kind aKind) : mKind(aKind) {
|
||||
MOZ_COUNT_CTOR(ProtoAndIfaceArray);
|
||||
if (aKind == WindowLike) {
|
||||
mArrayCache = new ArrayCache();
|
||||
} else {
|
||||
mPageTableCache = new PageTableCache();
|
||||
}
|
||||
}
|
||||
|
||||
~ProtoAndIfaceArray() {
|
||||
if (mKind == WindowLike) {
|
||||
delete mArrayCache;
|
||||
} else {
|
||||
delete mPageTableCache;
|
||||
}
|
||||
MOZ_COUNT_DTOR(ProtoAndIfaceArray);
|
||||
}
|
||||
|
||||
size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) {
|
||||
return aMallocSizeOf(this);
|
||||
#define FORWARD_OPERATION(opName, args) \
|
||||
do { \
|
||||
if (mKind == WindowLike) { \
|
||||
return mArrayCache->opName args; \
|
||||
} else { \
|
||||
return mPageTableCache->opName args; \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
JSObject* EntrySlotIfExists(size_t i) {
|
||||
FORWARD_OPERATION(EntrySlotIfExists, (i));
|
||||
}
|
||||
|
||||
JS::Heap<JSObject*>& EntrySlotOrCreate(size_t i) {
|
||||
FORWARD_OPERATION(EntrySlotOrCreate, (i));
|
||||
}
|
||||
|
||||
JS::Heap<JSObject*>& EntrySlotMustExist(size_t i) {
|
||||
FORWARD_OPERATION(EntrySlotMustExist, (i));
|
||||
}
|
||||
|
||||
void Trace(JSTracer *aTracer) {
|
||||
FORWARD_OPERATION(Trace, (aTracer));
|
||||
}
|
||||
|
||||
size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) {
|
||||
size_t n = aMallocSizeOf(this);
|
||||
n += (mKind == WindowLike
|
||||
? mArrayCache->SizeOfIncludingThis(aMallocSizeOf)
|
||||
: mPageTableCache->SizeOfIncludingThis(aMallocSizeOf));
|
||||
return n;
|
||||
}
|
||||
#undef FORWARD_OPERATION
|
||||
|
||||
private:
|
||||
union {
|
||||
ArrayCache *mArrayCache;
|
||||
PageTableCache *mPageTableCache;
|
||||
};
|
||||
Kind mKind;
|
||||
};
|
||||
|
||||
inline void
|
||||
AllocateProtoAndIfaceCache(JSObject* obj)
|
||||
AllocateProtoAndIfaceCache(JSObject* obj, ProtoAndIfaceArray::Kind aKind)
|
||||
{
|
||||
MOZ_ASSERT(js::GetObjectClass(obj)->flags & JSCLASS_DOM_GLOBAL);
|
||||
MOZ_ASSERT(js::GetReservedSlot(obj, DOM_PROTOTYPE_SLOT).isUndefined());
|
||||
|
||||
ProtoAndIfaceArray* protoAndIfaceArray = new ProtoAndIfaceArray();
|
||||
ProtoAndIfaceArray* protoAndIfaceArray = new ProtoAndIfaceArray(aKind);
|
||||
|
||||
js::SetReservedSlot(obj, DOM_PROTOTYPE_SLOT,
|
||||
JS::PrivateValue(protoAndIfaceArray));
|
||||
@ -328,12 +489,8 @@ TraceProtoAndIfaceCache(JSTracer* trc, JSObject* obj)
|
||||
|
||||
if (!HasProtoAndIfaceArray(obj))
|
||||
return;
|
||||
ProtoAndIfaceArray& protoAndIfaceArray = *GetProtoAndIfaceArray(obj);
|
||||
for (size_t i = 0; i < ArrayLength(protoAndIfaceArray); ++i) {
|
||||
if (protoAndIfaceArray[i]) {
|
||||
JS_CallHeapObjectTracer(trc, &protoAndIfaceArray[i], "protoAndIfaceArray[i]");
|
||||
}
|
||||
}
|
||||
ProtoAndIfaceArray* protoAndIfaceArray = GetProtoAndIfaceArray(obj);
|
||||
protoAndIfaceArray->Trace(trc);
|
||||
}
|
||||
|
||||
inline void
|
||||
@ -2124,7 +2281,7 @@ inline JSObject*
|
||||
GetUnforgeableHolder(JSObject* aGlobal, prototypes::ID aId)
|
||||
{
|
||||
ProtoAndIfaceArray& protoAndIfaceArray = *GetProtoAndIfaceArray(aGlobal);
|
||||
JSObject* interfaceProto = protoAndIfaceArray[aId];
|
||||
JSObject* interfaceProto = protoAndIfaceArray.EntrySlotMustExist(aId);
|
||||
return &js::GetReservedSlot(interfaceProto,
|
||||
DOM_INTERFACE_PROTO_SLOTS_BASE).toObject();
|
||||
}
|
||||
@ -2382,7 +2539,7 @@ CreateGlobal(JSContext* aCx, T* aObject, nsWrapperCache* aCache,
|
||||
|
||||
JSAutoCompartment ac(aCx, global);
|
||||
|
||||
dom::AllocateProtoAndIfaceCache(global);
|
||||
dom::AllocateProtoAndIfaceCache(global, ProtoAndIfaceArray::WindowLike);
|
||||
|
||||
js::SetReservedSlot(global, DOM_OBJECT_SLOT, PRIVATE_TO_JSVAL(aObject));
|
||||
NS_ADDREF(aObject);
|
||||
|
@ -2074,13 +2074,13 @@ if (!unforgeableHolder) {
|
||||
|
||||
if needInterfacePrototypeObject:
|
||||
protoClass = "&PrototypeClass.mBase"
|
||||
protoCache = "&aProtoAndIfaceArray[prototypes::id::%s]" % self.descriptor.name
|
||||
protoCache = "&aProtoAndIfaceArray.EntrySlotOrCreate(prototypes::id::%s)" % self.descriptor.name
|
||||
else:
|
||||
protoClass = "nullptr"
|
||||
protoCache = "nullptr"
|
||||
if needInterfaceObject:
|
||||
interfaceClass = "&InterfaceObjectClass.mBase"
|
||||
interfaceCache = "&aProtoAndIfaceArray[constructors::id::%s]" % self.descriptor.name
|
||||
interfaceCache = "&aProtoAndIfaceArray.EntrySlotOrCreate(constructors::id::%s)" % self.descriptor.name
|
||||
else:
|
||||
# We don't have slots to store the named constructors.
|
||||
assert len(self.descriptor.interface.namedConstructors) == 0
|
||||
@ -2120,7 +2120,7 @@ if (!unforgeableHolder) {
|
||||
if UseHolderForUnforgeable(self.descriptor):
|
||||
assert needInterfacePrototypeObject
|
||||
setUnforgeableHolder = CGGeneric(
|
||||
"JSObject* proto = aProtoAndIfaceArray[prototypes::id::%s];\n"
|
||||
"JSObject* proto = aProtoAndIfaceArray.EntrySlotOrCreate(prototypes::id::%s);\n"
|
||||
"if (proto) {\n"
|
||||
" js::SetReservedSlot(proto, DOM_INTERFACE_PROTO_SLOTS_BASE,\n"
|
||||
" JS::ObjectValue(*unforgeableHolder));\n"
|
||||
@ -2153,7 +2153,7 @@ class CGGetPerInterfaceObject(CGAbstractMethod):
|
||||
}
|
||||
/* Check to see whether the interface objects are already installed */
|
||||
ProtoAndIfaceArray& protoAndIfaceArray = *GetProtoAndIfaceArray(aGlobal);
|
||||
if (!protoAndIfaceArray[%s]) {
|
||||
if (!protoAndIfaceArray.EntrySlotIfExists(%s)) {
|
||||
CreateInterfaceObjects(aCx, aGlobal, protoAndIfaceArray, aDefineOnGlobal);
|
||||
}
|
||||
|
||||
@ -2164,8 +2164,7 @@ class CGGetPerInterfaceObject(CGAbstractMethod):
|
||||
* traced by TraceProtoAndIfaceCache() and its contents are never
|
||||
* changed after they have been set.
|
||||
*/
|
||||
return JS::Handle<JSObject*>::fromMarkedLocation(protoAndIfaceArray[%s].address());""" %
|
||||
(self.id, self.id))
|
||||
return JS::Handle<JSObject*>::fromMarkedLocation(protoAndIfaceArray.EntrySlotMustExist(%s).address());""" % (self.id, self.id))
|
||||
|
||||
class CGGetProtoObjectMethod(CGGetPerInterfaceObject):
|
||||
"""
|
||||
|
@ -389,7 +389,12 @@ CreateGlobalObject(JSContext *cx, const JSClass *clasp, nsIPrincipal *principal,
|
||||
#endif
|
||||
|
||||
if (clasp->flags & JSCLASS_DOM_GLOBAL) {
|
||||
AllocateProtoAndIfaceCache(global);
|
||||
const char* className = clasp->name;
|
||||
AllocateProtoAndIfaceCache(global,
|
||||
(strcmp(className, "Window") == 0 ||
|
||||
strcmp(className, "ChromeWindow") == 0)
|
||||
? ProtoAndIfaceArray::WindowLike
|
||||
: ProtoAndIfaceArray::NonWindowLike);
|
||||
}
|
||||
|
||||
return global;
|
||||
|
Loading…
Reference in New Issue
Block a user