[INFER] Allocate typeset data and properties from arenas, occasionally purge observed types in compartments, bug 679329.

This commit is contained in:
Brian Hackett 2011-08-17 06:48:14 -07:00
Родитель f3069475b1
Коммит 123ea20cc0
18 изменённых файлов: 320 добавлений и 233 удалений

Просмотреть файл

@ -4299,7 +4299,6 @@ JS_CloneFunctionObject(JSContext *cx, JSObject *funobj, JSObject *parent)
Value v; Value v;
if (!obj->getProperty(cx, r.front().propid, &v)) if (!obj->getProperty(cx, r.front().propid, &v))
return NULL; return NULL;
TypeScript::SetUpvar(cx, fun->script(), i, v);
clone->getFlatClosureUpvars()[i] = v; clone->getFlatClosureUpvars()[i] = v;
} }

Просмотреть файл

@ -298,6 +298,14 @@ ArenaAllocatedSize(const JSArenaPool &pool)
return res; 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 */ } /* namespace js */
#endif /* __cplusplus */ #endif /* __cplusplus */

Просмотреть файл

@ -136,7 +136,10 @@ JSCompartment::init(JSContext *cx)
activeAnalysis = activeInference = false; activeAnalysis = activeInference = false;
types.init(cx); 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(); freeLists.init();
if (!crossCompartmentWrappers.init()) if (!crossCompartmentWrappers.init())
@ -598,6 +601,13 @@ JSCompartment::sweep(JSContext *cx, uint32 releaseInterval)
#endif #endif
if (!activeAnalysis) { 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 * Sweep analysis information and everything depending on it from the
* compartment, including all remaining mjit code if inference is * 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) { for (JSCList *cursor = scripts.next; cursor != &scripts; cursor = cursor->next) {
JSScript *script = reinterpret_cast<JSScript *>(cursor); JSScript *script = reinterpret_cast<JSScript *>(cursor);
if (script->types) if (script->types) {
types::TypeScript::Sweep(cx, script); 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. */ /* 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 * 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. */ /* Data for tracking analysis/inference memory usage. */
typedef struct TypeInferenceMemoryStats typedef struct TypeInferenceMemoryStats
{ {
int64 scriptMain; int64 scripts;
int64 scriptSets; int64 objects;
int64 objectMain; int64 tables;
int64 objectSets; int64 temporary;
int64 poolMain; int64 emptyShapes;
} TypeInferenceMemoryStats; } TypeInferenceMemoryStats;
extern JS_FRIEND_API(void) 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; uintN level = fun->script()->staticLevel;
JSUpvarArray *uva = fun->script()->upvars(); 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]); upvars[i] = GetUpvar(cx, level, uva->vector[i]);
TypeScript::SetUpvar(cx, fun->script(), i, upvars[i]);
}
return closure; 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 * JIT code is discarded in inactive compartments, regardless of how often that
* code runs. * code runs.
*/ */
static const int64 JIT_SCRIPT_EIGHTH_LIFETIME = 120 * 1000 * 1000; static const int64 JIT_SCRIPT_EIGHTH_LIFETIME = 60 * 1000 * 1000;
JSBool JSBool
js_InitGC(JSRuntime *rt, uint32 maxbytes) 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 * 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. * 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()); markIfUnmarked(static_cast<GCMarker *>(trc)->getMarkColor());
}
#ifdef DEBUG #ifdef DEBUG
InlineMarkId(trc, name_, "type_name"); InlineMarkId(trc, name_, "type_name");

Просмотреть файл

@ -404,6 +404,11 @@ class HashTable : private AllocPolicy
destroyTable(*this, table, tableCapacity); destroyTable(*this, table, tableCapacity);
} }
size_t allocatedSize() const
{
return sizeof(Entry) * tableCapacity;
}
private: private:
static HashNumber hash1(HashNumber hash0, uint32 shift) { static HashNumber hash1(HashNumber hash0, uint32 shift) {
return hash0 >> shift; return hash0 >> shift;
@ -1106,6 +1111,9 @@ class HashMap
*/ */
unsigned generation() const { return impl.generation(); } 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: */ /* Shorthand operations: */
bool has(const Lookup &l) const { bool has(const Lookup &l) const {
@ -1305,6 +1313,9 @@ class HashSet
*/ */
unsigned generation() const { return impl.generation(); } 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: */ /* Shorthand operations: */
bool has(const Lookup &l) const { 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", InferSpew(ISpewOps, "typeSet: %sT%p%s intermediate %s",
InferSpewColor(res), res, InferSpewColorReset(), InferSpewColor(res), res, InferSpewColorReset(),
name); name);
res->setIntermediate();
return res; return res;
} }
@ -812,9 +811,7 @@ public:
TypeConstraintSubsetBarrier(JSScript *script, jsbytecode *pc, TypeSet *target) TypeConstraintSubsetBarrier(JSScript *script, jsbytecode *pc, TypeSet *target)
: TypeConstraint("subsetBarrier"), script(script), pc(pc), target(target) : TypeConstraint("subsetBarrier"), script(script), pc(pc), target(target)
{ {}
JS_ASSERT(!target->intermediate());
}
void newType(JSContext *cx, TypeSet *source, Type type) void newType(JSContext *cx, TypeSet *source, Type type)
{ {
@ -1951,7 +1948,7 @@ void
TypeCompartment::growPendingArray(JSContext *cx) TypeCompartment::growPendingArray(JSContext *cx)
{ {
unsigned newCapacity = js::Max(unsigned(100), pendingCapacity * 2); 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) { if (!newArray) {
cx->compartment->types.setPendingNukeTypes(cx); cx->compartment->types.setPendingNukeTypes(cx);
return; return;
@ -1992,9 +1989,10 @@ TypeCompartment::processPendingRecompiles(JSContext *cx)
void void
TypeCompartment::setPendingNukeTypes(JSContext *cx) TypeCompartment::setPendingNukeTypes(JSContext *cx)
{ {
JS_ASSERT(cx->compartment->activeInference); JS_ASSERT(compartment()->activeInference);
if (!pendingNukeTypes) { if (!pendingNukeTypes) {
js_ReportOutOfMemory(cx); if (cx->compartment)
js_ReportOutOfMemory(cx);
pendingNukeTypes = true; pendingNukeTypes = true;
} }
} }
@ -2623,17 +2621,13 @@ bool
TypeObject::addProperty(JSContext *cx, jsid id, Property **pprop) TypeObject::addProperty(JSContext *cx, jsid id, Property **pprop)
{ {
JS_ASSERT(!*pprop); JS_ASSERT(!*pprop);
Property *base = singleton Property *base = ArenaNew<Property>(cx->compartment->pool, id);
? ArenaNew<Property>(cx->compartment->pool, id)
: cx->new_<Property>(id);
if (!base) { if (!base) {
cx->compartment->types.setPendingNukeTypes(cx); cx->compartment->types.setPendingNukeTypes(cx);
return false; return false;
} }
if (singleton) { if (singleton) {
base->types.setIntermediate();
/* /*
* Fill the property in with any type the object already has in an * Fill the property in with any type the object already has in an
* own property. We are only interested in plain native properties * 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())) if (!state.phiNodes.append(newv->value.phiNode()))
return false; return false;
TypeSet &types = newv->value.phiNode()->types; TypeSet &types = newv->value.phiNode()->types;
types.setIntermediate();
InferSpew(ISpewOps, "typeSet: %sT%p%s phi #%u:%05u:%u", InferSpew(ISpewOps, "typeSet: %sT%p%s phi #%u:%05u:%u",
InferSpewColor(&types), &types, InferSpewColorReset(), InferSpewColor(&types), &types, InferSpewColorReset(),
script->id(), offset, newv->slot); script->id(), offset, newv->slot);
@ -3112,7 +3105,6 @@ ScriptAnalysis::analyzeTypesBytecode(JSContext *cx, unsigned offset,
return true; return true;
for (unsigned i = 0; i < defCount; i++) { for (unsigned i = 0; i < defCount; i++) {
pushed[i].setIntermediate();
InferSpew(ISpewOps, "typeSet: %sT%p%s pushed%u #%u:%05u", InferSpew(ISpewOps, "typeSet: %sT%p%s pushed%u #%u:%05u",
InferSpewColor(&pushed[i]), &pushed[i], InferSpewColorReset(), InferSpewColor(&pushed[i]), &pushed[i], InferSpewColorReset(),
i, script->id(), offset); i, script->id(), offset);
@ -3348,18 +3340,12 @@ ScriptAnalysis::analyzeTypesBytecode(JSContext *cx, unsigned offset,
poppedTypes(pc, 0)->addSubset(cx, &pushed[0]); poppedTypes(pc, 0)->addSubset(cx, &pushed[0]);
break; break;
case JSOP_GETXPROP: { case JSOP_GETXPROP:
TypeSet *seen = script->analysis()->bytecodeTypes(pc);
addTypeBarrier(cx, pc, seen, Type::UnknownType());
seen->addSubset(cx, &pushed[0]);
break;
}
case JSOP_GETFCSLOT: case JSOP_GETFCSLOT:
case JSOP_CALLFCSLOT: { case JSOP_CALLFCSLOT: {
unsigned index = GET_UINT16(pc); TypeSet *seen = bytecodeTypes(pc);
TypeSet *types = TypeScript::UpvarTypes(script, index); addTypeBarrier(cx, pc, seen, Type::UnknownType());
types->addSubset(cx, &pushed[0]); seen->addSubset(cx, &pushed[0]);
if (op == JSOP_CALLFCSLOT) { if (op == JSOP_CALLFCSLOT) {
pushed[1].addType(cx, Type::UndefinedType()); pushed[1].addType(cx, Type::UndefinedType());
pushed[0].addPropagateThis(cx, script, pc, Type::UndefinedType()); pushed[0].addPropagateThis(cx, script, pc, Type::UndefinedType());
@ -4516,10 +4502,6 @@ ScriptAnalysis::printTypes(JSContext *cx)
TypeScript::LocalTypes(script, i)->print(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"); printf("\n");
for (unsigned offset = 0; offset < script->length; offset++) { for (unsigned offset = 0; offset < script->length; offset++) {
@ -4931,12 +4913,6 @@ JSScript::makeTypes(JSContext *cx)
InferSpewColor(types), types, InferSpewColorReset(), InferSpewColor(types), types, InferSpewColorReset(),
i, id()); 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 #endif
return true; return true;
@ -5228,39 +5204,32 @@ JSObject::makeNewType(JSContext *cx, JSScript *newScript, bool unknown)
void void
TypeSet::sweep(JSContext *cx, JSCompartment *compartment) 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) { if (objectCount >= 2) {
bool removed = false; unsigned oldCapacity = HashSetCapacity(objectCount);
unsigned objectCapacity = HashSetCapacity(objectCount); TypeObjectKey **oldArray = objectSet;
for (unsigned i = 0; i < objectCapacity; i++) {
TypeObjectKey *object = objectSet[i]; clearObjects();
if (object && IsAboutToBeFinalized(cx, object)) { objectCount = 0;
objectSet[i] = NULL; for (unsigned i = 0; i < oldCapacity; i++) {
removed = true; 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) { setBaseObjectCount(objectCount);
/* 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);
}
} else if (objectCount == 1) { } else if (objectCount == 1) {
TypeObjectKey *object = (TypeObjectKey *) objectSet; TypeObjectKey *object = (TypeObjectKey *) objectSet;
if (IsAboutToBeFinalized(cx, object)) { if (IsAboutToBeFinalized(cx, object)) {
@ -5289,7 +5258,6 @@ JSObject::revertLazyType()
inline void inline void
TypeObject::clearProperties() TypeObject::clearProperties()
{ {
JS_ASSERT(singleton);
setBasePropertyCount(0); setBasePropertyCount(0);
propertySet = NULL; propertySet = NULL;
} }
@ -5301,27 +5269,26 @@ TypeObject::clearProperties()
* elsewhere. This also releases memory associated with dead type objects, * elsewhere. This also releases memory associated with dead type objects,
* so that type objects do not need later finalization. * so that type objects do not need later finalization.
*/ */
static inline void inline void
SweepTypeObject(JSContext *cx, TypeObject *object) TypeObject::sweep(JSContext *cx)
{ {
/* /*
* We may be regenerating existing type sets containing this object, * We may be regenerating existing type sets containing this object,
* so reset contributions on each GC to avoid tripping the limit. * so reset contributions on each GC to avoid tripping the limit.
*/ */
object->contribution = 0; contribution = 0;
if (object->singleton) { if (singleton) {
JS_ASSERT(!object->emptyShapes); JS_ASSERT(!emptyShapes);
JS_ASSERT(!object->newScript); JS_ASSERT(!newScript);
/* /*
* All properties on the object are allocated from the analysis pool, * All properties can be discarded. We will regenerate them as needed
* and can be discarded. We will regenerate them as needed as code gets * as code gets reanalyzed.
* reanalyzed.
*/ */
object->clearProperties(); clearProperties();
if (!object->isMarked()) { if (!isMarked()) {
/* /*
* Singleton objects do not hold strong references on their types. * Singleton objects do not hold strong references on their types.
* When removing the type, however, we need to fixup the singleton * 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' * proto must be live, since the type's prototype and its 'new'
* type are both strong references. * type are both strong references.
*/ */
JS_ASSERT_IF(object->singleton->isMarked() && object->proto, JS_ASSERT_IF(singleton->isMarked() && proto,
object->proto->isMarked() && object->proto->newType->isMarked()); proto->isMarked() && proto->newType->isMarked());
object->singleton->revertLazyType(); singleton->revertLazyType();
} }
return; return;
} }
if (!object->isMarked()) { if (!isMarked()) {
if (object->emptyShapes) if (emptyShapes)
Foreground::free_(object->emptyShapes); Foreground::free_(emptyShapes);
if (newScript)
Foreground::free_(newScript);
return;
}
unsigned count = object->getPropertyCount(); JSCompartment *compartment = this->compartment();
for (unsigned i = 0; i < count; i++) {
Property *prop = object->getProperty(i); /*
if (prop) { * Properties were allocated from the old arena, and need to be copied over
prop->types.clearObjects(); * to the new one. Don't hang onto properties without the OWN_PROPERTY
Foreground::delete_(prop); * 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) setBasePropertyCount(propertyCount);
Foreground::free_(object->propertySet); } else if (propertyCount == 1) {
Property *prop = (Property *) propertySet;
if (object->newScript) if (prop->types.isOwnProperty(false)) {
Foreground::free_(object->newScript); Property *newProp = ArenaNew<Property>(compartment->pool, *prop);
if (newProp) {
return; 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. */ if (basePropertyCount() <= SET_ARRAY_SIZE) {
unsigned count = object->getPropertyCount(); for (unsigned i = 0; i < basePropertyCount(); i++)
for (unsigned i = 0; i < count; i++) { JS_ASSERT(propertySet[i]);
Property *prop = object->getProperty(i);
if (prop)
prop->types.sweep(cx, object->compartment());
} }
/* /*
@ -5371,8 +5373,8 @@ SweepTypeObject(JSContext *cx, TypeObject *object)
* newScript information, these constraints will need to be regenerated * newScript information, these constraints will need to be regenerated
* the next time we compile code which depends on this info. * the next time we compile code which depends on this info.
*/ */
if (object->newScript) if (newScript)
object->flags |= OBJECT_FLAG_NEW_SCRIPT_REGENERATE; flags |= OBJECT_FLAG_NEW_SCRIPT_REGENERATE;
} }
void void
@ -5397,7 +5399,7 @@ SweepTypeObjects(JSContext *cx, JSCompartment *compartment)
thing = span->last; thing = span->last;
span = span->nextSpan(); span = span->nextSpan();
} else { } else {
SweepTypeObject(cx, reinterpret_cast<TypeObject *>(thing)); reinterpret_cast<TypeObject *>(thing)->sweep(cx);
} }
} }
} }
@ -5470,6 +5472,16 @@ TypeCompartment::sweep(JSContext *cx)
e.removeFront(); 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() TypeCompartment::~TypeCompartment()
@ -5537,17 +5549,39 @@ TypeScript::destroy()
Foreground::delete_(dynamicList); Foreground::delete_(dynamicList);
dynamicList = next; dynamicList = next;
} }
Foreground::free_(this);
} }
size_t inline size_t
TypeSet::dynamicSize() TypeSet::dynamicSize()
{ {
/* Get the amount of memory allocated from the analysis pool for this set. */
uint32 count = baseObjectCount(); uint32 count = baseObjectCount();
if (count >= 2) if (count >= 2)
return HashSetCapacity(count) * sizeof(TypeObject *); return HashSetCapacity(count) * sizeof(TypeObject *);
return 0; 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 static void
GetScriptMemoryStats(JSScript *script, TypeInferenceMemoryStats *stats) GetScriptMemoryStats(JSScript *script, TypeInferenceMemoryStats *stats)
{ {
@ -5555,28 +5589,41 @@ GetScriptMemoryStats(JSScript *script, TypeInferenceMemoryStats *stats)
return; return;
if (!script->compartment->types.inferenceEnabled) { if (!script->compartment->types.inferenceEnabled) {
stats->scriptMain += sizeof(TypeScript); stats->scripts += sizeof(TypeScript);
return; return;
} }
unsigned count = TypeScript::NumTypeSets(script); unsigned count = TypeScript::NumTypeSets(script);
stats->scriptMain += sizeof(TypeScript) + count * sizeof(TypeSet); stats->scripts += sizeof(TypeScript) + count * sizeof(TypeSet);
TypeSet *typeArray = script->types->typeArray();
for (unsigned i = 0; i < count; i++)
stats->scriptSets += typeArray[i].dynamicSize();
TypeResult *result = script->types->dynamicList; TypeResult *result = script->types->dynamicList;
while (result) { while (result) {
stats->scriptMain += sizeof(TypeResult); stats->scripts += sizeof(TypeResult);
result = result->next; 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_FRIEND_API(void)
JS_GetTypeInferenceMemoryStats(JSContext *cx, JSCompartment *compartment, JS_GetTypeInferenceMemoryStats(JSContext *cx, JSCompartment *compartment,
TypeInferenceMemoryStats *stats) 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; for (JSCList *cursor = compartment->scripts.next;
cursor != &compartment->scripts; cursor != &compartment->scripts;
cursor = cursor->next) { cursor = cursor->next) {
@ -5584,32 +5631,54 @@ JS_GetTypeInferenceMemoryStats(JSContext *cx, JSCompartment *compartment,
GetScriptMemoryStats(script, stats); 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_FRIEND_API(void)
JS_GetTypeInferenceObjectStats(void *object_, TypeInferenceMemoryStats *stats) JS_GetTypeInferenceObjectStats(void *object_, TypeInferenceMemoryStats *stats)
{ {
TypeObject *object = (TypeObject *) object_; TypeObject *object = (TypeObject *) object_;
stats->objectMain += sizeof(TypeObject); stats->objects += sizeof(TypeObject);
if (object->singleton) { if (object->singleton) {
/* /*
* Properties and TypeSet data for singletons are allocated in the * Properties and associated type sets for singletons are cleared on
* compartment's analysis pool. * 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; return;
} }
uint32 count = object->getPropertyCount(); if (object->newScript) {
if (count >= 2) size_t length = 0;
stats->objectMain += count * sizeof(Property *); for (TypeNewScript::Initializer *init = object->newScript->initializerList;; init++) {
length++;
for (unsigned i = 0; i < count; i++) { if (init->kind == TypeNewScript::Initializer::DONE)
Property *prop = object->getProperty(i); break;
if (prop) {
stats->objectMain += sizeof(Property);
stats->objectSets += prop->types.dynamicSize();
} }
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 * which occurs while we are not actively working with inference or other
* analysis information, we clear out all generated constraints, all type sets * analysis information, we clear out all generated constraints, all type sets
* describing stack types within scripts, and (normally) all data describing * describing stack types within scripts, and (normally) all data describing
* type objects describing particular JS objects (see the lazy type objects * type objects for particular JS objects (see the lazy type objects overview
* overview below). JIT code depends on this data and is cleared as well. * 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. */ /* Mask of normal type flags on a type set. */
TYPE_FLAG_BASE_MASK = 0x000100ff, 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. */ /* Flags for type sets which are on object properties. */
/* /*
* Whether there are subset constraints propagating the possible types * Whether there are subset constraints propagating the possible types
* for this property inherited from the object's prototypes. Reset on GC. * 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. */ /* 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 * Whether the property has ever been deleted or reconfigured to behave
* differently from a normal native property (e.g. made non-writable or * differently from a normal native property (e.g. made non-writable or
* given a scripted getter or setter). * 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 * Whether the property is definitely in a particular inline slot on all
* objects from which it has not been deleted or reconfigured. Implies * objects from which it has not been deleted or reconfigured. Implies
* OWN_PROPERTY and unlike OWN/CONFIGURED property, this cannot change. * 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. */ /* If the property is definite, mask and shift storing the slot. */
TYPE_FLAG_DEFINITE_MASK = 0x0f000000, TYPE_FLAG_DEFINITE_MASK = 0x0f000000,
@ -370,7 +372,7 @@ class TypeSet
void print(JSContext *cx); void print(JSContext *cx);
inline void sweep(JSContext *cx, JSCompartment *compartment); inline void sweep(JSContext *cx, JSCompartment *compartment);
size_t dynamicSize(); inline size_t dynamicSize();
/* Whether this set contains a specific type. */ /* Whether this set contains a specific type. */
inline bool hasType(Type type); inline bool hasType(Type type);
@ -412,8 +414,6 @@ class TypeSet
inline JSObject *getSingleObject(unsigned i); inline JSObject *getSingleObject(unsigned i);
inline TypeObject *getTypeObject(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) { void setOwnProperty(bool configurable) {
flags |= TYPE_FLAG_OWN_PROPERTY; flags |= TYPE_FLAG_OWN_PROPERTY;
if (configurable) if (configurable)
@ -446,8 +446,8 @@ class TypeSet
void addLazyArguments(JSContext *cx, TypeSet *target); void addLazyArguments(JSContext *cx, TypeSet *target);
/* /*
* Make an intermediate type set with the specified debugging name, * Make an type set with the specified debugging name, not embedded in
* not embedded in another structure. * another structure.
*/ */
static TypeSet *make(JSContext *cx, const char *name); 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. */ /* Get the single value which can appear in this type set, otherwise NULL. */
JSObject *getSingleton(JSContext *cx, bool freeze = true); JSObject *getSingleton(JSContext *cx, bool freeze = true);
static bool
SweepTypeSet(JSContext *cx, JSCompartment *compartment, TypeSet *types);
inline void clearObjects(); inline void clearObjects();
private: private:
@ -608,6 +605,10 @@ struct Property
: id(id) : id(id)
{} {}
Property(const Property &o)
: id(o.id), types(o.types)
{}
static uint32 keyBits(jsid id) { return (uint32) JSID_BITS(id); } static uint32 keyBits(jsid id) { return (uint32) JSID_BITS(id); }
static jsid getKey(Property *p) { return p->id; } static jsid getKey(Property *p) { return p->id; }
}; };
@ -833,6 +834,9 @@ struct TypeObject : gc::Cell
void trace(JSTracer *trc, bool weak = false); void trace(JSTracer *trc, bool weak = false);
inline void clearProperties(); inline void clearProperties();
inline void sweep(JSContext *cx);
inline size_t dynamicSize();
/* /*
* Type objects don't have explicit finalizers. Memory owned by a type * 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 *ThisTypes(JSScript *script);
static inline TypeSet *ArgTypes(JSScript *script, unsigned i); static inline TypeSet *ArgTypes(JSScript *script, unsigned i);
static inline TypeSet *LocalTypes(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. */ /* Follows slot layout in jsanalyze.h, can get this/arg/local type sets. */
static inline TypeSet *SlotTypes(JSScript *script, unsigned slot); 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 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, Type type);
static inline void SetArgument(JSContext *cx, JSScript *script, unsigned arg, const js::Value &value); 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); static void Sweep(JSContext *cx, JSScript *script);
void destroy(); void destroy();

Просмотреть файл

@ -455,7 +455,7 @@ UseNewTypeAtEntry(JSContext *cx, StackFrame *fp)
/* static */ inline unsigned /* static */ inline unsigned
TypeScript::NumTypeSets(JSScript *script) TypeScript::NumTypeSets(JSScript *script)
{ {
return script->nTypeSets + analyze::TotalSlots(script) + script->bindings.countUpvars(); return script->nTypeSets + analyze::TotalSlots(script);
} }
/* static */ inline TypeSet * /* static */ inline TypeSet *
@ -490,13 +490,6 @@ TypeScript::LocalTypes(JSScript *script, unsigned i)
return script->types->typeArray() + script->nTypeSets + js::analyze::LocalSlot(script, 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 * /* static */ inline TypeSet *
TypeScript::SlotTypes(JSScript *script, unsigned slot) 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 // TypeCompartment
///////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////
@ -796,7 +774,7 @@ HashKey(T v)
*/ */
template <class T, class U, class KEY> template <class T, class U, class KEY>
static U ** 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 capacity = HashSetCapacity(count);
unsigned insertpos = HashKey<T,KEY>(key) & (capacity - 1); 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]; return &values[insertpos];
} }
U **newValues = pool U **newValues = ArenaArray<U*>(compartment->pool, newCapacity);
? ArenaArray<U*>(cx->compartment->pool, newCapacity) if (!newValues)
: (U **) js::OffTheBooks::malloc_(newCapacity * sizeof(U*));
if (!newValues) {
cx->compartment->types.setPendingNukeTypes(cx);
return NULL; return NULL;
}
PodZero(newValues, newCapacity); PodZero(newValues, newCapacity);
for (unsigned i = 0; i < capacity; i++) { 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; values = newValues;
insertpos = HashKey<T,KEY>(key) & (newCapacity - 1); 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> template <class T, class U, class KEY>
static inline U ** 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) { if (count == 0) {
JS_ASSERT(values == NULL); JS_ASSERT(values == NULL);
@ -867,12 +839,9 @@ HashSetInsert(JSContext *cx, U **&values, unsigned &count, T key, bool pool)
if (KEY::getKey(oldData) == key) if (KEY::getKey(oldData) == key)
return (U **) &values; return (U **) &values;
values = pool values = ArenaArray<U*>(compartment->pool, SET_ARRAY_SIZE);
? ArenaArray<U*>(cx->compartment->pool, SET_ARRAY_SIZE)
: (U **) js::OffTheBooks::malloc_(SET_ARRAY_SIZE * sizeof(U*));
if (!values) { if (!values) {
values = (U **) oldData; values = (U **) oldData;
cx->compartment->types.setPendingNukeTypes(cx);
return NULL; return NULL;
} }
PodZero(values, SET_ARRAY_SIZE); 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. */ /* Lookup an entry in a hash set, return NULL if it does not exist. */
@ -964,8 +933,6 @@ TypeSet::setBaseObjectCount(uint32 count)
inline void inline void
TypeSet::clearObjects() TypeSet::clearObjects()
{ {
if (baseObjectCount() >= 2 && !intermediate())
Foreground::free_(objectSet);
setBaseObjectCount(0); setBaseObjectCount(0);
objectSet = NULL; objectSet = NULL;
} }
@ -999,8 +966,12 @@ TypeSet::addType(JSContext *cx, Type type)
uint32 objectCount = baseObjectCount(); uint32 objectCount = baseObjectCount();
TypeObjectKey *object = type.objectKey(); TypeObjectKey *object = type.objectKey();
TypeObjectKey **pentry = HashSetInsert<TypeObjectKey *,TypeObjectKey,TypeObjectKey> TypeObjectKey **pentry = HashSetInsert<TypeObjectKey *,TypeObjectKey,TypeObjectKey>
(cx, objectSet, objectCount, object, intermediate()); (cx->compartment, objectSet, objectCount, object);
if (!pentry || *pentry) if (!pentry) {
cx->compartment->types.setPendingNukeTypes(cx);
return;
}
if (*pentry)
return; return;
*pentry = object; *pentry = object;
@ -1168,9 +1139,11 @@ TypeObject::getProperty(JSContext *cx, jsid id, bool assign)
uint32 propertyCount = basePropertyCount(); uint32 propertyCount = basePropertyCount();
Property **pprop = HashSetInsert<jsid,Property,Property> Property **pprop = HashSetInsert<jsid,Property,Property>
(cx, propertySet, propertyCount, id, singleton != NULL); (cx->compartment, propertySet, propertyCount, id);
if (!pprop) if (!pprop) {
cx->compartment->types.setPendingNukeTypes(cx);
return NULL; return NULL;
}
if (!*pprop) { if (!*pprop) {
setBasePropertyCount(propertyCount); setBasePropertyCount(propertyCount);

Просмотреть файл

@ -4694,6 +4694,7 @@ BEGIN_CASE(JSOP_CALLFCSLOT)
JS_ASSERT(index < obj->getFunctionPrivate()->script()->bindings.countUpvars()); JS_ASSERT(index < obj->getFunctionPrivate()->script()->bindings.countUpvars());
PUSH_COPY(obj->getFlatClosureUpvar(index)); PUSH_COPY(obj->getFlatClosureUpvar(index));
TypeScript::Monitor(cx, script, regs.pc, regs.sp[-1]);
if (op == JSOP_CALLFCSLOT) if (op == JSOP_CALLFCSLOT)
PUSH_UNDEFINED(); 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 * in the function's u.i.script->upvars() array. The CALL variant computes the
* callee and this-object in preparation for a JSOP_CALL. * 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_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_CALLOP) 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: * 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); PurgeScriptFragments(script->compartment->traceMonitor(), script);
#endif #endif
if (script->types) { if (script->types)
script->types->destroy(); script->types->destroy();
Foreground::free_(script->types);
}
#ifdef JS_METHODJIT #ifdef JS_METHODJIT
mjit::ReleaseScriptCode(cx, script); mjit::ReleaseScriptCode(cx, script);

Просмотреть файл

@ -1330,6 +1330,7 @@ mjit::Compiler::finishThisUp(JITScript **jitp)
#endif #endif
JS_ASSERT(size_t(cursor - (uint8*)jit) == dataSize); JS_ASSERT(size_t(cursor - (uint8*)jit) == dataSize);
JS_ASSERT(jit->scriptDataSize() == dataSize);
/* Link fast and slow paths together. */ /* Link fast and slow paths together. */
stubcc.fixCrossJumps(result, masm.size(), masm.size() + stubcc.size()); stubcc.fixCrossJumps(result, masm.size(), masm.size() + stubcc.size());
@ -2511,8 +2512,11 @@ mjit::Compiler::generateMethod()
Address upvarAddress(reg, JSObject::getFlatClosureUpvarsOffset()); Address upvarAddress(reg, JSObject::getFlatClosureUpvarsOffset());
masm.loadPrivate(upvarAddress, reg); masm.loadPrivate(upvarAddress, reg);
// push ((Value *) reg)[index] // 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) if (op == JSOP_CALLFCSLOT)
frame.push(UndefinedValue()); frame.push(UndefinedValue());
} }

Просмотреть файл

@ -1487,6 +1487,7 @@ js_InternalInterpret(void *returnData, void *returnType, void *returnReg, js::VM
case JSOP_NAME: case JSOP_NAME:
case JSOP_GETGNAME: case JSOP_GETGNAME:
case JSOP_GETGLOBAL: case JSOP_GETGLOBAL:
case JSOP_GETFCSLOT:
case JSOP_GETPROP: case JSOP_GETPROP:
case JSOP_GETXPROP: case JSOP_GETXPROP:
case JSOP_LENGTH: case JSOP_LENGTH:
@ -1501,7 +1502,8 @@ js_InternalInterpret(void *returnData, void *returnType, void *returnReg, js::VM
break; break;
case JSOP_CALLGLOBAL: case JSOP_CALLGLOBAL:
/* |this| is always undefined for CALLGLOBAL. */ case JSOP_CALLFCSLOT:
/* |this| is always undefined for CALLGLOBAL/CALLFCSLOT. */
nextsp[-1].setUndefined(); nextsp[-1].setUndefined();
f.regs.pc = nextpc; f.regs.pc = nextpc;
break; break;

Просмотреть файл

@ -1153,6 +1153,9 @@ mjit::JITScript::scriptDataSize()
{ {
return sizeof(JITScript) + return sizeof(JITScript) +
sizeof(NativeMapEntry) * nNmapPairs + sizeof(NativeMapEntry) * nNmapPairs +
sizeof(InlineFrame) * nInlineFrames +
sizeof(CallSite) * nCallSites +
sizeof(JSObject *) * nRootedObjects +
#if defined JS_MONOIC #if defined JS_MONOIC
sizeof(ic::GetGlobalNameIC) * nGetGlobalNames + sizeof(ic::GetGlobalNameIC) * nGetGlobalNames +
sizeof(ic::SetGlobalNameIC) * nSetGlobalNames + sizeof(ic::SetGlobalNameIC) * nSetGlobalNames +
@ -1165,7 +1168,7 @@ mjit::JITScript::scriptDataSize()
sizeof(ic::GetElementIC) * nGetElems + sizeof(ic::GetElementIC) * nGetElems +
sizeof(ic::SetElementIC) * nSetElems + sizeof(ic::SetElementIC) * nSetElems +
#endif #endif
sizeof(CallSite) * nCallSites; 0;
} }
void void

Просмотреть файл

@ -1764,6 +1764,13 @@ ReportCompartmentStats(const CompartmentStats &stats,
"accesses fast.", "accesses fast.",
callback, closure); 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, ReportMemoryBytes0(MakeMemoryReporterPath(pathPrefix, stats.name,
"scripts"), "scripts"),
nsIMemoryReporter::KIND_HEAP, stats.scripts, nsIMemoryReporter::KIND_HEAP, stats.scripts,
@ -1814,44 +1821,32 @@ ReportCompartmentStats(const CompartmentStats &stats,
ReportMemoryBytes0(MakeMemoryReporterPath(pathPrefix, stats.name, ReportMemoryBytes0(MakeMemoryReporterPath(pathPrefix, stats.name,
"type-inference/script-main"), "type-inference/script-main"),
nsIMemoryReporter::KIND_HEAP, nsIMemoryReporter::KIND_HEAP,
stats.typeInferenceMemory.scriptMain, stats.typeInferenceMemory.scripts,
"Memory used during type inference to store type sets of variables " "Memory used during type inference to store type sets of variables "
"and dynamically observed types.", "and dynamically observed types.",
callback, closure); 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, ReportMemoryBytes0(MakeMemoryReporterPath(pathPrefix, stats.name,
"type-inference/object-main"), "type-inference/object-main"),
nsIMemoryReporter::KIND_HEAP, JS_GC_HEAP_KIND,
stats.typeInferenceMemory.objectMain, stats.typeInferenceMemory.objects,
"Memory used during type inference to store types and possible " "Memory used during type inference to store types and possible "
"property types of JS objects.", "property types of JS objects.",
callback, closure); callback, closure);
ReportMemoryBytes0(MakeMemoryReporterPath(pathPrefix, stats.name, ReportMemoryBytes0(MakeMemoryReporterPath(pathPrefix, stats.name,
"type-inference/object-typesets"), "type-inference/tables"),
nsIMemoryReporter::KIND_HEAP, nsIMemoryReporter::KIND_HEAP,
stats.typeInferenceMemory.objectSets, stats.typeInferenceMemory.tables,
"Memory used during type inference to hold the contents of type " "Memory used during type inference for compartment-wide tables.",
"sets associated with objects.",
callback, closure); 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, ReportMemoryBytes0(MakeMemoryReporterPath(pathPrefix, stats.name,
"type-inference-pools"), "type-inference-temporary"),
nsIMemoryReporter::KIND_HEAP, nsIMemoryReporter::KIND_HEAP,
stats.typeInferenceMemory.poolMain, stats.typeInferenceMemory.temporary,
"Memory used during type inference to hold transient analysis information.", "Memory used during type inference to hold transient analysis "
"information. Cleared on GC.",
callback, closure); callback, closure);
} }