[INFER] Objects with same shape have same type, objects with same type have same prototype, bug 619271.

This commit is contained in:
Brian Hackett
2010-12-18 20:44:51 -08:00
parent d2505f9622
commit 09a5a525ff
51 changed files with 1202 additions and 1784 deletions

View File

@@ -1055,7 +1055,7 @@ JSObject::makeDenseArraySlow(JSContext *cx)
{
JS_ASSERT(isDenseArray());
cx->markTypeArrayNotPacked(getTypeObject(), true);
cx->markTypeArrayNotPacked(getType(), true);
setDenseArrayNotPacked(cx);
/*
@@ -1065,9 +1065,8 @@ JSObject::makeDenseArraySlow(JSContext *cx)
JSObjectMap *oldMap = map;
/* Create a native scope. */
JSObject *arrayProto = getProto();
js::gc::FinalizeKind kind = js::gc::FinalizeKind(arena()->header()->thingKind);
if (!InitScopeForObject(cx, this, &js_SlowArrayClass, arrayProto, kind))
if (!InitScopeForObject(cx, this, &js_SlowArrayClass, getType(), kind))
return false;
uint32 initlen = getDenseArrayInitializedLength();
@@ -1110,7 +1109,7 @@ JSObject::makeDenseArraySlow(JSContext *cx)
/* initialized length is not used anymore. */
initializedLength = 0;
JS_ASSERT(emptyShapes == NULL);
JS_ASSERT(newType == NULL);
/*
* Dense arrays with different numbers of slots but the same number of fixed
@@ -2063,7 +2062,7 @@ array_push_slowly(JSContext *cx, JSObject *obj, uintN argc, Value *argv, Value *
/* watch for length overflowing to a double, and report to type inference. */
if (!rval->isInt32()) {
cx->markTypeCallerOverflow();
cx->addTypeProperty(obj->getTypeObject(), "length", *rval);
cx->addTypeProperty(obj->getType(), "length", *rval);
}
return js_SetLengthProperty(cx, obj, newlength);
@@ -2152,7 +2151,7 @@ array_push(JSContext *cx, uintN argc, Value *vp)
return JS_FALSE;
if (cx->isTypeCallerMonitored())
cx->markTypeObjectUnknownProperties(obj->getTypeObject());
cx->markTypeObjectUnknownProperties(obj->getType());
if (argc != 1 || !obj->isDenseArray())
return array_push_slowly(cx, obj, argc, vp + 2, vp);
@@ -2280,7 +2279,7 @@ array_unshift(JSContext *cx, uintN argc, Value *vp)
return JS_FALSE;
if (cx->isTypeCallerMonitored())
cx->markTypeObjectUnknownProperties(obj->getTypeObject());
cx->markTypeObjectUnknownProperties(obj->getType());
newlen = length;
if (argc > 0) {
@@ -2343,11 +2342,11 @@ array_splice(JSContext *cx, uintN argc, Value *vp)
JSObject *obj = ComputeThisFromVp(cx, vp);
/* Get the type object for the returned array. */
TypeObject *type = obj ? obj->getTypeObject() : NULL;
#ifdef JS_TYPE_INFERENCE
if (!type || !type->isArray(cx)) {
/* Get the type of the result object. */
TypeObject *type;
if (obj && obj->isArray()) {
type = obj->getType();
} else {
/*
* Make a new type object for the return value. This is an unexpected
* result of the call so mark it at the callsite.
@@ -2356,7 +2355,6 @@ array_splice(JSContext *cx, uintN argc, Value *vp)
cx->markTypeObjectUnknownProperties(type);
cx->markTypeCallerUnexpected((jstype) type);
}
#endif
if (cx->isTypeCallerMonitored())
cx->markTypeObjectUnknownProperties(type);
@@ -2367,9 +2365,10 @@ array_splice(JSContext *cx, uintN argc, Value *vp)
* arguments. We think this is best because it eliminates the need
* for callers to do an extra test to handle the empty splice case.
*/
JSObject *obj2 = js_NewArrayObject(cx, 0, NULL, type);
JSObject *obj2 = js_NewArrayObject(cx, 0, NULL);
if (!obj2)
return JS_FALSE;
obj2->setType(type);
vp->setObject(*obj2);
/* Nothing to do if no args. Otherwise get length. */
@@ -2527,12 +2526,6 @@ array_concat(JSContext *cx, uintN argc, Value *vp)
/* Treat our |this| object as the first argument; see ECMA 15.4.4.4. */
Value *p = JS_ARGV(cx, vp) - 1;
/* Get the type object to use for the result. */
TypeObject *ntype = cx->getTypeCallerInitObject(true);
if (cx->isTypeCallerMonitored())
cx->markTypeObjectUnknownProperties(ntype);
/* Create a new Array object and root it using *vp. */
JSObject *aobj = ComputeThisFromVp(cx, vp);
JSObject *nobj;
@@ -2540,7 +2533,7 @@ array_concat(JSContext *cx, uintN argc, Value *vp)
if (aobj->isDenseArray()) {
length = aobj->getArrayLength();
jsuint initlen = aobj->getDenseArrayInitializedLength();
nobj = js_NewArrayObject(cx, initlen, aobj->getDenseArrayElements(), ntype);
nobj = js_NewArrayObject(cx, initlen, aobj->getDenseArrayElements());
if (!nobj)
return JS_FALSE;
nobj->setArrayLength(cx, length);
@@ -2550,13 +2543,18 @@ array_concat(JSContext *cx, uintN argc, Value *vp)
argc--;
p++;
} else {
nobj = js_NewArrayObject(cx, 0, NULL, ntype);
nobj = js_NewArrayObject(cx, 0, NULL);
if (!nobj)
return JS_FALSE;
vp->setObject(*nobj);
length = 0;
}
/* Get the type object to use for the result. */
TypeObject *ntype = cx->getTypeCallerInitObject(true);
if (cx->isTypeCallerMonitored())
cx->markTypeObjectUnknownProperties(ntype);
AutoValueRooter tvr(cx);
/* Loop over [0, argc] to concat args into nobj, expanding all Arrays. */
@@ -2658,10 +2656,10 @@ array_slice(JSContext *cx, uintN argc, Value *vp)
begin = end;
/* Get the type object for the returned array. */
TypeObject *type = obj->getTypeObject();
#ifdef JS_TYPE_INFERENCE
if (!type->isArray(cx)) {
TypeObject *type;
if (obj->isArray()) {
type = obj->getType();
} else {
/*
* Make a new type object for the return value. This is an unexpected
* result of the call so mark it at the callsite.
@@ -2670,24 +2668,25 @@ array_slice(JSContext *cx, uintN argc, Value *vp)
cx->markTypeObjectUnknownProperties(type);
cx->markTypeCallerUnexpected((jstype) type);
}
#endif
if (cx->isTypeCallerMonitored())
cx->markTypeObjectUnknownProperties(type);
if (obj->isDenseArray() && end <= obj->getDenseArrayCapacity() &&
!js_PrototypeHasIndexedProperties(cx, obj)) {
nobj = js_NewArrayObject(cx, end - begin, obj->getDenseArrayElements() + begin, type);
nobj = js_NewArrayObject(cx, end - begin, obj->getDenseArrayElements() + begin);
if (!nobj)
return JS_FALSE;
nobj->setType(type);
vp->setObject(*nobj);
return JS_TRUE;
}
/* Create a new Array object and root it using *vp. */
nobj = js_NewArrayObject(cx, 0, NULL, type);
nobj = js_NewArrayObject(cx, 0, NULL);
if (!nobj)
return JS_FALSE;
nobj->setType(type);
vp->setObject(*nobj);
AutoValueRooter tvr(cx);
@@ -2865,10 +2864,11 @@ array_extra(JSContext *cx, ArrayExtraMode mode, uintN argc, Value *vp)
case MAP:
case FILTER:
newlen = (mode == MAP) ? length : 0;
newtype = cx->getTypeCallerInitObject(true);
newarr = js_NewArrayObject(cx, newlen, NULL, newtype);
newarr = js_NewArrayObject(cx, newlen, NULL);
if (!newarr)
return JS_FALSE;
newtype = cx->getTypeCallerInitObject(true);
newarr->setType(newtype);
vp->setObject(*newarr);
break;
case SOME:
@@ -3046,12 +3046,12 @@ static void array_TypeSort(JSContext *cx, JSTypeFunction *jsfun, JSTypeCallsite
TypeSet *funTypes = site->argumentTypes[0];
// make a callsite for the calls to the sorting function this will perform.
jstype globalType = (jstype) cx->getGlobalTypeObject();
/* Make a callsite for the calls to the sorting function this will perform. */
jstype globalType = (jstype) cx->globalTypeObject();
TypeCallsite *sortSite = ArenaNew<TypeCallsite>(site->pool(), site->code, false, 2);
sortSite->thisType = globalType;
// both arguments to the argument function are array elements.
/* Both arguments to the argument function are array elements. */
TypeSet *argTypes = sortSite->argumentTypes[0] = sortSite->argumentTypes[1] =
TypeSet::make(cx, site->pool(), "ArraySort");
site->thisTypes->addGetProperty(cx, site->code, argTypes, JSID_VOID);
@@ -3066,7 +3066,7 @@ static void array_TypeInsert(JSContext *cx, JSTypeFunction *jsfun, JSTypeCallsit
TypeCallsite *site = Valueify(jssite);
if (site->returnTypes) {
// the return type is an integer (array length).
/* The return type is an integer (array length). */
site->returnTypes->addType(cx, TYPE_INT32);
}
@@ -3100,11 +3100,11 @@ static void array_TypeSplice(JSContext *cx, JSTypeFunction *jsfun, JSTypeCallsit
site->forceThisTypes(cx);
if (site->returnTypes) {
// treat the returned array the same as the 'this' array.
/* Treat the returned array the same as the 'this' array. */
site->thisTypes->addSubset(cx, site->pool(), site->returnTypes);
}
// all arguments beyond the first two are new array elements.
/* All arguments beyond the first two are new array elements. */
for (size_t ind = 2; ind < site->argumentCount; ind++)
site->thisTypes->addSetProperty(cx, site->code, site->argumentTypes[ind], JSID_VOID);
#endif
@@ -3133,7 +3133,7 @@ static void array_TypeConcat(JSContext *cx, JSTypeFunction *jsfun, JSTypeCallsit
#endif
}
// general purpose handler for all higher order array builtins.
/* Handler for all higher order array builtins. */
static void array_TypeExtra(JSContext *cx, JSTypeFunction *jsfun, JSTypeCallsite *jssite,
ArrayExtraMode mode)
{
@@ -3147,8 +3147,10 @@ static void array_TypeExtra(JSContext *cx, JSTypeFunction *jsfun, JSTypeCallsite
return;
TypeSet *funTypes = site->argumentTypes[0];
// get a type set of all possible element types of this array, and the
// singleton type of array indexes.
/*
* Get a type set of all possible element types of this array, and the singleton
* type of array indexes.
*/
TypeSet *elemTypes = TypeSet::make(cx, pool, "array_extra");
TypeSet *intTypes = TypeSet::make(cx, pool, "array_extra_int");
intTypes->addType(cx, TYPE_INT32);
@@ -3158,14 +3160,14 @@ static void array_TypeExtra(JSContext *cx, JSTypeFunction *jsfun, JSTypeCallsite
site->thisTypes->addGetProperty(cx, code, elemTypes, JSID_VOID);
// make the call site to use for the higher order function.
/* Make the call site to use for the higher order function. */
TypeCallsite *extraSite = ArenaNew<TypeCallsite>(pool, code, false, REDUCE_MODE(mode) ? 4 : 3);
// figure out the 'this' type passed to the higher order function.
/* Figure out the 'this' type passed to the higher order function. */
if (site->argumentCount > 1 && !REDUCE_MODE(mode))
extraSite->thisTypes = site->argumentTypes[1];
else
extraSite->thisType = (jstype) cx->getGlobalTypeObject();
extraSite->thisType = (jstype) cx->globalTypeObject();
switch (mode) {
@@ -3174,12 +3176,14 @@ static void array_TypeExtra(JSContext *cx, JSTypeFunction *jsfun, JSTypeCallsite
break;
case REDUCE: {
// the return value of the function is also the return value of the reduce call.
/* The return value of the function is also the return value of the reduce call. */
extraSite->returnTypes = site->returnTypes;
// the first argument of the function is either its own return value,
// the second argument of reduce, or the array element type (if there
// is no second argument of reduce).
/*
* The first argument of the function is either its own return value, the second
* argument of reduce, or the array element type (if there is no second argument
* of reduce).
*/
extraSite->argumentTypes[0] = TypeSet::make(cx, pool, "ArrayReduce");
site->returnTypes->addSubset(cx, pool, extraSite->argumentTypes[0]);
@@ -3194,8 +3198,7 @@ static void array_TypeExtra(JSContext *cx, JSTypeFunction *jsfun, JSTypeCallsite
}
case MAP: {
// makes a new array whose element type is the return value of the
// argument function.
/* Makes a new array whose element type is the return value of the argument function. */
TypeObject *object = site->getInitObject(cx, true);
extraSite->returnTypes = object->getProperty(cx, JSID_VOID, true);
@@ -3204,10 +3207,11 @@ static void array_TypeExtra(JSContext *cx, JSTypeFunction *jsfun, JSTypeCallsite
}
case FILTER: {
// makes a new array, whose element type is the same as the element
// type of the 'this' array. TODO: could use the same type information
// as the 'this' array, but might run into problems when we're able
// to handle receiver types other than arrays.
/*
* Makes a new array, whose element type is the same as the element type of the
* 'this' array. TODO: could use the same type information as the 'this' array,
* but might run into problems when we're able to handle receiver types other than arrays.
*/
TypeObject *object = site->getInitObject(cx, true);
elemTypes->addSubset(cx, pool, object->getProperty(cx, JSID_VOID, true));
@@ -3223,8 +3227,10 @@ static void array_TypeExtra(JSContext *cx, JSTypeFunction *jsfun, JSTypeCallsite
JS_NOT_REACHED("Unexpected ArrayExtraMode");
}
// fill in the remaining argument types. regardless of mode, the last three
// arguments are the element value, element index, and array itself.
/*
* Fill in the remaining argument types. regardless of mode, the last three
* arguments are the element value, element index, and array itself.
*/
size_t argind = (mode == REDUCE) ? 1 : 0;
extraSite->argumentTypes[argind++] = elemTypes;
extraSite->argumentTypes[argind++] = intTypes;
@@ -3316,10 +3322,10 @@ static JSFunctionSpec array_static_methods[] = {
/* The count here is a guess for the final capacity. */
static inline JSObject *
NewDenseArrayObject(JSContext *cx, TypeObject *type, jsuint count)
NewDenseArrayObject(JSContext *cx, jsuint count)
{
gc::FinalizeKind kind = GuessObjectGCKind(count, true);
return NewNonFunction<WithProto::Class>(cx, &js_ArrayClass, NULL, NULL, type, kind);
return NewNonFunction<WithProto::Class>(cx, &js_ArrayClass, NULL, NULL, kind);
}
JSBool
@@ -3353,9 +3359,10 @@ js_Array(JSContext *cx, uintN argc, Value *vp)
cx->markTypeObjectUnknownProperties(type);
/* Whether called with 'new' or not, use a new Array object. */
JSObject *obj = NewDenseArrayObject(cx, type, length);
JSObject *obj = NewDenseArrayObject(cx, length);
if (!obj)
return JS_FALSE;
obj->setType(type);
vp->setObject(*obj);
return InitArrayObject(cx, obj, length, vector);
@@ -3369,16 +3376,17 @@ js_NewEmptyArray(JSContext* cx, JSObject* proto, int32 len)
JS_ASSERT(proto->isArray());
TypeObject *type = proto->getNewType(cx);
if (!type)
return NULL;
gc::FinalizeKind kind = GuessObjectGCKind(len, true);
JSObject* obj = js_NewGCObject(cx, kind);
if (!obj)
return NULL;
// TODO: pass type object to use in from tracer.
TypeObject *type = cx->getFixedTypeObject(TYPE_OBJECT_UNKNOWN_ARRAY);
/* Initialize all fields, calling init before setting obj->map. */
obj->init(cx, &js_ArrayClass, proto, proto->getParent(), type, (void*) len, true);
obj->init(cx, &js_ArrayClass, type, proto->getParent(), (void*) len, true);
obj->setSharedNonNativeMap();
return obj;
}
@@ -3390,6 +3398,7 @@ JS_DEFINE_CALLINFO_3(extern, OBJECT, js_NewEmptyArray, CONTEXT, OBJECT, INT32, 0
JSObject* JS_FASTCALL
js_NewPreallocatedArray(JSContext* cx, JSObject* proto, int32 len)
{
/* :FIXME: new Arrays do not have the right type when created on trace. */
JSObject *obj = js_NewEmptyArray(cx, proto, len);
if (!obj)
return NULL;
@@ -3439,21 +3448,19 @@ js_InitArrayClass(JSContext *cx, JSObject *obj)
if (!proto)
return NULL;
/*
* Assert that js_InitClass used the correct (slow array, not dense array)
* class for proto's emptyShape class.
*/
JS_ASSERT(proto->emptyShapes && proto->emptyShapes[0]->getClass() == proto->getClass());
JS_AddTypeProperty(cx, proto, "length", INT_TO_JSVAL(0));
proto->setArrayLength(cx, 0);
/* The default 'new' object for Array.prototype has unknown properties. */
cx->markTypeObjectUnknownProperties(proto->getNewType(cx));
return proto;
}
JSObject *
js_NewArrayObject(JSContext *cx, jsuint length, const Value *vector, TypeObject *type)
js_NewArrayObject(JSContext *cx, jsuint length, const Value *vector)
{
JSObject *obj = NewDenseArrayObject(cx, type, length);
JSObject *obj = NewDenseArrayObject(cx, length);
if (!obj)
return NULL;
@@ -3467,13 +3474,11 @@ js_NewArrayObject(JSContext *cx, jsuint length, const Value *vector, TypeObject
}
JSObject *
js_NewSlowArrayObject(JSContext *cx, TypeObject *type)
js_NewSlowArrayObject(JSContext *cx)
{
JSObject *obj = NewNonFunction<WithProto::Class>(cx, &js_SlowArrayClass, NULL, NULL, type);
JSObject *obj = NewNonFunction<WithProto::Class>(cx, &js_SlowArrayClass, NULL, NULL);
if (obj)
obj->setArrayLength(cx, 0);
cx->markTypeArrayNotPacked(type, true);
return obj;
}
@@ -3624,9 +3629,10 @@ js_CloneDensePrimitiveArray(JSContext *cx, JSObject *obj, JSObject **clone)
vector.append(val);
}
*clone = js_NewArrayObject(cx, initlen, vector.begin(), obj->getTypeObject());
*clone = js_NewArrayObject(cx, initlen, vector.begin());
if (!*clone)
return JS_FALSE;
(*clone)->setType(obj->getType());
(*clone)->setArrayLength(cx, length);
return JS_TRUE;