[INFER] Objects with same shape have same type, objects with same type have same prototype, bug 619271.
This commit is contained in:
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user