mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
[INFER] Allocate typeset data and properties from arenas, occasionally purge observed types in compartments, bug 679329.
This commit is contained in:
parent
4857992503
commit
f3b5be7a42
@ -4299,7 +4299,6 @@ JS_CloneFunctionObject(JSContext *cx, JSObject *funobj, JSObject *parent)
|
||||
Value v;
|
||||
if (!obj->getProperty(cx, r.front().propid, &v))
|
||||
return NULL;
|
||||
TypeScript::SetUpvar(cx, fun->script(), i, v);
|
||||
clone->getFlatClosureUpvars()[i] = v;
|
||||
}
|
||||
|
||||
|
@ -298,6 +298,14 @@ ArenaAllocatedSize(const JSArenaPool &pool)
|
||||
return res;
|
||||
}
|
||||
|
||||
/* Move the contents of oldPool into newPool, and reset oldPool. */
|
||||
inline void
|
||||
MoveArenaPool(JSArenaPool *oldPool, JSArenaPool *newPool)
|
||||
{
|
||||
*newPool = *oldPool;
|
||||
JS_InitArenaPool(oldPool, NULL, newPool->arenasize, newPool->mask + 1);
|
||||
}
|
||||
|
||||
} /* namespace js */
|
||||
|
||||
#endif /* __cplusplus */
|
||||
|
@ -136,7 +136,10 @@ JSCompartment::init(JSContext *cx)
|
||||
activeAnalysis = activeInference = false;
|
||||
types.init(cx);
|
||||
|
||||
JS_InitArenaPool(&pool, "analysis", 4096, 8);
|
||||
/* Duplicated from jscntxt.cpp. :XXX: bug 675150 fix hack. */
|
||||
static const size_t ARENA_HEADER_SIZE_HACK = 40;
|
||||
|
||||
JS_InitArenaPool(&pool, "analysis", 4096 - ARENA_HEADER_SIZE_HACK, 8);
|
||||
|
||||
freeLists.init();
|
||||
if (!crossCompartmentWrappers.init())
|
||||
@ -598,6 +601,13 @@ JSCompartment::sweep(JSContext *cx, uint32 releaseInterval)
|
||||
#endif
|
||||
|
||||
if (!activeAnalysis) {
|
||||
/*
|
||||
* Clear the analysis pool, but don't releas its data yet. While
|
||||
* sweeping types any live data will be allocated into the pool.
|
||||
*/
|
||||
JSArenaPool oldPool;
|
||||
MoveArenaPool(&pool, &oldPool);
|
||||
|
||||
/*
|
||||
* Sweep analysis information and everything depending on it from the
|
||||
* compartment, including all remaining mjit code if inference is
|
||||
@ -610,8 +620,19 @@ JSCompartment::sweep(JSContext *cx, uint32 releaseInterval)
|
||||
|
||||
for (JSCList *cursor = scripts.next; cursor != &scripts; cursor = cursor->next) {
|
||||
JSScript *script = reinterpret_cast<JSScript *>(cursor);
|
||||
if (script->types)
|
||||
if (script->types) {
|
||||
types::TypeScript::Sweep(cx, script);
|
||||
|
||||
/*
|
||||
* On each 1/8 lifetime, release observed types for all scripts.
|
||||
* This is always safe to do when there are no frames for the
|
||||
* compartment on the stack.
|
||||
*/
|
||||
if (discardScripts) {
|
||||
script->types->destroy();
|
||||
script->types = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -624,7 +645,7 @@ JSCompartment::sweep(JSContext *cx, uint32 releaseInterval)
|
||||
}
|
||||
|
||||
/* Reset the analysis pool, releasing all analysis and intermediate type data. */
|
||||
JS_FinishArenaPool(&pool);
|
||||
JS_FinishArenaPool(&oldPool);
|
||||
|
||||
/*
|
||||
* Destroy eval'ed scripts, now that any type inference information referring
|
||||
|
@ -78,11 +78,11 @@ JS_GetCustomIteratorCount(JSContext *cx);
|
||||
/* Data for tracking analysis/inference memory usage. */
|
||||
typedef struct TypeInferenceMemoryStats
|
||||
{
|
||||
int64 scriptMain;
|
||||
int64 scriptSets;
|
||||
int64 objectMain;
|
||||
int64 objectSets;
|
||||
int64 poolMain;
|
||||
int64 scripts;
|
||||
int64 objects;
|
||||
int64 tables;
|
||||
int64 temporary;
|
||||
int64 emptyShapes;
|
||||
} TypeInferenceMemoryStats;
|
||||
|
||||
extern JS_FRIEND_API(void)
|
||||
|
@ -2643,10 +2643,8 @@ js_NewFlatClosure(JSContext *cx, JSFunction *fun, JSOp op, size_t oplen)
|
||||
uintN level = fun->script()->staticLevel;
|
||||
JSUpvarArray *uva = fun->script()->upvars();
|
||||
|
||||
for (uint32 i = 0, n = uva->length; i < n; i++) {
|
||||
for (uint32 i = 0, n = uva->length; i < n; i++)
|
||||
upvars[i] = GetUpvar(cx, level, uva->vector[i]);
|
||||
TypeScript::SetUpvar(cx, fun->script(), i, upvars[i]);
|
||||
}
|
||||
|
||||
return closure;
|
||||
}
|
||||
|
@ -583,7 +583,7 @@ js_GCThingIsMarked(void *thing, uintN color = BLACK)
|
||||
* JIT code is discarded in inactive compartments, regardless of how often that
|
||||
* code runs.
|
||||
*/
|
||||
static const int64 JIT_SCRIPT_EIGHTH_LIFETIME = 120 * 1000 * 1000;
|
||||
static const int64 JIT_SCRIPT_EIGHTH_LIFETIME = 60 * 1000 * 1000;
|
||||
|
||||
JSBool
|
||||
js_InitGC(JSRuntime *rt, uint32 maxbytes)
|
||||
|
@ -899,8 +899,11 @@ js::types::TypeObject::trace(JSTracer *trc, bool weak)
|
||||
* from singleton JS objects, as if there are no outstanding refs we will
|
||||
* destroy the type object and revert the JS object to a lazy type.
|
||||
*/
|
||||
if (IS_GC_MARKING_TRACER(trc) && (!weak || !singleton))
|
||||
if (IS_GC_MARKING_TRACER(trc) && (!weak || !singleton)) {
|
||||
JS_ASSERT_IF(trc->context->runtime->gcCurrentCompartment,
|
||||
compartment() == trc->context->runtime->gcCurrentCompartment);
|
||||
markIfUnmarked(static_cast<GCMarker *>(trc)->getMarkColor());
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
InlineMarkId(trc, name_, "type_name");
|
||||
|
@ -404,6 +404,11 @@ class HashTable : private AllocPolicy
|
||||
destroyTable(*this, table, tableCapacity);
|
||||
}
|
||||
|
||||
size_t allocatedSize() const
|
||||
{
|
||||
return sizeof(Entry) * tableCapacity;
|
||||
}
|
||||
|
||||
private:
|
||||
static HashNumber hash1(HashNumber hash0, uint32 shift) {
|
||||
return hash0 >> shift;
|
||||
@ -1106,6 +1111,9 @@ class HashMap
|
||||
*/
|
||||
unsigned generation() const { return impl.generation(); }
|
||||
|
||||
/* Number of bytes of heap data allocated by this table. */
|
||||
size_t allocatedSize() const { return impl.allocatedSize(); }
|
||||
|
||||
/* Shorthand operations: */
|
||||
|
||||
bool has(const Lookup &l) const {
|
||||
@ -1305,6 +1313,9 @@ class HashSet
|
||||
*/
|
||||
unsigned generation() const { return impl.generation(); }
|
||||
|
||||
/* Number of bytes of heap data allocated by this table. */
|
||||
size_t allocatedSize() const { return impl.allocatedSize(); }
|
||||
|
||||
/* Shorthand operations: */
|
||||
|
||||
bool has(const Lookup &l) const {
|
||||
|
@ -356,7 +356,6 @@ TypeSet::make(JSContext *cx, const char *name)
|
||||
InferSpew(ISpewOps, "typeSet: %sT%p%s intermediate %s",
|
||||
InferSpewColor(res), res, InferSpewColorReset(),
|
||||
name);
|
||||
res->setIntermediate();
|
||||
|
||||
return res;
|
||||
}
|
||||
@ -812,9 +811,7 @@ public:
|
||||
|
||||
TypeConstraintSubsetBarrier(JSScript *script, jsbytecode *pc, TypeSet *target)
|
||||
: TypeConstraint("subsetBarrier"), script(script), pc(pc), target(target)
|
||||
{
|
||||
JS_ASSERT(!target->intermediate());
|
||||
}
|
||||
{}
|
||||
|
||||
void newType(JSContext *cx, TypeSet *source, Type type)
|
||||
{
|
||||
@ -1951,7 +1948,7 @@ void
|
||||
TypeCompartment::growPendingArray(JSContext *cx)
|
||||
{
|
||||
unsigned newCapacity = js::Max(unsigned(100), pendingCapacity * 2);
|
||||
PendingWork *newArray = (PendingWork *) js::OffTheBooks::calloc_(newCapacity * sizeof(PendingWork));
|
||||
PendingWork *newArray = (PendingWork *) OffTheBooks::calloc_(newCapacity * sizeof(PendingWork));
|
||||
if (!newArray) {
|
||||
cx->compartment->types.setPendingNukeTypes(cx);
|
||||
return;
|
||||
@ -1992,9 +1989,10 @@ TypeCompartment::processPendingRecompiles(JSContext *cx)
|
||||
void
|
||||
TypeCompartment::setPendingNukeTypes(JSContext *cx)
|
||||
{
|
||||
JS_ASSERT(cx->compartment->activeInference);
|
||||
JS_ASSERT(compartment()->activeInference);
|
||||
if (!pendingNukeTypes) {
|
||||
js_ReportOutOfMemory(cx);
|
||||
if (cx->compartment)
|
||||
js_ReportOutOfMemory(cx);
|
||||
pendingNukeTypes = true;
|
||||
}
|
||||
}
|
||||
@ -2623,17 +2621,13 @@ bool
|
||||
TypeObject::addProperty(JSContext *cx, jsid id, Property **pprop)
|
||||
{
|
||||
JS_ASSERT(!*pprop);
|
||||
Property *base = singleton
|
||||
? ArenaNew<Property>(cx->compartment->pool, id)
|
||||
: cx->new_<Property>(id);
|
||||
Property *base = ArenaNew<Property>(cx->compartment->pool, id);
|
||||
if (!base) {
|
||||
cx->compartment->types.setPendingNukeTypes(cx);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (singleton) {
|
||||
base->types.setIntermediate();
|
||||
|
||||
/*
|
||||
* Fill the property in with any type the object already has in an
|
||||
* own property. We are only interested in plain native properties
|
||||
@ -3096,7 +3090,6 @@ ScriptAnalysis::analyzeTypesBytecode(JSContext *cx, unsigned offset,
|
||||
if (!state.phiNodes.append(newv->value.phiNode()))
|
||||
return false;
|
||||
TypeSet &types = newv->value.phiNode()->types;
|
||||
types.setIntermediate();
|
||||
InferSpew(ISpewOps, "typeSet: %sT%p%s phi #%u:%05u:%u",
|
||||
InferSpewColor(&types), &types, InferSpewColorReset(),
|
||||
script->id(), offset, newv->slot);
|
||||
@ -3112,7 +3105,6 @@ ScriptAnalysis::analyzeTypesBytecode(JSContext *cx, unsigned offset,
|
||||
return true;
|
||||
|
||||
for (unsigned i = 0; i < defCount; i++) {
|
||||
pushed[i].setIntermediate();
|
||||
InferSpew(ISpewOps, "typeSet: %sT%p%s pushed%u #%u:%05u",
|
||||
InferSpewColor(&pushed[i]), &pushed[i], InferSpewColorReset(),
|
||||
i, script->id(), offset);
|
||||
@ -3348,18 +3340,12 @@ ScriptAnalysis::analyzeTypesBytecode(JSContext *cx, unsigned offset,
|
||||
poppedTypes(pc, 0)->addSubset(cx, &pushed[0]);
|
||||
break;
|
||||
|
||||
case JSOP_GETXPROP: {
|
||||
TypeSet *seen = script->analysis()->bytecodeTypes(pc);
|
||||
addTypeBarrier(cx, pc, seen, Type::UnknownType());
|
||||
seen->addSubset(cx, &pushed[0]);
|
||||
break;
|
||||
}
|
||||
|
||||
case JSOP_GETXPROP:
|
||||
case JSOP_GETFCSLOT:
|
||||
case JSOP_CALLFCSLOT: {
|
||||
unsigned index = GET_UINT16(pc);
|
||||
TypeSet *types = TypeScript::UpvarTypes(script, index);
|
||||
types->addSubset(cx, &pushed[0]);
|
||||
TypeSet *seen = bytecodeTypes(pc);
|
||||
addTypeBarrier(cx, pc, seen, Type::UnknownType());
|
||||
seen->addSubset(cx, &pushed[0]);
|
||||
if (op == JSOP_CALLFCSLOT) {
|
||||
pushed[1].addType(cx, Type::UndefinedType());
|
||||
pushed[0].addPropagateThis(cx, script, pc, Type::UndefinedType());
|
||||
@ -4516,10 +4502,6 @@ ScriptAnalysis::printTypes(JSContext *cx)
|
||||
TypeScript::LocalTypes(script, i)->print(cx);
|
||||
}
|
||||
}
|
||||
for (unsigned i = 0; i < script->bindings.countUpvars(); i++) {
|
||||
printf("\n upvar%u:", i);
|
||||
TypeScript::UpvarTypes(script, i)->print(cx);
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
for (unsigned offset = 0; offset < script->length; offset++) {
|
||||
@ -4931,12 +4913,6 @@ JSScript::makeTypes(JSContext *cx)
|
||||
InferSpewColor(types), types, InferSpewColorReset(),
|
||||
i, id());
|
||||
}
|
||||
for (unsigned i = 0; i < bindings.countUpvars(); i++) {
|
||||
TypeSet *types = TypeScript::UpvarTypes(this, i);
|
||||
InferSpew(ISpewOps, "typeSet: %sT%p%s upvar%u #%u",
|
||||
InferSpewColor(types), types, InferSpewColorReset(),
|
||||
i, id());
|
||||
}
|
||||
#endif
|
||||
|
||||
return true;
|
||||
@ -5228,39 +5204,32 @@ JSObject::makeNewType(JSContext *cx, JSScript *newScript, bool unknown)
|
||||
void
|
||||
TypeSet::sweep(JSContext *cx, JSCompartment *compartment)
|
||||
{
|
||||
JS_ASSERT(!intermediate());
|
||||
uint32 objectCount = baseObjectCount();
|
||||
|
||||
/*
|
||||
* Purge references to type objects that are no longer live. Type sets hold
|
||||
* only weak references. For type sets containing more than one object,
|
||||
* live entries in the object hash need to be copied to the compartment's
|
||||
* new arena.
|
||||
*/
|
||||
unsigned objectCount = baseObjectCount();
|
||||
if (objectCount >= 2) {
|
||||
bool removed = false;
|
||||
unsigned objectCapacity = HashSetCapacity(objectCount);
|
||||
for (unsigned i = 0; i < objectCapacity; i++) {
|
||||
TypeObjectKey *object = objectSet[i];
|
||||
if (object && IsAboutToBeFinalized(cx, object)) {
|
||||
objectSet[i] = NULL;
|
||||
removed = true;
|
||||
unsigned oldCapacity = HashSetCapacity(objectCount);
|
||||
TypeObjectKey **oldArray = objectSet;
|
||||
|
||||
clearObjects();
|
||||
objectCount = 0;
|
||||
for (unsigned i = 0; i < oldCapacity; i++) {
|
||||
TypeObjectKey *object = oldArray[i];
|
||||
if (object && !IsAboutToBeFinalized(cx, object)) {
|
||||
TypeObjectKey **pentry =
|
||||
HashSetInsert<TypeObjectKey *,TypeObjectKey,TypeObjectKey>
|
||||
(compartment, objectSet, objectCount, object);
|
||||
if (pentry)
|
||||
*pentry = object;
|
||||
else
|
||||
compartment->types.setPendingNukeTypes(cx);
|
||||
}
|
||||
}
|
||||
if (removed) {
|
||||
/* Reconstruct the type set to re-resolve hash collisions. */
|
||||
TypeObjectKey **oldArray = objectSet;
|
||||
objectSet = NULL;
|
||||
objectCount = 0;
|
||||
for (unsigned i = 0; i < objectCapacity; i++) {
|
||||
TypeObjectKey *object = oldArray[i];
|
||||
if (object) {
|
||||
TypeObjectKey **pentry =
|
||||
HashSetInsert<TypeObjectKey *,TypeObjectKey,TypeObjectKey>
|
||||
(cx, objectSet, objectCount, object, false);
|
||||
if (pentry)
|
||||
*pentry = object;
|
||||
else
|
||||
compartment->types.setPendingNukeTypes(cx);
|
||||
}
|
||||
}
|
||||
setBaseObjectCount(objectCount);
|
||||
cx->free_(oldArray);
|
||||
}
|
||||
setBaseObjectCount(objectCount);
|
||||
} else if (objectCount == 1) {
|
||||
TypeObjectKey *object = (TypeObjectKey *) objectSet;
|
||||
if (IsAboutToBeFinalized(cx, object)) {
|
||||
@ -5289,7 +5258,6 @@ JSObject::revertLazyType()
|
||||
inline void
|
||||
TypeObject::clearProperties()
|
||||
{
|
||||
JS_ASSERT(singleton);
|
||||
setBasePropertyCount(0);
|
||||
propertySet = NULL;
|
||||
}
|
||||
@ -5301,27 +5269,26 @@ TypeObject::clearProperties()
|
||||
* elsewhere. This also releases memory associated with dead type objects,
|
||||
* so that type objects do not need later finalization.
|
||||
*/
|
||||
static inline void
|
||||
SweepTypeObject(JSContext *cx, TypeObject *object)
|
||||
inline void
|
||||
TypeObject::sweep(JSContext *cx)
|
||||
{
|
||||
/*
|
||||
* We may be regenerating existing type sets containing this object,
|
||||
* so reset contributions on each GC to avoid tripping the limit.
|
||||
*/
|
||||
object->contribution = 0;
|
||||
contribution = 0;
|
||||
|
||||
if (object->singleton) {
|
||||
JS_ASSERT(!object->emptyShapes);
|
||||
JS_ASSERT(!object->newScript);
|
||||
if (singleton) {
|
||||
JS_ASSERT(!emptyShapes);
|
||||
JS_ASSERT(!newScript);
|
||||
|
||||
/*
|
||||
* All properties on the object are allocated from the analysis pool,
|
||||
* and can be discarded. We will regenerate them as needed as code gets
|
||||
* reanalyzed.
|
||||
* All properties can be discarded. We will regenerate them as needed
|
||||
* as code gets reanalyzed.
|
||||
*/
|
||||
object->clearProperties();
|
||||
clearProperties();
|
||||
|
||||
if (!object->isMarked()) {
|
||||
if (!isMarked()) {
|
||||
/*
|
||||
* Singleton objects do not hold strong references on their types.
|
||||
* When removing the type, however, we need to fixup the singleton
|
||||
@ -5329,41 +5296,76 @@ SweepTypeObject(JSContext *cx, TypeObject *object)
|
||||
* proto must be live, since the type's prototype and its 'new'
|
||||
* type are both strong references.
|
||||
*/
|
||||
JS_ASSERT_IF(object->singleton->isMarked() && object->proto,
|
||||
object->proto->isMarked() && object->proto->newType->isMarked());
|
||||
object->singleton->revertLazyType();
|
||||
JS_ASSERT_IF(singleton->isMarked() && proto,
|
||||
proto->isMarked() && proto->newType->isMarked());
|
||||
singleton->revertLazyType();
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!object->isMarked()) {
|
||||
if (object->emptyShapes)
|
||||
Foreground::free_(object->emptyShapes);
|
||||
if (!isMarked()) {
|
||||
if (emptyShapes)
|
||||
Foreground::free_(emptyShapes);
|
||||
if (newScript)
|
||||
Foreground::free_(newScript);
|
||||
return;
|
||||
}
|
||||
|
||||
unsigned count = object->getPropertyCount();
|
||||
for (unsigned i = 0; i < count; i++) {
|
||||
Property *prop = object->getProperty(i);
|
||||
if (prop) {
|
||||
prop->types.clearObjects();
|
||||
Foreground::delete_(prop);
|
||||
JSCompartment *compartment = this->compartment();
|
||||
|
||||
/*
|
||||
* Properties were allocated from the old arena, and need to be copied over
|
||||
* to the new one. Don't hang onto properties without the OWN_PROPERTY
|
||||
* flag; these were never directly assigned, and get any possible values
|
||||
* from the object's prototype.
|
||||
*/
|
||||
unsigned propertyCount = basePropertyCount();
|
||||
if (propertyCount >= 2) {
|
||||
unsigned oldCapacity = HashSetCapacity(propertyCount);
|
||||
Property **oldArray = propertySet;
|
||||
|
||||
clearProperties();
|
||||
propertyCount = 0;
|
||||
for (unsigned i = 0; i < oldCapacity; i++) {
|
||||
Property *prop = oldArray[i];
|
||||
if (prop && prop->types.isOwnProperty(false)) {
|
||||
Property *newProp = ArenaNew<Property>(compartment->pool, *prop);
|
||||
if (newProp) {
|
||||
Property **pentry =
|
||||
HashSetInsert<jsid,Property,Property>
|
||||
(compartment, propertySet, propertyCount, prop->id);
|
||||
if (pentry) {
|
||||
*pentry = newProp;
|
||||
newProp->types.sweep(cx, compartment);
|
||||
} else {
|
||||
compartment->types.setPendingNukeTypes(cx);
|
||||
}
|
||||
} else {
|
||||
compartment->types.setPendingNukeTypes(cx);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (count >= 2)
|
||||
Foreground::free_(object->propertySet);
|
||||
|
||||
if (object->newScript)
|
||||
Foreground::free_(object->newScript);
|
||||
|
||||
return;
|
||||
setBasePropertyCount(propertyCount);
|
||||
} else if (propertyCount == 1) {
|
||||
Property *prop = (Property *) propertySet;
|
||||
if (prop->types.isOwnProperty(false)) {
|
||||
Property *newProp = ArenaNew<Property>(compartment->pool, *prop);
|
||||
if (newProp) {
|
||||
propertySet = (Property **) newProp;
|
||||
newProp->types.sweep(cx, compartment);
|
||||
} else {
|
||||
compartment->types.setPendingNukeTypes(cx);
|
||||
}
|
||||
} else {
|
||||
propertySet = NULL;
|
||||
setBasePropertyCount(0);
|
||||
}
|
||||
}
|
||||
|
||||
/* Sweep type sets for all properties of the object. */
|
||||
unsigned count = object->getPropertyCount();
|
||||
for (unsigned i = 0; i < count; i++) {
|
||||
Property *prop = object->getProperty(i);
|
||||
if (prop)
|
||||
prop->types.sweep(cx, object->compartment());
|
||||
if (basePropertyCount() <= SET_ARRAY_SIZE) {
|
||||
for (unsigned i = 0; i < basePropertyCount(); i++)
|
||||
JS_ASSERT(propertySet[i]);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -5371,8 +5373,8 @@ SweepTypeObject(JSContext *cx, TypeObject *object)
|
||||
* newScript information, these constraints will need to be regenerated
|
||||
* the next time we compile code which depends on this info.
|
||||
*/
|
||||
if (object->newScript)
|
||||
object->flags |= OBJECT_FLAG_NEW_SCRIPT_REGENERATE;
|
||||
if (newScript)
|
||||
flags |= OBJECT_FLAG_NEW_SCRIPT_REGENERATE;
|
||||
}
|
||||
|
||||
void
|
||||
@ -5397,7 +5399,7 @@ SweepTypeObjects(JSContext *cx, JSCompartment *compartment)
|
||||
thing = span->last;
|
||||
span = span->nextSpan();
|
||||
} else {
|
||||
SweepTypeObject(cx, reinterpret_cast<TypeObject *>(thing));
|
||||
reinterpret_cast<TypeObject *>(thing)->sweep(cx);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -5470,6 +5472,16 @@ TypeCompartment::sweep(JSContext *cx)
|
||||
e.removeFront();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* The pending array is reset on GC, it can grow large (75+ KB) and is easy
|
||||
* to reallocate if the compartment becomes active again.
|
||||
*/
|
||||
if (pendingArray)
|
||||
cx->free_(pendingArray);
|
||||
|
||||
pendingArray = NULL;
|
||||
pendingCapacity = 0;
|
||||
}
|
||||
|
||||
TypeCompartment::~TypeCompartment()
|
||||
@ -5537,17 +5549,39 @@ TypeScript::destroy()
|
||||
Foreground::delete_(dynamicList);
|
||||
dynamicList = next;
|
||||
}
|
||||
|
||||
Foreground::free_(this);
|
||||
}
|
||||
|
||||
size_t
|
||||
inline size_t
|
||||
TypeSet::dynamicSize()
|
||||
{
|
||||
/* Get the amount of memory allocated from the analysis pool for this set. */
|
||||
uint32 count = baseObjectCount();
|
||||
if (count >= 2)
|
||||
return HashSetCapacity(count) * sizeof(TypeObject *);
|
||||
return 0;
|
||||
}
|
||||
|
||||
inline size_t
|
||||
TypeObject::dynamicSize()
|
||||
{
|
||||
size_t bytes = 0;
|
||||
|
||||
uint32 count = basePropertyCount();
|
||||
if (count >= 2)
|
||||
bytes += HashSetCapacity(count) * sizeof(TypeObject *);
|
||||
|
||||
count = getPropertyCount();
|
||||
for (unsigned i = 0; i < count; i++) {
|
||||
Property *prop = getProperty(i);
|
||||
if (prop)
|
||||
bytes += sizeof(Property) + prop->types.dynamicSize();
|
||||
}
|
||||
|
||||
return bytes;
|
||||
}
|
||||
|
||||
static void
|
||||
GetScriptMemoryStats(JSScript *script, TypeInferenceMemoryStats *stats)
|
||||
{
|
||||
@ -5555,28 +5589,41 @@ GetScriptMemoryStats(JSScript *script, TypeInferenceMemoryStats *stats)
|
||||
return;
|
||||
|
||||
if (!script->compartment->types.inferenceEnabled) {
|
||||
stats->scriptMain += sizeof(TypeScript);
|
||||
stats->scripts += sizeof(TypeScript);
|
||||
return;
|
||||
}
|
||||
|
||||
unsigned count = TypeScript::NumTypeSets(script);
|
||||
stats->scriptMain += sizeof(TypeScript) + count * sizeof(TypeSet);
|
||||
|
||||
TypeSet *typeArray = script->types->typeArray();
|
||||
for (unsigned i = 0; i < count; i++)
|
||||
stats->scriptSets += typeArray[i].dynamicSize();
|
||||
stats->scripts += sizeof(TypeScript) + count * sizeof(TypeSet);
|
||||
|
||||
TypeResult *result = script->types->dynamicList;
|
||||
while (result) {
|
||||
stats->scriptMain += sizeof(TypeResult);
|
||||
stats->scripts += sizeof(TypeResult);
|
||||
result = result->next;
|
||||
}
|
||||
|
||||
TypeSet *typeArray = script->types->typeArray();
|
||||
for (unsigned i = 0; i < count; i++) {
|
||||
size_t bytes = typeArray[i].dynamicSize();
|
||||
stats->scripts += bytes;
|
||||
stats->temporary -= bytes;
|
||||
}
|
||||
}
|
||||
|
||||
JS_FRIEND_API(void)
|
||||
JS_GetTypeInferenceMemoryStats(JSContext *cx, JSCompartment *compartment,
|
||||
TypeInferenceMemoryStats *stats)
|
||||
{
|
||||
/*
|
||||
* Note: not all data in the pool is temporary, and some will survive GCs
|
||||
* by being copied to the replacement pool. This memory will be counted too
|
||||
* and deducted from the amount of temporary data.
|
||||
*/
|
||||
stats->temporary += ArenaAllocatedSize(compartment->pool);
|
||||
|
||||
/* Pending arrays are cleared on GC along with the analysis pool. */
|
||||
stats->temporary += sizeof(TypeCompartment::PendingWork) * compartment->types.pendingCapacity;
|
||||
|
||||
for (JSCList *cursor = compartment->scripts.next;
|
||||
cursor != &compartment->scripts;
|
||||
cursor = cursor->next) {
|
||||
@ -5584,32 +5631,54 @@ JS_GetTypeInferenceMemoryStats(JSContext *cx, JSCompartment *compartment,
|
||||
GetScriptMemoryStats(script, stats);
|
||||
}
|
||||
|
||||
stats->poolMain += ArenaAllocatedSize(compartment->pool);
|
||||
if (compartment->types.allocationSiteTable)
|
||||
stats->tables += compartment->types.allocationSiteTable->allocatedSize();
|
||||
|
||||
if (compartment->types.arrayTypeTable)
|
||||
stats->tables += compartment->types.arrayTypeTable->allocatedSize();
|
||||
|
||||
if (compartment->types.objectTypeTable) {
|
||||
stats->tables += compartment->types.objectTypeTable->allocatedSize();
|
||||
|
||||
for (ObjectTypeTable::Enum e(*compartment->types.objectTypeTable);
|
||||
!e.empty();
|
||||
e.popFront()) {
|
||||
const ObjectTableKey &key = e.front().key;
|
||||
stats->tables += key.nslots * (sizeof(jsid) + sizeof(Type));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
JS_FRIEND_API(void)
|
||||
JS_GetTypeInferenceObjectStats(void *object_, TypeInferenceMemoryStats *stats)
|
||||
{
|
||||
TypeObject *object = (TypeObject *) object_;
|
||||
stats->objectMain += sizeof(TypeObject);
|
||||
stats->objects += sizeof(TypeObject);
|
||||
|
||||
if (object->singleton) {
|
||||
/*
|
||||
* Properties and TypeSet data for singletons are allocated in the
|
||||
* compartment's analysis pool.
|
||||
* Properties and associated type sets for singletons are cleared on
|
||||
* every GC. The type object is normally destroyed too, but we don't
|
||||
* charge this to 'temporary' as this is not for GC heap values.
|
||||
*/
|
||||
JS_ASSERT(!object->newScript && !object->emptyShapes);
|
||||
return;
|
||||
}
|
||||
|
||||
uint32 count = object->getPropertyCount();
|
||||
if (count >= 2)
|
||||
stats->objectMain += count * sizeof(Property *);
|
||||
|
||||
for (unsigned i = 0; i < count; i++) {
|
||||
Property *prop = object->getProperty(i);
|
||||
if (prop) {
|
||||
stats->objectMain += sizeof(Property);
|
||||
stats->objectSets += prop->types.dynamicSize();
|
||||
if (object->newScript) {
|
||||
size_t length = 0;
|
||||
for (TypeNewScript::Initializer *init = object->newScript->initializerList;; init++) {
|
||||
length++;
|
||||
if (init->kind == TypeNewScript::Initializer::DONE)
|
||||
break;
|
||||
}
|
||||
stats->objects += sizeof(TypeNewScript) + (length * sizeof(TypeNewScript::Initializer));
|
||||
}
|
||||
|
||||
if (object->emptyShapes)
|
||||
stats->emptyShapes += sizeof(EmptyShape*) * gc::FINALIZE_FUNCTION_AND_OBJECT_LAST;
|
||||
|
||||
size_t bytes = object->dynamicSize();
|
||||
stats->objects += bytes;
|
||||
stats->temporary -= bytes;
|
||||
}
|
||||
|
@ -178,8 +178,13 @@ inline Type GetValueType(JSContext *cx, const Value &val);
|
||||
* which occurs while we are not actively working with inference or other
|
||||
* analysis information, we clear out all generated constraints, all type sets
|
||||
* describing stack types within scripts, and (normally) all data describing
|
||||
* type objects describing particular JS objects (see the lazy type objects
|
||||
* overview below). JIT code depends on this data and is cleared as well.
|
||||
* type objects for particular JS objects (see the lazy type objects overview
|
||||
* below). JIT code depends on this data and is cleared as well.
|
||||
*
|
||||
* All this data is allocated into compartment->pool. Some type inference data
|
||||
* lives across GCs: type sets for scripts and non-singleton type objects, and
|
||||
* propeties for such type objects. This data is also allocated into
|
||||
* compartment->pool, but everything still live is copied to a new arena on GC.
|
||||
*/
|
||||
|
||||
/*
|
||||
@ -247,33 +252,30 @@ enum {
|
||||
/* Mask of normal type flags on a type set. */
|
||||
TYPE_FLAG_BASE_MASK = 0x000100ff,
|
||||
|
||||
/* Flag for type sets which are cleared on GC. */
|
||||
TYPE_FLAG_INTERMEDIATE_SET = 0x00020000,
|
||||
|
||||
/* Flags for type sets which are on object properties. */
|
||||
|
||||
/*
|
||||
* Whether there are subset constraints propagating the possible types
|
||||
* for this property inherited from the object's prototypes. Reset on GC.
|
||||
*/
|
||||
TYPE_FLAG_PROPAGATED_PROPERTY = 0x00040000,
|
||||
TYPE_FLAG_PROPAGATED_PROPERTY = 0x00020000,
|
||||
|
||||
/* Whether this property has ever been directly written. */
|
||||
TYPE_FLAG_OWN_PROPERTY = 0x00080000,
|
||||
TYPE_FLAG_OWN_PROPERTY = 0x00040000,
|
||||
|
||||
/*
|
||||
* Whether the property has ever been deleted or reconfigured to behave
|
||||
* differently from a normal native property (e.g. made non-writable or
|
||||
* given a scripted getter or setter).
|
||||
*/
|
||||
TYPE_FLAG_CONFIGURED_PROPERTY = 0x00100000,
|
||||
TYPE_FLAG_CONFIGURED_PROPERTY = 0x00080000,
|
||||
|
||||
/*
|
||||
* Whether the property is definitely in a particular inline slot on all
|
||||
* objects from which it has not been deleted or reconfigured. Implies
|
||||
* OWN_PROPERTY and unlike OWN/CONFIGURED property, this cannot change.
|
||||
*/
|
||||
TYPE_FLAG_DEFINITE_PROPERTY = 0x00200000,
|
||||
TYPE_FLAG_DEFINITE_PROPERTY = 0x00100000,
|
||||
|
||||
/* If the property is definite, mask and shift storing the slot. */
|
||||
TYPE_FLAG_DEFINITE_MASK = 0x0f000000,
|
||||
@ -370,7 +372,7 @@ class TypeSet
|
||||
void print(JSContext *cx);
|
||||
|
||||
inline void sweep(JSContext *cx, JSCompartment *compartment);
|
||||
size_t dynamicSize();
|
||||
inline size_t dynamicSize();
|
||||
|
||||
/* Whether this set contains a specific type. */
|
||||
inline bool hasType(Type type);
|
||||
@ -412,8 +414,6 @@ class TypeSet
|
||||
inline JSObject *getSingleObject(unsigned i);
|
||||
inline TypeObject *getTypeObject(unsigned i);
|
||||
|
||||
bool intermediate() { return !!(flags & TYPE_FLAG_INTERMEDIATE_SET); }
|
||||
void setIntermediate() { JS_ASSERT(!flags); flags = TYPE_FLAG_INTERMEDIATE_SET; }
|
||||
void setOwnProperty(bool configurable) {
|
||||
flags |= TYPE_FLAG_OWN_PROPERTY;
|
||||
if (configurable)
|
||||
@ -446,8 +446,8 @@ class TypeSet
|
||||
void addLazyArguments(JSContext *cx, TypeSet *target);
|
||||
|
||||
/*
|
||||
* Make an intermediate type set with the specified debugging name,
|
||||
* not embedded in another structure.
|
||||
* Make an type set with the specified debugging name, not embedded in
|
||||
* another structure.
|
||||
*/
|
||||
static TypeSet *make(JSContext *cx, const char *name);
|
||||
|
||||
@ -498,9 +498,6 @@ class TypeSet
|
||||
/* Get the single value which can appear in this type set, otherwise NULL. */
|
||||
JSObject *getSingleton(JSContext *cx, bool freeze = true);
|
||||
|
||||
static bool
|
||||
SweepTypeSet(JSContext *cx, JSCompartment *compartment, TypeSet *types);
|
||||
|
||||
inline void clearObjects();
|
||||
|
||||
private:
|
||||
@ -608,6 +605,10 @@ struct Property
|
||||
: id(id)
|
||||
{}
|
||||
|
||||
Property(const Property &o)
|
||||
: id(o.id), types(o.types)
|
||||
{}
|
||||
|
||||
static uint32 keyBits(jsid id) { return (uint32) JSID_BITS(id); }
|
||||
static jsid getKey(Property *p) { return p->id; }
|
||||
};
|
||||
@ -833,6 +834,9 @@ struct TypeObject : gc::Cell
|
||||
void trace(JSTracer *trc, bool weak = false);
|
||||
|
||||
inline void clearProperties();
|
||||
inline void sweep(JSContext *cx);
|
||||
|
||||
inline size_t dynamicSize();
|
||||
|
||||
/*
|
||||
* Type objects don't have explicit finalizers. Memory owned by a type
|
||||
@ -905,7 +909,6 @@ struct TypeScript
|
||||
static inline TypeSet *ThisTypes(JSScript *script);
|
||||
static inline TypeSet *ArgTypes(JSScript *script, unsigned i);
|
||||
static inline TypeSet *LocalTypes(JSScript *script, unsigned i);
|
||||
static inline TypeSet *UpvarTypes(JSScript *script, unsigned i);
|
||||
|
||||
/* Follows slot layout in jsanalyze.h, can get this/arg/local type sets. */
|
||||
static inline TypeSet *SlotTypes(JSScript *script, unsigned slot);
|
||||
@ -950,7 +953,6 @@ struct TypeScript
|
||||
static inline void SetLocal(JSContext *cx, JSScript *script, unsigned local, const js::Value &value);
|
||||
static inline void SetArgument(JSContext *cx, JSScript *script, unsigned arg, Type type);
|
||||
static inline void SetArgument(JSContext *cx, JSScript *script, unsigned arg, const js::Value &value);
|
||||
static inline void SetUpvar(JSContext *cx, JSScript *script, unsigned upvar, const js::Value &value);
|
||||
|
||||
static void Sweep(JSContext *cx, JSScript *script);
|
||||
void destroy();
|
||||
|
@ -455,7 +455,7 @@ UseNewTypeAtEntry(JSContext *cx, StackFrame *fp)
|
||||
/* static */ inline unsigned
|
||||
TypeScript::NumTypeSets(JSScript *script)
|
||||
{
|
||||
return script->nTypeSets + analyze::TotalSlots(script) + script->bindings.countUpvars();
|
||||
return script->nTypeSets + analyze::TotalSlots(script);
|
||||
}
|
||||
|
||||
/* static */ inline TypeSet *
|
||||
@ -490,13 +490,6 @@ TypeScript::LocalTypes(JSScript *script, unsigned i)
|
||||
return script->types->typeArray() + script->nTypeSets + js::analyze::LocalSlot(script, i);
|
||||
}
|
||||
|
||||
/* static */ inline TypeSet *
|
||||
TypeScript::UpvarTypes(JSScript *script, unsigned i)
|
||||
{
|
||||
JS_ASSERT(i < script->bindings.countUpvars());
|
||||
return script->types->typeArray() + script->nTypeSets + js::analyze::TotalSlots(script) + i;
|
||||
}
|
||||
|
||||
/* static */ inline TypeSet *
|
||||
TypeScript::SlotTypes(JSScript *script, unsigned slot)
|
||||
{
|
||||
@ -681,21 +674,6 @@ TypeScript::SetArgument(JSContext *cx, JSScript *script, unsigned arg, const js:
|
||||
}
|
||||
}
|
||||
|
||||
/* static */ inline void
|
||||
TypeScript::SetUpvar(JSContext *cx, JSScript *script, unsigned upvar, const js::Value &value)
|
||||
{
|
||||
if (!cx->typeInferenceEnabled() || !script->ensureHasTypes(cx))
|
||||
return;
|
||||
Type type = GetValueType(cx, value);
|
||||
if (!UpvarTypes(script, upvar)->hasType(type)) {
|
||||
AutoEnterTypeInference enter(cx);
|
||||
|
||||
InferSpew(ISpewOps, "externalType: setUpvar #%u %u: %s",
|
||||
script->id(), upvar, TypeString(type));
|
||||
UpvarTypes(script, upvar)->addType(cx, type);
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
// TypeCompartment
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
@ -796,7 +774,7 @@ HashKey(T v)
|
||||
*/
|
||||
template <class T, class U, class KEY>
|
||||
static U **
|
||||
HashSetInsertTry(JSContext *cx, U **&values, unsigned &count, T key, bool pool)
|
||||
HashSetInsertTry(JSCompartment *compartment, U **&values, unsigned &count, T key)
|
||||
{
|
||||
unsigned capacity = HashSetCapacity(count);
|
||||
unsigned insertpos = HashKey<T,KEY>(key) & (capacity - 1);
|
||||
@ -820,13 +798,9 @@ HashSetInsertTry(JSContext *cx, U **&values, unsigned &count, T key, bool pool)
|
||||
return &values[insertpos];
|
||||
}
|
||||
|
||||
U **newValues = pool
|
||||
? ArenaArray<U*>(cx->compartment->pool, newCapacity)
|
||||
: (U **) js::OffTheBooks::malloc_(newCapacity * sizeof(U*));
|
||||
if (!newValues) {
|
||||
cx->compartment->types.setPendingNukeTypes(cx);
|
||||
U **newValues = ArenaArray<U*>(compartment->pool, newCapacity);
|
||||
if (!newValues)
|
||||
return NULL;
|
||||
}
|
||||
PodZero(newValues, newCapacity);
|
||||
|
||||
for (unsigned i = 0; i < capacity; i++) {
|
||||
@ -838,8 +812,6 @@ HashSetInsertTry(JSContext *cx, U **&values, unsigned &count, T key, bool pool)
|
||||
}
|
||||
}
|
||||
|
||||
if (values && !pool)
|
||||
Foreground::free_(values);
|
||||
values = newValues;
|
||||
|
||||
insertpos = HashKey<T,KEY>(key) & (newCapacity - 1);
|
||||
@ -854,7 +826,7 @@ HashSetInsertTry(JSContext *cx, U **&values, unsigned &count, T key, bool pool)
|
||||
*/
|
||||
template <class T, class U, class KEY>
|
||||
static inline U **
|
||||
HashSetInsert(JSContext *cx, U **&values, unsigned &count, T key, bool pool)
|
||||
HashSetInsert(JSCompartment *compartment, U **&values, unsigned &count, T key)
|
||||
{
|
||||
if (count == 0) {
|
||||
JS_ASSERT(values == NULL);
|
||||
@ -867,12 +839,9 @@ HashSetInsert(JSContext *cx, U **&values, unsigned &count, T key, bool pool)
|
||||
if (KEY::getKey(oldData) == key)
|
||||
return (U **) &values;
|
||||
|
||||
values = pool
|
||||
? ArenaArray<U*>(cx->compartment->pool, SET_ARRAY_SIZE)
|
||||
: (U **) js::OffTheBooks::malloc_(SET_ARRAY_SIZE * sizeof(U*));
|
||||
values = ArenaArray<U*>(compartment->pool, SET_ARRAY_SIZE);
|
||||
if (!values) {
|
||||
values = (U **) oldData;
|
||||
cx->compartment->types.setPendingNukeTypes(cx);
|
||||
return NULL;
|
||||
}
|
||||
PodZero(values, SET_ARRAY_SIZE);
|
||||
@ -894,7 +863,7 @@ HashSetInsert(JSContext *cx, U **&values, unsigned &count, T key, bool pool)
|
||||
}
|
||||
}
|
||||
|
||||
return HashSetInsertTry<T,U,KEY>(cx, values, count, key, pool);
|
||||
return HashSetInsertTry<T,U,KEY>(compartment, values, count, key);
|
||||
}
|
||||
|
||||
/* Lookup an entry in a hash set, return NULL if it does not exist. */
|
||||
@ -964,8 +933,6 @@ TypeSet::setBaseObjectCount(uint32 count)
|
||||
inline void
|
||||
TypeSet::clearObjects()
|
||||
{
|
||||
if (baseObjectCount() >= 2 && !intermediate())
|
||||
Foreground::free_(objectSet);
|
||||
setBaseObjectCount(0);
|
||||
objectSet = NULL;
|
||||
}
|
||||
@ -999,8 +966,12 @@ TypeSet::addType(JSContext *cx, Type type)
|
||||
uint32 objectCount = baseObjectCount();
|
||||
TypeObjectKey *object = type.objectKey();
|
||||
TypeObjectKey **pentry = HashSetInsert<TypeObjectKey *,TypeObjectKey,TypeObjectKey>
|
||||
(cx, objectSet, objectCount, object, intermediate());
|
||||
if (!pentry || *pentry)
|
||||
(cx->compartment, objectSet, objectCount, object);
|
||||
if (!pentry) {
|
||||
cx->compartment->types.setPendingNukeTypes(cx);
|
||||
return;
|
||||
}
|
||||
if (*pentry)
|
||||
return;
|
||||
*pentry = object;
|
||||
|
||||
@ -1168,9 +1139,11 @@ TypeObject::getProperty(JSContext *cx, jsid id, bool assign)
|
||||
|
||||
uint32 propertyCount = basePropertyCount();
|
||||
Property **pprop = HashSetInsert<jsid,Property,Property>
|
||||
(cx, propertySet, propertyCount, id, singleton != NULL);
|
||||
if (!pprop)
|
||||
(cx->compartment, propertySet, propertyCount, id);
|
||||
if (!pprop) {
|
||||
cx->compartment->types.setPendingNukeTypes(cx);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!*pprop) {
|
||||
setBasePropertyCount(propertyCount);
|
||||
|
@ -4694,6 +4694,7 @@ BEGIN_CASE(JSOP_CALLFCSLOT)
|
||||
|
||||
JS_ASSERT(index < obj->getFunctionPrivate()->script()->bindings.countUpvars());
|
||||
PUSH_COPY(obj->getFlatClosureUpvar(index));
|
||||
TypeScript::Monitor(cx, script, regs.pc, regs.sp[-1]);
|
||||
if (op == JSOP_CALLFCSLOT)
|
||||
PUSH_UNDEFINED();
|
||||
}
|
||||
|
@ -370,8 +370,8 @@ OPDEF(JSOP_FINALLY, 135,"finally", NULL, 1, 0, 2, 0, JOF_BYTE)
|
||||
* in the function's u.i.script->upvars() array. The CALL variant computes the
|
||||
* callee and this-object in preparation for a JSOP_CALL.
|
||||
*/
|
||||
OPDEF(JSOP_GETFCSLOT, 136,"getfcslot", NULL, 3, 0, 1, 19, JOF_UINT16|JOF_NAME)
|
||||
OPDEF(JSOP_CALLFCSLOT, 137,"callfcslot", NULL, 3, 0, 2, 19, JOF_UINT16|JOF_NAME|JOF_CALLOP)
|
||||
OPDEF(JSOP_GETFCSLOT, 136,"getfcslot", NULL, 3, 0, 1, 19, JOF_UINT16|JOF_NAME|JOF_TYPESET)
|
||||
OPDEF(JSOP_CALLFCSLOT, 137,"callfcslot", NULL, 3, 0, 2, 19, JOF_UINT16|JOF_NAME|JOF_TYPESET|JOF_CALLOP)
|
||||
|
||||
/*
|
||||
* Bytecodes that avoid making an arguments object in most cases:
|
||||
|
@ -1419,10 +1419,8 @@ DestroyScript(JSContext *cx, JSScript *script, JSObject *owner, uint32 caller)
|
||||
PurgeScriptFragments(script->compartment->traceMonitor(), script);
|
||||
#endif
|
||||
|
||||
if (script->types) {
|
||||
if (script->types)
|
||||
script->types->destroy();
|
||||
Foreground::free_(script->types);
|
||||
}
|
||||
|
||||
#ifdef JS_METHODJIT
|
||||
mjit::ReleaseScriptCode(cx, script);
|
||||
|
@ -1330,6 +1330,7 @@ mjit::Compiler::finishThisUp(JITScript **jitp)
|
||||
#endif
|
||||
|
||||
JS_ASSERT(size_t(cursor - (uint8*)jit) == dataSize);
|
||||
JS_ASSERT(jit->scriptDataSize() == dataSize);
|
||||
|
||||
/* Link fast and slow paths together. */
|
||||
stubcc.fixCrossJumps(result, masm.size(), masm.size() + stubcc.size());
|
||||
@ -2511,8 +2512,11 @@ mjit::Compiler::generateMethod()
|
||||
Address upvarAddress(reg, JSObject::getFlatClosureUpvarsOffset());
|
||||
masm.loadPrivate(upvarAddress, reg);
|
||||
// push ((Value *) reg)[index]
|
||||
frame.freeReg(reg);
|
||||
frame.push(Address(reg, index * sizeof(Value)), knownPushedType(0));
|
||||
|
||||
BarrierState barrier = pushAddressMaybeBarrier(Address(reg, index * sizeof(Value)),
|
||||
knownPushedType(0), true);
|
||||
finishBarrier(barrier, REJOIN_GETTER, 0);
|
||||
|
||||
if (op == JSOP_CALLFCSLOT)
|
||||
frame.push(UndefinedValue());
|
||||
}
|
||||
|
@ -1487,6 +1487,7 @@ js_InternalInterpret(void *returnData, void *returnType, void *returnReg, js::VM
|
||||
case JSOP_NAME:
|
||||
case JSOP_GETGNAME:
|
||||
case JSOP_GETGLOBAL:
|
||||
case JSOP_GETFCSLOT:
|
||||
case JSOP_GETPROP:
|
||||
case JSOP_GETXPROP:
|
||||
case JSOP_LENGTH:
|
||||
@ -1501,7 +1502,8 @@ js_InternalInterpret(void *returnData, void *returnType, void *returnReg, js::VM
|
||||
break;
|
||||
|
||||
case JSOP_CALLGLOBAL:
|
||||
/* |this| is always undefined for CALLGLOBAL. */
|
||||
case JSOP_CALLFCSLOT:
|
||||
/* |this| is always undefined for CALLGLOBAL/CALLFCSLOT. */
|
||||
nextsp[-1].setUndefined();
|
||||
f.regs.pc = nextpc;
|
||||
break;
|
||||
|
@ -1153,6 +1153,9 @@ mjit::JITScript::scriptDataSize()
|
||||
{
|
||||
return sizeof(JITScript) +
|
||||
sizeof(NativeMapEntry) * nNmapPairs +
|
||||
sizeof(InlineFrame) * nInlineFrames +
|
||||
sizeof(CallSite) * nCallSites +
|
||||
sizeof(JSObject *) * nRootedObjects +
|
||||
#if defined JS_MONOIC
|
||||
sizeof(ic::GetGlobalNameIC) * nGetGlobalNames +
|
||||
sizeof(ic::SetGlobalNameIC) * nSetGlobalNames +
|
||||
@ -1165,7 +1168,7 @@ mjit::JITScript::scriptDataSize()
|
||||
sizeof(ic::GetElementIC) * nGetElems +
|
||||
sizeof(ic::SetElementIC) * nSetElems +
|
||||
#endif
|
||||
sizeof(CallSite) * nCallSites;
|
||||
0;
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -1764,6 +1764,13 @@ ReportCompartmentStats(const CompartmentStats &stats,
|
||||
"accesses fast.",
|
||||
callback, closure);
|
||||
|
||||
ReportMemoryBytes0(MakeMemoryReporterPath(pathPrefix, stats.name,
|
||||
"object-empty-shapes"),
|
||||
nsIMemoryReporter::KIND_HEAP,
|
||||
stats.typeInferenceMemory.emptyShapes,
|
||||
"Arrays attached to prototype JS objects managing shape information.",
|
||||
callback, closure);
|
||||
|
||||
ReportMemoryBytes0(MakeMemoryReporterPath(pathPrefix, stats.name,
|
||||
"scripts"),
|
||||
nsIMemoryReporter::KIND_HEAP, stats.scripts,
|
||||
@ -1814,44 +1821,32 @@ ReportCompartmentStats(const CompartmentStats &stats,
|
||||
ReportMemoryBytes0(MakeMemoryReporterPath(pathPrefix, stats.name,
|
||||
"type-inference/script-main"),
|
||||
nsIMemoryReporter::KIND_HEAP,
|
||||
stats.typeInferenceMemory.scriptMain,
|
||||
stats.typeInferenceMemory.scripts,
|
||||
"Memory used during type inference to store type sets of variables "
|
||||
"and dynamically observed types.",
|
||||
callback, closure);
|
||||
|
||||
ReportMemoryBytes0(MakeMemoryReporterPath(pathPrefix, stats.name,
|
||||
"type-inference/script-typesets"),
|
||||
nsIMemoryReporter::KIND_HEAP,
|
||||
stats.typeInferenceMemory.scriptSets,
|
||||
"Memory used during type inference to hold the contents of type "
|
||||
"sets associated with scripts.",
|
||||
callback, closure);
|
||||
|
||||
ReportMemoryBytes0(MakeMemoryReporterPath(pathPrefix, stats.name,
|
||||
"type-inference/object-main"),
|
||||
nsIMemoryReporter::KIND_HEAP,
|
||||
stats.typeInferenceMemory.objectMain,
|
||||
JS_GC_HEAP_KIND,
|
||||
stats.typeInferenceMemory.objects,
|
||||
"Memory used during type inference to store types and possible "
|
||||
"property types of JS objects.",
|
||||
callback, closure);
|
||||
|
||||
ReportMemoryBytes0(MakeMemoryReporterPath(pathPrefix, stats.name,
|
||||
"type-inference/object-typesets"),
|
||||
"type-inference/tables"),
|
||||
nsIMemoryReporter::KIND_HEAP,
|
||||
stats.typeInferenceMemory.objectSets,
|
||||
"Memory used during type inference to hold the contents of type "
|
||||
"sets associated with objects.",
|
||||
stats.typeInferenceMemory.tables,
|
||||
"Memory used during type inference for compartment-wide tables.",
|
||||
callback, closure);
|
||||
|
||||
/*
|
||||
* This is in a different category from the rest of type inference
|
||||
* data as this can be large but is volatile and cleared on GC.
|
||||
*/
|
||||
ReportMemoryBytes0(MakeMemoryReporterPath(pathPrefix, stats.name,
|
||||
"type-inference-pools"),
|
||||
"type-inference-temporary"),
|
||||
nsIMemoryReporter::KIND_HEAP,
|
||||
stats.typeInferenceMemory.poolMain,
|
||||
"Memory used during type inference to hold transient analysis information.",
|
||||
stats.typeInferenceMemory.temporary,
|
||||
"Memory used during type inference to hold transient analysis "
|
||||
"information. Cleared on GC.",
|
||||
callback, closure);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user