Track whether default 'new' types need unknown properties on the prototype, bug 700501.

This commit is contained in:
Brian Hackett 2011-11-08 18:34:11 -08:00
parent d2fe69d826
commit 708b16abe9
9 changed files with 72 additions and 14 deletions

View File

@ -0,0 +1,13 @@
Function.prototype.__proto__["p"] = 3
c = [].__proto__
c[5] = 3
Namespace.prototype.__proto__[4] = function() {}
gc()
Function("\
{\
function f(d) {}\
for each(let z in[0]) {\
f(z)\
}\
}\
")()

View File

@ -3172,8 +3172,8 @@ JS_NewObject(JSContext *cx, JSClass *jsclasp, JSObject *proto, JSObject *parent)
JS_ASSERT(clasp != &FunctionClass);
JS_ASSERT(!(clasp->flags & JSCLASS_IS_GLOBAL));
if (proto)
proto->getNewType(cx, NULL, /* markUnknown = */ true);
if (proto && !proto->setNewTypeUnknown(cx))
return NULL;
JSObject *obj = NewObjectWithClassProto(cx, clasp, proto, parent);
if (obj) {

View File

@ -3662,7 +3662,8 @@ js_InitArrayClass(JSContext *cx, JSObject *obj)
return NULL;
/* The default 'new' object for Array.prototype has unknown properties. */
arrayProto->getNewType(cx, NULL, /* markUnknown = */ true);
if (!arrayProto->setNewTypeUnknown(cx))
return NULL;
if (!LinkConstructorAndPrototype(cx, ctor, arrayProto))
return NULL;

View File

@ -5726,8 +5726,29 @@ JSObject::hasNewType(TypeObject *type)
}
#endif /* DEBUG */
bool
JSObject::setNewTypeUnknown(JSContext *cx)
{
if (!setFlag(cx, js::BaseShape::NEW_TYPE_UNKNOWN))
return false;
/*
* If the object already has a new type, mark that type as unknown. It will
* not have the SETS_MARKED_UNKNOWN bit set, so may require a type set
* crawl if prototypes of the object change dynamically in the future.
*/
JSCompartment::NewTypeObjectSet &table = compartment()->newTypeObjects;
if (table.initialized()) {
JSCompartment::NewTypeObjectSet::Ptr p = table.lookup(this);
if (p)
MarkTypeObjectUnknownProperties(cx, *p);
}
return true;
}
TypeObject *
JSObject::getNewType(JSContext *cx, JSFunction *fun, bool markUnknown)
JSObject::getNewType(JSContext *cx, JSFunction *fun)
{
if (!setDelegate(cx))
return NULL;
@ -5754,12 +5775,12 @@ JSObject::getNewType(JSContext *cx, JSFunction *fun, bool markUnknown)
*/
if (type->newScript && type->newScript->fun != fun)
type->clearNewScript(cx);
if (markUnknown && cx->typeInferenceEnabled() && !type->unknownProperties())
type->markUnknown(cx);
return type;
}
bool markUnknown = lastProperty()->hasObjectFlag(BaseShape::NEW_TYPE_UNKNOWN);
TypeObject *type = cx->compartment->types.newTypeObject(cx, NULL,
JSProto_Object, this, markUnknown);
if (!type)

View File

@ -4997,8 +4997,11 @@ SetProto(JSContext *cx, JSObject *obj, JSObject *proto, bool checkForCycles)
return true;
}
if (proto && !proto->setNewTypeUnknown(cx))
return false;
TypeObject *type = proto
? proto->getNewType(cx, NULL, /* markUnknown = */ true)
? proto->getNewType(cx, NULL)
: cx->compartment->getEmptyType(cx);
if (!type)
return false;

View File

@ -817,15 +817,27 @@ struct JSObject : js::gc::Cell
inline void setType(js::types::TypeObject *newType);
js::types::TypeObject *getNewType(JSContext *cx, JSFunction *fun = NULL,
bool markUnknown = false);
js::types::TypeObject *getNewType(JSContext *cx, JSFunction *fun = NULL);
#ifdef DEBUG
bool hasNewType(js::types::TypeObject *newType);
#endif
/*
* Mark an object that has been iterated over and is a singleton. We need
* to recover this information in the object's type information after it
* is purged on GC.
*/
inline bool setIteratedSingleton(JSContext *cx);
/*
* Mark an object as requiring its default 'new' type to have unknown
* properties. This is set for a few builtins like Object.prototype and
* Array.prototype; several places in the VM require that the default
* type for these objects have unknown contents.
*/
bool setNewTypeUnknown(JSContext *cx);
/* Set a new prototype for an object with a singleton type. */
bool splicePrototype(JSContext *cx, JSObject *proto);

View File

@ -1428,8 +1428,8 @@ js::NewProxyObject(JSContext *cx, ProxyHandler *handler, const Value &priv, JSOb
* their properties and so that we don't need to walk the compartment if
* their prototype changes later.
*/
if (proto)
proto->getNewType(cx, NULL, /* markUnknown = */ true);
if (proto && !proto->setNewTypeUnknown(cx))
return NULL;
JSObject *obj = NewObjectWithGivenProto(cx, clasp, proto, parent);
if (!obj)

View File

@ -368,8 +368,9 @@ class BaseShape : public js::gc::Cell
VAROBJ = 0x200,
WATCHED = 0x400,
ITERATED_SINGLETON = 0x800,
NEW_TYPE_UNKNOWN = 0x1000,
OBJECT_FLAG_MASK = 0xff0
OBJECT_FLAG_MASK = 0x1ff0
};
private:

View File

@ -103,7 +103,11 @@ GlobalObject::initFunctionAndObjectClasses(JSContext *cx)
JSObject *objectProto = NewObjectWithGivenProto(cx, &ObjectClass, NULL, this);
if (!objectProto || !objectProto->setSingletonType(cx))
return NULL;
types::TypeObject *objectType = objectProto->getNewType(cx, NULL, /* markUnknown = */ true);
if (!objectProto->setNewTypeUnknown(cx))
return NULL;
types::TypeObject *objectType = objectProto->getNewType(cx);
if (!objectType || !objectType->getEmptyShape(cx, &ObjectClass, gc::FINALIZE_OBJECT0))
return NULL;
@ -138,7 +142,10 @@ GlobalObject::initFunctionAndObjectClasses(JSContext *cx)
if (!proto->setSingletonType(cx))
return NULL;
types::TypeObject *functionType = proto->getNewType(cx, NULL, /* markUnknown = */ true);
if (!proto->setNewTypeUnknown(cx))
return NULL;
types::TypeObject *functionType = proto->getNewType(cx);
if (!functionType || !functionType->getEmptyShape(cx, &FunctionClass, gc::FINALIZE_OBJECT0))
return NULL;
}