[INFER] Cleanup type info tracking object classes, track which type objects are definitely typed arrays, bug 663485.

This commit is contained in:
Brian Hackett 2011-06-15 11:26:12 -07:00
Родитель ebe43e7ca0
Коммит 1c6c11df0b
17 изменённых файлов: 148 добавлений и 103 удалений

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

@ -2983,7 +2983,7 @@ array_extra(JSContext *cx, ArrayExtraMode mode, uintN argc, Value *vp)
newarr = NewDenseAllocatedArray(cx, newlen);
if (!newarr)
return JS_FALSE;
newtype = GetTypeCallerInitObject(cx, true);
newtype = GetTypeCallerInitObject(cx, JSProto_Array);
if (!newtype)
return JS_FALSE;
newarr->setType(newtype);
@ -3202,7 +3202,7 @@ js_Array(JSContext *cx, uintN argc, Value *vp)
{
JSObject *obj;
TypeObject *type = GetTypeCallerInitObject(cx, true);
TypeObject *type = GetTypeCallerInitObject(cx, JSProto_Array);
if (!type)
return JS_FALSE;

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

@ -103,7 +103,7 @@ JS_NewObjectWithUniqueType(JSContext *cx, JSClass *clasp, JSObject *proto, JSObj
return NULL;
types::TypeObject *type = cx->compartment->types.newTypeObject(cx, NULL, "Unique", "",
false, false, proto);
JSProto_Object, proto);
if (!type)
return NULL;
if (obj->hasSpecialEquality())

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

@ -1803,7 +1803,7 @@ ResolveInterpretedFunctionPrototype(JSContext *cx, JSObject *obj)
TypeObject *protoType = cx->compartment->types.newTypeObject(cx, NULL,
obj->getType()->name(),
"prototype",
false, false, objProto);
JSProto_Object, objProto);
if (!protoType || !proto->setTypeAndUniqueShape(cx, protoType))
return NULL;
@ -2802,7 +2802,7 @@ js_NewFunction(JSContext *cx, JSObject *funobj, Native native, uintN nargs,
name = "Unnamed";
#endif
TypeObject *type = cx->compartment->types.newTypeObject(cx, NULL, name, "",
true, false,
JSProto_Function,
funobj->getProto());
if (!type || !funobj->setTypeAndUniqueShape(cx, type))
return NULL;
@ -2907,7 +2907,7 @@ js_CloneFunctionObject(JSContext *cx, JSFunction *fun, JSObject *parent,
js_CallNewScriptHook(cx, cfun->script(), cfun);
} else {
TypeObject *type = cx->compartment->types.newTypeObject(cx, NULL, "ClonedFunction", "",
true, false,
JSProto_Function,
clone->getProto());
if (!type || !clone->setTypeAndUniqueShape(cx, type))
return NULL;

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

@ -1842,7 +1842,7 @@ TypeCompartment::init(JSContext *cx)
TypeObject *
TypeCompartment::newTypeObject(JSContext *cx, JSScript *script,
const char *name, const char *postfix,
bool isFunction, bool isArray, JSObject *proto)
JSProtoKey key, JSObject *proto)
{
#ifdef DEBUG
if (*postfix) {
@ -1867,7 +1867,7 @@ TypeCompartment::newTypeObject(JSContext *cx, JSScript *script,
jsid id = JSID_VOID;
#endif
TypeObject *object = cx->new_<TypeObject>(id, proto, isFunction);
TypeObject *object = cx->new_<TypeObject>(id, proto, key == JSProto_Function);
if (!object)
return NULL;
@ -1877,8 +1877,8 @@ TypeCompartment::newTypeObject(JSContext *cx, JSScript *script,
if (!cx->typeInferenceEnabled())
object->flags = OBJECT_FLAG_UNKNOWN_MASK;
else if (!isArray)
object->flags = OBJECT_FLAG_NON_DENSE_ARRAY | OBJECT_FLAG_NON_PACKED_ARRAY;
else
object->setFlagsFromKey(cx, key);
if (proto) {
/* Thread onto the prototype's list of instance type objects. */
@ -1894,27 +1894,23 @@ TypeCompartment::newTypeObject(JSContext *cx, JSScript *script,
TypeObject *
TypeCompartment::newInitializerTypeObject(JSContext *cx, JSScript *script,
uint32 offset, bool isArray)
uint32 offset, JSProtoKey key)
{
char *name = NULL;
#ifdef DEBUG
name = (char *) alloca(40);
JS_snprintf(name, 40, "#%lu:%lu:%s", script->id(), offset, isArray ? "Array" : "Object");
JS_snprintf(name, 40, "#%lu:%lu", script->id(), offset);
#endif
JSObject *proto;
JSProtoKey key = isArray ? JSProto_Array : JSProto_Object;
if (!js_GetClassPrototype(cx, script->global(), key, &proto, NULL))
return NULL;
TypeObject *res = newTypeObject(cx, script, name, "", false, isArray, proto);
TypeObject *res = newTypeObject(cx, script, name, "", key, proto);
if (!res)
return NULL;
if (isArray)
res->initializerArray = true;
else
res->initializerObject = true;
res->initializerKey = key;
res->initializerOffset = offset;
jsbytecode *pc = script->code + offset;
@ -2358,7 +2354,7 @@ TypeCompartment::fixArrayType(JSContext *cx, JSObject *obj)
JS_snprintf(name, 20, "TableArray:%u", ++count);
#endif
TypeObject *objType = newTypeObject(cx, NULL, name, "", false, true, obj->getProto());
TypeObject *objType = newTypeObject(cx, NULL, name, "", JSProto_Array, obj->getProto());
if (!objType) {
cx->compartment->types.setPendingNukeTypes(cx);
return;
@ -2492,7 +2488,7 @@ TypeCompartment::fixObjectType(JSContext *cx, JSObject *obj)
JS_snprintf(name, 20, "TableObject:%u", ++count);
#endif
TypeObject *objType = newTypeObject(cx, NULL, name, "", false, false, obj->getProto());
TypeObject *objType = newTypeObject(cx, NULL, name, "", JSProto_Object, obj->getProto());
if (!objType) {
cx->compartment->types.setPendingNukeTypes(cx);
return;
@ -2990,6 +2986,8 @@ TypeObject::print(JSContext *cx)
printf(" packed");
if (!hasAnyFlags(OBJECT_FLAG_NON_DENSE_ARRAY))
printf(" dense");
if (!hasAnyFlags(OBJECT_FLAG_NON_TYPED_ARRAY))
printf(" typed");
if (hasAnyFlags(OBJECT_FLAG_UNINLINEABLE))
printf(" uninlineable");
if (hasAnyFlags(OBJECT_FLAG_SPECIAL_EQUALITY))
@ -3058,7 +3056,7 @@ GetInitializerType(JSContext *cx, JSScript *script, jsbytecode *pc)
JS_ASSERT(op == JSOP_NEWARRAY || op == JSOP_NEWOBJECT || op == JSOP_NEWINIT);
bool isArray = (op == JSOP_NEWARRAY || (op == JSOP_NEWINIT && pc[1] == JSProto_Array));
return script->types.initObject(cx, pc, isArray);
return script->types.initObject(cx, pc, isArray ? JSProto_Array : JSProto_Object);
}
inline void
@ -5063,7 +5061,7 @@ JSScript::typeSetFunction(JSContext *cx, JSFunction *fun)
#endif
TypeObject *type = cx->compartment->types.newTypeObject(cx, this, name, "",
true, false, fun->getProto());
JSProto_Function, fun->getProto());
if (!type)
return false;
@ -5142,7 +5140,7 @@ JSObject::makeNewType(JSContext *cx, JSScript *newScript)
JS_ASSERT(!newType);
TypeObject *type = cx->compartment->types.newTypeObject(cx, NULL, getType()->name(), "new",
false, false, this);
JSProto_Object, this);
if (!type)
return;

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

@ -273,17 +273,20 @@ enum {
/* Whether any objects this represents are not packed arrays. */
OBJECT_FLAG_NON_PACKED_ARRAY = 1 << 1,
/* Whether any objects this represents are not typed arrays. */
OBJECT_FLAG_NON_TYPED_ARRAY = 1 << 2,
/* Whether any represented script has had arguments objects created. */
OBJECT_FLAG_CREATED_ARGUMENTS = 1 << 2,
OBJECT_FLAG_CREATED_ARGUMENTS = 1 << 3,
/* Whether any represented script is considered uninlineable. */
OBJECT_FLAG_UNINLINEABLE = 1 << 3,
OBJECT_FLAG_UNINLINEABLE = 1 << 4,
/* Whether any objects have an equality hook. */
OBJECT_FLAG_SPECIAL_EQUALITY = 1 << 4,
OBJECT_FLAG_SPECIAL_EQUALITY = 1 << 5,
/* Whether any objects have been iterated over. */
OBJECT_FLAG_ITERATED = 1 << 5
OBJECT_FLAG_ITERATED = 1 << 6
};
typedef uint32 TypeObjectFlags;
@ -642,11 +645,10 @@ struct TypeObject
TypeNewScript *newScript;
/*
* Whether this is an Object or Array keyed to an offset in the script containing
* this in its objects list.
* Whether this is an object (plain Object, Array, or typed array) keyed to
* an offset in the script containing this in its objects list.
*/
bool initializerObject;
bool initializerArray;
JSProtoKey initializerKey;
uint32 initializerOffset;
/*
@ -742,6 +744,9 @@ struct TypeObject
inline unsigned getPropertyCount();
inline Property *getProperty(unsigned i);
/* Set flags on this object which are implied by the specified key. */
inline void setFlagsFromKey(JSContext *cx, JSProtoKey key);
/* Helpers */
bool addProperty(JSContext *cx, jsid id, Property **pprop);
@ -801,9 +806,6 @@ struct TypeCallsite
inline TypeCallsite(JSContext *cx, JSScript *script, jsbytecode *pc,
bool isNew, unsigned argumentCount);
/* Get the new object at this callsite. */
inline TypeObject* getInitObject(JSContext *cx, bool isArray);
};
/* Persistent type information for a script, retained across GCs. */
@ -851,7 +853,7 @@ struct TypeScript
inline TypeObject *standardType(JSContext *cx, JSProtoKey key);
/* Get a type object for an allocation site in this script. */
inline TypeObject *initObject(JSContext *cx, const jsbytecode *pc, bool isArray);
inline TypeObject *initObject(JSContext *cx, const jsbytecode *pc, JSProtoKey key);
/*
* Monitor a bytecode pushing a value which is not accounted for by the
@ -998,14 +1000,19 @@ struct TypeCompartment
/* Prints results of this compartment if spew is enabled, checks for warnings. */
void print(JSContext *cx, JSCompartment *compartment);
/* Make a function or non-function object associated with an optional script. */
/*
* Make a function or non-function object associated with an optional
* script. The 'key' parameter here may be an array, typed array, function
* or JSProto_Object to indicate a type whose class is unknown (not just
* js_ObjectClass).
*/
TypeObject *newTypeObject(JSContext *cx, JSScript *script,
const char *base, const char *postfix,
bool isFunction, bool isArray, JSObject *proto);
JSProtoKey key, JSObject *proto);
/* Make an initializer object. */
TypeObject *newInitializerTypeObject(JSContext *cx, JSScript *script,
uint32 offset, bool isArray);
uint32 offset, JSProtoKey key);
void nukeTypes(JSContext *cx);
void processPendingRecompiles(JSContext *cx);

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

@ -239,15 +239,15 @@ GetTypeNewObject(JSContext *cx, JSProtoKey key)
/* Get a type object for the immediate allocation site within a native. */
inline TypeObject *
GetTypeCallerInitObject(JSContext *cx, bool isArray)
GetTypeCallerInitObject(JSContext *cx, JSProtoKey key)
{
if (cx->typeInferenceEnabled()) {
jsbytecode *pc;
JSScript *script = cx->stack.currentScript(&pc);
if (script && script->compartment == cx->compartment)
return script->types.initObject(cx, pc, isArray);
return script->types.initObject(cx, pc, key);
}
return GetTypeNewObject(cx, isArray ? JSProto_Array : JSProto_Object);
return GetTypeNewObject(cx, key);
}
/*
@ -497,30 +497,28 @@ TypeScript::standardType(JSContext *cx, JSProtoKey key)
}
inline TypeObject *
TypeScript::initObject(JSContext *cx, const jsbytecode *pc, bool isArray)
TypeScript::initObject(JSContext *cx, const jsbytecode *pc, JSProtoKey key)
{
if (!cx->typeInferenceEnabled() || !script()->hasGlobal())
return GetTypeNewObject(cx, isArray ? JSProto_Array : JSProto_Object);
return GetTypeNewObject(cx, key);
uint32 offset = pc - script()->code;
TypeObject *prev = NULL, *obj = typeObjects;
while (obj) {
if (isArray ? obj->initializerArray : obj->initializerObject) {
if (obj->initializerOffset == offset) {
/* Move this to the head of the objects list, maintain LRU order. */
if (prev) {
prev->next = obj->next;
obj->next = typeObjects;
typeObjects = obj;
}
return obj;
if (obj->initializerKey == key && obj->initializerOffset == offset) {
/* Move this to the head of the objects list, maintain LRU order. */
if (prev) {
prev->next = obj->next;
obj->next = typeObjects;
typeObjects = obj;
}
return obj;
}
prev = obj;
obj = obj->next;
}
return cx->compartment->types.newInitializerTypeObject(cx, script(), offset, isArray);
return cx->compartment->types.newInitializerTypeObject(cx, script(), offset, key);
}
inline void
@ -1102,19 +1100,36 @@ TypeCallsite::TypeCallsite(JSContext *cx, JSScript *script, jsbytecode *pc,
argumentTypes = ArenaArray<TypeSet*>(cx->compartment->pool, argumentCount);
}
inline TypeObject *
TypeCallsite::getInitObject(JSContext *cx, bool isArray)
{
TypeObject *type = script->types.initObject(cx, pc, isArray);
if (!type)
cx->compartment->types.setPendingNukeTypes(cx);
return type;
}
/////////////////////////////////////////////////////////////////////
// TypeObject
/////////////////////////////////////////////////////////////////////
inline const char *
TypeObject::name()
{
#ifdef DEBUG
return TypeIdString(name_);
#else
return NULL;
#endif
}
inline TypeObject::TypeObject(jsid name, JSObject *proto, bool isFunction)
: proto(proto), emptyShapes(NULL),
flags(0), isFunction(isFunction), isFunctionNative(false),
marked(false), newScriptCleared(false),
newScript(NULL), initializerKey(JSProto_Null), initializerOffset(0),
contribution(0), propertySet(NULL), propertyCount(0),
instanceList(NULL), instanceNext(NULL), next(NULL),
singleton(NULL), functionScript(NULL)
{
#ifdef DEBUG
this->name_ = name;
#endif
InferSpew(ISpewOps, "newObject: %s", this->name());
}
inline TypeSet *
TypeObject::getProperty(JSContext *cx, jsid id, bool assign)
{
@ -1153,34 +1168,44 @@ TypeObject::getProperty(unsigned i)
return propertySet[i];
}
/////////////////////////////////////////////////////////////////////
// TypeObject
/////////////////////////////////////////////////////////////////////
inline const char *
TypeObject::name()
inline void
TypeObject::setFlagsFromKey(JSContext *cx, JSProtoKey key)
{
#ifdef DEBUG
return TypeIdString(name_);
#else
return NULL;
#endif
}
TypeObjectFlags flags = 0;
inline TypeObject::TypeObject(jsid name, JSObject *proto, bool isFunction)
: proto(proto), emptyShapes(NULL),
flags(0), isFunction(isFunction), isFunctionNative(false),
marked(false), newScriptCleared(false),
newScript(NULL), initializerObject(false), initializerArray(false), initializerOffset(0),
contribution(0), propertySet(NULL), propertyCount(0),
instanceList(NULL), instanceNext(NULL), next(NULL),
singleton(NULL), functionScript(NULL)
{
#ifdef DEBUG
this->name_ = name;
#endif
switch (key) {
case JSProto_Function:
JS_ASSERT(isFunction);
/* FALLTHROUGH */
InferSpew(ISpewOps, "newObject: %s", this->name());
case JSProto_Object:
flags = OBJECT_FLAG_NON_DENSE_ARRAY
| OBJECT_FLAG_NON_PACKED_ARRAY
| OBJECT_FLAG_NON_TYPED_ARRAY;
break;
case JSProto_Array:
flags = OBJECT_FLAG_NON_TYPED_ARRAY;
break;
default:
/* :XXX: abstract */
JS_ASSERT(key == JSProto_Int8Array ||
key == JSProto_Uint8Array ||
key == JSProto_Int16Array ||
key == JSProto_Uint16Array ||
key == JSProto_Int32Array ||
key == JSProto_Uint32Array ||
key == JSProto_Float32Array ||
key == JSProto_Float64Array ||
key == JSProto_Uint8ClampedArray);
flags = OBJECT_FLAG_NON_DENSE_ARRAY
| OBJECT_FLAG_NON_PACKED_ARRAY;
break;
}
if (!hasAllFlags(flags))
setFlags(cx, flags);
}
inline void

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

@ -5889,7 +5889,7 @@ BEGIN_CASE(JSOP_NEWINIT)
if (!obj)
goto error;
TypeObject *type = script->types.initObject(cx, regs.pc, i == JSProto_Array);
TypeObject *type = script->types.initObject(cx, regs.pc, (JSProtoKey) i);
if (!type)
goto error;
if (i == JSProto_Array) {
@ -5911,7 +5911,7 @@ BEGIN_CASE(JSOP_NEWARRAY)
if (!obj)
goto error;
TypeObject *type = script->types.initObject(cx, regs.pc, true);
TypeObject *type = script->types.initObject(cx, regs.pc, JSProto_Array);
if (!type)
goto error;
obj->setType(type);
@ -5926,7 +5926,7 @@ BEGIN_CASE(JSOP_NEWOBJECT)
JSObject *baseobj;
LOAD_OBJECT(0, baseobj);
TypeObject *type = script->types.initObject(cx, regs.pc, false);
TypeObject *type = script->types.initObject(cx, regs.pc, JSProto_Object);
if (!type)
goto error;

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

@ -875,7 +875,7 @@ js_InitMathClass(JSContext *cx, JSObject *obj)
return NULL;
types::TypeObject *type = cx->compartment->types.newTypeObject(cx, NULL, js_Math_str, "",
false, false,
JSProto_Object,
Math->getProto());
if (!type || !Math->setTypeAndUniqueShape(cx, type))
return NULL;

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

@ -2872,7 +2872,7 @@ js_Object(JSContext *cx, uintN argc, Value *vp)
obj = NewBuiltinClassInstance(cx, &js_ObjectClass, kind);
if (!obj)
return JS_FALSE;
TypeObject *type = GetTypeCallerInitObject(cx, false);
TypeObject *type = GetTypeCallerInitObject(cx, JSProto_Object);
if (!type || !obj->setTypeAndEmptyShape(cx, type))
return JS_FALSE;
}
@ -3011,7 +3011,7 @@ js_CreateThisForFunction(JSContext *cx, JSObject *callee, bool newType)
types::AutoEnterTypeInference enter(cx);
types::TypeObject *type = cx->compartment->types.newTypeObject(cx, NULL, name, "",
false, false,
JSProto_Object,
obj->getProto());
/*
@ -4080,10 +4080,15 @@ DefineConstructorAndPrototype(JSContext *cx, JSObject *obj, JSProtoKey key, JSAt
if (!proto)
return NULL;
/*
* Specialize the key for inference, which only wants to see function,
* object, array and typed array keys.
*/
JSProtoKey typeKey = (clasp == &js_FunctionClass) ? JSProto_Function : JSProto_Object;
TypeObject *protoType = cx->compartment->types.newTypeObject(cx, NULL,
clasp->name, "prototype",
clasp == &js_FunctionClass, false,
proto->getProto());
typeKey, proto->getProto());
if (!protoType || !proto->setTypeAndUniqueShape(cx, protoType))
return NULL;
protoType->singleton = proto;

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

@ -934,7 +934,7 @@ js_InitJSONClass(JSContext *cx, JSObject *obj)
return NULL;
TypeObject *type = cx->compartment->types.newTypeObject(cx, NULL, js_JSON_str, "",
false, false,
JSProto_Object,
JSON->getProto());
if (!type || !JSON->setTypeAndUniqueShape(cx, type))
return NULL;

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

@ -1462,7 +1462,7 @@ js_InitProxyClass(JSContext *cx, JSObject *obj)
types::TypeObject *type = cx->compartment->types.newTypeObject(cx, NULL,
js_ProxyClass.name, "",
false, false,
JSProto_Object,
module->getProto());
if (!type || !module->setTypeAndUniqueShape(cx, type))
return NULL;

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

@ -3309,7 +3309,7 @@ js_InitReflectClass(JSContext *cx, JSObject *obj)
types::TypeObject *type = cx->compartment->types.newTypeObject(cx, NULL,
js_ReflectClass.name, "",
false, false,
JSProto_Object,
Reflect->getProto());
if (!type || !Reflect->setTypeAndUniqueShape(cx, type))
return NULL;

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

@ -829,7 +829,7 @@ js_InitRegExpClass(JSContext *cx, JSObject *global)
types::TypeObject *protoType = cx->compartment->types.newTypeObject(cx, NULL,
"RegExp", "prototype",
false, false,
JSProto_Object,
proto->getProto());
if (!protoType || !proto->setTypeAndUniqueShape(cx, protoType))
return NULL;

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

@ -2725,7 +2725,7 @@ str_split(JSContext *cx, uintN argc, Value *vp)
if (!str)
return false;
TypeObject *type = GetTypeCallerInitObject(cx, true);
TypeObject *type = GetTypeCallerInitObject(cx, JSProto_Array);
if (!type)
return false;
AddTypePropertyId(cx, type, JSID_VOID, types::TYPE_STRING);
@ -3480,7 +3480,7 @@ js_InitStringClass(JSContext *cx, JSObject *global)
types::TypeObject *protoType = cx->compartment->types.newTypeObject(cx, NULL,
"String", "prototype",
false, false,
JSProto_Object,
proto->getProto());
if (!protoType || !proto->setTypeAndUniqueShape(cx, protoType))
return NULL;

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

@ -736,6 +736,16 @@ class TypedArrayTemplate
if (!obj)
return NULL;
/*
* Specialize the type of the object on the current scripted location,
* and mark the type as definitely a typed array.
*/
JSProtoKey key = JSCLASS_CACHED_PROTO_KEY(slowClass());
types::TypeObject *type = types::GetTypeCallerInitObject(cx, key);
if (!type)
return NULL;
obj->setType(type);
ThisTypeArray *tarray = cx->new_<ThisTypeArray>(bufobj, byteOffset, len);
if (!tarray)
return NULL;

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

@ -6373,7 +6373,7 @@ mjit::Compiler::jsop_newinit()
/* Don't bake in types for non-compileAndGo scripts. */
types::TypeObject *type = NULL;
if (globalObj) {
type = script->types.initObject(cx, PC, isArray);
type = script->types.initObject(cx, PC, isArray ? JSProto_Array : JSProto_Object);
if (!type)
return false;
}

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

@ -115,7 +115,7 @@ GlobalObject::create(JSContext *cx, Class *clasp)
return NULL;
types::TypeObject *type = cx->compartment->types.newTypeObject(cx, NULL, "Global", "",
false, false, NULL);
JSProto_Object, NULL);
if (!type || !obj->setTypeAndUniqueShape(cx, type))
return NULL;
if (clasp->ext.equality)