Bug 1051155 - Simplify and clean up TypeNewScript, r=jandem.

This commit is contained in:
Brian Hackett 2014-08-11 10:44:25 -08:00
Родитель 6423e1dd3a
Коммит 19d4fe6a25
8 изменённых файлов: 63 добавлений и 178 удалений

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

@ -795,7 +795,7 @@ class JitCode;
}
namespace types {
struct TypeObject;
struct TypeObjectAddendum;
struct TypeNewScript;
}
typedef PreBarriered<JSObject*> PreBarrieredObject;
@ -821,7 +821,7 @@ typedef HeapPtr<Shape*> HeapPtrShape;
typedef HeapPtr<UnownedBaseShape*> HeapPtrUnownedBaseShape;
typedef HeapPtr<jit::JitCode*> HeapPtrJitCode;
typedef HeapPtr<types::TypeObject*> HeapPtrTypeObject;
typedef HeapPtr<types::TypeObjectAddendum*> HeapPtrTypeObjectAddendum;
typedef HeapPtr<types::TypeNewScript*> HeapPtrTypeNewScript;
typedef PreBarriered<Value> PreBarrieredValue;
typedef RelocatablePtr<Value> RelocatableValue;

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

@ -1406,7 +1406,7 @@ ScanTypeObject(GCMarker *gcmarker, types::TypeObject *type)
if (type->singleton() && !type->lazy())
PushMarkStack(gcmarker, type->singleton());
if (type->hasNewScript()) {
if (type->newScript()) {
PushMarkStack(gcmarker, type->newScript()->fun);
PushMarkStack(gcmarker, type->newScript()->templateObject);
}
@ -1431,7 +1431,7 @@ gc::MarkChildren(JSTracer *trc, types::TypeObject *type)
if (type->singleton() && !type->lazy())
MarkObject(trc, &type->singletonRaw(), "type_singleton");
if (type->hasNewScript()) {
if (type->newScript()) {
MarkObject(trc, &type->newScript()->fun, "type_new_function");
MarkObject(trc, &type->newScript()->templateObject, "type_new_template");
}

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

@ -4867,7 +4867,7 @@ IonBuilder::createThisScriptedSingleton(JSFunction *target, MDefinition *callee)
// calling Ion code will be invalidated, but any baseline template object
// may be stale. Update to the correct template object in this case.
types::TypeObject *templateType = templateObject->type();
if (templateType->hasNewScript()) {
if (templateType->newScript()) {
templateObject = templateType->newScript()->templateObject;
JS_ASSERT(templateObject->type() == templateType);

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

@ -4171,15 +4171,15 @@ GCRuntime::beginSweepingZoneGroup()
// overapproximates the possible types in the zone), but the
// constraints might not have been triggered on the deoptimization
// or even copied over completely. In this case, destroy all JIT
// code and new script addendums in the zone, the only things whose
// correctness depends on the type constraints.
// code and new script information in the zone, the only things
// whose correctness depends on the type constraints.
bool oom = false;
zone->sweep(&fop, releaseTypes && !zone->isPreservingCode(), &oom);
if (oom) {
zone->setPreservingCode(false);
zone->discardJitCode(&fop);
zone->types.clearAllNewScriptAddendumsOnOOM();
zone->types.clearAllNewScriptsOnOOM();
}
}
}

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

@ -981,7 +981,7 @@ TypeObjectKey::singleton()
TypeNewScript *
TypeObjectKey::newScript()
{
if (isTypeObject() && asTypeObject()->hasNewScript())
if (isTypeObject() && asTypeObject()->newScript())
return asTypeObject()->newScript();
return nullptr;
}
@ -1575,7 +1575,7 @@ class ConstraintDataFreezeObjectForNewScriptTemplate
bool invalidateOnNewType(Type type) { return false; }
bool invalidateOnNewPropertyState(TypeSet *property) { return false; }
bool invalidateOnNewObjectState(TypeObject *object) {
return !object->hasNewScript() || object->newScript()->templateObject != templateObject;
return !object->newScript() || object->newScript()->templateObject != templateObject;
}
bool constraintHolds(JSContext *cx,
@ -3004,11 +3004,9 @@ TypeObject::markUnknown(ExclusiveContext *cx)
JS_ASSERT(cx->compartment()->activeAnalysis);
JS_ASSERT(!unknownProperties());
if (!(flags() & OBJECT_FLAG_ADDENDUM_CLEARED))
clearAddendum(cx);
InferSpew(ISpewOps, "UnknownProperties: %s", TypeObjectString(this));
clearNewScript(cx);
ObjectStateChange(cx, this, true);
/*
@ -3031,12 +3029,12 @@ TypeObject::markUnknown(ExclusiveContext *cx)
}
void
TypeObject::maybeClearNewScriptAddendumOnOOM()
TypeObject::maybeClearNewScriptOnOOM()
{
if (!isMarked())
return;
if (!addendum || addendum->kind != TypeObjectAddendum::NewScript)
if (!newScript_)
return;
for (unsigned i = 0; i < getPropertyCount(); i++) {
@ -3049,47 +3047,19 @@ TypeObject::maybeClearNewScriptAddendumOnOOM()
// This method is called during GC sweeping, so there is no write barrier
// that needs to be triggered.
js_free(addendum);
addendum.unsafeSet(nullptr);
js_free(newScript_);
newScript_.unsafeSet(nullptr);
}
void
TypeObject::clearAddendum(ExclusiveContext *cx)
TypeObject::clearNewScript(ExclusiveContext *cx)
{
JS_ASSERT(!(flags() & OBJECT_FLAG_ADDENDUM_CLEARED));
addFlags(OBJECT_FLAG_ADDENDUM_CLEARED);
/*
* It is possible for the object to not have a new script or other
* addendum yet, but to have one added in the future. When
* analyzing properties of new scripts we mix in adding
* constraints to trigger clearNewScript with changes to the type
* sets themselves (from breakTypeBarriers). It is possible that
* we could trigger one of these constraints before
* AnalyzeNewScriptProperties has finished, in which case we want
* to make sure that call fails.
*/
if (!addendum)
if (!newScript_)
return;
switch (addendum->kind) {
case TypeObjectAddendum::NewScript:
clearNewScriptAddendum(cx);
break;
}
TypeNewScript *newScript = newScript_;
newScript_ = nullptr;
/* We nullptr out addendum *before* freeing it so the write barrier works. */
TypeObjectAddendum *savedAddendum = addendum;
addendum = nullptr;
js_free(savedAddendum);
markStateChange(cx);
}
void
TypeObject::clearNewScriptAddendum(ExclusiveContext *cx)
{
AutoEnterAnalysis enter(cx);
/*
@ -3113,16 +3083,16 @@ TypeObject::clearNewScriptAddendum(ExclusiveContext *cx)
* If we cleared the new script while in the middle of initializing an
* object, it will still have the new script's shape and reflect the no
* longer correct state of the object once its initialization is completed.
* We can't really detect the possibility of this statically, but the new
* script keeps track of where each property is initialized so we can walk
* the stack and fix up any such objects.
* We can't detect the possibility of this statically while remaining
* robust, but the new script keeps track of where each property is
* initialized so we can walk the stack and fix up any such objects.
*/
if (cx->isJSContext()) {
Vector<uint32_t, 32> pcOffsets(cx);
for (ScriptFrameIter iter(cx->asJSContext()); !iter.done(); ++iter) {
pcOffsets.append(iter.script()->pcToOffset(iter.pc()));
if (!iter.isConstructing() ||
iter.callee() != newScript()->fun ||
iter.callee() != newScript->fun ||
!iter.thisv().isObject() ||
iter.thisv().toObject().hasLazyType() ||
iter.thisv().toObject().type() != this)
@ -3149,7 +3119,7 @@ TypeObject::clearNewScriptAddendum(ExclusiveContext *cx)
// Index in pcOffsets of the frame currently being checked for a SETPROP.
int setpropDepth = callDepth;
for (TypeNewScript::Initializer *init = newScript()->initializerList;; init++) {
for (TypeNewScript::Initializer *init = newScript->initializerList;; init++) {
if (init->kind == TypeNewScript::Initializer::SETPROP) {
if (!pastProperty && pcOffsets[setpropDepth] < init->offset) {
// Have not yet reached this setprop.
@ -3189,6 +3159,9 @@ TypeObject::clearNewScriptAddendum(ExclusiveContext *cx)
// Threads with an ExclusiveContext are not allowed to run scripts.
JS_ASSERT(!cx->perThreadData->activation());
}
js_free(newScript);
markStateChange(cx);
}
void
@ -3254,20 +3227,14 @@ class TypeConstraintClearDefiniteGetterSetter : public TypeConstraint
const char *kind() { return "clearDefiniteGetterSetter"; }
void newPropertyState(JSContext *cx, TypeSet *source)
{
if (!object->hasNewScript())
return;
void newPropertyState(JSContext *cx, TypeSet *source) {
/*
* Clear out the newScript shape and definite property information from
* an object if the source type set could be a setter or could be
* non-writable.
*/
if (!(object->flags() & OBJECT_FLAG_ADDENDUM_CLEARED) &&
(source->nonDataProperty() || source->nonWritableProperty()))
{
object->clearAddendum(cx);
}
if (source->nonDataProperty() || source->nonWritableProperty())
object->clearNewScript(cx);
}
void newType(JSContext *cx, TypeSet *source, Type type) {}
@ -3319,11 +3286,8 @@ class TypeConstraintClearDefiniteSingle : public TypeConstraint
const char *kind() { return "clearDefiniteSingle"; }
void newType(JSContext *cx, TypeSet *source, Type type) {
if (object->flags() & OBJECT_FLAG_ADDENDUM_CLEARED)
return;
if (source->baseFlags() || source->getObjectCount() > 1)
object->clearAddendum(cx);
object->clearNewScript(cx);
}
bool sweep(TypeZone &zone, TypeConstraint **res) {
@ -3386,9 +3350,7 @@ static void
CheckNewScriptProperties(JSContext *cx, TypeObject *type, JSFunction *fun)
{
JS_ASSERT(cx->compartment()->activeAnalysis);
if (type->unknownProperties())
return;
JS_ASSERT(!type->newScript());
/* Strawman object to add properties to and watch for duplicates. */
RootedObject baseobj(cx, NewBuiltinClassInstance(cx, &JSObject::class_, gc::FINALIZE_OBJECT16));
@ -3397,27 +3359,11 @@ CheckNewScriptProperties(JSContext *cx, TypeObject *type, JSFunction *fun)
Vector<TypeNewScript::Initializer> initializerList(cx);
if (!jit::AnalyzeNewScriptProperties(cx, fun, type, baseobj, &initializerList) ||
baseobj->slotSpan() == 0 ||
!!(type->flags() & OBJECT_FLAG_ADDENDUM_CLEARED))
{
if (type->hasNewScript())
type->clearAddendum(cx);
if (!jit::AnalyzeNewScriptProperties(cx, fun, type, baseobj, &initializerList))
return;
}
/*
* If the type already has a new script, we are just regenerating the type
* constraints and don't need to make another TypeNewScript. Make sure that
* the properties added to baseobj match the type's definite properties.
*/
if (type->hasNewScript()) {
if (!type->matchDefiniteProperties(baseobj))
type->clearAddendum(cx);
if (baseobj->slotSpan() == 0 || type->unknownProperties())
return;
}
JS_ASSERT(!type->hasNewScript());
JS_ASSERT(!(type->flags() & OBJECT_FLAG_ADDENDUM_CLEARED));
gc::AllocKind kind = gc::GetGCObjectKind(baseobj->slotSpan());
@ -3449,7 +3395,7 @@ CheckNewScriptProperties(JSContext *cx, TypeObject *type, JSFunction *fun)
new (newScript) TypeNewScript();
type->setAddendum(newScript);
type->setNewScript(newScript);
newScript->fun = fun;
newScript->templateObject = baseobj;
@ -3868,7 +3814,7 @@ ExclusiveContext::getNewType(const Class *clasp, TaggedProto proto, JSFunction *
TypeObject *type = p->object;
JS_ASSERT(type->clasp() == clasp);
JS_ASSERT(type->proto() == proto);
JS_ASSERT_IF(type->hasNewScript(), type->newScript()->fun == fun);
JS_ASSERT_IF(type->newScript(), type->newScript()->fun == fun);
return type;
}
@ -4079,8 +4025,8 @@ inline void
TypeObject::sweep(FreeOp *fop, bool *oom)
{
if (!isMarked()) {
if (addendum)
fop->free_(addendum);
if (newScript_)
fop->free_(newScript_);
return;
}
@ -4337,7 +4283,7 @@ TypeCompartment::addSizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf,
size_t
TypeObject::sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const
{
return mallocSizeOf(addendum);
return mallocSizeOf(newScript_);
}
TypeZone::TypeZone(Zone *zone)
@ -4452,13 +4398,13 @@ TypeZone::sweep(FreeOp *fop, bool releaseTypes, bool *oom)
}
void
TypeZone::clearAllNewScriptAddendumsOnOOM()
TypeZone::clearAllNewScriptsOnOOM()
{
for (gc::ZoneCellIterUnderGC iter(zone(), gc::FINALIZE_TYPE_OBJECT);
!iter.done(); iter.next())
{
TypeObject *object = iter.get<TypeObject>();
object->maybeClearNewScriptAddendumOnOOM();
object->maybeClearNewScriptOnOOM();
}
}
@ -4521,16 +4467,8 @@ TypeScript::printTypes(JSContext *cx, HandleScript script) const
#endif /* DEBUG */
void
TypeObject::setAddendum(TypeObjectAddendum *addendum)
TypeObject::setNewScript(TypeNewScript *newScript)
{
this->addendum = addendum;
JS_ASSERT(!newScript_);
newScript_ = newScript;
}
TypeObjectAddendum::TypeObjectAddendum(Kind kind)
: kind(kind)
{}
TypeNewScript::TypeNewScript()
: TypeObjectAddendum(NewScript)
{}

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

@ -436,24 +436,21 @@ enum MOZ_ENUM_TYPE(uint32_t) {
/* Whether this type object is associated with some allocation site. */
OBJECT_FLAG_FROM_ALLOCATION_SITE = 0x1,
/* If set, addendum information should not be installed on this object. */
OBJECT_FLAG_ADDENDUM_CLEARED = 0x2,
/*
* If set, the object's prototype might be in the nursery and can't be
* used during Ion compilation (which may be occurring off thread).
*/
OBJECT_FLAG_NURSERY_PROTO = 0x4,
OBJECT_FLAG_NURSERY_PROTO = 0x2,
/*
* Whether we have ensured all type sets in the compartment contain
* ANYOBJECT instead of this object.
*/
OBJECT_FLAG_SETS_MARKED_UNKNOWN = 0x8,
OBJECT_FLAG_SETS_MARKED_UNKNOWN = 0x4,
/* Mask/shift for the number of properties in propertySet */
OBJECT_FLAG_PROPERTY_COUNT_MASK = 0xfff0,
OBJECT_FLAG_PROPERTY_COUNT_SHIFT = 4,
OBJECT_FLAG_PROPERTY_COUNT_MASK = 0xfff8,
OBJECT_FLAG_PROPERTY_COUNT_SHIFT = 3,
OBJECT_FLAG_PROPERTY_COUNT_LIMIT =
OBJECT_FLAG_PROPERTY_COUNT_MASK >> OBJECT_FLAG_PROPERTY_COUNT_SHIFT,
@ -824,32 +821,6 @@ struct Property
static jsid getKey(Property *p) { return p->id; }
};
struct TypeNewScript;
struct TypeObjectAddendum
{
enum Kind {
NewScript
};
explicit TypeObjectAddendum(Kind kind);
const Kind kind;
bool isNewScript() {
return kind == NewScript;
}
TypeNewScript *asNewScript() {
JS_ASSERT(isNewScript());
return (TypeNewScript*) this;
}
static inline void writeBarrierPre(TypeObjectAddendum *type);
static void writeBarrierPost(TypeObjectAddendum *newScript, void *addr) {}
};
/*
* Information attached to a TypeObject if it is always constructed using 'new'
* on a particular script. This is used to manage state related to the definite
@ -860,10 +831,8 @@ struct TypeObjectAddendum
* remove the definite property information and repair the JS stack if the
* constraints are violated.
*/
struct TypeNewScript : public TypeObjectAddendum
struct TypeNewScript
{
TypeNewScript();
HeapPtrFunction fun;
/*
@ -899,6 +868,7 @@ struct TypeNewScript : public TypeObjectAddendum
Initializer *initializerList;
static inline void writeBarrierPre(TypeNewScript *newScript);
static void writeBarrierPost(TypeNewScript *newScript, void *addr) {}
};
/*
@ -982,16 +952,12 @@ struct TypeObject : gc::BarrieredCell<TypeObject>
TypeObjectFlags flags_;
/*
* This field allows various special classes of objects to attach
* additional information to a type object:
*
* - `TypeNewScript`: If addendum is a `TypeNewScript`, it
* indicates that objects of this type have always been
* constructed using 'new' on the specified script, which adds
* some number of properties to the object in a definite order
* before the object escapes.
* If specified, holds information about properties which are definitely
* added to objects of this type after being constructed by a particular
* script.
*/
HeapPtrTypeObjectAddendum addendum;
HeapPtrTypeNewScript newScript_;
public:
TypeObjectFlags flags() const {
@ -1006,15 +972,11 @@ struct TypeObject : gc::BarrieredCell<TypeObject>
flags_ &= ~flags;
}
bool hasNewScript() const {
return addendum && addendum->isNewScript();
}
TypeNewScript *newScript() {
return addendum->asNewScript();
return newScript_;
}
void setAddendum(TypeObjectAddendum *addendum);
void setNewScript(TypeNewScript *newScript);
private:
/*
@ -1094,7 +1056,7 @@ struct TypeObject : gc::BarrieredCell<TypeObject>
// this bit reliably.
if (unknownProperties())
return false;
return (flags() & OBJECT_FLAG_FROM_ALLOCATION_SITE) || hasNewScript();
return (flags() & OBJECT_FLAG_FROM_ALLOCATION_SITE) || newScript();
}
void setShouldPreTenure(ExclusiveContext *cx) {
@ -1127,9 +1089,8 @@ struct TypeObject : gc::BarrieredCell<TypeObject>
void markStateChange(ExclusiveContext *cx);
void setFlags(ExclusiveContext *cx, TypeObjectFlags flags);
void markUnknown(ExclusiveContext *cx);
void maybeClearNewScriptAddendumOnOOM();
void clearAddendum(ExclusiveContext *cx);
void clearNewScriptAddendum(ExclusiveContext *cx);
void maybeClearNewScriptOnOOM();
void clearNewScript(ExclusiveContext *cx);
bool isPropertyNonData(jsid id);
bool isPropertyNonWritable(jsid id);
@ -1604,7 +1565,7 @@ struct TypeZone
JS::Zone *zone() const { return zone_; }
void sweep(FreeOp *fop, bool releaseTypes, bool *oom);
void clearAllNewScriptAddendumsOnOOM();
void clearAllNewScriptsOnOOM();
/* Mark a script as needing recompilation once inference has finished. */
void addPendingRecompile(JSContext *cx, const RecompileInfo &info);

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

@ -1276,20 +1276,6 @@ TypeObject::getProperty(unsigned i)
return propertySet[i];
}
inline void
TypeObjectAddendum::writeBarrierPre(TypeObjectAddendum *type)
{
#ifdef JSGC_INCREMENTAL
if (!type)
return;
switch (type->kind) {
case NewScript:
return TypeNewScript::writeBarrierPre(type->asNewScript());
}
#endif
}
inline void
TypeNewScript::writeBarrierPre(TypeNewScript *newScript)
{

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

@ -1686,7 +1686,7 @@ static inline JSObject *
CreateThisForFunctionWithType(JSContext *cx, HandleTypeObject type, JSObject *parent,
NewObjectKind newKind)
{
if (type->hasNewScript()) {
if (type->newScript()) {
/*
* Make an object with the type's associated finalize kind and shape,
* which reflects any properties that will definitely be added to the
@ -2905,7 +2905,7 @@ JSObject::growSlots(ThreadSafeContext *cx, HandleObject obj, uint32_t oldCount,
* type to give these objects a larger number of fixed slots when future
* objects are constructed.
*/
if (!obj->hasLazyType() && !oldCount && obj->type()->hasNewScript()) {
if (!obj->hasLazyType() && !oldCount && obj->type()->newScript()) {
JSObject *oldTemplate = obj->type()->newScript()->templateObject;
gc::AllocKind kind = gc::GetGCObjectFixedSlotsKind(oldTemplate->numFixedSlots());
uint32_t newScriptSlots = gc::GetGCKindSlots(kind);