зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1245965 - Remove the NewObjectCache. r=terrence
This commit is contained in:
Родитель
02e277f76d
Коммит
6df1030632
|
@ -42,6 +42,7 @@ ecma_5/Object/15.2.3.6-redefinition-1-of-4.js
|
||||||
ecma_5/Object/15.2.3.6-redefinition-2-of-4.js
|
ecma_5/Object/15.2.3.6-redefinition-2-of-4.js
|
||||||
ecma_5/Object/15.2.3.6-redefinition-3-of-4.js
|
ecma_5/Object/15.2.3.6-redefinition-3-of-4.js
|
||||||
ecma_5/Object/15.2.3.6-redefinition-4-of-4.js
|
ecma_5/Object/15.2.3.6-redefinition-4-of-4.js
|
||||||
|
ecma_6/extensions/array-isArray-proxy-recursion.js
|
||||||
ecma_6/String/normalize-generateddata-part0.js
|
ecma_6/String/normalize-generateddata-part0.js
|
||||||
ecma_6/String/normalize-generateddata-part1-not-listed.js
|
ecma_6/String/normalize-generateddata-part1-not-listed.js
|
||||||
ecma_6/String/normalize-generateddata-part1.js
|
ecma_6/String/normalize-generateddata-part1.js
|
||||||
|
@ -50,6 +51,7 @@ ecma_6/String/normalize-generateddata-part3.js
|
||||||
js1_5/GC/regress-203278-2.js
|
js1_5/GC/regress-203278-2.js
|
||||||
js1_5/GC/regress-203278-3.js
|
js1_5/GC/regress-203278-3.js
|
||||||
js1_5/GC/regress-278725.js
|
js1_5/GC/regress-278725.js
|
||||||
|
js1_5/Regress/regress-203278-1.js
|
||||||
js1_5/Regress/regress-312588.js
|
js1_5/Regress/regress-312588.js
|
||||||
js1_5/Regress/regress-360969-01.js
|
js1_5/Regress/regress-360969-01.js
|
||||||
js1_5/Regress/regress-360969-02.js
|
js1_5/Regress/regress-360969-02.js
|
||||||
|
@ -58,3 +60,5 @@ js1_5/Regress/regress-360969-04.js
|
||||||
js1_5/Regress/regress-360969-05.js
|
js1_5/Regress/regress-360969-05.js
|
||||||
js1_5/Regress/regress-360969-06.js
|
js1_5/Regress/regress-360969-06.js
|
||||||
js1_8_5/extensions/clone-complex-object.js
|
js1_8_5/extensions/clone-complex-object.js
|
||||||
|
js1_8_5/extensions/clone-many-transferables.js
|
||||||
|
js1_8_5/extensions/clone-object.js
|
||||||
|
|
|
@ -685,10 +685,6 @@ js::Nursery::doCollection(JSRuntime* rt, JS::gcreason::Reason reason,
|
||||||
}
|
}
|
||||||
maybeEndProfile(ProfileKey::MarkDebugger);
|
maybeEndProfile(ProfileKey::MarkDebugger);
|
||||||
|
|
||||||
maybeStartProfile(ProfileKey::ClearNewObjectCache);
|
|
||||||
rt->contextFromMainThread()->caches.newObjectCache.clearNurseryObjects(rt);
|
|
||||||
maybeEndProfile(ProfileKey::ClearNewObjectCache);
|
|
||||||
|
|
||||||
// Most of the work is done here. This loop iterates over objects that have
|
// Most of the work is done here. This loop iterates over objects that have
|
||||||
// been moved to the major heap. If these objects have any outgoing pointers
|
// been moved to the major heap. If these objects have any outgoing pointers
|
||||||
// to the nursery, then those nursery objects get moved as well, until no
|
// to the nursery, then those nursery objects get moved as well, until no
|
||||||
|
|
|
@ -36,7 +36,6 @@
|
||||||
_(CheckHashTables, "ckTbls") \
|
_(CheckHashTables, "ckTbls") \
|
||||||
_(MarkRuntime, "mkRntm") \
|
_(MarkRuntime, "mkRntm") \
|
||||||
_(MarkDebugger, "mkDbgr") \
|
_(MarkDebugger, "mkDbgr") \
|
||||||
_(ClearNewObjectCache, "clrNOC") \
|
|
||||||
_(CollectToFP, "collct") \
|
_(CollectToFP, "collct") \
|
||||||
_(ObjectsTenuredCallback, "tenCB") \
|
_(ObjectsTenuredCallback, "tenCB") \
|
||||||
_(SweepArrayBufferViewList, "swpABO") \
|
_(SweepArrayBufferViewList, "swpABO") \
|
||||||
|
|
|
@ -42,7 +42,6 @@
|
||||||
|
|
||||||
#include "vm/ArgumentsObject-inl.h"
|
#include "vm/ArgumentsObject-inl.h"
|
||||||
#include "vm/ArrayObject-inl.h"
|
#include "vm/ArrayObject-inl.h"
|
||||||
#include "vm/Caches-inl.h"
|
|
||||||
#include "vm/Interpreter-inl.h"
|
#include "vm/Interpreter-inl.h"
|
||||||
#include "vm/NativeObject-inl.h"
|
#include "vm/NativeObject-inl.h"
|
||||||
#include "vm/UnboxedObject-inl.h"
|
#include "vm/UnboxedObject-inl.h"
|
||||||
|
@ -3382,31 +3381,6 @@ NewArray(ExclusiveContext* cxArg, uint32_t length,
|
||||||
if (!proto && !GetBuiltinPrototype(cxArg, JSProto_Array, &proto))
|
if (!proto && !GetBuiltinPrototype(cxArg, JSProto_Array, &proto))
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
Rooted<TaggedProto> taggedProto(cxArg, TaggedProto(proto));
|
|
||||||
bool isCachable = NewObjectWithTaggedProtoIsCachable(cxArg, taggedProto, newKind, &ArrayObject::class_);
|
|
||||||
if (isCachable) {
|
|
||||||
JSContext* cx = cxArg->asJSContext();
|
|
||||||
NewObjectCache& cache = cx->caches.newObjectCache;
|
|
||||||
NewObjectCache::EntryIndex entry = -1;
|
|
||||||
if (cache.lookupProto(&ArrayObject::class_, proto, allocKind, &entry)) {
|
|
||||||
gc::InitialHeap heap = GetInitialHeap(newKind, &ArrayObject::class_);
|
|
||||||
AutoSetNewObjectMetadata metadata(cx);
|
|
||||||
JSObject* obj = cache.newObjectFromHit(cx, entry, heap);
|
|
||||||
if (obj) {
|
|
||||||
/* Fixup the elements pointer and length, which may be incorrect. */
|
|
||||||
ArrayObject* arr = &obj->as<ArrayObject>();
|
|
||||||
arr->setFixedElements();
|
|
||||||
arr->setLength(cx, length);
|
|
||||||
if (maxLength > 0 &&
|
|
||||||
!EnsureNewArrayElements(cx, arr, std::min(maxLength, length)))
|
|
||||||
{
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
return arr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
RootedObjectGroup group(cxArg, ObjectGroup::defaultNewGroup(cxArg, &ArrayObject::class_,
|
RootedObjectGroup group(cxArg, ObjectGroup::defaultNewGroup(cxArg, &ArrayObject::class_,
|
||||||
TaggedProto(proto)));
|
TaggedProto(proto)));
|
||||||
if (!group)
|
if (!group)
|
||||||
|
@ -3439,13 +3413,6 @@ NewArray(ExclusiveContext* cxArg, uint32_t length,
|
||||||
if (newKind == SingletonObject && !JSObject::setSingleton(cxArg, arr))
|
if (newKind == SingletonObject && !JSObject::setSingleton(cxArg, arr))
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
if (isCachable) {
|
|
||||||
NewObjectCache& cache = cxArg->asJSContext()->caches.newObjectCache;
|
|
||||||
NewObjectCache::EntryIndex entry = -1;
|
|
||||||
cache.lookupProto(&ArrayObject::class_, proto, allocKind, &entry);
|
|
||||||
cache.fillProto(entry, &ArrayObject::class_, taggedProto, allocKind, arr);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (maxLength > 0 && !EnsureNewArrayElements(cxArg, arr, std::min(maxLength, length)))
|
if (maxLength > 0 && !EnsureNewArrayElements(cxArg, arr, std::min(maxLength, length)))
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
|
|
|
@ -3597,7 +3597,6 @@ GCRuntime::purgeRuntime(AutoLockForExclusiveAccess& lock)
|
||||||
JSContext* cx = rt->contextFromMainThread();
|
JSContext* cx = rt->contextFromMainThread();
|
||||||
cx->caches.gsnCache.purge();
|
cx->caches.gsnCache.purge();
|
||||||
cx->caches.envCoordinateNameCache.purge();
|
cx->caches.envCoordinateNameCache.purge();
|
||||||
cx->caches.newObjectCache.purge();
|
|
||||||
cx->caches.nativeIterCache.purge();
|
cx->caches.nativeIterCache.purge();
|
||||||
cx->caches.uncompressedSourceCache.purge();
|
cx->caches.uncompressedSourceCache.purge();
|
||||||
if (cx->caches.evalCache.initialized())
|
if (cx->caches.evalCache.initialized())
|
||||||
|
@ -5492,7 +5491,6 @@ GCRuntime::compactPhase(JS::gcreason::Reason reason, SliceBudget& sliceBudget,
|
||||||
|
|
||||||
// Clear caches that can contain cell pointers.
|
// Clear caches that can contain cell pointers.
|
||||||
JSContext* cx = rt->contextFromMainThread();
|
JSContext* cx = rt->contextFromMainThread();
|
||||||
cx->caches.newObjectCache.purge();
|
|
||||||
cx->caches.nativeIterCache.purge();
|
cx->caches.nativeIterCache.purge();
|
||||||
if (cx->caches.evalCache.initialized())
|
if (cx->caches.evalCache.initialized())
|
||||||
cx->caches.evalCache.clear();
|
cx->caches.evalCache.clear();
|
||||||
|
|
118
js/src/jsobj.cpp
118
js/src/jsobj.cpp
|
@ -62,7 +62,6 @@
|
||||||
|
|
||||||
#include "vm/ArrayObject-inl.h"
|
#include "vm/ArrayObject-inl.h"
|
||||||
#include "vm/BooleanObject-inl.h"
|
#include "vm/BooleanObject-inl.h"
|
||||||
#include "vm/Caches-inl.h"
|
|
||||||
#include "vm/Interpreter-inl.h"
|
#include "vm/Interpreter-inl.h"
|
||||||
#include "vm/NativeObject-inl.h"
|
#include "vm/NativeObject-inl.h"
|
||||||
#include "vm/NumberObject-inl.h"
|
#include "vm/NumberObject-inl.h"
|
||||||
|
@ -683,26 +682,6 @@ NewObject(ExclusiveContext* cx, HandleObjectGroup group, gc::AllocKind kind,
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
NewObjectCache::fillProto(EntryIndex entry, const Class* clasp, js::TaggedProto proto,
|
|
||||||
gc::AllocKind kind, NativeObject* obj)
|
|
||||||
{
|
|
||||||
MOZ_ASSERT_IF(proto.isObject(), !proto.toObject()->is<GlobalObject>());
|
|
||||||
MOZ_ASSERT(obj->taggedProto() == proto);
|
|
||||||
return fill(entry, clasp, proto.raw(), kind, obj);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
js::NewObjectWithTaggedProtoIsCachable(ExclusiveContext* cxArg, Handle<TaggedProto> proto,
|
|
||||||
NewObjectKind newKind, const Class* clasp)
|
|
||||||
{
|
|
||||||
return cxArg->isJSContext() &&
|
|
||||||
proto.isObject() &&
|
|
||||||
newKind == GenericObject &&
|
|
||||||
clasp->isNative() &&
|
|
||||||
!proto.toObject()->is<GlobalObject>();
|
|
||||||
}
|
|
||||||
|
|
||||||
JSObject*
|
JSObject*
|
||||||
js::NewObjectWithGivenTaggedProto(ExclusiveContext* cxArg, const Class* clasp,
|
js::NewObjectWithGivenTaggedProto(ExclusiveContext* cxArg, const Class* clasp,
|
||||||
Handle<TaggedProto> proto,
|
Handle<TaggedProto> proto,
|
||||||
|
@ -712,42 +691,11 @@ js::NewObjectWithGivenTaggedProto(ExclusiveContext* cxArg, const Class* clasp,
|
||||||
if (CanBeFinalizedInBackground(allocKind, clasp))
|
if (CanBeFinalizedInBackground(allocKind, clasp))
|
||||||
allocKind = GetBackgroundAllocKind(allocKind);
|
allocKind = GetBackgroundAllocKind(allocKind);
|
||||||
|
|
||||||
bool isCachable = NewObjectWithTaggedProtoIsCachable(cxArg, proto, newKind, clasp);
|
|
||||||
if (isCachable) {
|
|
||||||
JSContext* cx = cxArg->asJSContext();
|
|
||||||
NewObjectCache& cache = cx->caches.newObjectCache;
|
|
||||||
NewObjectCache::EntryIndex entry = -1;
|
|
||||||
if (cache.lookupProto(clasp, proto.toObject(), allocKind, &entry)) {
|
|
||||||
JSObject* obj = cache.newObjectFromHit(cx, entry, GetInitialHeap(newKind, clasp));
|
|
||||||
if (obj)
|
|
||||||
return obj;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
RootedObjectGroup group(cxArg, ObjectGroup::defaultNewGroup(cxArg, clasp, proto, nullptr));
|
RootedObjectGroup group(cxArg, ObjectGroup::defaultNewGroup(cxArg, clasp, proto, nullptr));
|
||||||
if (!group)
|
if (!group)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
RootedObject obj(cxArg, NewObject(cxArg, group, allocKind, newKind, initialShapeFlags));
|
return NewObject(cxArg, group, allocKind, newKind, initialShapeFlags);
|
||||||
if (!obj)
|
|
||||||
return nullptr;
|
|
||||||
|
|
||||||
if (isCachable && !obj->as<NativeObject>().hasDynamicSlots()) {
|
|
||||||
NewObjectCache& cache = cxArg->asJSContext()->caches.newObjectCache;
|
|
||||||
NewObjectCache::EntryIndex entry = -1;
|
|
||||||
cache.lookupProto(clasp, proto.toObject(), allocKind, &entry);
|
|
||||||
cache.fillProto(entry, clasp, proto, allocKind, &obj->as<NativeObject>());
|
|
||||||
}
|
|
||||||
|
|
||||||
return obj;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool
|
|
||||||
NewObjectIsCachable(ExclusiveContext* cxArg, NewObjectKind newKind, const Class* clasp)
|
|
||||||
{
|
|
||||||
return cxArg->isJSContext() &&
|
|
||||||
newKind == GenericObject &&
|
|
||||||
clasp->isNative();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
JSObject*
|
JSObject*
|
||||||
|
@ -760,20 +708,6 @@ js::NewObjectWithClassProtoCommon(ExclusiveContext* cx, const Class* clasp, Hand
|
||||||
if (CanBeFinalizedInBackground(allocKind, clasp))
|
if (CanBeFinalizedInBackground(allocKind, clasp))
|
||||||
allocKind = GetBackgroundAllocKind(allocKind);
|
allocKind = GetBackgroundAllocKind(allocKind);
|
||||||
|
|
||||||
Handle<GlobalObject*> global = cx->global();
|
|
||||||
|
|
||||||
bool isCachable = NewObjectIsCachable(cx, newKind, clasp);
|
|
||||||
if (isCachable) {
|
|
||||||
NewObjectCache& cache = cx->asJSContext()->caches.newObjectCache;
|
|
||||||
NewObjectCache::EntryIndex entry = -1;
|
|
||||||
if (cache.lookupGlobal(clasp, global, allocKind, &entry)) {
|
|
||||||
gc::InitialHeap heap = GetInitialHeap(newKind, clasp);
|
|
||||||
JSObject* obj = cache.newObjectFromHit(cx->asJSContext(), entry, heap);
|
|
||||||
if (obj)
|
|
||||||
return obj;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Find the appropriate proto for clasp. Built-in classes have a cached
|
// Find the appropriate proto for clasp. Built-in classes have a cached
|
||||||
// proto on cx->global(); all others get %ObjectPrototype%.
|
// proto on cx->global(); all others get %ObjectPrototype%.
|
||||||
JSProtoKey protoKey = JSCLASS_CACHED_PROTO_KEY(clasp);
|
JSProtoKey protoKey = JSCLASS_CACHED_PROTO_KEY(clasp);
|
||||||
|
@ -788,30 +722,7 @@ js::NewObjectWithClassProtoCommon(ExclusiveContext* cx, const Class* clasp, Hand
|
||||||
if (!group)
|
if (!group)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
JSObject* obj = NewObject(cx, group, allocKind, newKind);
|
return NewObject(cx, group, allocKind, newKind);
|
||||||
if (!obj)
|
|
||||||
return nullptr;
|
|
||||||
|
|
||||||
if (isCachable && !obj->as<NativeObject>().hasDynamicSlots()) {
|
|
||||||
NewObjectCache& cache = cx->asJSContext()->caches.newObjectCache;
|
|
||||||
NewObjectCache::EntryIndex entry = -1;
|
|
||||||
cache.lookupGlobal(clasp, global, allocKind, &entry);
|
|
||||||
cache.fillGlobal(entry, clasp, global, allocKind,
|
|
||||||
&obj->as<NativeObject>());
|
|
||||||
}
|
|
||||||
|
|
||||||
return obj;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool
|
|
||||||
NewObjectWithGroupIsCachable(ExclusiveContext* cx, HandleObjectGroup group,
|
|
||||||
NewObjectKind newKind)
|
|
||||||
{
|
|
||||||
return group->proto().isObject() &&
|
|
||||||
newKind == GenericObject &&
|
|
||||||
group->clasp()->isNative() &&
|
|
||||||
(!group->newScript() || group->newScript()->analyzed()) &&
|
|
||||||
cx->isJSContext();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -826,30 +737,7 @@ js::NewObjectWithGroupCommon(ExclusiveContext* cx, HandleObjectGroup group,
|
||||||
if (CanBeFinalizedInBackground(allocKind, group->clasp()))
|
if (CanBeFinalizedInBackground(allocKind, group->clasp()))
|
||||||
allocKind = GetBackgroundAllocKind(allocKind);
|
allocKind = GetBackgroundAllocKind(allocKind);
|
||||||
|
|
||||||
bool isCachable = NewObjectWithGroupIsCachable(cx, group, newKind);
|
return NewObject(cx, group, allocKind, newKind);
|
||||||
if (isCachable) {
|
|
||||||
NewObjectCache& cache = cx->asJSContext()->caches.newObjectCache;
|
|
||||||
NewObjectCache::EntryIndex entry = -1;
|
|
||||||
if (cache.lookupGroup(group, allocKind, &entry)) {
|
|
||||||
JSObject* obj = cache.newObjectFromHit(cx->asJSContext(), entry,
|
|
||||||
GetInitialHeap(newKind, group->clasp()));
|
|
||||||
if (obj)
|
|
||||||
return obj;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
JSObject* obj = NewObject(cx, group, allocKind, newKind);
|
|
||||||
if (!obj)
|
|
||||||
return nullptr;
|
|
||||||
|
|
||||||
if (isCachable && !obj->as<NativeObject>().hasDynamicSlots()) {
|
|
||||||
NewObjectCache& cache = cx->asJSContext()->caches.newObjectCache;
|
|
||||||
NewObjectCache::EntryIndex entry = -1;
|
|
||||||
cache.lookupGroup(group, allocKind, &entry);
|
|
||||||
cache.fillGroup(entry, group, allocKind, &obj->as<NativeObject>());
|
|
||||||
}
|
|
||||||
|
|
||||||
return obj;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
|
|
|
@ -73,7 +73,6 @@ extern const Class JSONClass;
|
||||||
extern const Class MathClass;
|
extern const Class MathClass;
|
||||||
|
|
||||||
class GlobalObject;
|
class GlobalObject;
|
||||||
class NewObjectCache;
|
|
||||||
|
|
||||||
// Forward declarations, required for later friend declarations.
|
// Forward declarations, required for later friend declarations.
|
||||||
bool PreventExtensions(JSContext* cx, JS::HandleObject obj, JS::ObjectOpResult& result);
|
bool PreventExtensions(JSContext* cx, JS::HandleObject obj, JS::ObjectOpResult& result);
|
||||||
|
@ -103,7 +102,6 @@ class JSObject : public js::gc::Cell
|
||||||
private:
|
private:
|
||||||
friend class js::Shape;
|
friend class js::Shape;
|
||||||
friend class js::GCMarker;
|
friend class js::GCMarker;
|
||||||
friend class js::NewObjectCache;
|
|
||||||
friend class js::Nursery;
|
friend class js::Nursery;
|
||||||
friend class js::gc::RelocationOverlay;
|
friend class js::gc::RelocationOverlay;
|
||||||
friend bool js::PreventExtensions(JSContext* cx, JS::HandleObject obj, JS::ObjectOpResult& result);
|
friend bool js::PreventExtensions(JSContext* cx, JS::HandleObject obj, JS::ObjectOpResult& result);
|
||||||
|
@ -1128,10 +1126,6 @@ GetInitialHeap(NewObjectKind newKind, const Class* clasp)
|
||||||
return gc::DefaultHeap;
|
return gc::DefaultHeap;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
|
||||||
NewObjectWithTaggedProtoIsCachable(ExclusiveContext* cxArg, Handle<TaggedProto> proto,
|
|
||||||
NewObjectKind newKind, const Class* clasp);
|
|
||||||
|
|
||||||
// ES6 9.1.15 GetPrototypeFromConstructor.
|
// ES6 9.1.15 GetPrototypeFromConstructor.
|
||||||
extern bool
|
extern bool
|
||||||
GetPrototypeFromConstructor(JSContext* cx, js::HandleObject newTarget, js::MutableHandleObject proto);
|
GetPrototypeFromConstructor(JSContext* cx, js::HandleObject newTarget, js::MutableHandleObject proto);
|
||||||
|
|
|
@ -1,82 +0,0 @@
|
||||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
|
||||||
* vim: set ts=8 sts=4 et sw=4 tw=99:
|
|
||||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
||||||
|
|
||||||
#ifndef vm_Caches_inl_h
|
|
||||||
#define vm_Caches_inl_h
|
|
||||||
|
|
||||||
#include "vm/Caches.h"
|
|
||||||
|
|
||||||
#include "jscompartment.h"
|
|
||||||
|
|
||||||
#include "gc/Allocator.h"
|
|
||||||
#include "gc/GCTrace.h"
|
|
||||||
#include "vm/Probes.h"
|
|
||||||
|
|
||||||
#include "jsobjinlines.h"
|
|
||||||
|
|
||||||
namespace js {
|
|
||||||
|
|
||||||
inline bool
|
|
||||||
NewObjectCache::lookupProto(const Class* clasp, JSObject* proto, gc::AllocKind kind, EntryIndex* pentry)
|
|
||||||
{
|
|
||||||
MOZ_ASSERT(!proto->is<GlobalObject>());
|
|
||||||
return lookup(clasp, proto, kind, pentry);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool
|
|
||||||
NewObjectCache::lookupGlobal(const Class* clasp, GlobalObject* global, gc::AllocKind kind, EntryIndex* pentry)
|
|
||||||
{
|
|
||||||
return lookup(clasp, global, kind, pentry);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void
|
|
||||||
NewObjectCache::fillGlobal(EntryIndex entry, const Class* clasp, GlobalObject* global,
|
|
||||||
gc::AllocKind kind, NativeObject* obj)
|
|
||||||
{
|
|
||||||
//MOZ_ASSERT(global == obj->getGlobal());
|
|
||||||
return fill(entry, clasp, global, kind, obj);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline NativeObject*
|
|
||||||
NewObjectCache::newObjectFromHit(JSContext* cx, EntryIndex entryIndex, gc::InitialHeap heap)
|
|
||||||
{
|
|
||||||
MOZ_ASSERT(unsigned(entryIndex) < mozilla::ArrayLength(entries));
|
|
||||||
Entry* entry = &entries[entryIndex];
|
|
||||||
|
|
||||||
NativeObject* templateObj = reinterpret_cast<NativeObject*>(&entry->templateObject);
|
|
||||||
|
|
||||||
// Do an end run around JSObject::group() to avoid doing AutoUnprotectCell
|
|
||||||
// on the templateObj, which is not a GC thing and can't use runtimeFromAnyThread.
|
|
||||||
ObjectGroup* group = templateObj->group_;
|
|
||||||
|
|
||||||
MOZ_ASSERT(!group->hasUnanalyzedPreliminaryObjects());
|
|
||||||
|
|
||||||
if (group->shouldPreTenure())
|
|
||||||
heap = gc::TenuredHeap;
|
|
||||||
|
|
||||||
if (cx->runtime()->gc.upcomingZealousGC())
|
|
||||||
return nullptr;
|
|
||||||
|
|
||||||
NativeObject* obj = static_cast<NativeObject*>(Allocate<JSObject, NoGC>(cx, entry->kind, 0,
|
|
||||||
heap, group->clasp()));
|
|
||||||
if (!obj)
|
|
||||||
return nullptr;
|
|
||||||
|
|
||||||
copyCachedToObject(obj, templateObj, entry->kind);
|
|
||||||
|
|
||||||
if (group->clasp()->shouldDelayMetadataBuilder())
|
|
||||||
cx->compartment()->setObjectPendingMetadata(cx, obj);
|
|
||||||
else
|
|
||||||
obj = static_cast<NativeObject*>(SetNewObjectMetadata(cx, obj));
|
|
||||||
|
|
||||||
probes::CreateObject(cx, obj);
|
|
||||||
gc::TraceCreateObject(obj);
|
|
||||||
return obj;
|
|
||||||
}
|
|
||||||
|
|
||||||
} /* namespace js */
|
|
||||||
|
|
||||||
#endif /* vm_Caches_inl_h */
|
|
|
@ -4,13 +4,14 @@
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
#include "vm/Caches-inl.h"
|
#include "vm/Caches.h"
|
||||||
|
|
||||||
#include "mozilla/PodOperations.h"
|
#include "mozilla/PodOperations.h"
|
||||||
|
|
||||||
using namespace js;
|
#include "jscntxt.h"
|
||||||
|
#include "jsmath.h"
|
||||||
|
|
||||||
using mozilla::PodZero;
|
using namespace js;
|
||||||
|
|
||||||
MathCache*
|
MathCache*
|
||||||
ContextCaches::createMathCache(JSContext* cx)
|
ContextCaches::createMathCache(JSContext* cx)
|
||||||
|
@ -35,18 +36,3 @@ ContextCaches::init()
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
NewObjectCache::clearNurseryObjects(JSRuntime* rt)
|
|
||||||
{
|
|
||||||
for (unsigned i = 0; i < mozilla::ArrayLength(entries); ++i) {
|
|
||||||
Entry& e = entries[i];
|
|
||||||
NativeObject* obj = reinterpret_cast<NativeObject*>(&e.templateObject);
|
|
||||||
if (IsInsideNursery(e.key) ||
|
|
||||||
rt->gc.nursery.isInside(obj->slots_) ||
|
|
||||||
rt->gc.nursery.isInside(obj->elements_))
|
|
||||||
{
|
|
||||||
PodZero(&e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -149,137 +149,6 @@ class NativeIterCache
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
|
||||||
* Cache for speeding up repetitive creation of objects in the VM.
|
|
||||||
* When an object is created which matches the criteria in the 'key' section
|
|
||||||
* below, an entry is filled with the resulting object.
|
|
||||||
*/
|
|
||||||
class NewObjectCache
|
|
||||||
{
|
|
||||||
/* Statically asserted to be equal to sizeof(JSObject_Slots16) */
|
|
||||||
static const unsigned MAX_OBJ_SIZE = 4 * sizeof(void*) + 16 * sizeof(Value);
|
|
||||||
|
|
||||||
static void staticAsserts() {
|
|
||||||
JS_STATIC_ASSERT(NewObjectCache::MAX_OBJ_SIZE == sizeof(JSObject_Slots16));
|
|
||||||
JS_STATIC_ASSERT(gc::AllocKind::OBJECT_LAST == gc::AllocKind::OBJECT16_BACKGROUND);
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Entry
|
|
||||||
{
|
|
||||||
/* Class of the constructed object. */
|
|
||||||
const Class* clasp;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Key with one of three possible values:
|
|
||||||
*
|
|
||||||
* - Global for the object. The object must have a standard class for
|
|
||||||
* which the global's prototype can be determined, and the object's
|
|
||||||
* parent will be the global.
|
|
||||||
*
|
|
||||||
* - Prototype for the object (cannot be global). The object's parent
|
|
||||||
* will be the prototype's parent.
|
|
||||||
*
|
|
||||||
* - Type for the object. The object's parent will be the type's
|
|
||||||
* prototype's parent.
|
|
||||||
*/
|
|
||||||
gc::Cell* key;
|
|
||||||
|
|
||||||
/* Allocation kind for the constructed object. */
|
|
||||||
gc::AllocKind kind;
|
|
||||||
|
|
||||||
/* Number of bytes to copy from the template object. */
|
|
||||||
uint32_t nbytes;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Template object to copy from, with the initial values of fields,
|
|
||||||
* fixed slots (undefined) and private data (nullptr).
|
|
||||||
*/
|
|
||||||
char templateObject[MAX_OBJ_SIZE];
|
|
||||||
};
|
|
||||||
|
|
||||||
Entry entries[41]; // TODO: reconsider size
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
typedef int EntryIndex;
|
|
||||||
|
|
||||||
NewObjectCache() { mozilla::PodZero(this); }
|
|
||||||
void purge() { mozilla::PodZero(this); }
|
|
||||||
|
|
||||||
/* Remove any cached items keyed on moved objects. */
|
|
||||||
void clearNurseryObjects(JSRuntime* rt);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Get the entry index for the given lookup, return whether there was a hit
|
|
||||||
* on an existing entry.
|
|
||||||
*/
|
|
||||||
inline bool lookupProto(const Class* clasp, JSObject* proto, gc::AllocKind kind, EntryIndex* pentry);
|
|
||||||
inline bool lookupGlobal(const Class* clasp, js::GlobalObject* global, gc::AllocKind kind,
|
|
||||||
EntryIndex* pentry);
|
|
||||||
|
|
||||||
bool lookupGroup(js::ObjectGroup* group, gc::AllocKind kind, EntryIndex* pentry) {
|
|
||||||
return lookup(group->clasp(), group, kind, pentry);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Return a new object from a cache hit produced by a lookup method, or
|
|
||||||
* nullptr if returning the object could possibly trigger GC (does not
|
|
||||||
* indicate failure).
|
|
||||||
*/
|
|
||||||
inline NativeObject* newObjectFromHit(JSContext* cx, EntryIndex entry, js::gc::InitialHeap heap);
|
|
||||||
|
|
||||||
/* Fill an entry after a cache miss. */
|
|
||||||
void fillProto(EntryIndex entry, const Class* clasp, js::TaggedProto proto,
|
|
||||||
gc::AllocKind kind, NativeObject* obj);
|
|
||||||
|
|
||||||
inline void fillGlobal(EntryIndex entry, const Class* clasp, js::GlobalObject* global,
|
|
||||||
gc::AllocKind kind, NativeObject* obj);
|
|
||||||
|
|
||||||
void fillGroup(EntryIndex entry, js::ObjectGroup* group, gc::AllocKind kind,
|
|
||||||
NativeObject* obj)
|
|
||||||
{
|
|
||||||
MOZ_ASSERT(obj->group() == group);
|
|
||||||
return fill(entry, group->clasp(), group, kind, obj);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Invalidate any entries which might produce an object with shape/proto. */
|
|
||||||
void invalidateEntriesForShape(JSContext* cx, HandleShape shape, HandleObject proto);
|
|
||||||
|
|
||||||
private:
|
|
||||||
EntryIndex makeIndex(const Class* clasp, gc::Cell* key, gc::AllocKind kind) {
|
|
||||||
uintptr_t hash = (uintptr_t(clasp) ^ uintptr_t(key)) + size_t(kind);
|
|
||||||
return hash % mozilla::ArrayLength(entries);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool lookup(const Class* clasp, gc::Cell* key, gc::AllocKind kind, EntryIndex* pentry) {
|
|
||||||
*pentry = makeIndex(clasp, key, kind);
|
|
||||||
Entry* entry = &entries[*pentry];
|
|
||||||
|
|
||||||
/* N.B. Lookups with the same clasp/key but different kinds map to different entries. */
|
|
||||||
return entry->clasp == clasp && entry->key == key;
|
|
||||||
}
|
|
||||||
|
|
||||||
void fill(EntryIndex entry_, const Class* clasp, gc::Cell* key, gc::AllocKind kind,
|
|
||||||
NativeObject* obj) {
|
|
||||||
MOZ_ASSERT(unsigned(entry_) < mozilla::ArrayLength(entries));
|
|
||||||
MOZ_ASSERT(entry_ == makeIndex(clasp, key, kind));
|
|
||||||
Entry* entry = &entries[entry_];
|
|
||||||
|
|
||||||
entry->clasp = clasp;
|
|
||||||
entry->key = key;
|
|
||||||
entry->kind = kind;
|
|
||||||
|
|
||||||
entry->nbytes = gc::Arena::thingSize(kind);
|
|
||||||
js_memcpy(&entry->templateObject, obj, entry->nbytes);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void copyCachedToObject(NativeObject* dst, NativeObject* src, gc::AllocKind kind) {
|
|
||||||
js_memcpy(dst, src, gc::Arena::thingSize(kind));
|
|
||||||
Shape::writeBarrierPost(&dst->shape_, nullptr, dst->shape_);
|
|
||||||
ObjectGroup::writeBarrierPost(&dst->group_, nullptr, dst->group_);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
class MathCache;
|
class MathCache;
|
||||||
|
|
||||||
class ContextCaches
|
class ContextCaches
|
||||||
|
@ -291,7 +160,6 @@ class ContextCaches
|
||||||
public:
|
public:
|
||||||
js::GSNCache gsnCache;
|
js::GSNCache gsnCache;
|
||||||
js::EnvironmentCoordinateNameCache envCoordinateNameCache;
|
js::EnvironmentCoordinateNameCache envCoordinateNameCache;
|
||||||
js::NewObjectCache newObjectCache;
|
|
||||||
js::NativeIterCache nativeIterCache;
|
js::NativeIterCache nativeIterCache;
|
||||||
js::UncompressedSourceCache uncompressedSourceCache;
|
js::UncompressedSourceCache uncompressedSourceCache;
|
||||||
js::EvalCache evalCache;
|
js::EvalCache evalCache;
|
||||||
|
|
|
@ -307,8 +307,6 @@ struct Class;
|
||||||
class GCMarker;
|
class GCMarker;
|
||||||
class Shape;
|
class Shape;
|
||||||
|
|
||||||
class NewObjectCache;
|
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
static inline bool
|
static inline bool
|
||||||
IsObjectValueInCompartment(Value v, JSCompartment* comp);
|
IsObjectValueInCompartment(Value v, JSCompartment* comp);
|
||||||
|
@ -534,7 +532,6 @@ class NativeObject : public ShapedObject
|
||||||
protected:
|
protected:
|
||||||
friend class GCMarker;
|
friend class GCMarker;
|
||||||
friend class Shape;
|
friend class Shape;
|
||||||
friend class NewObjectCache;
|
|
||||||
|
|
||||||
void invalidateSlotRange(uint32_t start, uint32_t length) {
|
void invalidateSlotRange(uint32_t start, uint32_t length) {
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
|
|
|
@ -24,7 +24,6 @@
|
||||||
#include "jscompartmentinlines.h"
|
#include "jscompartmentinlines.h"
|
||||||
#include "jsobjinlines.h"
|
#include "jsobjinlines.h"
|
||||||
|
|
||||||
#include "vm/Caches-inl.h"
|
|
||||||
#include "vm/NativeObject-inl.h"
|
#include "vm/NativeObject-inl.h"
|
||||||
|
|
||||||
using namespace js;
|
using namespace js;
|
||||||
|
@ -1530,35 +1529,6 @@ EmptyShape::getInitialShape(ExclusiveContext* cx, const Class* clasp, TaggedProt
|
||||||
return getInitialShape(cx, clasp, proto, GetGCKindSlots(kind, clasp), objectFlags);
|
return getInitialShape(cx, clasp, proto, GetGCKindSlots(kind, clasp), objectFlags);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
NewObjectCache::invalidateEntriesForShape(JSContext* cx, HandleShape shape, HandleObject proto)
|
|
||||||
{
|
|
||||||
const Class* clasp = shape->getObjectClass();
|
|
||||||
|
|
||||||
gc::AllocKind kind = gc::GetGCObjectKind(shape->numFixedSlots());
|
|
||||||
if (CanBeFinalizedInBackground(kind, clasp))
|
|
||||||
kind = GetBackgroundAllocKind(kind);
|
|
||||||
|
|
||||||
RootedObjectGroup group(cx, ObjectGroup::defaultNewGroup(cx, clasp, TaggedProto(proto)));
|
|
||||||
if (!group) {
|
|
||||||
purge();
|
|
||||||
cx->recoverFromOutOfMemory();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
EntryIndex entry;
|
|
||||||
for (CompartmentsInZoneIter comp(shape->zone()); !comp.done(); comp.next()) {
|
|
||||||
if (GlobalObject* global = comp->unsafeUnbarrieredMaybeGlobal()) {
|
|
||||||
if (lookupGlobal(clasp, global, kind, &entry))
|
|
||||||
PodZero(&entries[entry]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!proto->is<GlobalObject>() && lookupProto(clasp, proto, kind, &entry))
|
|
||||||
PodZero(&entries[entry]);
|
|
||||||
if (lookupGroup(group, kind, &entry))
|
|
||||||
PodZero(&entries[entry]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* static */ void
|
/* static */ void
|
||||||
EmptyShape::insertInitialShape(ExclusiveContext* cx, HandleShape shape, HandleObject proto)
|
EmptyShape::insertInitialShape(ExclusiveContext* cx, HandleShape shape, HandleObject proto)
|
||||||
{
|
{
|
||||||
|
@ -1583,21 +1553,6 @@ EmptyShape::insertInitialShape(ExclusiveContext* cx, HandleShape shape, HandleOb
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
entry.shape = ReadBarrieredShape(shape);
|
entry.shape = ReadBarrieredShape(shape);
|
||||||
|
|
||||||
/*
|
|
||||||
* This affects the shape that will be produced by the various NewObject
|
|
||||||
* methods, so clear any cache entry referring to the old shape. This is
|
|
||||||
* not required for correctness: the NewObject must always check for a
|
|
||||||
* nativeEmpty() result and generate the appropriate properties if found.
|
|
||||||
* Clearing the cache entry avoids this duplicate regeneration.
|
|
||||||
*
|
|
||||||
* Clearing is not necessary when this context is running off the main
|
|
||||||
* thread, as it will not use the new object cache for allocations.
|
|
||||||
*/
|
|
||||||
if (cx->isJSContext()) {
|
|
||||||
JSContext* ncx = cx->asJSContext();
|
|
||||||
ncx->caches.newObjectCache.invalidateEntriesForShape(ncx, shape, proto);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
@ -12,8 +12,6 @@
|
||||||
#include "gc/Barrier.h"
|
#include "gc/Barrier.h"
|
||||||
#include "gc/Zone.h"
|
#include "gc/Zone.h"
|
||||||
|
|
||||||
#include "vm/Caches-inl.h"
|
|
||||||
|
|
||||||
namespace js {
|
namespace js {
|
||||||
|
|
||||||
/* static */ void
|
/* static */ void
|
||||||
|
|
Загрузка…
Ссылка в новой задаче