[INFER] Remove isTypeCallerMonitored and rejoin from native calls triggering recompilation, bug 638977.

This commit is contained in:
Brian Hackett
2011-03-05 17:13:40 -08:00
parent 0f358c511a
commit 9b95d078c6
6 changed files with 76 additions and 60 deletions

View File

@@ -1402,14 +1402,39 @@ array_toLocaleString(JSContext *cx, uintN argc, Value *vp)
return array_toString_sub(cx, obj, JS_TRUE, NULL, vp);
}
static inline bool
InitArrayTypes(JSContext *cx, TypeObject *type, const Value *vector, unsigned count)
{
if (cx->typeInferenceEnabled() && !type->unknownProperties) {
AutoEnterTypeInference enter(cx);
TypeSet *types = type->getProperty(cx, JSID_VOID, true);
if (!types)
return JS_FALSE;
for (unsigned i = 0; i < count; i++) {
if (vector[i].isMagic(JS_ARRAY_HOLE))
continue;
jstype valtype = GetValueType(cx, vector[i]);
types->addType(cx, valtype);
}
return cx->compartment->types.checkPendingRecompiles(cx);
}
return true;
}
static JSBool
InitArrayElements(JSContext *cx, JSObject *obj, jsuint start, jsuint count, Value *vector)
InitArrayElements(JSContext *cx, JSObject *obj, jsuint start, jsuint count, Value *vector, bool updateTypes)
{
JS_ASSERT(count < MAXINDEX);
if (count == 0)
return JS_TRUE;
if (updateTypes && !InitArrayTypes(cx, obj->getType(), vector, count))
return JS_FALSE;
/*
* Optimize for dense arrays so long as adding the given set of elements
* wouldn't otherwise make the array slow.
@@ -1479,6 +1504,9 @@ InitArrayObject(JSContext *cx, JSObject *obj, jsuint length, const Value *vector
if (!vector || !length)
return true;
if (!InitArrayTypes(cx, obj->getType(), vector, length))
return false;
/* Avoid ensureDenseArrayElements to skip sparse array checks there. */
if (!obj->ensureSlots(cx, length))
return false;
@@ -2041,7 +2069,7 @@ js::array_sort(JSContext *cx, uintN argc, Value *vp)
* InitArrayElements easier.
*/
tvr.changeLength(newlen);
if (!InitArrayElements(cx, obj, 0, newlen, vec))
if (!InitArrayElements(cx, obj, 0, newlen, vec, false))
return false;
}
@@ -2073,7 +2101,7 @@ array_push_slowly(JSContext *cx, JSObject *obj, uintN argc, Value *argv, Value *
if (!js_GetLengthProperty(cx, obj, &length))
return JS_FALSE;
if (!InitArrayElements(cx, obj, length, argc, argv))
if (!InitArrayElements(cx, obj, length, argc, argv, true))
return JS_FALSE;
/* Per ECMA-262, return the new array length. */
@@ -2100,6 +2128,9 @@ array_push1_dense(JSContext* cx, JSObject* obj, const Value &v, Value *rval)
break;
}
if (cx->typeInferenceEnabled() && !cx->addTypePropertyId(obj->getType(), JSID_VOID, v))
return false;
obj->setDenseArrayLength(length + 1);
obj->setDenseArrayElement(length, v);
rval->setNumber(obj->getArrayLength());
@@ -2176,9 +2207,6 @@ array_push(JSContext *cx, uintN argc, Value *vp)
if (!obj)
return false;
if (cx->isTypeCallerMonitored() && !cx->markTypeObjectUnknownProperties(obj->getType()))
return false;
/* Insist on one argument and obj of the expected class. */
if (argc != 1 || !obj->isDenseArray())
return array_push_slowly(cx, obj, argc, vp + 2, vp);
@@ -2312,9 +2340,6 @@ array_unshift(JSContext *cx, uintN argc, Value *vp)
if (!js_GetLengthProperty(cx, obj, &length))
return JS_FALSE;
if (cx->isTypeCallerMonitored() && !cx->markTypeObjectUnknownProperties(obj->getType()))
return false;
newlen = length;
if (argc > 0) {
/* Slide up the array to make room for argc at the bottom. */
@@ -2355,7 +2380,7 @@ array_unshift(JSContext *cx, uintN argc, Value *vp)
}
/* Copy from argv to the bottom of the array. */
if (!InitArrayElements(cx, obj, 0, argc, argv))
if (!InitArrayElements(cx, obj, 0, argc, argv, true))
return JS_FALSE;
newlen += argc;
@@ -2402,9 +2427,6 @@ array_splice(JSContext *cx, uintN argc, Value *vp)
return false;
}
if (cx->isTypeCallerMonitored() && !cx->markTypeObjectUnknownProperties(type))
return false;
/* Create a new array value to return. */
JSObject *obj2 = NewDenseEmptyArray(cx);
if (!obj2)
@@ -2470,6 +2492,9 @@ array_splice(JSContext *cx, uintN argc, Value *vp)
return JS_FALSE;
}
if (!cx->addTypePropertyId(obj2->getType(), JSID_VOID, tvr.value()))
return JS_FALSE;
/* Copy tvr.value() to the new array unless it's a hole. */
if (!hole && !SetArrayElement(cx, obj2, last - begin, tvr.value()))
return JS_FALSE;
@@ -2554,7 +2579,7 @@ array_splice(JSContext *cx, uintN argc, Value *vp)
* Copy from argv into the hole to complete the splice, and update length in
* case we deleted elements from the end.
*/
return InitArrayElements(cx, obj, begin, argc, argv) &&
return InitArrayElements(cx, obj, begin, argc, argv, true) &&
js_SetLengthProperty(cx, obj, length);
}
@@ -2571,8 +2596,6 @@ array_concat(JSContext *cx, uintN argc, Value *vp)
TypeObject *ntype = cx->getTypeCallerInitObject(true);
if (!ntype)
return false;
if (cx->isTypeCallerMonitored() && !cx->markTypeObjectUnknownProperties(ntype))
return false;
/* Create a new Array object and root it using *vp. */
JSObject *aobj = ToObject(cx, &vp[1]);
@@ -2583,13 +2606,18 @@ array_concat(JSContext *cx, uintN argc, Value *vp)
jsuint length;
if (aobj->isDenseArray()) {
length = aobj->getArrayLength();
Value *vector = aobj->getDenseArrayElements();
jsuint initlen = aobj->getDenseArrayInitializedLength();
nobj = NewDenseCopiedArray(cx, initlen, aobj->getDenseArrayElements());
nobj = NewDenseCopiedArray(cx, initlen, vector);
if (!nobj)
return JS_FALSE;
nobj->setType(ntype);
if (!nobj->setArrayLength(cx, length))
return JS_FALSE;
if (!InitArrayTypes(cx, ntype, vector, length))
return JS_FALSE;
if (!aobj->isPackedDenseArray() && !nobj->setDenseArrayNotPacked(cx))
return JS_FALSE;
vp->setObject(*nobj);
if (argc == 0)
return JS_TRUE;
@@ -2604,9 +2632,6 @@ array_concat(JSContext *cx, uintN argc, Value *vp)
length = 0;
}
if (aobj->isDenseArray() && !aobj->isPackedDenseArray() && !nobj->setDenseArrayNotPacked(cx))
return false;
AutoValueRooter tvr(cx);
/* Loop over [0, argc] to concat args into nobj, expanding all Arrays. */
@@ -2631,6 +2656,9 @@ array_concat(JSContext *cx, uintN argc, Value *vp)
return false;
}
if (!hole && !cx->addTypePropertyId(ntype, JSID_VOID, tvr.value()))
return false;
/*
* Per ECMA 262, 15.4.4.4, step 9, ignore nonexistent
* properties.
@@ -2645,10 +2673,6 @@ array_concat(JSContext *cx, uintN argc, Value *vp)
}
}
/*
* The type handler for Array.concat only handles array arguments.
* Inform type inference of any non-array arguments passed in.
*/
if (!cx->addTypePropertyId(ntype, JSID_VOID, v))
return false;
@@ -2726,9 +2750,6 @@ array_slice(JSContext *cx, uintN argc, Value *vp)
return false;
}
if (cx->isTypeCallerMonitored() && !cx->markTypeObjectUnknownProperties(type))
return false;
if (obj->isDenseArray() && end <= obj->getDenseArrayCapacity() &&
!js_PrototypeHasIndexedProperties(cx, obj)) {
nobj = NewDenseCopiedArray(cx, end - begin, obj->getDenseArrayElements() + begin);
@@ -2754,6 +2775,8 @@ array_slice(JSContext *cx, uintN argc, Value *vp)
!GetElement(cx, obj, slot, &hole, tvr.addr())) {
return JS_FALSE;
}
if (!hole && !cx->addTypePropertyId(nobj->getType(), JSID_VOID, tvr.value()))
return false;
if (!hole && !SetArrayElement(cx, nobj, slot - begin, tvr.value()))
return JS_FALSE;
}
@@ -2958,15 +2981,6 @@ array_extra(JSContext *cx, ArrayExtraMode mode, uintN argc, Value *vp)
Value thisv = (argc > 1 && !REDUCE_MODE(mode)) ? argv[1] : UndefinedValue();
/*
* If the callsite is being monitored for type inference, and we are modifying
* the output array, monitor any reads on the array in the future.
*/
if (cx->isTypeCallerMonitored() && (mode == MAP || mode == FILTER) &&
!cx->markTypeObjectUnknownProperties(newtype)) {
return false;
}
/*
* For all but REDUCE, we call with 3 args (value, index, array). REDUCE
* requires 4 args (accum, value, index, array).
@@ -3367,12 +3381,12 @@ js_Array(JSContext *cx, uintN argc, Value *vp)
if (argc == 0) {
obj = NewDenseEmptyArray(cx);
} else if (argc > 1) {
if (!InitArrayTypes(cx, type, vp + 2, argc))
return false;
obj = NewDenseCopiedArray(cx, argc, vp + 2);
} else if (!vp[2].isNumber()) {
/* Unexpected case for type inference. */
if (!cx->addTypeProperty(type, NULL, vp[2]))
return false;
obj = NewDenseCopiedArray(cx, 1, vp + 2);
} else {
jsuint length;
@@ -3385,8 +3399,6 @@ js_Array(JSContext *cx, uintN argc, Value *vp)
return JS_FALSE;
obj->setType(type);
if (cx->isTypeCallerMonitored() && !cx->markTypeObjectUnknownProperties(type))
return false;
/* If the length calculation overflowed, make sure that is marked for the new type. */
if (obj->getArrayLength() > INT32_MAX && !obj->setArrayLength(cx, obj->getArrayLength()))