Bug 605192 - JM: make f.apply(x, obj) fast, part 1 (r=waldo)

This commit is contained in:
Luke Wagner
2010-10-20 23:52:55 -07:00
parent e561db181e
commit 6513a85492
6 changed files with 95 additions and 78 deletions

View File

@@ -346,8 +346,7 @@ IndexToId(JSContext* cx, JSObject* obj, jsdouble index, JSBool* hole, jsid* idp,
* properly rooted and can be used as GC-protected storage for temporaries.
*/
static JSBool
GetArrayElement(JSContext *cx, JSObject *obj, jsdouble index, JSBool *hole,
Value *vp)
GetElement(JSContext *cx, JSObject *obj, jsdouble index, JSBool *hole, Value *vp)
{
JS_ASSERT(index >= 0);
if (obj->isDenseArray() && index < obj->getDenseArrayCapacity() &&
@@ -392,6 +391,58 @@ GetArrayElement(JSContext *cx, JSObject *obj, jsdouble index, JSBool *hole,
return JS_TRUE;
}
struct STATIC_SKIP_INFERENCE CopyNonHoleArgs
{
CopyNonHoleArgs(JSObject *aobj, Value *dst) : aobj(aobj), dst(dst) {}
JSObject *aobj;
Value *dst;
void operator()(uintN argi, Value *src) {
if (aobj->getArgsElement(argi).isMagic(JS_ARGS_HOLE))
dst->setUndefined();
else
*dst = *src;
++dst;
}
};
namespace js {
bool
GetElements(JSContext *cx, JSObject *aobj, jsuint length, Value *vp)
{
if (aobj->isDenseArray() && length <= aobj->getDenseArrayCapacity()) {
Value *srcbeg = aobj->getDenseArrayElements();
Value *srcend = srcbeg + length;
for (Value *dst = vp, *src = srcbeg; src < srcend; ++dst, ++src)
*dst = src->isMagic(JS_ARRAY_HOLE) ? UndefinedValue() : *src;
} else if (aobj->isArguments() && !aobj->isArgsLengthOverridden()) {
/*
* Two cases, two loops: note how in the case of an active stack frame
* backing aobj, even though we copy from fp->argv, we still must check
* aobj->getArgsElement(i) for a hole, to handle a delete on the
* corresponding arguments element. See args_delProperty.
*/
if (JSStackFrame *fp = (JSStackFrame *) aobj->getPrivate()) {
JS_ASSERT(fp->numActualArgs() <= JS_ARGS_LENGTH_MAX);
fp->forEachCanonicalActualArg(CopyNonHoleArgs(aobj, vp));
} else {
Value *srcbeg = aobj->getArgsElements();
Value *srcend = srcbeg + length;
for (Value *dst = vp, *src = srcbeg; src < srcend; ++dst, ++src)
*dst = src->isMagic(JS_ARGS_HOLE) ? UndefinedValue() : *src;
}
} else {
for (uintN i = 0; i < length; i++) {
if (!aobj->getProperty(cx, INT_TO_JSID(jsint(i)), &vp[i]))
return JS_FALSE;
}
}
return true;
}
}
/*
* Set the value of the property at the given index to v assuming v is rooted.
*/
@@ -1124,7 +1175,7 @@ array_toSource(JSContext *cx, uintN argc, Value *vp)
/* Use vp to locally root each element value. */
JSBool hole;
if (!JS_CHECK_OPERATION_LIMIT(cx) ||
!GetArrayElement(cx, obj, index, &hole, vp)) {
!GetElement(cx, obj, index, &hole, vp)) {
goto out;
}
@@ -1228,7 +1279,7 @@ array_toString_sub(JSContext *cx, JSObject *obj, JSBool locale,
/* Use rval to locally root each element value. */
JSBool hole;
if (!JS_CHECK_OPERATION_LIMIT(cx) ||
!GetArrayElement(cx, obj, index, &hole, rval)) {
!GetElement(cx, obj, index, &hole, rval)) {
goto out;
}
@@ -1456,8 +1507,8 @@ array_reverse(JSContext *cx, uintN argc, Value *vp)
for (jsuint i = 0, half = len / 2; i < half; i++) {
JSBool hole, hole2;
if (!JS_CHECK_OPERATION_LIMIT(cx) ||
!GetArrayElement(cx, obj, i, &hole, tvr.addr()) ||
!GetArrayElement(cx, obj, len - i - 1, &hole2, vp) ||
!GetElement(cx, obj, i, &hole, tvr.addr()) ||
!GetElement(cx, obj, len - i - 1, &hole2, vp) ||
!SetOrDeleteArrayElement(cx, obj, len - i - 1, hole, tvr.value()) ||
!SetOrDeleteArrayElement(cx, obj, i, hole2, *vp)) {
return false;
@@ -1777,7 +1828,7 @@ js::array_sort(JSContext *cx, uintN argc, Value *vp)
JSBool hole;
vec[newlen].setNull();
tvr.changeLength(newlen + 1);
if (!GetArrayElement(cx, obj, i, &hole, &vec[newlen]))
if (!GetElement(cx, obj, i, &hole, &vec[newlen]))
return false;
if (hole)
@@ -2038,7 +2089,7 @@ array_pop_slowly(JSContext *cx, JSObject* obj, Value *vp)
index--;
/* Get the to-be-deleted property's value into vp. */
if (!GetArrayElement(cx, obj, index, &hole, vp))
if (!GetElement(cx, obj, index, &hole, vp))
return JS_FALSE;
if (!hole && !DeleteArrayElement(cx, obj, index, true))
return JS_FALSE;
@@ -2058,7 +2109,7 @@ array_pop_dense(JSContext *cx, JSObject* obj, Value *vp)
return JS_TRUE;
}
index--;
if (!GetArrayElement(cx, obj, index, &hole, vp))
if (!GetElement(cx, obj, index, &hole, vp))
return JS_FALSE;
if (!hole && !DeleteArrayElement(cx, obj, index, true))
return JS_FALSE;
@@ -2105,14 +2156,14 @@ array_shift(JSContext *cx, uintN argc, Value *vp)
}
/* Get the to-be-deleted property's value into vp ASAP. */
if (!GetArrayElement(cx, obj, 0, &hole, vp))
if (!GetElement(cx, obj, 0, &hole, vp))
return JS_FALSE;
/* Slide down the array above the first element. */
AutoValueRooter tvr(cx);
for (i = 0; i != length; i++) {
if (!JS_CHECK_OPERATION_LIMIT(cx) ||
!GetArrayElement(cx, obj, i + 1, &hole, tvr.addr()) ||
!GetElement(cx, obj, i + 1, &hole, tvr.addr()) ||
!SetOrDeleteArrayElement(cx, obj, i, hole, tvr.value())) {
return JS_FALSE;
}
@@ -2157,7 +2208,7 @@ array_unshift(JSContext *cx, uintN argc, Value *vp)
do {
--last, --upperIndex;
if (!JS_CHECK_OPERATION_LIMIT(cx) ||
!GetArrayElement(cx, obj, last, &hole, tvr.addr()) ||
!GetElement(cx, obj, last, &hole, tvr.addr()) ||
!SetOrDeleteArrayElement(cx, obj, upperIndex, hole, tvr.value())) {
return JS_FALSE;
}
@@ -2252,7 +2303,7 @@ array_splice(JSContext *cx, uintN argc, Value *vp)
} else {
for (last = begin; last < end; last++) {
if (!JS_CHECK_OPERATION_LIMIT(cx) ||
!GetArrayElement(cx, obj, last, &hole, tvr.addr())) {
!GetElement(cx, obj, last, &hole, tvr.addr())) {
return JS_FALSE;
}
@@ -2288,7 +2339,7 @@ array_splice(JSContext *cx, uintN argc, Value *vp)
/* (uint) end could be 0, so we can't use a vanilla >= test. */
while (last-- > end) {
if (!JS_CHECK_OPERATION_LIMIT(cx) ||
!GetArrayElement(cx, obj, last, &hole, tvr.addr()) ||
!GetElement(cx, obj, last, &hole, tvr.addr()) ||
!SetOrDeleteArrayElement(cx, obj, last + delta, hole, tvr.value())) {
return JS_FALSE;
}
@@ -2309,7 +2360,7 @@ array_splice(JSContext *cx, uintN argc, Value *vp)
} else {
for (last = end; last < length; last++) {
if (!JS_CHECK_OPERATION_LIMIT(cx) ||
!GetArrayElement(cx, obj, last, &hole, tvr.addr()) ||
!GetElement(cx, obj, last, &hole, tvr.addr()) ||
!SetOrDeleteArrayElement(cx, obj, last - delta, hole, tvr.value())) {
return JS_FALSE;
}
@@ -2388,7 +2439,7 @@ array_concat(JSContext *cx, uintN argc, Value *vp)
for (jsuint slot = 0; slot < alength; slot++) {
JSBool hole;
if (!JS_CHECK_OPERATION_LIMIT(cx) ||
!GetArrayElement(cx, aobj, slot, &hole, tvr.addr())) {
!GetElement(cx, aobj, slot, &hole, tvr.addr())) {
return false;
}
@@ -2480,7 +2531,7 @@ array_slice(JSContext *cx, uintN argc, Value *vp)
AutoValueRooter tvr(cx);
for (slot = begin; slot < end; slot++) {
if (!JS_CHECK_OPERATION_LIMIT(cx) ||
!GetArrayElement(cx, obj, slot, &hole, tvr.addr())) {
!GetElement(cx, obj, slot, &hole, tvr.addr())) {
return JS_FALSE;
}
if (!hole && !SetArrayElement(cx, nobj, slot - begin, tvr.value()))
@@ -2544,7 +2595,7 @@ array_indexOfHelper(JSContext *cx, JSBool isLast, uintN argc, Value *vp)
for (;;) {
if (!JS_CHECK_OPERATION_LIMIT(cx) ||
!GetArrayElement(cx, obj, (jsuint)i, &hole, vp)) {
!GetElement(cx, obj, (jsuint)i, &hole, vp)) {
return JS_FALSE;
}
if (!hole && StrictlyEqual(cx, *vp, tosearch)) {
@@ -2634,7 +2685,7 @@ array_extra(JSContext *cx, ArrayExtraMode mode, uintN argc, Value *vp)
} else {
JSBool hole;
do {
if (!GetArrayElement(cx, obj, start, &hole, vp))
if (!GetElement(cx, obj, start, &hole, vp))
return JS_FALSE;
start += step;
} while (hole && start != end);
@@ -2689,7 +2740,7 @@ array_extra(JSContext *cx, ArrayExtraMode mode, uintN argc, Value *vp)
for (jsint i = start; i != end; i += step) {
JSBool hole;
ok = JS_CHECK_OPERATION_LIMIT(cx) &&
GetArrayElement(cx, obj, i, &hole, tvr.addr());
GetElement(cx, obj, i, &hole, tvr.addr());
if (!ok)
goto out;
if (hole)