Merge TM -> JM
This commit is contained in:
@@ -53,16 +53,18 @@
|
||||
* getDenseArrayCapacity().
|
||||
* - The array's initialized length, accessible with getDenseArrayInitializedLength().
|
||||
*
|
||||
* In dense mode, holes in the array are represented by (JS_ARRAY_HOLE) invalid
|
||||
* values. Elements between the initialized length and the length property
|
||||
* are left uninitialized, but are conceptually holes. Arrays with no holes
|
||||
* below the initialized length are "packed" arrays.
|
||||
* In dense mode, holes in the array are represented by
|
||||
* MagicValue(JS_ARRAY_HOLE) invalid values. Elements between the initialized
|
||||
* length and the length property are left uninitialized, but are conceptually holes.
|
||||
* Arrays with no holes below the initialized length are "packed" arrays.
|
||||
*
|
||||
* NB: the capacity and length of a dense array are entirely unrelated! The
|
||||
* length may be greater than, less than, or equal to the capacity. See
|
||||
* array_length_setter for an explanation of how the first, most surprising
|
||||
* case may occur. The initialized length is always less than or equal to both
|
||||
* the length and capacity.
|
||||
* length may be greater than, less than, or equal to the capacity. The first
|
||||
* case may occur when the user writes "new Array(100), in which case the
|
||||
* length is 100 while the capacity remains 0 (indices below length and above
|
||||
* capacity must be treated as holes). See array_length_setter for another
|
||||
* explanation of how the first case may occur. The initialized length is always
|
||||
* less than or equal to both the length and capacity.
|
||||
*
|
||||
* Arrays are converted to use js_SlowArrayClass when any of these conditions
|
||||
* are met:
|
||||
@@ -149,10 +151,10 @@ ENSURE_SLOW_ARRAY(JSContext *cx, JSObject *obj)
|
||||
* 'id' is passed as a jsboxedword since the given id need not necessarily hold
|
||||
* an atomized string.
|
||||
*/
|
||||
JSBool
|
||||
js_StringIsIndex(JSString *str, jsuint *indexp)
|
||||
bool
|
||||
js_StringIsIndex(JSLinearString *str, jsuint *indexp)
|
||||
{
|
||||
jschar *cp = str->chars();
|
||||
const jschar *cp = str->chars();
|
||||
if (JS7_ISDEC(*cp) && str->length() < sizeof(MAXSTR)) {
|
||||
jsuint index = JS7_UNDEC(*cp++);
|
||||
jsuint oldIndex = 0;
|
||||
@@ -172,20 +174,22 @@ js_StringIsIndex(JSString *str, jsuint *indexp)
|
||||
(oldIndex == (MAXINDEX / 10) && c < (MAXINDEX % 10))))
|
||||
{
|
||||
*indexp = index;
|
||||
return JS_TRUE;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return JS_FALSE;
|
||||
return false;
|
||||
}
|
||||
|
||||
static jsuint
|
||||
ValueIsLength(JSContext *cx, Value* vp)
|
||||
static bool
|
||||
ValueToLength(JSContext *cx, Value* vp, jsuint* plength)
|
||||
{
|
||||
if (vp->isInt32()) {
|
||||
int32_t i = vp->toInt32();
|
||||
if (i < 0)
|
||||
goto error;
|
||||
return (jsuint) i;
|
||||
|
||||
*plength = (jsuint)(i);
|
||||
return true;
|
||||
}
|
||||
|
||||
jsdouble d;
|
||||
@@ -194,18 +198,20 @@ ValueIsLength(JSContext *cx, Value* vp)
|
||||
|
||||
if (JSDOUBLE_IS_NaN(d))
|
||||
goto error;
|
||||
|
||||
jsuint length;
|
||||
length = (jsuint) d;
|
||||
if (d != (jsdouble) length)
|
||||
goto error;
|
||||
vp->setNumber(length);
|
||||
return length;
|
||||
|
||||
error:
|
||||
|
||||
*plength = length;
|
||||
return true;
|
||||
|
||||
error:
|
||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
|
||||
JSMSG_BAD_ARRAY_LENGTH);
|
||||
vp->setNull();
|
||||
return 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
JSBool
|
||||
@@ -575,8 +581,10 @@ js_HasLengthProperty(JSContext *cx, JSObject *obj, jsuint *lengthp)
|
||||
if (!ok)
|
||||
return false;
|
||||
|
||||
*lengthp = ValueIsLength(cx, tvr.addr());
|
||||
return !tvr.value().isNull();
|
||||
if (!ValueToLength(cx, tvr.addr(), lengthp))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -599,27 +607,20 @@ array_length_getter(JSContext *cx, JSObject *obj, jsid id, Value *vp)
|
||||
}
|
||||
|
||||
static JSBool
|
||||
array_length_setter(JSContext *cx, JSObject *obj, jsid id, Value *vp, JSBool strict)
|
||||
array_length_setter(JSContext *cx, JSObject *obj, jsid id, Value *vp)
|
||||
{
|
||||
jsuint newlen, oldlen, gap, index;
|
||||
Value junk;
|
||||
|
||||
/* Check for a sealed object first. */
|
||||
if (!obj->isExtensible()) {
|
||||
return js_ReportValueErrorFlags(cx, JSREPORT_ERROR, JSMSG_READ_ONLY,
|
||||
JSDVG_IGNORE_STACK, IdToValue(id), NULL,
|
||||
NULL, NULL);
|
||||
}
|
||||
|
||||
if (!obj->isArray()) {
|
||||
jsid lengthId = ATOM_TO_JSID(cx->runtime->atomState.lengthAtom);
|
||||
|
||||
return obj->defineProperty(cx, lengthId, *vp, NULL, NULL, JSPROP_ENUMERATE);
|
||||
}
|
||||
|
||||
newlen = ValueIsLength(cx, vp);
|
||||
if (vp->isNull())
|
||||
if (!ValueToLength(cx, vp, &newlen))
|
||||
return false;
|
||||
|
||||
oldlen = obj->getArrayLength();
|
||||
|
||||
if (oldlen == newlen)
|
||||
@@ -654,8 +655,6 @@ array_length_setter(JSContext *cx, JSObject *obj, jsid id, Value *vp, JSBool str
|
||||
}
|
||||
if (!DeleteArrayElement(cx, obj, oldlen, true)) {
|
||||
obj->setArrayLength(cx, oldlen + 1);
|
||||
if (strict)
|
||||
return false;
|
||||
JS_ClearPendingException(cx);
|
||||
return true;
|
||||
}
|
||||
@@ -817,7 +816,7 @@ array_setProperty(JSContext *cx, JSObject *obj, jsid id, Value *vp, JSBool stric
|
||||
uint32 i;
|
||||
|
||||
if (JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom))
|
||||
return array_length_setter(cx, obj, id, vp, strict);
|
||||
return array_length_setter(cx, obj, id, vp);
|
||||
|
||||
if (!obj->isDenseArray())
|
||||
return js_SetProperty(cx, obj, id, vp, strict);
|
||||
@@ -847,17 +846,6 @@ array_setProperty(JSContext *cx, JSObject *obj, jsid id, Value *vp, JSBool stric
|
||||
return js_SetProperty(cx, obj, id, vp, strict);
|
||||
}
|
||||
|
||||
static JSBool
|
||||
slowarray_setProperty(JSContext *cx, JSObject *obj, jsid id, Value *vp, JSBool strict)
|
||||
{
|
||||
JS_ASSERT(obj->isSlowArray());
|
||||
|
||||
if (JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom))
|
||||
return array_length_setter(cx, obj, id, vp, strict);
|
||||
|
||||
return js_SetProperty(cx, obj, id, vp, strict);
|
||||
}
|
||||
|
||||
JSBool
|
||||
js_PrototypeHasIndexedProperties(JSContext *cx, JSObject *obj)
|
||||
{
|
||||
@@ -884,21 +872,35 @@ static JSBool
|
||||
array_defineProperty(JSContext *cx, JSObject *obj, jsid id, const Value *value,
|
||||
PropertyOp getter, PropertyOp setter, uintN attrs)
|
||||
{
|
||||
uint32 i = 0; // init to shut GCC up
|
||||
JSBool isIndex;
|
||||
|
||||
if (JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom))
|
||||
return JS_TRUE;
|
||||
|
||||
isIndex = js_IdIsIndex(id, &i);
|
||||
if (!isIndex || attrs != JSPROP_ENUMERATE) {
|
||||
if (!ENSURE_SLOW_ARRAY(cx, obj))
|
||||
return JS_FALSE;
|
||||
if (!obj->isDenseArray())
|
||||
return js_DefineProperty(cx, obj, id, value, getter, setter, attrs);
|
||||
}
|
||||
|
||||
Value tmp = *value;
|
||||
return array_setProperty(cx, obj, id, &tmp, false);
|
||||
do {
|
||||
uint32 i = 0; // init to shut GCC up
|
||||
bool isIndex = js_IdIsIndex(id, &i);
|
||||
if (!isIndex || attrs != JSPROP_ENUMERATE)
|
||||
break;
|
||||
|
||||
JSObject::EnsureDenseResult result = obj->ensureDenseArrayElements(cx, i, 1);
|
||||
if (result != JSObject::ED_OK) {
|
||||
if (result == JSObject::ED_FAILED)
|
||||
return false;
|
||||
JS_ASSERT(result == JSObject::ED_SPARSE);
|
||||
break;
|
||||
}
|
||||
|
||||
if (i >= obj->getArrayLength())
|
||||
obj->setArrayLength(cx, i + 1);
|
||||
obj->setDenseArrayElement(i, *value);
|
||||
return true;
|
||||
} while (false);
|
||||
|
||||
if (!obj->makeDenseArraySlow(cx))
|
||||
return false;
|
||||
return js_DefineProperty(cx, obj, id, value, getter, setter, attrs);
|
||||
}
|
||||
|
||||
static JSBool
|
||||
@@ -1017,34 +1019,7 @@ Class js_SlowArrayClass = {
|
||||
PropertyStub, /* setProperty */
|
||||
EnumerateStub,
|
||||
ResolveStub,
|
||||
js_TryValueOf,
|
||||
NULL, /* finalize */
|
||||
NULL, /* reserved0 */
|
||||
NULL, /* checkAccess */
|
||||
NULL, /* call */
|
||||
NULL, /* construct */
|
||||
NULL, /* xdrObject */
|
||||
NULL, /* hasInstance */
|
||||
NULL, /* mark */
|
||||
JS_NULL_CLASS_EXT,
|
||||
{
|
||||
NULL, /* lookupProperty */
|
||||
NULL, /* defineProperty */
|
||||
NULL, /* getProperty */
|
||||
/*
|
||||
* For assignments to 'length', we need to know the setter's strictness. A property's
|
||||
* setter isn't passed that, but the ObjectOps member is, so use that.
|
||||
*/
|
||||
slowarray_setProperty,
|
||||
NULL, /* getAttributes */
|
||||
NULL, /* setAttributes */
|
||||
NULL, /* deleteProperty */
|
||||
NULL, /* enumerate */
|
||||
NULL, /* typeOf */
|
||||
NULL, /* trace */
|
||||
NULL, /* thisObject */
|
||||
NULL, /* clear */
|
||||
}
|
||||
js_TryValueOf
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -1076,7 +1051,7 @@ JSObject::makeDenseArraySlow(JSContext *cx)
|
||||
* The getter/setter here will directly access the object's private value.
|
||||
*/
|
||||
if (!addProperty(cx, ATOM_TO_JSID(cx->runtime->atomState.lengthAtom),
|
||||
array_length_getter, NULL,
|
||||
array_length_getter, array_length_setter,
|
||||
SHAPE_INVALID_SLOT, JSPROP_PERMANENT | JSPROP_SHARED, 0, 0)) {
|
||||
setMap(oldMap);
|
||||
return false;
|
||||
@@ -1215,12 +1190,13 @@ array_toSource(JSContext *cx, uintN argc, Value *vp)
|
||||
goto out;
|
||||
}
|
||||
vp->setString(str);
|
||||
const jschar *chars;
|
||||
size_t charlen;
|
||||
str->getCharsAndLength(chars, charlen);
|
||||
|
||||
const jschar *chars = str->getChars(cx);
|
||||
if (!chars)
|
||||
goto out;
|
||||
|
||||
/* Append element to buffer. */
|
||||
if (!cb.append(chars, charlen))
|
||||
if (!cb.append(chars, chars + str->length()))
|
||||
goto out;
|
||||
if (index + 1 != length) {
|
||||
if (!js_AppendLiteral(cb, ", "))
|
||||
@@ -1254,6 +1230,20 @@ array_toString_sub(JSContext *cx, JSObject *obj, JSBool locale,
|
||||
{
|
||||
JS_CHECK_RECURSION(cx, return false);
|
||||
|
||||
/* Get characters to use for the separator. */
|
||||
static const jschar comma = ',';
|
||||
const jschar *sep;
|
||||
size_t seplen;
|
||||
if (sepstr) {
|
||||
seplen = sepstr->length();
|
||||
sep = sepstr->getChars(cx);
|
||||
if (!sep)
|
||||
return false;
|
||||
} else {
|
||||
sep = ,
|
||||
seplen = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Use HashTable entry as the cycle indicator. On first visit, create the
|
||||
* entry, and, when leaving, remove the entry.
|
||||
@@ -1263,10 +1253,8 @@ array_toString_sub(JSContext *cx, JSObject *obj, JSBool locale,
|
||||
uint32 genBefore;
|
||||
if (!hashp) {
|
||||
/* Not in hash table, so not a cycle. */
|
||||
if (!cx->busyArrays.add(hashp, obj)) {
|
||||
JS_ReportOutOfMemory(cx);
|
||||
if (!cx->busyArrays.add(hashp, obj))
|
||||
return false;
|
||||
}
|
||||
genBefore = cx->busyArrays.generation();
|
||||
} else {
|
||||
/* Cycle, so return empty string. */
|
||||
@@ -1280,17 +1268,6 @@ array_toString_sub(JSContext *cx, JSObject *obj, JSBool locale,
|
||||
MUST_FLOW_THROUGH("out");
|
||||
bool ok = false;
|
||||
|
||||
/* Get characters to use for the separator. */
|
||||
static const jschar comma = ',';
|
||||
const jschar *sep;
|
||||
size_t seplen;
|
||||
if (sepstr) {
|
||||
sepstr->getCharsAndLength(sep, seplen);
|
||||
} else {
|
||||
sep = ,
|
||||
seplen = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* This object will take responsibility for the jschar buffer until the
|
||||
* buffer is transferred to the returned JSString.
|
||||
@@ -1792,15 +1769,10 @@ comparator_stack_cast(JSRedComparator func)
|
||||
static int
|
||||
sort_compare_strings(void *arg, const void *a, const void *b, int *result)
|
||||
{
|
||||
const Value *av = (const Value *)a, *bv = (const Value *)b;
|
||||
|
||||
JS_ASSERT(av->isString());
|
||||
JS_ASSERT(bv->isString());
|
||||
if (!JS_CHECK_OPERATION_LIMIT((JSContext *)arg))
|
||||
return JS_FALSE;
|
||||
|
||||
*result = (int) js_CompareStrings(av->toString(), bv->toString());
|
||||
return JS_TRUE;
|
||||
JSContext *cx = (JSContext *)arg;
|
||||
JSString *astr = ((const Value *)a)->toString();
|
||||
JSString *bstr = ((const Value *)b)->toString();
|
||||
return JS_CHECK_OPERATION_LIMIT(cx) && CompareStrings(cx, astr, bstr, result);
|
||||
}
|
||||
|
||||
JSBool
|
||||
@@ -2367,7 +2339,7 @@ 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);
|
||||
JSObject *obj2 = NewDenseEmptyArray(cx);
|
||||
if (!obj2)
|
||||
return JS_FALSE;
|
||||
obj2->setType(type);
|
||||
@@ -2421,7 +2393,6 @@ array_splice(JSContext *cx, uintN argc, Value *vp)
|
||||
/* If there are elements to remove, put them into the return value. */
|
||||
if (count > 0) {
|
||||
if (obj->isDenseArray() && !js_PrototypeHasIndexedProperties(cx, obj) &&
|
||||
!js_PrototypeHasIndexedProperties(cx, obj2) &&
|
||||
end <= obj->getDenseArrayCapacity()) {
|
||||
if (!InitArrayObject(cx, obj2, count, obj->getDenseArrayElements() + begin))
|
||||
return JS_FALSE;
|
||||
@@ -2535,7 +2506,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());
|
||||
nobj = NewDenseCopiedArray(cx, initlen, aobj->getDenseArrayElements());
|
||||
if (!nobj)
|
||||
return JS_FALSE;
|
||||
nobj->setArrayLength(cx, length);
|
||||
@@ -2545,7 +2516,7 @@ array_concat(JSContext *cx, uintN argc, Value *vp)
|
||||
argc--;
|
||||
p++;
|
||||
} else {
|
||||
nobj = js_NewArrayObject(cx, 0, NULL);
|
||||
nobj = NewDenseEmptyArray(cx);
|
||||
if (!nobj)
|
||||
return JS_FALSE;
|
||||
vp->setObject(*nobj);
|
||||
@@ -2556,9 +2527,13 @@ array_concat(JSContext *cx, uintN argc, Value *vp)
|
||||
TypeObject *ntype = cx->getTypeCallerInitObject(true);
|
||||
if (!ntype)
|
||||
return JS_FALSE;
|
||||
nobj->setType(ntype);
|
||||
if (cx->isTypeCallerMonitored())
|
||||
cx->markTypeObjectUnknownProperties(ntype);
|
||||
|
||||
if (aobj->isDenseArray() && !aobj->isPackedDenseArray())
|
||||
nobj->setDenseArrayNotPacked(cx);
|
||||
|
||||
AutoValueRooter tvr(cx);
|
||||
|
||||
/* Loop over [0, argc] to concat args into nobj, expanding all Arrays. */
|
||||
@@ -2573,8 +2548,8 @@ array_concat(JSContext *cx, uintN argc, Value *vp)
|
||||
jsid id = ATOM_TO_JSID(cx->runtime->atomState.lengthAtom);
|
||||
if (!aobj->getProperty(cx, id, tvr.addr()))
|
||||
return false;
|
||||
jsuint alength = ValueIsLength(cx, tvr.addr());
|
||||
if (tvr.value().isNull())
|
||||
jsuint alength;
|
||||
if (!ValueToLength(cx, tvr.addr(), &alength))
|
||||
return false;
|
||||
for (jsuint slot = 0; slot < alength; slot++) {
|
||||
JSBool hole;
|
||||
@@ -2680,16 +2655,18 @@ array_slice(JSContext *cx, uintN argc, Value *vp)
|
||||
|
||||
if (obj->isDenseArray() && end <= obj->getDenseArrayCapacity() &&
|
||||
!js_PrototypeHasIndexedProperties(cx, obj)) {
|
||||
nobj = js_NewArrayObject(cx, end - begin, obj->getDenseArrayElements() + begin);
|
||||
nobj = NewDenseCopiedArray(cx, end - begin, obj->getDenseArrayElements() + begin);
|
||||
if (!nobj)
|
||||
return JS_FALSE;
|
||||
nobj->setType(type);
|
||||
if (!obj->isPackedDenseArray())
|
||||
nobj->setDenseArrayNotPacked(cx);
|
||||
vp->setObject(*nobj);
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
/* Create a new Array object and root it using *vp. */
|
||||
nobj = js_NewArrayObject(cx, 0, NULL);
|
||||
nobj = NewDenseAllocatedArray(cx, end - begin);
|
||||
if (!nobj)
|
||||
return JS_FALSE;
|
||||
nobj->setType(type);
|
||||
@@ -2705,7 +2682,7 @@ array_slice(JSContext *cx, uintN argc, Value *vp)
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
return js_SetLengthProperty(cx, nobj, end - begin);
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
#if JS_HAS_ARRAY_EXTRAS
|
||||
@@ -2765,11 +2742,16 @@ array_indexOfHelper(JSContext *cx, JSBool isLast, uintN argc, Value *vp)
|
||||
!GetElement(cx, obj, (jsuint)i, &hole, vp)) {
|
||||
return JS_FALSE;
|
||||
}
|
||||
if (!hole && StrictlyEqual(cx, *vp, tosearch)) {
|
||||
vp->setNumber(i);
|
||||
if (!vp->isInt32())
|
||||
cx->markTypeCallerOverflow();
|
||||
return JS_TRUE;
|
||||
if (!hole) {
|
||||
JSBool equal;
|
||||
if (!StrictlyEqual(cx, *vp, tosearch, &equal))
|
||||
return JS_FALSE;
|
||||
if (equal) {
|
||||
vp->setNumber(i);
|
||||
if (!vp->isInt32())
|
||||
cx->markTypeCallerOverflow();
|
||||
return JS_TRUE;
|
||||
}
|
||||
}
|
||||
if (i == stop)
|
||||
goto not_found;
|
||||
@@ -2870,7 +2852,7 @@ array_extra(JSContext *cx, ArrayExtraMode mode, uintN argc, Value *vp)
|
||||
case MAP:
|
||||
case FILTER:
|
||||
newlen = (mode == MAP) ? length : 0;
|
||||
newarr = js_NewArrayObject(cx, newlen, NULL);
|
||||
newarr = NewDenseAllocatedArray(cx, newlen);
|
||||
if (!newarr)
|
||||
return JS_FALSE;
|
||||
newtype = cx->getTypeCallerInitObject(true);
|
||||
@@ -3123,6 +3105,12 @@ static void array_TypeConcat(JSContext *cx, JSTypeFunction *jsfun, JSTypeCallsit
|
||||
#ifdef JS_TYPE_INFERENCE
|
||||
TypeCallsite *site = Valueify(jssite);
|
||||
|
||||
if (!site->compileAndGo()) {
|
||||
if (site->returnTypes)
|
||||
site->returnTypes->addType(cx, TYPE_UNKNOWN);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Treat the returned array as a new allocation site. */
|
||||
TypeObject *object = site->getInitObject(cx, true);
|
||||
|
||||
@@ -3205,27 +3193,30 @@ static void array_TypeExtra(JSContext *cx, JSTypeFunction *jsfun, JSTypeCallsite
|
||||
break;
|
||||
}
|
||||
|
||||
case MAP: {
|
||||
/* 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);
|
||||
|
||||
site->returnTypes->addType(cx, (jstype) object);
|
||||
case MAP:
|
||||
if (site->compileAndGo()) {
|
||||
/* 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);
|
||||
site->returnTypes->addType(cx, (jstype) object);
|
||||
} else {
|
||||
site->returnTypes->addType(cx, TYPE_UNKNOWN);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
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.
|
||||
*/
|
||||
TypeObject *object = site->getInitObject(cx, true);
|
||||
elemTypes->addSubset(cx, pool, object->getProperty(cx, JSID_VOID, true));
|
||||
|
||||
site->returnTypes->addType(cx, (jstype) object);
|
||||
case FILTER:
|
||||
if (site->compileAndGo()) {
|
||||
/*
|
||||
* Makes a new array, whose element type is the same as the element type
|
||||
* of the 'this' array.
|
||||
*/
|
||||
TypeObject *object = site->getInitObject(cx, true);
|
||||
elemTypes->addSubset(cx, pool, object->getProperty(cx, JSID_VOID, true));
|
||||
site->returnTypes->addType(cx, (jstype) object);
|
||||
} else {
|
||||
site->returnTypes->addType(cx, TYPE_UNKNOWN);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case SOME:
|
||||
site->returnTypes->addType(cx, TYPE_BOOLEAN);
|
||||
@@ -3328,104 +3319,42 @@ static JSFunctionSpec array_static_methods[] = {
|
||||
JS_FS_END
|
||||
};
|
||||
|
||||
/* The count here is a guess for the final capacity. */
|
||||
static inline JSObject *
|
||||
NewDenseArrayObject(JSContext *cx, jsuint count)
|
||||
{
|
||||
gc::FinalizeKind kind = GuessObjectGCKind(count, true);
|
||||
return NewNonFunction<WithProto::Class>(cx, &js_ArrayClass, NULL, NULL, kind);
|
||||
}
|
||||
|
||||
JSBool
|
||||
js_Array(JSContext *cx, uintN argc, Value *vp)
|
||||
{
|
||||
jsuint length;
|
||||
const Value *vector;
|
||||
JSObject *obj;
|
||||
|
||||
TypeObject *type = cx->getTypeCallerInitObject(true);
|
||||
if (!type)
|
||||
return JS_FALSE;
|
||||
|
||||
if (argc == 0) {
|
||||
length = 0;
|
||||
vector = NULL;
|
||||
obj = NewDenseEmptyArray(cx);
|
||||
} else if (argc > 1) {
|
||||
length = (jsuint) argc;
|
||||
vector = vp + 2;
|
||||
obj = NewDenseCopiedArray(cx, argc, vp + 2);
|
||||
} else if (!vp[2].isNumber()) {
|
||||
length = 1;
|
||||
vector = vp + 2;
|
||||
|
||||
/* Unexpected case for type inference. */
|
||||
cx->addTypeProperty(type, NULL, vp[2]);
|
||||
|
||||
obj = NewDenseCopiedArray(cx, 1, vp + 2);
|
||||
} else {
|
||||
length = ValueIsLength(cx, vp + 2);
|
||||
if (vp[2].isNull())
|
||||
jsuint length;
|
||||
if (!ValueToLength(cx, vp + 2, &length))
|
||||
return JS_FALSE;
|
||||
vector = NULL;
|
||||
obj = NewDenseUnallocatedArray(cx, length);
|
||||
}
|
||||
|
||||
if (cx->isTypeCallerMonitored() && vector)
|
||||
cx->markTypeObjectUnknownProperties(type);
|
||||
|
||||
/* Whether called with 'new' or not, use a new Array object. */
|
||||
JSObject *obj = NewDenseArrayObject(cx, length);
|
||||
if (!obj)
|
||||
return JS_FALSE;
|
||||
|
||||
obj->setType(type);
|
||||
if (cx->isTypeCallerMonitored())
|
||||
cx->markTypeObjectUnknownProperties(type);
|
||||
|
||||
vp->setObject(*obj);
|
||||
|
||||
return InitArrayObject(cx, obj, length, vector);
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
JSObject* JS_FASTCALL
|
||||
js_NewEmptyArray(JSContext* cx, JSObject* proto, int32 len)
|
||||
{
|
||||
if (len < 0)
|
||||
return NULL;
|
||||
|
||||
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;
|
||||
|
||||
/* Initialize all fields, calling init before setting obj->map. */
|
||||
obj->init(cx, &js_ArrayClass, type, proto->getParent(), (void*) len, true);
|
||||
obj->setSharedNonNativeMap();
|
||||
return obj;
|
||||
}
|
||||
#ifdef JS_TRACER
|
||||
JS_DEFINE_CALLINFO_3(extern, OBJECT, js_NewEmptyArray, CONTEXT, OBJECT, INT32, 0,
|
||||
nanojit::ACCSET_STORE_ANY)
|
||||
#endif
|
||||
|
||||
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;
|
||||
|
||||
/* Avoid ensureDenseArrayElements to skip sparse array checks there. */
|
||||
if (!obj->ensureSlots(cx, len))
|
||||
return NULL;
|
||||
ClearValueRange(obj->getDenseArrayElements(), len, true);
|
||||
obj->setDenseArrayInitializedLength(len);
|
||||
obj->setDenseArrayNotPacked(cx);
|
||||
return obj;
|
||||
}
|
||||
#ifdef JS_TRACER
|
||||
JS_DEFINE_CALLINFO_3(extern, OBJECT, js_NewPreallocatedArray, CONTEXT, OBJECT, INT32,
|
||||
0, nanojit::ACCSET_STORE_ANY)
|
||||
#endif
|
||||
|
||||
// specialized handler for Array() that propagates arguments into indexes
|
||||
// of the resulting array.
|
||||
static void array_TypeNew(JSContext *cx, JSTypeFunction *jsfun, JSTypeCallsite *jssite)
|
||||
@@ -3433,6 +3362,12 @@ static void array_TypeNew(JSContext *cx, JSTypeFunction *jsfun, JSTypeCallsite *
|
||||
#ifdef JS_TYPE_INFERENCE
|
||||
TypeCallsite *site = Valueify(jssite);
|
||||
|
||||
if (!site->compileAndGo()) {
|
||||
if (site->returnTypes)
|
||||
site->returnTypes->addType(cx, TYPE_UNKNOWN);
|
||||
return;
|
||||
}
|
||||
|
||||
TypeObject *object = site->getInitObject(cx, true);
|
||||
if (site->returnTypes)
|
||||
site->returnTypes->addType(cx, (jstype) object);
|
||||
@@ -3467,31 +3402,98 @@ js_InitArrayClass(JSContext *cx, JSObject *obj)
|
||||
return proto;
|
||||
}
|
||||
|
||||
JSObject *
|
||||
js_NewArrayObject(JSContext *cx, jsuint length, const Value *vector)
|
||||
/*
|
||||
* Array allocation functions.
|
||||
*/
|
||||
namespace js {
|
||||
|
||||
template<bool allocateCapacity>
|
||||
static JS_ALWAYS_INLINE JSObject *
|
||||
NewArray(JSContext *cx, jsuint length, JSObject *proto)
|
||||
{
|
||||
JSObject *obj = NewDenseArrayObject(cx, length);
|
||||
JS_ASSERT_IF(proto, proto->isArray());
|
||||
|
||||
gc::FinalizeKind kind = GuessObjectGCKind(length, true);
|
||||
JSObject *obj = detail::NewObject<WithProto::Class, false>(cx, &js_ArrayClass, proto, NULL, kind);
|
||||
|
||||
obj->setArrayLength(cx, length);
|
||||
|
||||
if (allocateCapacity && !obj->ensureSlots(cx, length))
|
||||
return NULL;
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
JSObject * JS_FASTCALL
|
||||
NewDenseEmptyArray(JSContext *cx, JSObject *proto)
|
||||
{
|
||||
return NewArray<false>(cx, 0, proto);
|
||||
}
|
||||
|
||||
JSObject * JS_FASTCALL
|
||||
NewDenseAllocatedArray(JSContext *cx, uint32 length, JSObject *proto)
|
||||
{
|
||||
return NewArray<true>(cx, length, proto);
|
||||
}
|
||||
|
||||
JSObject * JS_FASTCALL
|
||||
NewDenseAllocatedEmptyArray(JSContext *cx, uint length, JSObject *proto)
|
||||
{
|
||||
JSObject *obj = NewArray<true>(cx, length, proto);
|
||||
if (!obj)
|
||||
return NULL;
|
||||
obj->setDenseArrayInitializedLength(length);
|
||||
obj->setDenseArrayNotPacked(cx);
|
||||
ClearValueRange(obj->getSlots(), length, true);
|
||||
return obj;
|
||||
}
|
||||
|
||||
JSObject * JS_FASTCALL
|
||||
NewDenseUnallocatedArray(JSContext *cx, uint32 length, JSObject *proto)
|
||||
{
|
||||
return NewArray<false>(cx, length, proto);
|
||||
}
|
||||
|
||||
JSObject *
|
||||
NewDenseCopiedArray(JSContext *cx, uintN length, Value *vp, JSObject *proto)
|
||||
{
|
||||
JSObject* obj = NewArray<true>(cx, length, proto);
|
||||
JS_ASSERT(obj->getDenseArrayCapacity() >= length);
|
||||
|
||||
if (vp)
|
||||
memcpy(obj->getDenseArrayElements(), vp, length * sizeof(Value));
|
||||
|
||||
obj->setDenseArrayInitializedLength(length);
|
||||
return obj;
|
||||
}
|
||||
|
||||
#ifdef JS_TRACER
|
||||
JS_DEFINE_CALLINFO_2(extern, OBJECT, NewDenseEmptyArray, CONTEXT, OBJECT, 0,
|
||||
nanojit::ACCSET_STORE_ANY)
|
||||
JS_DEFINE_CALLINFO_3(extern, OBJECT, NewDenseAllocatedArray, CONTEXT, UINT32, OBJECT, 0,
|
||||
nanojit::ACCSET_STORE_ANY)
|
||||
JS_DEFINE_CALLINFO_3(extern, OBJECT, NewDenseAllocatedEmptyArray, CONTEXT, UINT32, OBJECT, 0,
|
||||
nanojit::ACCSET_STORE_ANY)
|
||||
JS_DEFINE_CALLINFO_3(extern, OBJECT, NewDenseUnallocatedArray, CONTEXT, UINT32, OBJECT, 0,
|
||||
nanojit::ACCSET_STORE_ANY)
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
JSObject *
|
||||
NewSlowEmptyArray(JSContext *cx)
|
||||
{
|
||||
JSObject *obj = NewNonFunction<WithProto::Class>(cx, &js_SlowArrayClass, NULL, NULL);
|
||||
if (!obj)
|
||||
return NULL;
|
||||
|
||||
/*
|
||||
* If this fails, the global object was not initialized and its class does
|
||||
* not have JSCLASS_IS_GLOBAL.
|
||||
*/
|
||||
JS_ASSERT(obj->getProto());
|
||||
|
||||
return InitArrayObject(cx, obj, length, vector) ? obj : NULL;
|
||||
}
|
||||
|
||||
JSObject *
|
||||
js_NewSlowArrayObject(JSContext *cx)
|
||||
{
|
||||
JSObject *obj = NewNonFunction<WithProto::Class>(cx, &js_SlowArrayClass, NULL, NULL);
|
||||
if (obj)
|
||||
obj->setArrayLength(cx, 0);
|
||||
obj->setArrayLength(cx, 0);
|
||||
return obj;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
#ifdef DEBUG
|
||||
JSBool
|
||||
js_ArrayInfo(JSContext *cx, uintN argc, jsval *vp)
|
||||
@@ -3639,10 +3641,14 @@ js_CloneDensePrimitiveArray(JSContext *cx, JSObject *obj, JSObject **clone)
|
||||
vector.append(val);
|
||||
}
|
||||
|
||||
*clone = js_NewArrayObject(cx, initlen, vector.begin());
|
||||
*clone = NewDenseCopiedArray(cx, initlen, vector.begin());
|
||||
if (!*clone)
|
||||
return JS_FALSE;
|
||||
(*clone)->setArrayLength(cx, length);
|
||||
|
||||
if (!obj->isPackedDenseArray())
|
||||
(*clone)->setDenseArrayNotPacked(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