Merge TM -> JM
This commit is contained in:
@@ -204,40 +204,6 @@ js_StringIsIndex(JSLinearString *str, jsuint *indexp)
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool
|
||||
ValueToLength(JSContext *cx, Value* vp, jsuint* plength)
|
||||
{
|
||||
if (vp->isInt32()) {
|
||||
int32_t i = vp->toInt32();
|
||||
if (i < 0)
|
||||
goto error;
|
||||
|
||||
*plength = (jsuint)(i);
|
||||
return true;
|
||||
}
|
||||
|
||||
jsdouble d;
|
||||
if (!ValueToNumber(cx, *vp, &d))
|
||||
goto error;
|
||||
|
||||
if (JSDOUBLE_IS_NaN(d))
|
||||
goto error;
|
||||
|
||||
jsuint length;
|
||||
length = (jsuint) d;
|
||||
if (d != (jsdouble) length)
|
||||
goto error;
|
||||
|
||||
|
||||
*plength = length;
|
||||
return true;
|
||||
|
||||
error:
|
||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
|
||||
JSMSG_BAD_ARRAY_LENGTH);
|
||||
return false;
|
||||
}
|
||||
|
||||
JSBool
|
||||
js_GetLengthProperty(JSContext *cx, JSObject *obj, jsuint *lengthp)
|
||||
{
|
||||
@@ -583,23 +549,6 @@ js_SetLengthProperty(JSContext *cx, JSObject *obj, jsdouble length)
|
||||
return obj->setProperty(cx, id, &v, false);
|
||||
}
|
||||
|
||||
JSBool
|
||||
js_HasLengthProperty(JSContext *cx, JSObject *obj, jsuint *lengthp)
|
||||
{
|
||||
JSErrorReporter older = JS_SetErrorReporter(cx, NULL);
|
||||
AutoValueRooter tvr(cx);
|
||||
jsid id = ATOM_TO_JSID(cx->runtime->atomState.lengthAtom);
|
||||
JSBool ok = obj->getProperty(cx, id, tvr.addr());
|
||||
JS_SetErrorReporter(cx, older);
|
||||
if (!ok)
|
||||
return false;
|
||||
|
||||
if (!ValueToLength(cx, tvr.addr(), lengthp))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Since SpiderMonkey supports cross-class prototype-based delegation, we have
|
||||
* to be careful about the length getter and setter being called on an object
|
||||
@@ -622,20 +571,26 @@ array_length_getter(JSContext *cx, JSObject *obj, jsid id, Value *vp)
|
||||
static JSBool
|
||||
array_length_setter(JSContext *cx, JSObject *obj, jsid id, JSBool strict, Value *vp)
|
||||
{
|
||||
jsuint newlen, oldlen, gap, index;
|
||||
Value junk;
|
||||
|
||||
if (!obj->isArray()) {
|
||||
jsid lengthId = ATOM_TO_JSID(cx->runtime->atomState.lengthAtom);
|
||||
|
||||
return obj->defineProperty(cx, lengthId, *vp, NULL, NULL, JSPROP_ENUMERATE);
|
||||
}
|
||||
|
||||
if (!ValueToLength(cx, vp, &newlen))
|
||||
uint32 newlen;
|
||||
if (!ValueToECMAUint32(cx, *vp, &newlen))
|
||||
return false;
|
||||
|
||||
oldlen = obj->getArrayLength();
|
||||
jsdouble d;
|
||||
if (!ValueToNumber(cx, *vp, &d))
|
||||
return false;
|
||||
|
||||
if (d != newlen) {
|
||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_ARRAY_LENGTH);
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32 oldlen = obj->getArrayLength();
|
||||
if (oldlen == newlen)
|
||||
return true;
|
||||
|
||||
@@ -689,12 +644,14 @@ array_length_setter(JSContext *cx, JSObject *obj, jsid id, JSBool strict, Value
|
||||
/* Protect iter against GC under JSObject::deleteProperty. */
|
||||
AutoObjectRooter tvr(cx, iter);
|
||||
|
||||
gap = oldlen - newlen;
|
||||
jsuint gap = oldlen - newlen;
|
||||
for (;;) {
|
||||
if (!JS_CHECK_OPERATION_LIMIT(cx) || !JS_NextProperty(cx, iter, &id))
|
||||
return false;
|
||||
if (JSID_IS_VOID(id))
|
||||
break;
|
||||
jsuint index;
|
||||
Value junk;
|
||||
if (js_IdIsIndex(id, &index) && index - newlen < gap &&
|
||||
!obj->deleteProperty(cx, id, &junk, false)) {
|
||||
return false;
|
||||
@@ -1002,7 +959,7 @@ Class js_ArrayClass = {
|
||||
StrictPropertyStub, /* setProperty */
|
||||
EnumerateStub,
|
||||
ResolveStub,
|
||||
js_TryValueOf,
|
||||
ConvertStub,
|
||||
NULL,
|
||||
NULL, /* reserved0 */
|
||||
NULL, /* checkAccess */
|
||||
@@ -1038,7 +995,7 @@ Class js_SlowArrayClass = {
|
||||
StrictPropertyStub, /* setProperty */
|
||||
EnumerateStub,
|
||||
ResolveStub,
|
||||
js_TryValueOf
|
||||
ConvertStub
|
||||
};
|
||||
|
||||
static bool
|
||||
@@ -2207,8 +2164,10 @@ array_push1_dense(JSContext* cx, JSObject* obj, const Value &v, Value *rval)
|
||||
}
|
||||
|
||||
JS_ALWAYS_INLINE JSBool
|
||||
ArrayCompPushImpl(JSContext *cx, JSObject *obj, const Value &v)
|
||||
NewbornArrayPushImpl(JSContext *cx, JSObject *obj, const Value &v)
|
||||
{
|
||||
JS_ASSERT(!v.isMagic());
|
||||
|
||||
uint32 length = obj->getArrayLength();
|
||||
if (obj->isSlowArray()) {
|
||||
/* This can happen in one evil case. See bug 630377. */
|
||||
@@ -2220,20 +2179,8 @@ ArrayCompPushImpl(JSContext *cx, JSObject *obj, const Value &v)
|
||||
JS_ASSERT(obj->isDenseArray());
|
||||
JS_ASSERT(length <= obj->getDenseArrayCapacity());
|
||||
|
||||
if (length == obj->getDenseArrayCapacity()) {
|
||||
if (length > JS_ARGS_LENGTH_MAX) {
|
||||
JS_ReportErrorNumberUC(cx, js_GetErrorMessage, NULL,
|
||||
JSMSG_ARRAY_INIT_TOO_BIG);
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* An array comprehension cannot add holes to the array. So we can use
|
||||
* ensureSlots instead of ensureDenseArrayElements.
|
||||
*/
|
||||
if (!obj->ensureSlots(cx, length + 1))
|
||||
return false;
|
||||
}
|
||||
if (length == obj->getDenseArrayCapacity() && !obj->ensureSlots(cx, length + 1))
|
||||
return false;
|
||||
|
||||
if (cx->typeInferenceEnabled())
|
||||
obj->setDenseArrayInitializedLength(length + 1);
|
||||
@@ -2243,25 +2190,25 @@ ArrayCompPushImpl(JSContext *cx, JSObject *obj, const Value &v)
|
||||
}
|
||||
|
||||
JSBool
|
||||
js_ArrayCompPush(JSContext *cx, JSObject *obj, const Value &vp)
|
||||
js_NewbornArrayPush(JSContext *cx, JSObject *obj, const Value &vp)
|
||||
{
|
||||
return ArrayCompPushImpl(cx, obj, vp);
|
||||
return NewbornArrayPushImpl(cx, obj, vp);
|
||||
}
|
||||
|
||||
#ifdef JS_TRACER
|
||||
JSBool JS_FASTCALL
|
||||
js_ArrayCompPush_tn(JSContext *cx, JSObject *obj, ValueArgType v)
|
||||
js_NewbornArrayPush_tn(JSContext *cx, JSObject *obj, ValueArgType v)
|
||||
{
|
||||
TraceMonitor *tm = JS_TRACE_MONITOR_ON_TRACE(cx);
|
||||
|
||||
if (!ArrayCompPushImpl(cx, obj, ValueArgToConstRef(v))) {
|
||||
if (!NewbornArrayPushImpl(cx, obj, ValueArgToConstRef(v))) {
|
||||
SetBuiltinError(tm);
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
return WasBuiltinSuccessful(tm);
|
||||
}
|
||||
JS_DEFINE_CALLINFO_3(extern, BOOL_FAIL, js_ArrayCompPush_tn, CONTEXT, OBJECT,
|
||||
JS_DEFINE_CALLINFO_3(extern, BOOL_FAIL, js_NewbornArrayPush_tn, CONTEXT, OBJECT,
|
||||
VALUE, 0, nanojit::ACCSET_STORE_ANY)
|
||||
#endif
|
||||
|
||||
@@ -2674,8 +2621,6 @@ array_concat(JSContext *cx, uintN argc, Value *vp)
|
||||
length = 0;
|
||||
}
|
||||
|
||||
AutoValueRooter tvr(cx);
|
||||
|
||||
/* Loop over [0, argc] to concat args into nobj, expanding all Arrays. */
|
||||
for (uintN i = 0; i <= argc; i++) {
|
||||
if (!JS_CHECK_OPERATION_LIMIT(cx))
|
||||
@@ -2683,29 +2628,22 @@ array_concat(JSContext *cx, uintN argc, Value *vp)
|
||||
const Value &v = p[i];
|
||||
if (v.isObject()) {
|
||||
aobj = &v.toObject();
|
||||
if (aobj->isArray() ||
|
||||
(aobj->isWrapper() && aobj->unwrap()->isArray())) {
|
||||
jsid id = ATOM_TO_JSID(cx->runtime->atomState.lengthAtom);
|
||||
if (!aobj->getProperty(cx, id, tvr.addr()))
|
||||
return false;
|
||||
if (aobj->isArray() || (aobj->isWrapper() && aobj->unwrap()->isArray())) {
|
||||
jsuint alength;
|
||||
if (!ValueToLength(cx, tvr.addr(), &alength))
|
||||
if (!js_GetLengthProperty(cx, aobj, &alength))
|
||||
return false;
|
||||
for (jsuint slot = 0; slot < alength; slot++) {
|
||||
for (uint32 slot = 0; slot < alength; slot++) {
|
||||
JSBool hole;
|
||||
if (!JS_CHECK_OPERATION_LIMIT(cx) ||
|
||||
!GetElement(cx, aobj, slot, &hole, tvr.addr())) {
|
||||
Value tmp;
|
||||
if (!JS_CHECK_OPERATION_LIMIT(cx) || !GetElement(cx, aobj, slot, &hole, &tmp))
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Per ECMA 262, 15.4.4.4, step 9, ignore nonexistent
|
||||
* properties.
|
||||
*/
|
||||
if (!hole &&
|
||||
!SetArrayElement(cx, nobj, length+slot, tvr.value())) {
|
||||
if (!hole && !SetArrayElement(cx, nobj, length + slot, tmp))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
length += alength;
|
||||
continue;
|
||||
@@ -2948,7 +2886,8 @@ array_extra(JSContext *cx, ArrayExtraMode mode, uintN argc, Value *vp)
|
||||
newlen = 0;
|
||||
newarr = NULL;
|
||||
#endif
|
||||
jsint start = 0, end = length, step = 1;
|
||||
jsuint start = 0, end = length;
|
||||
jsint step = 1;
|
||||
|
||||
switch (mode) {
|
||||
case REDUCE_RIGHT:
|
||||
@@ -3021,7 +2960,7 @@ array_extra(JSContext *cx, ArrayExtraMode mode, uintN argc, Value *vp)
|
||||
|
||||
Value objv = ObjectValue(*obj);
|
||||
AutoValueRooter tvr(cx);
|
||||
for (jsint i = start; i != end; i += step) {
|
||||
for (jsuint i = start; i != end; i += step) {
|
||||
JSBool hole;
|
||||
ok = JS_CHECK_OPERATION_LIMIT(cx) &&
|
||||
GetElement(cx, obj, i, &hole, tvr.addr());
|
||||
@@ -3197,33 +3136,47 @@ static JSFunctionSpec array_static_methods[] = {
|
||||
JS_FS_END
|
||||
};
|
||||
|
||||
/* ES5 15.4.2 */
|
||||
JSBool
|
||||
js_Array(JSContext *cx, uintN argc, Value *vp)
|
||||
{
|
||||
JSObject *obj;
|
||||
|
||||
TypeObject *type = GetTypeCallerInitObject(cx, JSProto_Array);
|
||||
if (!type)
|
||||
return JS_FALSE;
|
||||
|
||||
if (argc == 0) {
|
||||
obj = NewDenseEmptyArray(cx);
|
||||
} else if (argc > 1) {
|
||||
if (argc != 1 || !vp[2].isNumber()) {
|
||||
if (!InitArrayTypes(cx, type, vp + 2, argc))
|
||||
return false;
|
||||
obj = NewDenseCopiedArray(cx, argc, vp + 2);
|
||||
} else if (!vp[2].isNumber()) {
|
||||
AddTypePropertyId(cx, type, JSID_VOID, vp[2]);
|
||||
obj = NewDenseCopiedArray(cx, 1, vp + 2);
|
||||
} else {
|
||||
jsuint length;
|
||||
if (!ValueToLength(cx, vp + 2, &length))
|
||||
return JS_FALSE;
|
||||
obj = NewDenseUnallocatedArray(cx, length);
|
||||
JSObject *obj = (argc == 0)
|
||||
? NewDenseEmptyArray(cx)
|
||||
: NewDenseCopiedArray(cx, argc, vp + 2);
|
||||
if (!obj)
|
||||
return false;
|
||||
obj->setType(type);
|
||||
vp->setObject(*obj);
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32 length;
|
||||
if (vp[2].isInt32()) {
|
||||
int32_t i = vp[2].toInt32();
|
||||
if (i < 0) {
|
||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_ARRAY_LENGTH);
|
||||
return false;
|
||||
}
|
||||
length = uint32(i);
|
||||
} else {
|
||||
jsdouble d = vp[2].toDouble();
|
||||
length = js_DoubleToECMAUint32(d);
|
||||
if (d != jsdouble(length)) {
|
||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_ARRAY_LENGTH);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
JSObject *obj = NewDenseUnallocatedArray(cx, length);
|
||||
if (!obj)
|
||||
return JS_FALSE;
|
||||
return false;
|
||||
|
||||
obj->setType(type);
|
||||
|
||||
@@ -3232,7 +3185,7 @@ js_Array(JSContext *cx, uintN argc, Value *vp)
|
||||
obj->setArrayLength(cx, obj->getArrayLength());
|
||||
|
||||
vp->setObject(*obj);
|
||||
return JS_TRUE;
|
||||
return true;
|
||||
}
|
||||
|
||||
JSObject *
|
||||
@@ -3412,128 +3365,3 @@ js_ArrayInfo(JSContext *cx, uintN argc, jsval *vp)
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
JS_FRIEND_API(JSBool)
|
||||
js_CoerceArrayToCanvasImageData(JSObject *obj, jsuint offset, jsuint count,
|
||||
JSUint8 *dest)
|
||||
{
|
||||
uint32 length;
|
||||
|
||||
if (!obj || !obj->isDenseArray())
|
||||
return JS_FALSE;
|
||||
|
||||
length = obj->getArrayLength();
|
||||
if (length < offset + count)
|
||||
return JS_FALSE;
|
||||
|
||||
JSUint8 *dp = dest;
|
||||
for (uintN i = offset; i < offset+count; i++) {
|
||||
const Value &v = obj->getDenseArrayElement(i);
|
||||
if (v.isInt32()) {
|
||||
jsint vi = v.toInt32();
|
||||
if (jsuint(vi) > 255)
|
||||
vi = (vi < 0) ? 0 : 255;
|
||||
*dp++ = JSUint8(vi);
|
||||
} else if (v.isDouble()) {
|
||||
jsdouble vd = v.toDouble();
|
||||
if (!(vd >= 0)) /* Not < so that NaN coerces to 0 */
|
||||
*dp++ = 0;
|
||||
else if (vd > 255)
|
||||
*dp++ = 255;
|
||||
else {
|
||||
jsdouble toTruncate = vd + 0.5;
|
||||
JSUint8 val = JSUint8(toTruncate);
|
||||
|
||||
/*
|
||||
* now val is rounded to nearest, ties rounded up. We want
|
||||
* rounded to nearest ties to even, so check whether we had a
|
||||
* tie.
|
||||
*/
|
||||
if (val == toTruncate) {
|
||||
/*
|
||||
* It was a tie (since adding 0.5 gave us the exact integer
|
||||
* we want). Since we rounded up, we either already have an
|
||||
* even number or we have an odd number but the number we
|
||||
* want is one less. So just unconditionally masking out the
|
||||
* ones bit should do the trick to get us the value we
|
||||
* want.
|
||||
*/
|
||||
*dp++ = (val & ~1);
|
||||
} else {
|
||||
*dp++ = val;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return JS_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
JS_FRIEND_API(JSBool)
|
||||
js_IsDensePrimitiveArray(JSObject *obj)
|
||||
{
|
||||
if (!obj || !obj->isDenseArray())
|
||||
return JS_FALSE;
|
||||
|
||||
jsuint capacity = obj->getDenseArrayCapacity();
|
||||
for (jsuint i = 0; i < capacity; i++) {
|
||||
if (obj->getDenseArrayElement(i).isObject())
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
JS_FRIEND_API(JSBool)
|
||||
js_CloneDensePrimitiveArray(JSContext *cx, JSObject *obj, JSObject **clone)
|
||||
{
|
||||
JS_ASSERT(obj);
|
||||
if (!obj->isDenseArray()) {
|
||||
/*
|
||||
* This wasn't a dense array. Return JS_TRUE but a NULL clone to signal
|
||||
* that no exception was encountered.
|
||||
*/
|
||||
*clone = NULL;
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
jsuint length = obj->getArrayLength();
|
||||
jsuint initlen = obj->getDenseArrayInitializedLength();
|
||||
|
||||
AutoValueVector vector(cx);
|
||||
if (!vector.reserve(initlen))
|
||||
return JS_FALSE;
|
||||
|
||||
for (jsuint i = 0; i < initlen; i++) {
|
||||
const Value &val = obj->getDenseArrayElement(i);
|
||||
|
||||
if (val.isString()) {
|
||||
// Strings must be made immutable before being copied to a clone.
|
||||
if (!val.toString()->ensureFixed(cx))
|
||||
return JS_FALSE;
|
||||
} else if (val.isObject()) {
|
||||
/*
|
||||
* This wasn't an array of primitives. Return JS_TRUE but a null
|
||||
* clone to signal that no exception was encountered.
|
||||
*/
|
||||
*clone = NULL;
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
vector.infallibleAppend(val);
|
||||
}
|
||||
|
||||
*clone = NewDenseCopiedArray(cx, initlen, vector.begin());
|
||||
if (!*clone)
|
||||
return JS_FALSE;
|
||||
|
||||
if (!obj->isPackedDenseArray())
|
||||
(*clone)->markDenseArrayNotPacked(cx);
|
||||
|
||||
/* The length will be set to the initlen, above, but length might be larger. */
|
||||
(*clone)->setArrayLength(cx, length);
|
||||
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user