2009-06-11 01:29:44 +00:00
|
|
|
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
2006-10-05 23:28:51 +00:00
|
|
|
* vim: set sw=4 ts=8 et tw=78:
|
1998-03-28 02:44:41 +00:00
|
|
|
*
|
2012-05-21 11:12:37 +00:00
|
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
1998-03-28 02:44:41 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* JS array class.
|
2008-02-18 21:01:47 +00:00
|
|
|
*
|
2009-03-04 08:12:35 +00:00
|
|
|
* Array objects begin as "dense" arrays, optimized for index-only property
|
2010-04-27 01:33:36 +00:00
|
|
|
* access over a vector of slots with high load factor. Array methods
|
|
|
|
* optimize for denseness by testing that the object's class is
|
2011-09-03 00:23:26 +00:00
|
|
|
* &ArrayClass, and can then directly manipulate the slots for efficiency.
|
2008-03-02 17:45:33 +00:00
|
|
|
*
|
2008-02-18 21:01:47 +00:00
|
|
|
* We track these pieces of metadata for arrays in dense mode:
|
2010-04-30 03:22:33 +00:00
|
|
|
* - The array's length property as a uint32, accessible with
|
2010-07-23 01:45:21 +00:00
|
|
|
* getArrayLength(), setArrayLength().
|
2010-04-30 03:22:33 +00:00
|
|
|
* - The number of element slots (capacity), gettable with
|
2010-04-27 01:33:36 +00:00
|
|
|
* getDenseArrayCapacity().
|
2011-06-01 18:15:51 +00:00
|
|
|
* - The array's initialized length, accessible with
|
|
|
|
* getDenseArrayInitializedLength().
|
2008-03-02 17:45:33 +00:00
|
|
|
*
|
2010-12-14 00:22:59 +00:00
|
|
|
* In dense mode, holes in the array are represented by
|
2011-06-01 18:15:51 +00:00
|
|
|
* MagicValue(JS_ARRAY_HOLE) invalid values.
|
2008-03-02 17:45:33 +00:00
|
|
|
*
|
2009-05-11 21:57:18 +00:00
|
|
|
* NB: the capacity and length of a dense array are entirely unrelated! The
|
2010-12-14 00:22:59 +00:00
|
|
|
* length may be greater than, less than, or equal to the capacity. The first
|
2012-01-20 12:11:42 +00:00
|
|
|
* case may occur when the user writes "new Array(100)", in which case the
|
2010-12-14 00:22:59 +00:00
|
|
|
* length is 100 while the capacity remains 0 (indices below length and above
|
2010-12-20 17:06:43 +00:00
|
|
|
* capacity must be treated as holes). See array_length_setter for another
|
2011-06-01 18:15:51 +00:00
|
|
|
* explanation of how the first case may occur.
|
|
|
|
*
|
|
|
|
* The initialized length of a dense array specifies the number of elements
|
|
|
|
* that have been initialized. All elements above the initialized length are
|
|
|
|
* holes in the array, and the memory for all elements between the initialized
|
|
|
|
* length and capacity is left uninitialized. When type inference is disabled,
|
|
|
|
* the initialized length always equals the array's capacity. When inference is
|
|
|
|
* enabled, the initialized length is some value less than or equal to both the
|
|
|
|
* array's length and the array's capacity.
|
|
|
|
*
|
|
|
|
* With inference enabled, there is flexibility in exactly the value the
|
|
|
|
* initialized length must hold, e.g. if an array has length 5, capacity 10,
|
|
|
|
* completely empty, it is valid for the initialized length to be any value
|
|
|
|
* between zero and 5, as long as the in memory values below the initialized
|
|
|
|
* length have been initialized with a hole value. However, in such cases we
|
|
|
|
* want to keep the initialized length as small as possible: if the array is
|
|
|
|
* known to have no hole values below its initialized length, then it is a
|
|
|
|
* "packed" array and can be accessed much faster by JIT code.
|
2009-05-11 21:57:18 +00:00
|
|
|
*
|
2011-09-03 00:23:26 +00:00
|
|
|
* Arrays are converted to use SlowArrayClass when any of these conditions
|
2008-02-18 21:01:47 +00:00
|
|
|
* are met:
|
2011-04-06 01:12:03 +00:00
|
|
|
* - there are more than MIN_SPARSE_INDEX slots total and the load factor
|
|
|
|
* (COUNT / capacity) is less than 0.25
|
2010-10-14 14:12:19 +00:00
|
|
|
* - a property is set that is not indexed (and not "length")
|
2009-02-21 21:33:50 +00:00
|
|
|
* - a property is defined that has non-default property attributes.
|
2008-02-18 21:01:47 +00:00
|
|
|
*
|
2009-02-21 21:33:50 +00:00
|
|
|
* Dense arrays do not track property creation order, so unlike other native
|
|
|
|
* objects and slow arrays, enumerating an array does not necessarily visit the
|
|
|
|
* properties in the order they were created. We could instead maintain the
|
|
|
|
* scope to track property enumeration order, but still use the fast slot
|
|
|
|
* access. That would have the same memory cost as just using a
|
2011-09-03 00:23:26 +00:00
|
|
|
* SlowArrayClass, but have the same performance characteristics as a dense
|
2009-02-21 21:33:50 +00:00
|
|
|
* array for slot accesses, at some cost in code complexity.
|
1998-03-28 02:44:41 +00:00
|
|
|
*/
|
2012-01-23 11:43:16 +00:00
|
|
|
|
|
|
|
#include "mozilla/FloatingPoint.h"
|
|
|
|
#include "mozilla/RangedPtr.h"
|
|
|
|
|
2011-09-23 19:13:11 +00:00
|
|
|
#include <limits.h>
|
1998-03-28 02:44:41 +00:00
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
2011-09-23 19:13:11 +00:00
|
|
|
|
1998-10-14 10:22:38 +00:00
|
|
|
#include "jstypes.h"
|
2010-10-01 23:46:54 +00:00
|
|
|
#include "jsutil.h"
|
2011-04-26 02:40:00 +00:00
|
|
|
|
1998-03-28 02:44:41 +00:00
|
|
|
#include "jsapi.h"
|
|
|
|
#include "jsarray.h"
|
|
|
|
#include "jsatom.h"
|
2005-04-17 18:31:59 +00:00
|
|
|
#include "jsbool.h"
|
1998-03-28 02:44:41 +00:00
|
|
|
#include "jscntxt.h"
|
2008-09-05 17:19:17 +00:00
|
|
|
#include "jsversion.h"
|
1998-03-28 02:44:41 +00:00
|
|
|
#include "jsfun.h"
|
|
|
|
#include "jsgc.h"
|
|
|
|
#include "jsinterp.h"
|
2010-06-04 04:41:01 +00:00
|
|
|
#include "jsiter.h"
|
1998-03-28 02:44:41 +00:00
|
|
|
#include "jslock.h"
|
|
|
|
#include "jsnum.h"
|
|
|
|
#include "jsobj.h"
|
2008-02-18 21:01:47 +00:00
|
|
|
#include "jsscope.h"
|
2010-10-22 22:40:11 +00:00
|
|
|
#include "jswrapper.h"
|
2011-07-05 23:52:39 +00:00
|
|
|
#include "methodjit/MethodJIT.h"
|
2011-04-02 00:26:34 +00:00
|
|
|
#include "methodjit/StubCalls.h"
|
|
|
|
#include "methodjit/StubCalls-inl.h"
|
1998-03-28 02:44:41 +00:00
|
|
|
|
2012-05-01 21:30:18 +00:00
|
|
|
#include "gc/Marking.h"
|
2011-04-26 02:40:00 +00:00
|
|
|
#include "vm/ArgumentsObject.h"
|
2012-02-20 21:56:10 +00:00
|
|
|
#include "vm/MethodGuard.h"
|
2012-04-19 23:18:24 +00:00
|
|
|
#include "vm/NumericConversions.h"
|
2012-03-14 22:29:29 +00:00
|
|
|
#include "vm/StringBuffer.h"
|
2011-04-26 02:40:00 +00:00
|
|
|
|
2011-11-16 14:00:32 +00:00
|
|
|
#include "ds/Sort.h"
|
|
|
|
|
2011-06-02 17:40:27 +00:00
|
|
|
#include "jsarrayinlines.h"
|
2009-07-13 21:55:04 +00:00
|
|
|
#include "jsatominlines.h"
|
2010-03-04 01:52:26 +00:00
|
|
|
#include "jscntxtinlines.h"
|
2010-10-06 19:04:31 +00:00
|
|
|
#include "jsobjinlines.h"
|
2010-12-08 01:11:37 +00:00
|
|
|
#include "jsscopeinlines.h"
|
2011-03-14 20:59:53 +00:00
|
|
|
#include "jsstrinlines.h"
|
2009-07-13 21:55:04 +00:00
|
|
|
|
2011-04-26 02:40:00 +00:00
|
|
|
#include "vm/ArgumentsObject-inl.h"
|
2012-02-23 23:39:32 +00:00
|
|
|
#include "vm/ObjectImpl-inl.h"
|
2011-04-13 16:27:37 +00:00
|
|
|
#include "vm/Stack-inl.h"
|
|
|
|
|
2011-09-23 19:13:11 +00:00
|
|
|
using namespace mozilla;
|
2010-01-22 22:49:18 +00:00
|
|
|
using namespace js;
|
2010-09-24 17:54:39 +00:00
|
|
|
using namespace js::gc;
|
2010-10-29 15:05:55 +00:00
|
|
|
using namespace js::types;
|
2010-01-22 22:49:18 +00:00
|
|
|
|
1998-04-24 00:31:11 +00:00
|
|
|
JSBool
|
2012-03-06 23:52:55 +00:00
|
|
|
js_GetLengthProperty(JSContext *cx, JSObject *obj, uint32_t *lengthp)
|
1998-04-24 00:31:11 +00:00
|
|
|
{
|
2010-03-05 04:44:09 +00:00
|
|
|
if (obj->isArray()) {
|
2010-04-06 01:32:16 +00:00
|
|
|
*lengthp = obj->getArrayLength();
|
2010-03-30 07:44:28 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2011-04-26 02:40:00 +00:00
|
|
|
if (obj->isArguments()) {
|
2012-01-02 23:02:05 +00:00
|
|
|
ArgumentsObject &argsobj = obj->asArguments();
|
|
|
|
if (!argsobj.hasOverriddenLength()) {
|
|
|
|
*lengthp = argsobj.initialLength();
|
2011-04-26 02:40:00 +00:00
|
|
|
return true;
|
|
|
|
}
|
2008-02-18 21:01:47 +00:00
|
|
|
}
|
1998-04-24 00:31:11 +00:00
|
|
|
|
2012-05-24 23:05:18 +00:00
|
|
|
RootedValue value(cx);
|
2012-05-01 00:10:30 +00:00
|
|
|
if (!obj->getProperty(cx, cx->runtime->atomState.lengthAtom, value.address()))
|
2010-03-30 07:44:28 +00:00
|
|
|
return false;
|
2009-05-29 21:57:32 +00:00
|
|
|
|
2012-05-01 00:10:30 +00:00
|
|
|
if (value.reference().isInt32()) {
|
|
|
|
*lengthp = uint32_t(value.reference().toInt32()); /* uint32_t cast does ToUint32_t */
|
2010-03-30 07:44:28 +00:00
|
|
|
return true;
|
1998-04-24 00:31:11 +00:00
|
|
|
}
|
2009-05-29 21:57:32 +00:00
|
|
|
|
2012-05-19 19:56:17 +00:00
|
|
|
|
2012-05-01 00:10:30 +00:00
|
|
|
return ToUint32(cx, value, (uint32_t *)lengthp);
|
1998-04-24 00:31:11 +00:00
|
|
|
}
|
|
|
|
|
2011-08-05 22:37:54 +00:00
|
|
|
namespace js {
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Determine if the id represents an array index or an XML property index.
|
|
|
|
*
|
|
|
|
* An id is an array index according to ECMA by (15.4):
|
|
|
|
*
|
|
|
|
* "Array objects give special treatment to a certain class of property names.
|
|
|
|
* A property name P (in the form of a string value) is an array index if and
|
|
|
|
* only if ToString(ToUint32(P)) is equal to P and ToUint32(P) is not equal
|
|
|
|
* to 2^32-1."
|
|
|
|
*
|
2011-11-16 14:00:32 +00:00
|
|
|
* This means the largest allowed index is actually 2^32-2 (4294967294).
|
|
|
|
*
|
2011-08-05 22:37:54 +00:00
|
|
|
* In our implementation, it would be sufficient to check for JSVAL_IS_INT(id)
|
|
|
|
* except that by using signed 31-bit integers we miss the top half of the
|
|
|
|
* valid range. This function checks the string representation itself; note
|
|
|
|
* that calling a standard conversion routine might allow strings such as
|
|
|
|
* "08" or "4.0" as array indices, which they are not.
|
|
|
|
*
|
|
|
|
*/
|
2011-10-13 13:36:09 +00:00
|
|
|
JS_FRIEND_API(bool)
|
2012-03-06 23:52:55 +00:00
|
|
|
StringIsArrayIndex(JSLinearString *str, uint32_t *indexp)
|
2011-08-05 22:37:54 +00:00
|
|
|
{
|
|
|
|
const jschar *s = str->chars();
|
Bug 708735 - Use <stdint.h> types in JSAPI and throughout SpiderMonkey. Continue to provide the {u,}int{8,16,32,64} and JS{Uint,Int}{8,16,32,64} integer types through a single header, however, for a simpler backout strategy -- and also to ease the transition for embedders. r=timeless on switching the jsd API to use the <stdint.h> types, r=luke, r=dmandelin
2011-12-09 03:54:10 +00:00
|
|
|
uint32_t length = str->length();
|
2011-08-05 22:37:54 +00:00
|
|
|
const jschar *end = s + length;
|
|
|
|
|
|
|
|
if (length == 0 || length > (sizeof("4294967294") - 1) || !JS7_ISDEC(*s))
|
|
|
|
return false;
|
|
|
|
|
Bug 708735 - Use <stdint.h> types in JSAPI and throughout SpiderMonkey. Continue to provide the {u,}int{8,16,32,64} and JS{Uint,Int}{8,16,32,64} integer types through a single header, however, for a simpler backout strategy -- and also to ease the transition for embedders. r=timeless on switching the jsd API to use the <stdint.h> types, r=luke, r=dmandelin
2011-12-09 03:54:10 +00:00
|
|
|
uint32_t c = 0, previous = 0;
|
|
|
|
uint32_t index = JS7_UNDEC(*s++);
|
2011-08-05 22:37:54 +00:00
|
|
|
|
|
|
|
/* Don't allow leading zeros. */
|
|
|
|
if (index == 0 && s != end)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
for (; s < end; s++) {
|
|
|
|
if (!JS7_ISDEC(*s))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
previous = index;
|
|
|
|
c = JS7_UNDEC(*s);
|
|
|
|
index = 10 * index + c;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Make sure we didn't overflow. */
|
2011-11-16 14:00:32 +00:00
|
|
|
if (previous < (MAX_ARRAY_INDEX / 10) || (previous == (MAX_ARRAY_INDEX / 10) &&
|
2011-08-05 22:37:54 +00:00
|
|
|
c <= (MAX_ARRAY_INDEX % 10))) {
|
|
|
|
JS_ASSERT(index <= MAX_ARRAY_INDEX);
|
|
|
|
*indexp = index;
|
|
|
|
return true;
|
|
|
|
}
|
2011-11-16 14:00:32 +00:00
|
|
|
|
2011-08-05 22:37:54 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
1998-04-24 00:31:11 +00:00
|
|
|
static JSBool
|
2012-03-06 23:52:55 +00:00
|
|
|
BigIndexToId(JSContext *cx, JSObject *obj, uint32_t index, JSBool createAtom,
|
2006-08-12 08:41:54 +00:00
|
|
|
jsid *idp)
|
1998-04-24 00:31:11 +00:00
|
|
|
{
|
2012-05-19 19:56:17 +00:00
|
|
|
|
2010-07-15 06:19:36 +00:00
|
|
|
JS_ASSERT(index > JSID_INT_MAX);
|
2006-08-12 08:41:54 +00:00
|
|
|
|
2011-09-03 00:23:26 +00:00
|
|
|
jschar buf[10];
|
2011-10-11 06:00:28 +00:00
|
|
|
jschar *start = ArrayEnd(buf);
|
2006-08-12 08:41:54 +00:00
|
|
|
do {
|
|
|
|
--start;
|
|
|
|
*start = (jschar)('0' + index % 10);
|
|
|
|
index /= 10;
|
|
|
|
} while (index != 0);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Skip the atomization if the class is known to store atoms corresponding
|
|
|
|
* to big indexes together with elements. In such case we know that the
|
|
|
|
* array does not have an element at the given index if its atom does not
|
2011-09-03 00:23:26 +00:00
|
|
|
* exist. Dense arrays don't use atoms for any indexes, though it would be
|
|
|
|
* rare to see them have a big index in any case.
|
2006-08-12 08:41:54 +00:00
|
|
|
*/
|
2011-09-03 00:23:26 +00:00
|
|
|
JSAtom *atom;
|
|
|
|
if (!createAtom && (obj->isSlowArray() || obj->isArguments() || obj->isObject())) {
|
2011-10-11 06:00:28 +00:00
|
|
|
atom = js_GetExistingStringAtom(cx, start, ArrayEnd(buf) - start);
|
2006-08-12 08:41:54 +00:00
|
|
|
if (!atom) {
|
2010-07-15 06:19:36 +00:00
|
|
|
*idp = JSID_VOID;
|
2006-08-12 08:41:54 +00:00
|
|
|
return JS_TRUE;
|
|
|
|
}
|
1998-03-28 02:44:41 +00:00
|
|
|
} else {
|
2011-10-11 06:00:28 +00:00
|
|
|
atom = js_AtomizeChars(cx, start, ArrayEnd(buf) - start);
|
2003-06-12 00:26:40 +00:00
|
|
|
if (!atom)
|
|
|
|
return JS_FALSE;
|
2006-08-08 23:52:08 +00:00
|
|
|
}
|
2006-08-12 08:41:54 +00:00
|
|
|
|
2012-05-06 20:45:19 +00:00
|
|
|
*idp = NON_INTEGER_ATOM_TO_JSID(atom);
|
1998-03-28 02:44:41 +00:00
|
|
|
return JS_TRUE;
|
|
|
|
}
|
|
|
|
|
2010-10-14 14:12:19 +00:00
|
|
|
bool
|
2012-02-28 23:11:11 +00:00
|
|
|
JSObject::willBeSparseDenseArray(unsigned requiredCapacity, unsigned newElementsHint)
|
2010-10-14 14:12:19 +00:00
|
|
|
{
|
|
|
|
JS_ASSERT(isDenseArray());
|
|
|
|
JS_ASSERT(requiredCapacity > MIN_SPARSE_INDEX);
|
|
|
|
|
2012-02-28 23:11:11 +00:00
|
|
|
unsigned cap = getDenseArrayCapacity();
|
2010-10-14 14:12:19 +00:00
|
|
|
JS_ASSERT(requiredCapacity >= cap);
|
|
|
|
|
2011-10-14 18:06:15 +00:00
|
|
|
if (requiredCapacity >= JSObject::NELEMENTS_LIMIT)
|
2010-10-14 14:12:19 +00:00
|
|
|
return true;
|
2011-04-11 08:38:27 +00:00
|
|
|
|
2012-02-28 23:11:11 +00:00
|
|
|
unsigned minimalDenseCount = requiredCapacity / 4;
|
2010-10-14 14:12:19 +00:00
|
|
|
if (newElementsHint >= minimalDenseCount)
|
|
|
|
return false;
|
|
|
|
minimalDenseCount -= newElementsHint;
|
|
|
|
|
|
|
|
if (minimalDenseCount > cap)
|
|
|
|
return true;
|
2011-04-11 08:38:27 +00:00
|
|
|
|
2012-02-28 23:11:11 +00:00
|
|
|
unsigned len = getDenseArrayInitializedLength();
|
2011-07-13 22:43:33 +00:00
|
|
|
const Value *elems = getDenseArrayElements();
|
2012-02-28 23:11:11 +00:00
|
|
|
for (unsigned i = 0; i < len; i++) {
|
2010-10-14 14:12:19 +00:00
|
|
|
if (!elems[i].isMagic(JS_ARRAY_HOLE) && !--minimalDenseCount)
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2009-01-12 21:07:48 +00:00
|
|
|
static bool
|
2012-02-24 22:19:52 +00:00
|
|
|
ReallyBigIndexToId(JSContext* cx, double index, jsid* idp)
|
2009-01-12 21:07:48 +00:00
|
|
|
{
|
2012-05-06 20:45:19 +00:00
|
|
|
return ValueToId(cx, DoubleValue(index), idp);
|
2009-01-12 21:07:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static bool
|
2012-02-24 22:19:52 +00:00
|
|
|
IndexToId(JSContext* cx, JSObject* obj, double index, JSBool* hole, jsid* idp,
|
2009-01-12 21:07:48 +00:00
|
|
|
JSBool createAtom = JS_FALSE)
|
|
|
|
{
|
2010-07-15 06:19:36 +00:00
|
|
|
if (index <= JSID_INT_MAX) {
|
2009-09-23 18:16:30 +00:00
|
|
|
*idp = INT_TO_JSID(int(index));
|
2009-01-12 21:07:48 +00:00
|
|
|
return JS_TRUE;
|
|
|
|
}
|
|
|
|
|
2012-03-06 23:52:55 +00:00
|
|
|
if (index <= uint32_t(-1)) {
|
|
|
|
if (!BigIndexToId(cx, obj, uint32_t(index), createAtom, idp))
|
2009-01-12 21:07:48 +00:00
|
|
|
return JS_FALSE;
|
2010-07-15 06:19:36 +00:00
|
|
|
if (hole && JSID_IS_VOID(*idp))
|
2009-01-12 21:07:48 +00:00
|
|
|
*hole = JS_TRUE;
|
|
|
|
return JS_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ReallyBigIndexToId(cx, index, idp);
|
|
|
|
}
|
|
|
|
|
2011-06-28 19:46:00 +00:00
|
|
|
bool
|
|
|
|
JSObject::arrayGetOwnDataElement(JSContext *cx, size_t i, Value *vp)
|
|
|
|
{
|
|
|
|
JS_ASSERT(isArray());
|
|
|
|
|
|
|
|
if (isDenseArray()) {
|
|
|
|
if (i >= getArrayLength())
|
|
|
|
vp->setMagic(JS_ARRAY_HOLE);
|
|
|
|
else
|
Bug 708735 - Use <stdint.h> types in JSAPI and throughout SpiderMonkey. Continue to provide the {u,}int{8,16,32,64} and JS{Uint,Int}{8,16,32,64} integer types through a single header, however, for a simpler backout strategy -- and also to ease the transition for embedders. r=timeless on switching the jsd API to use the <stdint.h> types, r=luke, r=dmandelin
2011-12-09 03:54:10 +00:00
|
|
|
*vp = getDenseArrayElement(uint32_t(i));
|
2011-06-28 19:46:00 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
JSBool hole;
|
|
|
|
jsid id;
|
|
|
|
if (!IndexToId(cx, this, i, &hole, &id))
|
|
|
|
return false;
|
|
|
|
|
2011-08-16 10:27:34 +00:00
|
|
|
const Shape *shape = nativeLookup(cx, id);
|
2011-06-28 19:46:00 +00:00
|
|
|
if (!shape || !shape->isDataDescriptor())
|
|
|
|
vp->setMagic(JS_ARRAY_HOLE);
|
|
|
|
else
|
2011-09-28 22:04:55 +00:00
|
|
|
*vp = getSlot(shape->slot());
|
2011-06-28 19:46:00 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2006-08-12 08:41:54 +00:00
|
|
|
/*
|
|
|
|
* If the property at the given index exists, get its value into location
|
|
|
|
* pointed by vp and set *hole to false. Otherwise set *hole to true and *vp
|
|
|
|
* to JSVAL_VOID. This function assumes that the location pointed by vp is
|
|
|
|
* properly rooted and can be used as GC-protected storage for temporaries.
|
|
|
|
*/
|
2011-11-04 16:18:52 +00:00
|
|
|
static inline JSBool
|
2012-05-01 00:10:30 +00:00
|
|
|
DoGetElement(JSContext *cx, JSObject *obj_, double index, JSBool *hole, Value *vp)
|
2005-07-13 16:38:46 +00:00
|
|
|
{
|
2012-05-24 23:05:18 +00:00
|
|
|
RootedObject obj(cx, obj_);
|
|
|
|
RootedId id(cx);
|
2009-01-12 21:07:48 +00:00
|
|
|
|
|
|
|
*hole = JS_FALSE;
|
2012-05-01 00:10:30 +00:00
|
|
|
if (!IndexToId(cx, obj, index, hole, id.address()))
|
2009-01-12 21:07:48 +00:00
|
|
|
return JS_FALSE;
|
|
|
|
if (*hole) {
|
2010-07-15 06:19:36 +00:00
|
|
|
vp->setUndefined();
|
2009-01-12 21:07:48 +00:00
|
|
|
return JS_TRUE;
|
2006-08-12 08:41:54 +00:00
|
|
|
}
|
|
|
|
|
2009-01-12 21:07:48 +00:00
|
|
|
JSObject *obj2;
|
|
|
|
JSProperty *prop;
|
2012-05-01 00:10:30 +00:00
|
|
|
if (!obj->lookupGeneric(cx, id, &obj2, &prop))
|
2005-07-13 16:38:46 +00:00
|
|
|
return JS_FALSE;
|
2006-08-12 08:41:54 +00:00
|
|
|
if (!prop) {
|
2010-07-15 06:19:36 +00:00
|
|
|
vp->setUndefined();
|
2011-11-04 16:18:52 +00:00
|
|
|
*hole = JS_TRUE;
|
2006-08-12 08:41:54 +00:00
|
|
|
} else {
|
2012-05-01 00:10:30 +00:00
|
|
|
if (!obj->getGeneric(cx, id, vp))
|
2006-08-12 08:41:54 +00:00
|
|
|
return JS_FALSE;
|
|
|
|
*hole = JS_FALSE;
|
|
|
|
}
|
2005-07-13 16:38:46 +00:00
|
|
|
return JS_TRUE;
|
|
|
|
}
|
|
|
|
|
2011-11-04 16:18:52 +00:00
|
|
|
static inline JSBool
|
2012-05-19 22:03:45 +00:00
|
|
|
DoGetElement(JSContext *cx, HandleObject obj, uint32_t index, JSBool *hole, Value *vp)
|
2011-11-04 16:18:52 +00:00
|
|
|
{
|
|
|
|
bool present;
|
|
|
|
if (!obj->getElementIfPresent(cx, obj, index, vp, &present))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
*hole = !present;
|
|
|
|
if (*hole)
|
|
|
|
vp->setUndefined();
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2012-03-22 05:21:16 +00:00
|
|
|
template<typename IndexType>
|
|
|
|
static void
|
|
|
|
AssertGreaterThanZero(IndexType index)
|
|
|
|
{
|
|
|
|
JS_ASSERT(index >= 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
template<>
|
|
|
|
void
|
|
|
|
AssertGreaterThanZero(uint32_t index)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2011-11-04 16:18:52 +00:00
|
|
|
template<typename IndexType>
|
|
|
|
static JSBool
|
|
|
|
GetElement(JSContext *cx, JSObject *obj, IndexType index, JSBool *hole, Value *vp)
|
|
|
|
{
|
2012-03-22 05:21:16 +00:00
|
|
|
AssertGreaterThanZero(index);
|
2011-11-04 16:18:52 +00:00
|
|
|
if (obj->isDenseArray() && index < obj->getDenseArrayInitializedLength() &&
|
Bug 708735 - Use <stdint.h> types in JSAPI and throughout SpiderMonkey. Continue to provide the {u,}int{8,16,32,64} and JS{Uint,Int}{8,16,32,64} integer types through a single header, however, for a simpler backout strategy -- and also to ease the transition for embedders. r=timeless on switching the jsd API to use the <stdint.h> types, r=luke, r=dmandelin
2011-12-09 03:54:10 +00:00
|
|
|
!(*vp = obj->getDenseArrayElement(uint32_t(index))).isMagic(JS_ARRAY_HOLE)) {
|
2011-11-04 16:18:52 +00:00
|
|
|
*hole = JS_FALSE;
|
|
|
|
return JS_TRUE;
|
|
|
|
}
|
|
|
|
if (obj->isArguments()) {
|
2012-02-23 21:59:10 +00:00
|
|
|
if (obj->asArguments().maybeGetElement(uint32_t(index), vp)) {
|
2011-11-04 16:18:52 +00:00
|
|
|
*hole = JS_FALSE;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return DoGetElement(cx, obj, index, hole, vp);
|
|
|
|
}
|
|
|
|
|
2010-10-21 06:52:55 +00:00
|
|
|
namespace js {
|
|
|
|
|
2011-04-26 02:40:00 +00:00
|
|
|
static bool
|
2012-05-01 00:10:30 +00:00
|
|
|
GetElementsSlow(JSContext *cx, HandleObject aobj, uint32_t length, Value *vp)
|
2011-04-26 02:40:00 +00:00
|
|
|
{
|
Bug 708735 - Use <stdint.h> types in JSAPI and throughout SpiderMonkey. Continue to provide the {u,}int{8,16,32,64} and JS{Uint,Int}{8,16,32,64} integer types through a single header, however, for a simpler backout strategy -- and also to ease the transition for embedders. r=timeless on switching the jsd API to use the <stdint.h> types, r=luke, r=dmandelin
2011-12-09 03:54:10 +00:00
|
|
|
for (uint32_t i = 0; i < length; i++) {
|
2011-08-10 21:54:52 +00:00
|
|
|
if (!aobj->getElement(cx, i, &vp[i]))
|
2011-04-26 02:40:00 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2010-10-21 06:52:55 +00:00
|
|
|
bool
|
2012-05-01 00:10:30 +00:00
|
|
|
GetElements(JSContext *cx, HandleObject aobj, uint32_t length, Value *vp)
|
2010-10-21 06:52:55 +00:00
|
|
|
{
|
2011-03-10 17:56:51 +00:00
|
|
|
if (aobj->isDenseArray() && length <= aobj->getDenseArrayInitializedLength() &&
|
2010-11-09 17:06:57 +00:00
|
|
|
!js_PrototypeHasIndexedProperties(cx, aobj)) {
|
|
|
|
/* The prototype does not have indexed properties so hole = undefined */
|
2011-07-13 22:43:33 +00:00
|
|
|
const Value *srcbeg = aobj->getDenseArrayElements();
|
|
|
|
const Value *srcend = srcbeg + length;
|
|
|
|
const Value *src = srcbeg;
|
|
|
|
for (Value *dst = vp; src < srcend; ++dst, ++src)
|
2010-10-21 06:52:55 +00:00
|
|
|
*dst = src->isMagic(JS_ARRAY_HOLE) ? UndefinedValue() : *src;
|
2011-04-26 02:40:00 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (aobj->isArguments()) {
|
2012-01-02 23:02:05 +00:00
|
|
|
ArgumentsObject &argsobj = aobj->asArguments();
|
|
|
|
if (!argsobj.hasOverriddenLength()) {
|
2012-02-23 21:59:10 +00:00
|
|
|
if (argsobj.maybeGetElements(0, length, vp))
|
2011-04-26 02:40:00 +00:00
|
|
|
return true;
|
2010-10-21 06:52:55 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-04-26 02:40:00 +00:00
|
|
|
return GetElementsSlow(cx, aobj, length, vp);
|
2010-10-21 06:52:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2006-08-12 08:41:54 +00:00
|
|
|
/*
|
|
|
|
* Set the value of the property at the given index to v assuming v is rooted.
|
|
|
|
*/
|
|
|
|
static JSBool
|
2012-04-12 16:23:51 +00:00
|
|
|
SetArrayElement(JSContext *cx, HandleObject obj, double index, const Value &v)
|
2006-08-12 08:41:54 +00:00
|
|
|
{
|
2009-01-12 21:07:48 +00:00
|
|
|
JS_ASSERT(index >= 0);
|
2006-08-12 08:41:54 +00:00
|
|
|
|
2010-03-05 04:44:09 +00:00
|
|
|
if (obj->isDenseArray()) {
|
2009-01-12 21:07:48 +00:00
|
|
|
/* Predicted/prefetched code should favor the remains-dense case. */
|
2010-10-14 14:12:19 +00:00
|
|
|
JSObject::EnsureDenseResult result = JSObject::ED_SPARSE;
|
|
|
|
do {
|
2012-03-06 23:52:55 +00:00
|
|
|
if (index > uint32_t(-1))
|
2010-10-14 14:12:19 +00:00
|
|
|
break;
|
2012-03-06 23:52:55 +00:00
|
|
|
uint32_t idx = uint32_t(index);
|
2010-10-14 14:12:19 +00:00
|
|
|
result = obj->ensureDenseArrayElements(cx, idx, 1);
|
|
|
|
if (result != JSObject::ED_OK)
|
|
|
|
break;
|
|
|
|
if (idx >= obj->getArrayLength())
|
2011-03-03 22:07:48 +00:00
|
|
|
obj->setDenseArrayLength(idx + 1);
|
2011-05-16 23:15:37 +00:00
|
|
|
obj->setDenseArrayElementWithType(cx, idx, v);
|
2010-10-14 14:12:19 +00:00
|
|
|
return true;
|
|
|
|
} while (false);
|
Kind of an Array initialiser tour-de-force for bug 452878:
1. Split FastNewArray from FastNewObject built-in for greater speed/specialization and further splitting into Array_1str, etc.
2. Add Array_1str, Array_2obj, and Array_3num builtins for benchmarked new Array(...) constructions.
3. Export ARRAY_SET_DENSE_LENGTH and ARRAY_GROWBY via jsarray.h to jstracer.cpp.
4. Tweaked SetArrayElement to make common/best case code be the predicted/prefetched path.
5. js_MakeArraySlow now preserves the pre-slow length in JSSLOT_ARRAY_COUTN as a jsval-tagged int if possible -- this will help the tracer avoid aborting on dense arrays that turned slow but not sparse by addition of a named property.
6. Export js_fun_apply and js_Object from their respective .cpp files, in these cases just to jstracer.cpp via local prototypes (no .h files involved).
7. More INS_CONSTPTR and INS_CONST macrology for better names in trace debug spew.
8. Fix TraceRecorder::test_property_cache to avoid aborting on JSOP_SETNAME that creates a new global, by setting it to undefined so it can be lazily imported. This helps 3d-raytrace.js, which has an unintended global loop control variable in a function.
9. JSTraceableNative loses its premature-deadwood tclasp member (my bad).
10. TraceRecorder::record_JSOP_NEW() handles 'new Object' now along with the 'new Array' variations. I also cut down the copy-paste code from JSOP_CALL's record method to mostly what is needed now.
11. Add KNOWN_NATIVE_DECL macro for concise prototype of library-private js_* native functions, and alphabetized the lists (too long for any other order to be winning).
12. Big honking special case for foo.apply(obj, [str]), which we can generalize as needed. Helps string-tagcloud.js. What's cool is how tracing allows us to rewrite this to foo(str) with this set to obj, eliminating the Function.prototype.apply. This requires some rewriting in JSOP_ENDINIT's record method.
2008-09-01 08:24:58 +00:00
|
|
|
|
2010-10-14 14:12:19 +00:00
|
|
|
if (result == JSObject::ED_FAILED)
|
|
|
|
return false;
|
|
|
|
JS_ASSERT(result == JSObject::ED_SPARSE);
|
2012-04-12 16:23:51 +00:00
|
|
|
if (!JSObject::makeDenseArraySlow(cx, obj))
|
Kind of an Array initialiser tour-de-force for bug 452878:
1. Split FastNewArray from FastNewObject built-in for greater speed/specialization and further splitting into Array_1str, etc.
2. Add Array_1str, Array_2obj, and Array_3num builtins for benchmarked new Array(...) constructions.
3. Export ARRAY_SET_DENSE_LENGTH and ARRAY_GROWBY via jsarray.h to jstracer.cpp.
4. Tweaked SetArrayElement to make common/best case code be the predicted/prefetched path.
5. js_MakeArraySlow now preserves the pre-slow length in JSSLOT_ARRAY_COUTN as a jsval-tagged int if possible -- this will help the tracer avoid aborting on dense arrays that turned slow but not sparse by addition of a named property.
6. Export js_fun_apply and js_Object from their respective .cpp files, in these cases just to jstracer.cpp via local prototypes (no .h files involved).
7. More INS_CONSTPTR and INS_CONST macrology for better names in trace debug spew.
8. Fix TraceRecorder::test_property_cache to avoid aborting on JSOP_SETNAME that creates a new global, by setting it to undefined so it can be lazily imported. This helps 3d-raytrace.js, which has an unintended global loop control variable in a function.
9. JSTraceableNative loses its premature-deadwood tclasp member (my bad).
10. TraceRecorder::record_JSOP_NEW() handles 'new Object' now along with the 'new Array' variations. I also cut down the copy-paste code from JSOP_CALL's record method to mostly what is needed now.
11. Add KNOWN_NATIVE_DECL macro for concise prototype of library-private js_* native functions, and alphabetized the lists (too long for any other order to be winning).
12. Big honking special case for foo.apply(obj, [str]), which we can generalize as needed. Helps string-tagcloud.js. What's cool is how tracing allows us to rewrite this to foo(str) with this set to obj, eliminating the Function.prototype.apply. This requires some rewriting in JSOP_ENDINIT's record method.
2008-09-01 08:24:58 +00:00
|
|
|
return JS_FALSE;
|
2008-02-18 21:01:47 +00:00
|
|
|
}
|
|
|
|
|
2012-05-24 23:05:18 +00:00
|
|
|
RootedId id(cx);
|
2009-01-12 21:07:48 +00:00
|
|
|
|
2012-05-19 22:03:45 +00:00
|
|
|
if (!IndexToId(cx, obj, index, NULL, id.address(), JS_TRUE))
|
2009-01-12 21:07:48 +00:00
|
|
|
return JS_FALSE;
|
2012-05-19 22:03:45 +00:00
|
|
|
JS_ASSERT(!JSID_IS_VOID(id));
|
2009-01-12 21:07:48 +00:00
|
|
|
|
2012-05-24 23:05:18 +00:00
|
|
|
RootedValue tmp(cx, v);
|
2012-05-19 22:03:45 +00:00
|
|
|
return obj->setGeneric(cx, id, tmp.address(), true);
|
2006-08-12 08:41:54 +00:00
|
|
|
}
|
2005-10-02 06:27:07 +00:00
|
|
|
|
2011-02-09 19:31:40 +00:00
|
|
|
/*
|
|
|
|
* Delete the element |index| from |obj|. If |strict|, do a strict
|
|
|
|
* deletion: throw if the property is not configurable.
|
|
|
|
*
|
|
|
|
* - Return 1 if the deletion succeeds (that is, ES5's [[Delete]] would
|
|
|
|
* return true)
|
|
|
|
*
|
|
|
|
* - Return 0 if the deletion fails because the property is not
|
|
|
|
* configurable (that is, [[Delete]] would return false). Note that if
|
|
|
|
* |strict| is true we will throw, not return zero.
|
|
|
|
*
|
|
|
|
* - Return -1 if an exception occurs (that is, [[Delete]] would throw).
|
|
|
|
*/
|
|
|
|
static int
|
2012-04-12 16:23:51 +00:00
|
|
|
DeleteArrayElement(JSContext *cx, HandleObject obj, double index, bool strict)
|
2005-10-02 06:27:07 +00:00
|
|
|
{
|
2009-01-12 21:07:48 +00:00
|
|
|
JS_ASSERT(index >= 0);
|
2011-12-28 22:33:20 +00:00
|
|
|
JS_ASSERT(floor(index) == index);
|
|
|
|
|
2010-03-05 04:44:09 +00:00
|
|
|
if (obj->isDenseArray()) {
|
2011-12-28 22:33:20 +00:00
|
|
|
if (index <= UINT32_MAX) {
|
|
|
|
uint32_t idx = uint32_t(index);
|
2010-11-05 14:37:09 +00:00
|
|
|
if (idx < obj->getDenseArrayInitializedLength()) {
|
2011-06-01 18:15:51 +00:00
|
|
|
obj->markDenseArrayNotPacked(cx);
|
2010-07-15 06:19:36 +00:00
|
|
|
obj->setDenseArrayElement(idx, MagicValue(JS_ARRAY_HOLE));
|
2011-09-23 19:13:11 +00:00
|
|
|
if (!js_SuppressDeletedElement(cx, obj, idx))
|
2011-02-09 19:31:40 +00:00
|
|
|
return -1;
|
2009-01-12 21:07:48 +00:00
|
|
|
}
|
2008-02-18 21:01:47 +00:00
|
|
|
}
|
2011-02-09 19:31:40 +00:00
|
|
|
return 1;
|
2008-02-18 21:01:47 +00:00
|
|
|
}
|
|
|
|
|
2011-02-09 19:31:40 +00:00
|
|
|
Value v;
|
2011-12-28 22:33:20 +00:00
|
|
|
if (index <= UINT32_MAX) {
|
|
|
|
if (!obj->deleteElement(cx, uint32_t(index), &v, strict))
|
|
|
|
return -1;
|
|
|
|
} else {
|
|
|
|
if (!obj->deleteByValue(cx, DoubleValue(index), &v, strict))
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2011-02-09 19:31:40 +00:00
|
|
|
return v.isTrue() ? 1 : 0;
|
2006-08-12 08:41:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* When hole is true, delete the property at the given index. Otherwise set
|
|
|
|
* its value to v assuming v is rooted.
|
|
|
|
*/
|
|
|
|
static JSBool
|
2012-04-12 16:23:51 +00:00
|
|
|
SetOrDeleteArrayElement(JSContext *cx, HandleObject obj, double index,
|
2010-07-15 06:19:36 +00:00
|
|
|
JSBool hole, const Value &v)
|
2006-08-12 08:41:54 +00:00
|
|
|
{
|
|
|
|
if (hole) {
|
2010-07-15 06:19:36 +00:00
|
|
|
JS_ASSERT(v.isUndefined());
|
2011-02-09 19:31:40 +00:00
|
|
|
return DeleteArrayElement(cx, obj, index, true) >= 0;
|
2006-08-12 08:41:54 +00:00
|
|
|
}
|
2008-02-18 21:01:47 +00:00
|
|
|
return SetArrayElement(cx, obj, index, v);
|
2006-08-08 20:25:30 +00:00
|
|
|
}
|
|
|
|
|
1998-04-24 00:31:11 +00:00
|
|
|
JSBool
|
2012-02-24 22:19:52 +00:00
|
|
|
js_SetLengthProperty(JSContext *cx, JSObject *obj, double length)
|
1998-03-28 02:44:41 +00:00
|
|
|
{
|
2011-10-06 00:16:25 +00:00
|
|
|
Value v = NumberValue(length);
|
1998-03-28 02:44:41 +00:00
|
|
|
|
2010-09-15 20:43:55 +00:00
|
|
|
/* We don't support read-only array length yet. */
|
2011-10-06 00:16:25 +00:00
|
|
|
return obj->setProperty(cx, cx->runtime->atomState.lengthAtom, &v, false);
|
1998-03-28 02:44:41 +00:00
|
|
|
}
|
|
|
|
|
1998-04-24 00:31:11 +00:00
|
|
|
/*
|
2007-08-02 20:36:53 +00:00
|
|
|
* Since SpiderMonkey supports cross-class prototype-based delegation, we have
|
|
|
|
* to be careful about the length getter and setter being called on an object
|
|
|
|
* not of Array class. For the getter, we search obj's prototype chain for the
|
|
|
|
* array that caused this getter to be invoked. In the setter case to overcome
|
|
|
|
* the JSPROP_SHARED attribute, we must define a shadowing length property.
|
1998-04-24 00:31:11 +00:00
|
|
|
*/
|
|
|
|
static JSBool
|
2012-05-19 22:03:45 +00:00
|
|
|
array_length_getter(JSContext *cx, HandleObject obj_, HandleId id, Value *vp)
|
1998-04-24 00:31:11 +00:00
|
|
|
{
|
2012-05-19 22:03:45 +00:00
|
|
|
JSObject *obj = obj_;
|
2007-08-02 20:36:53 +00:00
|
|
|
do {
|
2010-07-15 06:19:36 +00:00
|
|
|
if (obj->isArray()) {
|
|
|
|
vp->setNumber(obj->getArrayLength());
|
|
|
|
return JS_TRUE;
|
|
|
|
}
|
2010-03-05 04:44:09 +00:00
|
|
|
} while ((obj = obj->getProto()) != NULL);
|
2007-08-02 04:33:52 +00:00
|
|
|
return JS_TRUE;
|
1998-03-28 02:44:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static JSBool
|
2012-05-19 22:03:45 +00:00
|
|
|
array_length_setter(JSContext *cx, HandleObject obj, HandleId id, JSBool strict, Value *vp)
|
1998-03-28 02:44:41 +00:00
|
|
|
{
|
2010-03-05 04:44:09 +00:00
|
|
|
if (!obj->isArray()) {
|
2011-10-05 08:00:23 +00:00
|
|
|
return obj->defineProperty(cx, cx->runtime->atomState.lengthAtom, *vp,
|
|
|
|
NULL, NULL, JSPROP_ENUMERATE);
|
2007-08-02 20:36:53 +00:00
|
|
|
}
|
|
|
|
|
Bug 708735 - Use <stdint.h> types in JSAPI and throughout SpiderMonkey. Continue to provide the {u,}int{8,16,32,64} and JS{Uint,Int}{8,16,32,64} integer types through a single header, however, for a simpler backout strategy -- and also to ease the transition for embedders. r=timeless on switching the jsd API to use the <stdint.h> types, r=luke, r=dmandelin
2011-12-09 03:54:10 +00:00
|
|
|
uint32_t newlen;
|
2011-12-05 22:10:02 +00:00
|
|
|
if (!ToUint32(cx, *vp, &newlen))
|
2011-06-28 17:05:53 +00:00
|
|
|
return false;
|
|
|
|
|
2012-02-24 22:19:52 +00:00
|
|
|
double d;
|
2011-06-14 04:49:59 +00:00
|
|
|
if (!ToNumber(cx, *vp, &d))
|
2010-01-11 17:52:21 +00:00
|
|
|
return false;
|
2010-12-14 00:22:59 +00:00
|
|
|
|
2011-06-28 17:05:53 +00:00
|
|
|
if (d != newlen) {
|
|
|
|
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_ARRAY_LENGTH);
|
|
|
|
return false;
|
|
|
|
}
|
2008-02-18 21:01:47 +00:00
|
|
|
|
Bug 708735 - Use <stdint.h> types in JSAPI and throughout SpiderMonkey. Continue to provide the {u,}int{8,16,32,64} and JS{Uint,Int}{8,16,32,64} integer types through a single header, however, for a simpler backout strategy -- and also to ease the transition for embedders. r=timeless on switching the jsd API to use the <stdint.h> types, r=luke, r=dmandelin
2011-12-09 03:54:10 +00:00
|
|
|
uint32_t oldlen = obj->getArrayLength();
|
2008-02-18 21:01:47 +00:00
|
|
|
if (oldlen == newlen)
|
2010-01-11 17:52:21 +00:00
|
|
|
return true;
|
2008-03-02 17:45:33 +00:00
|
|
|
|
2010-07-15 06:19:36 +00:00
|
|
|
vp->setNumber(newlen);
|
2011-05-16 23:15:37 +00:00
|
|
|
if (oldlen < newlen) {
|
|
|
|
obj->setArrayLength(cx, newlen);
|
|
|
|
return true;
|
|
|
|
}
|
2008-02-18 21:01:47 +00:00
|
|
|
|
2010-03-05 04:44:09 +00:00
|
|
|
if (obj->isDenseArray()) {
|
2010-07-23 01:45:21 +00:00
|
|
|
/*
|
|
|
|
* Don't reallocate if we're not actually shrinking our slots. If we do
|
2010-11-05 14:37:09 +00:00
|
|
|
* shrink slots here, shrink the initialized length too. This permits us
|
|
|
|
* us to disregard length when reading from arrays as long we are within
|
|
|
|
* the initialized capacity.
|
2010-07-23 01:45:21 +00:00
|
|
|
*/
|
2012-03-06 23:52:55 +00:00
|
|
|
uint32_t oldcap = obj->getDenseArrayCapacity();
|
|
|
|
uint32_t oldinit = obj->getDenseArrayInitializedLength();
|
2011-10-10 18:41:03 +00:00
|
|
|
if (oldinit > newlen)
|
2010-11-05 14:37:09 +00:00
|
|
|
obj->setDenseArrayInitializedLength(newlen);
|
2011-10-25 23:07:42 +00:00
|
|
|
if (oldcap > newlen)
|
2011-11-14 17:13:33 +00:00
|
|
|
obj->shrinkElements(cx, newlen);
|
2008-02-18 21:01:47 +00:00
|
|
|
} else if (oldlen - newlen < (1 << 24)) {
|
|
|
|
do {
|
|
|
|
--oldlen;
|
2010-09-15 20:43:55 +00:00
|
|
|
if (!JS_CHECK_OPERATION_LIMIT(cx)) {
|
2011-05-16 23:15:37 +00:00
|
|
|
obj->setArrayLength(cx, oldlen + 1);
|
2010-01-11 17:52:21 +00:00
|
|
|
return false;
|
2010-09-15 20:43:55 +00:00
|
|
|
}
|
2011-02-09 19:31:40 +00:00
|
|
|
int deletion = DeleteArrayElement(cx, obj, oldlen, strict);
|
|
|
|
if (deletion <= 0) {
|
2011-05-16 23:15:37 +00:00
|
|
|
obj->setArrayLength(cx, oldlen + 1);
|
2011-02-09 19:31:40 +00:00
|
|
|
return deletion >= 0;
|
2010-09-15 20:43:55 +00:00
|
|
|
}
|
2008-02-18 21:01:47 +00:00
|
|
|
} while (oldlen != newlen);
|
|
|
|
} else {
|
|
|
|
/*
|
|
|
|
* We are going to remove a lot of indexes in a presumably sparse
|
|
|
|
* array. So instead of looping through indexes between newlen and
|
|
|
|
* oldlen, we iterate through all properties and remove those that
|
|
|
|
* correspond to indexes in the half-open range [newlen, oldlen). See
|
|
|
|
* bug 322135.
|
|
|
|
*/
|
2010-01-11 17:52:21 +00:00
|
|
|
JSObject *iter = JS_NewPropertyIterator(cx, obj);
|
2008-02-18 21:01:47 +00:00
|
|
|
if (!iter)
|
2010-01-11 17:52:21 +00:00
|
|
|
return false;
|
2008-03-02 17:45:33 +00:00
|
|
|
|
2012-03-06 23:52:55 +00:00
|
|
|
uint32_t gap = oldlen - newlen;
|
2008-02-18 21:01:47 +00:00
|
|
|
for (;;) {
|
2012-05-19 22:03:45 +00:00
|
|
|
jsid nid;
|
|
|
|
if (!JS_CHECK_OPERATION_LIMIT(cx) || !JS_NextProperty(cx, iter, &nid))
|
2010-03-29 07:02:13 +00:00
|
|
|
return false;
|
2012-05-19 22:03:45 +00:00
|
|
|
if (JSID_IS_VOID(nid))
|
2008-02-18 21:01:47 +00:00
|
|
|
break;
|
2012-03-06 23:52:55 +00:00
|
|
|
uint32_t index;
|
2011-06-28 17:05:53 +00:00
|
|
|
Value junk;
|
2012-05-19 22:03:45 +00:00
|
|
|
if (js_IdIsIndex(nid, &index) && index - newlen < gap &&
|
2011-10-05 00:49:57 +00:00
|
|
|
!obj->deleteElement(cx, index, &junk, false)) {
|
2010-03-29 07:02:13 +00:00
|
|
|
return false;
|
2006-07-01 19:58:44 +00:00
|
|
|
}
|
|
|
|
}
|
2008-02-18 21:01:47 +00:00
|
|
|
}
|
|
|
|
|
2011-05-16 23:15:37 +00:00
|
|
|
obj->setArrayLength(cx, newlen);
|
|
|
|
return true;
|
2008-02-18 21:01:47 +00:00
|
|
|
}
|
|
|
|
|
2011-08-10 21:54:52 +00:00
|
|
|
/* Returns true if the dense array has an own property at the index. */
|
|
|
|
static inline bool
|
Bug 708735 - Use <stdint.h> types in JSAPI and throughout SpiderMonkey. Continue to provide the {u,}int{8,16,32,64} and JS{Uint,Int}{8,16,32,64} integer types through a single header, however, for a simpler backout strategy -- and also to ease the transition for embedders. r=timeless on switching the jsd API to use the <stdint.h> types, r=luke, r=dmandelin
2011-12-09 03:54:10 +00:00
|
|
|
IsDenseArrayIndex(JSObject *obj, uint32_t index)
|
2011-08-10 21:54:52 +00:00
|
|
|
{
|
|
|
|
JS_ASSERT(obj->isDenseArray());
|
|
|
|
|
|
|
|
return index < obj->getDenseArrayInitializedLength() &&
|
|
|
|
!obj->getDenseArrayElement(index).isMagic(JS_ARRAY_HOLE);
|
|
|
|
}
|
|
|
|
|
2009-04-17 09:37:59 +00:00
|
|
|
/*
|
2010-11-05 14:37:09 +00:00
|
|
|
* We have only indexed properties up to initialized length, plus the
|
2009-04-17 09:37:59 +00:00
|
|
|
* length property. For all else, we delegate to the prototype.
|
|
|
|
*/
|
|
|
|
static inline bool
|
|
|
|
IsDenseArrayId(JSContext *cx, JSObject *obj, jsid id)
|
|
|
|
{
|
2010-03-05 04:44:09 +00:00
|
|
|
JS_ASSERT(obj->isDenseArray());
|
2009-04-17 09:37:59 +00:00
|
|
|
|
Bug 708735 - Use <stdint.h> types in JSAPI and throughout SpiderMonkey. Continue to provide the {u,}int{8,16,32,64} and JS{Uint,Int}{8,16,32,64} integer types through a single header, however, for a simpler backout strategy -- and also to ease the transition for embedders. r=timeless on switching the jsd API to use the <stdint.h> types, r=luke, r=dmandelin
2011-12-09 03:54:10 +00:00
|
|
|
uint32_t i;
|
2010-07-15 06:19:36 +00:00
|
|
|
return JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom) ||
|
2011-08-10 21:54:52 +00:00
|
|
|
(js_IdIsIndex(id, &i) && IsDenseArrayIndex(obj, i));
|
2009-04-17 09:37:59 +00:00
|
|
|
}
|
|
|
|
|
2008-02-18 21:01:47 +00:00
|
|
|
static JSBool
|
2012-05-19 22:03:45 +00:00
|
|
|
array_lookupGeneric(JSContext *cx, HandleObject obj, HandleId id, JSObject **objp,
|
2011-10-08 22:45:04 +00:00
|
|
|
JSProperty **propp)
|
2008-02-18 21:01:47 +00:00
|
|
|
{
|
2010-03-05 04:44:09 +00:00
|
|
|
if (!obj->isDenseArray())
|
2012-05-19 22:03:45 +00:00
|
|
|
return baseops::LookupProperty(cx, obj, id, objp, propp);
|
2008-02-18 21:01:47 +00:00
|
|
|
|
2009-04-17 09:37:59 +00:00
|
|
|
if (IsDenseArrayId(cx, obj, id)) {
|
2010-07-15 06:19:36 +00:00
|
|
|
*propp = (JSProperty *) 1; /* non-null to indicate found */
|
2009-04-17 09:37:59 +00:00
|
|
|
*objp = obj;
|
|
|
|
return JS_TRUE;
|
2008-02-15 09:48:53 +00:00
|
|
|
}
|
2008-02-18 21:01:47 +00:00
|
|
|
|
2010-03-05 04:44:09 +00:00
|
|
|
JSObject *proto = obj->getProto();
|
2009-04-17 09:37:59 +00:00
|
|
|
if (!proto) {
|
|
|
|
*objp = NULL;
|
|
|
|
*propp = NULL;
|
|
|
|
return JS_TRUE;
|
|
|
|
}
|
2011-10-08 22:45:04 +00:00
|
|
|
return proto->lookupGeneric(cx, id, objp, propp);
|
|
|
|
}
|
|
|
|
|
|
|
|
static JSBool
|
2012-05-19 22:03:45 +00:00
|
|
|
array_lookupProperty(JSContext *cx, HandleObject obj, HandlePropertyName name, JSObject **objp,
|
2011-10-08 22:45:04 +00:00
|
|
|
JSProperty **propp)
|
|
|
|
{
|
2012-05-24 23:05:18 +00:00
|
|
|
return array_lookupGeneric(cx, obj, RootedId(cx, NameToId(name)), objp, propp);
|
2008-02-18 21:01:47 +00:00
|
|
|
}
|
|
|
|
|
2011-08-10 21:54:51 +00:00
|
|
|
static JSBool
|
2012-05-19 22:03:45 +00:00
|
|
|
array_lookupElement(JSContext *cx, HandleObject obj, uint32_t index, JSObject **objp,
|
2011-08-10 21:54:51 +00:00
|
|
|
JSProperty **propp)
|
|
|
|
{
|
2011-08-10 21:54:52 +00:00
|
|
|
if (!obj->isDenseArray())
|
2012-05-19 22:03:45 +00:00
|
|
|
return baseops::LookupElement(cx, obj, index, objp, propp);
|
2011-08-10 21:54:52 +00:00
|
|
|
|
|
|
|
if (IsDenseArrayIndex(obj, index)) {
|
|
|
|
*propp = (JSProperty *) 1; /* non-null to indicate found */
|
|
|
|
*objp = obj;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (JSObject *proto = obj->getProto())
|
|
|
|
return proto->lookupElement(cx, index, objp, propp);
|
|
|
|
|
|
|
|
*objp = NULL;
|
|
|
|
*propp = NULL;
|
|
|
|
return true;
|
2011-08-10 21:54:51 +00:00
|
|
|
}
|
|
|
|
|
2011-08-12 18:26:48 +00:00
|
|
|
static JSBool
|
2012-05-19 22:03:45 +00:00
|
|
|
array_lookupSpecial(JSContext *cx, HandleObject obj, HandleSpecialId sid, JSObject **objp,
|
2011-08-12 18:26:48 +00:00
|
|
|
JSProperty **propp)
|
|
|
|
{
|
2012-05-24 23:05:18 +00:00
|
|
|
return array_lookupGeneric(cx, obj, RootedId(cx, SPECIALID_TO_JSID(sid)), objp, propp);
|
2011-08-12 18:26:48 +00:00
|
|
|
}
|
|
|
|
|
2009-04-17 09:37:59 +00:00
|
|
|
JSBool
|
2010-07-15 06:19:36 +00:00
|
|
|
js_GetDenseArrayElementValue(JSContext *cx, JSObject *obj, jsid id, Value *vp)
|
2009-03-31 19:42:31 +00:00
|
|
|
{
|
2010-07-15 06:19:36 +00:00
|
|
|
JS_ASSERT(obj->isDenseArray());
|
2009-04-17 09:37:59 +00:00
|
|
|
|
Bug 708735 - Use <stdint.h> types in JSAPI and throughout SpiderMonkey. Continue to provide the {u,}int{8,16,32,64} and JS{Uint,Int}{8,16,32,64} integer types through a single header, however, for a simpler backout strategy -- and also to ease the transition for embedders. r=timeless on switching the jsd API to use the <stdint.h> types, r=luke, r=dmandelin
2011-12-09 03:54:10 +00:00
|
|
|
uint32_t i;
|
2009-04-17 09:37:59 +00:00
|
|
|
if (!js_IdIsIndex(id, &i)) {
|
2010-07-15 06:19:36 +00:00
|
|
|
JS_ASSERT(JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom));
|
|
|
|
vp->setNumber(obj->getArrayLength());
|
|
|
|
return JS_TRUE;
|
2009-04-17 09:37:59 +00:00
|
|
|
}
|
2010-04-27 01:33:36 +00:00
|
|
|
*vp = obj->getDenseArrayElement(i);
|
2009-04-17 09:37:59 +00:00
|
|
|
return JS_TRUE;
|
2009-03-31 19:42:31 +00:00
|
|
|
}
|
|
|
|
|
2008-02-18 21:01:47 +00:00
|
|
|
static JSBool
|
2012-05-19 22:03:45 +00:00
|
|
|
array_getProperty(JSContext *cx, HandleObject obj, HandleObject receiver, HandlePropertyName name, Value *vp)
|
2008-02-18 21:01:47 +00:00
|
|
|
{
|
2011-09-15 18:44:10 +00:00
|
|
|
if (name == cx->runtime->atomState.lengthAtom) {
|
2010-07-15 06:19:36 +00:00
|
|
|
vp->setNumber(obj->getArrayLength());
|
2011-09-15 18:44:10 +00:00
|
|
|
return true;
|
2010-07-15 06:19:36 +00:00
|
|
|
}
|
2008-02-18 21:01:47 +00:00
|
|
|
|
2011-09-15 18:44:10 +00:00
|
|
|
if (name == cx->runtime->atomState.protoAtom) {
|
2010-07-15 06:19:36 +00:00
|
|
|
vp->setObjectOrNull(obj->getProto());
|
2011-09-15 18:44:10 +00:00
|
|
|
return true;
|
2008-02-18 21:01:47 +00:00
|
|
|
}
|
|
|
|
|
2010-03-05 04:44:09 +00:00
|
|
|
if (!obj->isDenseArray())
|
2012-05-24 23:05:18 +00:00
|
|
|
return baseops::GetProperty(cx, obj, receiver, RootedId(cx, NameToId(name)), vp);
|
2008-02-18 21:01:47 +00:00
|
|
|
|
2011-09-15 18:44:10 +00:00
|
|
|
JSObject *proto = obj->getProto();
|
|
|
|
if (!proto) {
|
|
|
|
vp->setUndefined();
|
|
|
|
return true;
|
2008-02-18 21:01:47 +00:00
|
|
|
}
|
|
|
|
|
2011-09-15 18:44:10 +00:00
|
|
|
return proto->getProperty(cx, receiver, name, vp);
|
2011-09-15 18:44:10 +00:00
|
|
|
}
|
|
|
|
|
2011-08-10 21:54:51 +00:00
|
|
|
static JSBool
|
2012-05-19 22:03:45 +00:00
|
|
|
array_getElement(JSContext *cx, HandleObject obj, HandleObject receiver, uint32_t index, Value *vp)
|
2011-08-10 21:54:51 +00:00
|
|
|
{
|
2011-08-10 21:54:52 +00:00
|
|
|
if (!obj->isDenseArray())
|
2012-05-19 22:03:45 +00:00
|
|
|
return baseops::GetElement(cx, obj, receiver, index, vp);
|
2011-08-10 21:54:52 +00:00
|
|
|
|
2011-09-15 18:44:10 +00:00
|
|
|
if (index < obj->getDenseArrayInitializedLength()) {
|
2011-08-10 21:54:52 +00:00
|
|
|
*vp = obj->getDenseArrayElement(index);
|
2011-09-15 18:44:10 +00:00
|
|
|
if (!vp->isMagic(JS_ARRAY_HOLE)) {
|
|
|
|
/* Type information for dense array elements must be correct. */
|
|
|
|
JS_ASSERT_IF(!obj->hasSingletonType(),
|
|
|
|
js::types::TypeHasProperty(cx, obj->type(), JSID_VOID, *vp));
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
2011-08-10 21:54:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
JSObject *proto = obj->getProto();
|
|
|
|
if (!proto) {
|
|
|
|
vp->setUndefined();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2011-11-04 16:26:03 +00:00
|
|
|
return proto->getElement(cx, receiver, index, vp);
|
2011-08-10 21:54:51 +00:00
|
|
|
}
|
|
|
|
|
2011-08-12 18:26:48 +00:00
|
|
|
static JSBool
|
2012-05-19 22:03:45 +00:00
|
|
|
array_getSpecial(JSContext *cx, HandleObject obj, HandleObject receiver, HandleSpecialId sid, Value *vp)
|
2011-08-12 18:26:48 +00:00
|
|
|
{
|
2011-09-15 18:44:10 +00:00
|
|
|
if (obj->isDenseArray() && !obj->getProto()) {
|
|
|
|
vp->setUndefined();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2012-05-24 23:05:18 +00:00
|
|
|
return baseops::GetProperty(cx, obj, receiver, RootedId(cx, SPECIALID_TO_JSID(sid)), vp);
|
2011-09-15 18:44:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static JSBool
|
2012-05-19 22:03:45 +00:00
|
|
|
array_getGeneric(JSContext *cx, HandleObject obj, HandleObject receiver, HandleId id, Value *vp)
|
2011-09-15 18:44:10 +00:00
|
|
|
{
|
|
|
|
Value idval = IdToValue(id);
|
|
|
|
|
|
|
|
uint32_t index;
|
|
|
|
if (IsDefinitelyIndex(idval, &index))
|
|
|
|
return array_getElement(cx, obj, receiver, index, vp);
|
|
|
|
|
|
|
|
SpecialId sid;
|
|
|
|
if (ValueIsSpecial(obj, &idval, &sid, cx))
|
2012-05-24 23:05:18 +00:00
|
|
|
return array_getSpecial(cx, obj, receiver, Rooted<SpecialId>(cx, sid), vp);
|
2011-09-15 18:44:10 +00:00
|
|
|
|
|
|
|
JSAtom *atom;
|
|
|
|
if (!js_ValueToAtom(cx, idval, &atom))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (atom->isIndex(&index))
|
|
|
|
return array_getElement(cx, obj, receiver, index, vp);
|
|
|
|
|
2012-05-24 23:05:18 +00:00
|
|
|
return array_getProperty(cx, obj, receiver, RootedPropertyName(cx, atom->asPropertyName()), vp);
|
2011-08-12 18:26:48 +00:00
|
|
|
}
|
|
|
|
|
2008-02-15 09:48:53 +00:00
|
|
|
static JSBool
|
2012-05-19 22:03:45 +00:00
|
|
|
slowarray_addProperty(JSContext *cx, HandleObject obj, HandleId id, Value *vp)
|
2008-02-15 09:48:53 +00:00
|
|
|
{
|
2012-03-06 23:52:55 +00:00
|
|
|
uint32_t index, length;
|
2008-03-02 17:45:33 +00:00
|
|
|
|
2004-10-05 10:19:07 +00:00
|
|
|
if (!js_IdIsIndex(id, &index))
|
2003-06-12 00:26:40 +00:00
|
|
|
return JS_TRUE;
|
2010-04-06 01:32:16 +00:00
|
|
|
length = obj->getArrayLength();
|
2011-05-16 23:15:37 +00:00
|
|
|
if (index >= length)
|
|
|
|
obj->setArrayLength(cx, index + 1);
|
2008-02-18 21:01:47 +00:00
|
|
|
return JS_TRUE;
|
|
|
|
}
|
|
|
|
|
2010-02-23 00:30:22 +00:00
|
|
|
static JSType
|
2012-05-19 22:03:45 +00:00
|
|
|
array_typeOf(JSContext *cx, HandleObject obj)
|
2010-02-23 00:30:22 +00:00
|
|
|
{
|
|
|
|
return JSTYPE_OBJECT;
|
|
|
|
}
|
|
|
|
|
2008-02-18 21:01:47 +00:00
|
|
|
static JSBool
|
2012-05-19 22:03:45 +00:00
|
|
|
array_setGeneric(JSContext *cx, HandleObject obj, HandleId id, Value *vp, JSBool strict)
|
2008-02-18 21:01:47 +00:00
|
|
|
{
|
2010-07-15 06:19:36 +00:00
|
|
|
if (JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom))
|
2011-02-09 19:31:40 +00:00
|
|
|
return array_length_setter(cx, obj, id, strict, vp);
|
2008-02-18 21:01:47 +00:00
|
|
|
|
2010-03-05 04:44:09 +00:00
|
|
|
if (!obj->isDenseArray())
|
2012-05-19 22:03:45 +00:00
|
|
|
return baseops::SetPropertyHelper(cx, obj, id, 0, vp, strict);
|
2008-02-18 21:01:47 +00:00
|
|
|
|
2010-10-14 14:12:19 +00:00
|
|
|
do {
|
2012-04-12 16:23:51 +00:00
|
|
|
uint32_t i;
|
2010-10-14 14:12:19 +00:00
|
|
|
if (!js_IdIsIndex(id, &i))
|
|
|
|
break;
|
|
|
|
if (js_PrototypeHasIndexedProperties(cx, obj))
|
|
|
|
break;
|
2008-02-18 21:01:47 +00:00
|
|
|
|
2010-10-14 14:12:19 +00:00
|
|
|
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;
|
|
|
|
}
|
2008-02-18 21:01:47 +00:00
|
|
|
|
2010-10-14 14:12:19 +00:00
|
|
|
if (i >= obj->getArrayLength())
|
2011-03-03 22:07:48 +00:00
|
|
|
obj->setDenseArrayLength(i + 1);
|
2011-05-16 23:15:37 +00:00
|
|
|
obj->setDenseArrayElementWithType(cx, i, *vp);
|
2010-10-14 14:12:19 +00:00
|
|
|
return true;
|
|
|
|
} while (false);
|
|
|
|
|
2012-04-12 16:23:51 +00:00
|
|
|
if (!JSObject::makeDenseArraySlow(cx, obj))
|
2010-10-14 14:12:19 +00:00
|
|
|
return false;
|
2012-05-19 22:03:45 +00:00
|
|
|
return baseops::SetPropertyHelper(cx, obj, id, 0, vp, strict);
|
2008-02-18 21:01:47 +00:00
|
|
|
}
|
|
|
|
|
2011-10-06 00:16:25 +00:00
|
|
|
static JSBool
|
2012-05-19 22:03:45 +00:00
|
|
|
array_setProperty(JSContext *cx, HandleObject obj, HandlePropertyName name, Value *vp, JSBool strict)
|
2011-10-06 00:16:25 +00:00
|
|
|
{
|
2012-05-24 23:05:18 +00:00
|
|
|
return array_setGeneric(cx, obj, RootedId(cx, NameToId(name)), vp, strict);
|
2011-10-06 00:16:25 +00:00
|
|
|
}
|
|
|
|
|
2011-08-10 21:54:51 +00:00
|
|
|
static JSBool
|
2012-05-19 22:03:45 +00:00
|
|
|
array_setElement(JSContext *cx, HandleObject obj, uint32_t index, Value *vp, JSBool strict)
|
2011-08-10 21:54:51 +00:00
|
|
|
{
|
2012-05-24 23:05:18 +00:00
|
|
|
RootedId id(cx);
|
2012-05-19 22:03:45 +00:00
|
|
|
if (!IndexToId(cx, index, id.address()))
|
2011-08-10 21:54:51 +00:00
|
|
|
return false;
|
2011-08-10 21:54:52 +00:00
|
|
|
|
|
|
|
if (!obj->isDenseArray())
|
2012-05-19 22:03:45 +00:00
|
|
|
return baseops::SetPropertyHelper(cx, obj, id, 0, vp, strict);
|
2011-08-10 21:54:52 +00:00
|
|
|
|
|
|
|
do {
|
|
|
|
/*
|
|
|
|
* UINT32_MAX is not an array index and must not affect the length
|
|
|
|
* property, so specifically reject it.
|
|
|
|
*/
|
|
|
|
if (index == UINT32_MAX)
|
|
|
|
break;
|
|
|
|
if (js_PrototypeHasIndexedProperties(cx, obj))
|
|
|
|
break;
|
|
|
|
|
|
|
|
JSObject::EnsureDenseResult result = obj->ensureDenseArrayElements(cx, index, 1);
|
|
|
|
if (result != JSObject::ED_OK) {
|
|
|
|
if (result == JSObject::ED_FAILED)
|
|
|
|
return false;
|
|
|
|
JS_ASSERT(result == JSObject::ED_SPARSE);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (index >= obj->getArrayLength())
|
|
|
|
obj->setDenseArrayLength(index + 1);
|
|
|
|
obj->setDenseArrayElementWithType(cx, index, *vp);
|
|
|
|
return true;
|
|
|
|
} while (false);
|
|
|
|
|
2012-04-12 16:23:51 +00:00
|
|
|
if (!JSObject::makeDenseArraySlow(cx, obj))
|
2011-08-10 21:54:52 +00:00
|
|
|
return false;
|
2012-05-19 22:03:45 +00:00
|
|
|
return baseops::SetPropertyHelper(cx, obj, id, 0, vp, strict);
|
2011-08-10 21:54:51 +00:00
|
|
|
}
|
|
|
|
|
2011-08-12 18:26:48 +00:00
|
|
|
static JSBool
|
2012-05-19 22:03:45 +00:00
|
|
|
array_setSpecial(JSContext *cx, HandleObject obj, HandleSpecialId sid, Value *vp, JSBool strict)
|
2011-08-12 18:26:48 +00:00
|
|
|
{
|
2012-05-24 23:05:18 +00:00
|
|
|
return array_setGeneric(cx, obj, RootedId(cx, SPECIALID_TO_JSID(sid)), vp, strict);
|
2011-08-12 18:26:48 +00:00
|
|
|
}
|
|
|
|
|
2009-03-04 05:58:56 +00:00
|
|
|
JSBool
|
|
|
|
js_PrototypeHasIndexedProperties(JSContext *cx, JSObject *obj)
|
2009-03-04 02:04:15 +00:00
|
|
|
{
|
2009-03-04 08:12:35 +00:00
|
|
|
/*
|
|
|
|
* Walk up the prototype chain and see if this indexed element already
|
|
|
|
* exists. If we hit the end of the prototype chain, it's safe to set the
|
|
|
|
* element on the original object.
|
|
|
|
*/
|
2009-08-28 05:53:26 +00:00
|
|
|
while ((obj = obj->getProto()) != NULL) {
|
2009-03-04 02:04:15 +00:00
|
|
|
/*
|
2009-03-04 08:12:35 +00:00
|
|
|
* If the prototype is a non-native object (possibly a dense array), or
|
|
|
|
* a native object (possibly a slow array) that has indexed properties,
|
|
|
|
* return true.
|
2009-03-04 02:04:15 +00:00
|
|
|
*/
|
2010-04-01 05:13:51 +00:00
|
|
|
if (!obj->isNative())
|
2009-03-04 08:12:35 +00:00
|
|
|
return JS_TRUE;
|
2010-08-29 18:57:08 +00:00
|
|
|
if (obj->isIndexed())
|
2009-03-04 02:04:15 +00:00
|
|
|
return JS_TRUE;
|
|
|
|
}
|
|
|
|
return JS_FALSE;
|
|
|
|
}
|
|
|
|
|
2011-10-05 08:00:23 +00:00
|
|
|
static JSBool
|
2012-05-19 22:03:45 +00:00
|
|
|
array_defineGeneric(JSContext *cx, HandleObject obj, HandleId id, const Value *value,
|
2012-02-28 23:11:11 +00:00
|
|
|
JSPropertyOp getter, StrictPropertyOp setter, unsigned attrs)
|
2008-02-18 21:01:47 +00:00
|
|
|
{
|
2010-07-15 06:19:36 +00:00
|
|
|
if (JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom))
|
2008-02-18 21:01:47 +00:00
|
|
|
return JS_TRUE;
|
|
|
|
|
2010-12-16 21:33:49 +00:00
|
|
|
if (!obj->isDenseArray())
|
2012-05-19 22:03:45 +00:00
|
|
|
return baseops::DefineProperty(cx, obj, id, value, getter, setter, attrs);
|
2008-02-18 21:01:47 +00:00
|
|
|
|
2010-12-16 21:33:49 +00:00
|
|
|
do {
|
Bug 708735 - Use <stdint.h> types in JSAPI and throughout SpiderMonkey. Continue to provide the {u,}int{8,16,32,64} and JS{Uint,Int}{8,16,32,64} integer types through a single header, however, for a simpler backout strategy -- and also to ease the transition for embedders. r=timeless on switching the jsd API to use the <stdint.h> types, r=luke, r=dmandelin
2011-12-09 03:54:10 +00:00
|
|
|
uint32_t i = 0; // init to shut GCC up
|
2010-12-16 21:33:49 +00:00
|
|
|
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())
|
2011-03-03 22:07:48 +00:00
|
|
|
obj->setDenseArrayLength(i + 1);
|
2011-05-16 23:15:37 +00:00
|
|
|
obj->setDenseArrayElementWithType(cx, i, *value);
|
2010-12-16 21:33:49 +00:00
|
|
|
return true;
|
|
|
|
} while (false);
|
|
|
|
|
2012-05-24 15:52:21 +00:00
|
|
|
AutoRooterGetterSetter gsRoot(cx, attrs, &getter, &setter);
|
2012-05-19 22:03:45 +00:00
|
|
|
|
2012-04-12 16:23:51 +00:00
|
|
|
if (!JSObject::makeDenseArraySlow(cx, obj))
|
2010-12-16 21:33:49 +00:00
|
|
|
return false;
|
2012-05-19 22:03:45 +00:00
|
|
|
return baseops::DefineProperty(cx, obj, id, value, getter, setter, attrs);
|
2008-02-18 21:01:47 +00:00
|
|
|
}
|
|
|
|
|
2011-10-05 08:00:23 +00:00
|
|
|
static JSBool
|
2012-05-19 22:03:45 +00:00
|
|
|
array_defineProperty(JSContext *cx, HandleObject obj, HandlePropertyName name, const Value *value,
|
2012-02-28 23:11:11 +00:00
|
|
|
JSPropertyOp getter, StrictPropertyOp setter, unsigned attrs)
|
2011-10-05 08:00:23 +00:00
|
|
|
{
|
2012-05-24 23:05:18 +00:00
|
|
|
return array_defineGeneric(cx, obj, RootedId(cx, NameToId(name)), value, getter, setter, attrs);
|
2011-10-05 08:00:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
namespace js {
|
|
|
|
|
2011-08-10 21:54:51 +00:00
|
|
|
/* non-static for direct definition of array elements within the engine */
|
|
|
|
JSBool
|
2012-05-19 22:03:45 +00:00
|
|
|
array_defineElement(JSContext *cx, HandleObject obj, uint32_t index, const Value *value,
|
2012-02-28 23:11:11 +00:00
|
|
|
PropertyOp getter, StrictPropertyOp setter, unsigned attrs)
|
2011-08-10 21:54:51 +00:00
|
|
|
{
|
2011-08-10 21:54:52 +00:00
|
|
|
if (!obj->isDenseArray())
|
2012-05-19 22:03:45 +00:00
|
|
|
return baseops::DefineElement(cx, obj, index, value, getter, setter, attrs);
|
2011-08-10 21:54:52 +00:00
|
|
|
|
|
|
|
do {
|
|
|
|
/*
|
|
|
|
* UINT32_MAX is not an array index and must not affect the length
|
|
|
|
* property, so specifically reject it.
|
|
|
|
*/
|
|
|
|
if (attrs != JSPROP_ENUMERATE || index == UINT32_MAX)
|
|
|
|
break;
|
|
|
|
|
|
|
|
JSObject::EnsureDenseResult result = obj->ensureDenseArrayElements(cx, index, 1);
|
|
|
|
if (result != JSObject::ED_OK) {
|
|
|
|
if (result == JSObject::ED_FAILED)
|
|
|
|
return false;
|
|
|
|
JS_ASSERT(result == JSObject::ED_SPARSE);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (index >= obj->getArrayLength())
|
|
|
|
obj->setDenseArrayLength(index + 1);
|
|
|
|
obj->setDenseArrayElementWithType(cx, index, *value);
|
|
|
|
return true;
|
|
|
|
} while (false);
|
|
|
|
|
2012-05-24 15:52:21 +00:00
|
|
|
AutoRooterGetterSetter gsRoot(cx, attrs, &getter, &setter);
|
2012-05-01 00:10:30 +00:00
|
|
|
|
2012-05-19 22:03:45 +00:00
|
|
|
if (!JSObject::makeDenseArraySlow(cx, obj))
|
2011-08-10 21:54:52 +00:00
|
|
|
return false;
|
2012-05-19 22:03:45 +00:00
|
|
|
return baseops::DefineElement(cx, obj, index, value, getter, setter, attrs);
|
2011-08-10 21:54:51 +00:00
|
|
|
}
|
|
|
|
|
2011-05-05 04:24:15 +00:00
|
|
|
} // namespace js
|
|
|
|
|
2011-08-12 18:26:48 +00:00
|
|
|
static JSBool
|
2012-05-19 22:03:45 +00:00
|
|
|
array_defineSpecial(JSContext *cx, HandleObject obj, HandleSpecialId sid, const Value *value,
|
2012-02-28 23:11:11 +00:00
|
|
|
PropertyOp getter, StrictPropertyOp setter, unsigned attrs)
|
2011-08-12 18:26:48 +00:00
|
|
|
{
|
2012-05-24 23:05:18 +00:00
|
|
|
return array_defineGeneric(cx, obj, RootedId(cx, SPECIALID_TO_JSID(sid)),
|
2012-05-19 22:03:45 +00:00
|
|
|
value, getter, setter, attrs);
|
2011-08-12 18:26:48 +00:00
|
|
|
}
|
|
|
|
|
2008-02-18 21:01:47 +00:00
|
|
|
static JSBool
|
2012-05-19 22:03:45 +00:00
|
|
|
array_getGenericAttributes(JSContext *cx, HandleObject obj, HandleId id, unsigned *attrsp)
|
2008-02-18 21:01:47 +00:00
|
|
|
{
|
2010-07-15 06:19:36 +00:00
|
|
|
*attrsp = JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom)
|
2008-02-18 21:01:47 +00:00
|
|
|
? JSPROP_PERMANENT : JSPROP_ENUMERATE;
|
2011-10-05 00:21:06 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static JSBool
|
2012-05-19 22:03:45 +00:00
|
|
|
array_getPropertyAttributes(JSContext *cx, HandleObject obj, HandlePropertyName name, unsigned *attrsp)
|
2011-10-05 00:21:06 +00:00
|
|
|
{
|
|
|
|
*attrsp = (name == cx->runtime->atomState.lengthAtom)
|
|
|
|
? JSPROP_PERMANENT
|
|
|
|
: JSPROP_ENUMERATE;
|
|
|
|
return true;
|
2008-02-18 21:01:47 +00:00
|
|
|
}
|
|
|
|
|
2011-08-10 21:54:51 +00:00
|
|
|
static JSBool
|
2012-05-19 22:03:45 +00:00
|
|
|
array_getElementAttributes(JSContext *cx, HandleObject obj, uint32_t index, unsigned *attrsp)
|
2011-08-10 21:54:51 +00:00
|
|
|
{
|
2011-08-10 21:54:52 +00:00
|
|
|
*attrsp = JSPROP_ENUMERATE;
|
|
|
|
return true;
|
2011-08-10 21:54:51 +00:00
|
|
|
}
|
|
|
|
|
2011-08-12 18:26:48 +00:00
|
|
|
static JSBool
|
2012-05-19 22:03:45 +00:00
|
|
|
array_getSpecialAttributes(JSContext *cx, HandleObject obj, HandleSpecialId sid, unsigned *attrsp)
|
2011-08-12 18:26:48 +00:00
|
|
|
{
|
2011-10-05 00:21:06 +00:00
|
|
|
*attrsp = JSPROP_ENUMERATE;
|
|
|
|
return true;
|
2011-08-12 18:26:48 +00:00
|
|
|
}
|
|
|
|
|
2008-02-18 21:01:47 +00:00
|
|
|
static JSBool
|
2012-05-19 22:03:45 +00:00
|
|
|
array_setGenericAttributes(JSContext *cx, HandleObject obj, HandleId id, unsigned *attrsp)
|
2011-10-05 00:21:06 +00:00
|
|
|
{
|
|
|
|
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_SET_ARRAY_ATTRS);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
static JSBool
|
2012-05-19 22:03:45 +00:00
|
|
|
array_setPropertyAttributes(JSContext *cx, HandleObject obj, HandlePropertyName name, unsigned *attrsp)
|
2008-02-18 21:01:47 +00:00
|
|
|
{
|
2011-08-10 21:54:52 +00:00
|
|
|
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_SET_ARRAY_ATTRS);
|
|
|
|
return false;
|
2008-02-18 21:01:47 +00:00
|
|
|
}
|
|
|
|
|
2011-08-10 21:54:51 +00:00
|
|
|
static JSBool
|
2012-05-19 22:03:45 +00:00
|
|
|
array_setElementAttributes(JSContext *cx, HandleObject obj, uint32_t index, unsigned *attrsp)
|
2011-08-10 21:54:51 +00:00
|
|
|
{
|
2011-08-10 21:54:52 +00:00
|
|
|
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_SET_ARRAY_ATTRS);
|
|
|
|
return false;
|
2011-08-10 21:54:51 +00:00
|
|
|
}
|
|
|
|
|
2011-08-12 18:26:48 +00:00
|
|
|
static JSBool
|
2012-05-19 22:03:45 +00:00
|
|
|
array_setSpecialAttributes(JSContext *cx, HandleObject obj, HandleSpecialId sid, unsigned *attrsp)
|
2011-08-12 18:26:48 +00:00
|
|
|
{
|
2011-10-05 00:21:06 +00:00
|
|
|
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_SET_ARRAY_ATTRS);
|
|
|
|
return false;
|
2011-08-12 18:26:48 +00:00
|
|
|
}
|
|
|
|
|
2011-10-05 00:49:57 +00:00
|
|
|
static JSBool
|
2012-05-19 22:03:45 +00:00
|
|
|
array_deleteProperty(JSContext *cx, HandleObject obj, HandlePropertyName name, Value *rval, JSBool strict)
|
2008-02-18 21:01:47 +00:00
|
|
|
{
|
2010-03-05 04:44:09 +00:00
|
|
|
if (!obj->isDenseArray())
|
2012-05-19 22:03:45 +00:00
|
|
|
return baseops::DeleteProperty(cx, obj, name, rval, strict);
|
2008-02-18 21:01:47 +00:00
|
|
|
|
2011-12-28 22:33:20 +00:00
|
|
|
if (name == cx->runtime->atomState.lengthAtom) {
|
2010-07-15 06:19:36 +00:00
|
|
|
rval->setBoolean(false);
|
2011-08-10 21:54:52 +00:00
|
|
|
return true;
|
1998-03-28 02:44:41 +00:00
|
|
|
}
|
2008-02-18 21:01:47 +00:00
|
|
|
|
2010-07-15 06:19:36 +00:00
|
|
|
rval->setBoolean(true);
|
2011-08-10 21:54:52 +00:00
|
|
|
return true;
|
1998-03-28 02:44:41 +00:00
|
|
|
}
|
|
|
|
|
2011-10-05 00:49:57 +00:00
|
|
|
namespace js {
|
|
|
|
|
2011-08-10 21:54:51 +00:00
|
|
|
/* non-static for direct deletion of array elements within the engine */
|
|
|
|
JSBool
|
2012-05-19 22:03:45 +00:00
|
|
|
array_deleteElement(JSContext *cx, HandleObject obj, uint32_t index, Value *rval, JSBool strict)
|
2011-08-10 21:54:51 +00:00
|
|
|
{
|
2011-08-10 21:54:52 +00:00
|
|
|
if (!obj->isDenseArray())
|
2012-05-19 22:03:45 +00:00
|
|
|
return baseops::DeleteElement(cx, obj, index, rval, strict);
|
2011-08-10 21:54:52 +00:00
|
|
|
|
|
|
|
if (index < obj->getDenseArrayInitializedLength()) {
|
|
|
|
obj->markDenseArrayNotPacked(cx);
|
|
|
|
obj->setDenseArrayElement(index, MagicValue(JS_ARRAY_HOLE));
|
|
|
|
}
|
|
|
|
|
2012-05-24 23:05:18 +00:00
|
|
|
if (!js_SuppressDeletedElement(cx, RootedObject(cx, obj), index))
|
2011-08-10 21:54:51 +00:00
|
|
|
return false;
|
2011-08-10 21:54:52 +00:00
|
|
|
|
|
|
|
rval->setBoolean(true);
|
|
|
|
return true;
|
2011-08-10 21:54:51 +00:00
|
|
|
}
|
|
|
|
|
2011-05-05 04:24:15 +00:00
|
|
|
} // namespace js
|
|
|
|
|
2011-08-12 18:26:48 +00:00
|
|
|
static JSBool
|
2012-05-19 22:03:45 +00:00
|
|
|
array_deleteSpecial(JSContext *cx, HandleObject obj, HandleSpecialId sid, Value *rval, JSBool strict)
|
2011-08-12 18:26:48 +00:00
|
|
|
{
|
2011-12-28 22:33:20 +00:00
|
|
|
if (!obj->isDenseArray())
|
2012-05-19 22:03:45 +00:00
|
|
|
return baseops::DeleteSpecial(cx, obj, sid, rval, strict);
|
2011-12-28 22:33:20 +00:00
|
|
|
|
|
|
|
rval->setBoolean(true);
|
|
|
|
return true;
|
2011-08-12 18:26:48 +00:00
|
|
|
}
|
|
|
|
|
2008-02-18 21:01:47 +00:00
|
|
|
static void
|
|
|
|
array_trace(JSTracer *trc, JSObject *obj)
|
|
|
|
{
|
2009-12-30 21:49:26 +00:00
|
|
|
JS_ASSERT(obj->isDenseArray());
|
2008-02-18 21:01:47 +00:00
|
|
|
|
Bug 708735 - Use <stdint.h> types in JSAPI and throughout SpiderMonkey. Continue to provide the {u,}int{8,16,32,64} and JS{Uint,Int}{8,16,32,64} integer types through a single header, however, for a simpler backout strategy -- and also to ease the transition for embedders. r=timeless on switching the jsd API to use the <stdint.h> types, r=luke, r=dmandelin
2011-12-09 03:54:10 +00:00
|
|
|
uint32_t initLength = obj->getDenseArrayInitializedLength();
|
2012-02-17 19:46:11 +00:00
|
|
|
MarkArraySlots(trc, initLength, obj->getDenseArrayElements(), "element");
|
2008-02-18 21:01:47 +00:00
|
|
|
}
|
|
|
|
|
2011-09-03 00:23:26 +00:00
|
|
|
Class js::ArrayClass = {
|
2008-02-18 21:01:47 +00:00
|
|
|
"Array",
|
2012-02-07 18:57:16 +00:00
|
|
|
Class::NON_NATIVE | JSCLASS_HAS_CACHED_PROTO(JSProto_Array) | JSCLASS_FOR_OF_ITERATION,
|
2011-09-20 18:40:24 +00:00
|
|
|
JS_PropertyStub, /* addProperty */
|
|
|
|
JS_PropertyStub, /* delProperty */
|
|
|
|
JS_PropertyStub, /* getProperty */
|
|
|
|
JS_StrictPropertyStub, /* setProperty */
|
|
|
|
JS_EnumerateStub,
|
|
|
|
JS_ResolveStub,
|
|
|
|
JS_ConvertStub,
|
2010-10-13 18:49:22 +00:00
|
|
|
NULL,
|
2010-06-12 16:29:04 +00:00
|
|
|
NULL, /* checkAccess */
|
|
|
|
NULL, /* call */
|
|
|
|
NULL, /* construct */
|
|
|
|
NULL, /* hasInstance */
|
2011-03-07 06:31:43 +00:00
|
|
|
array_trace, /* trace */
|
2012-02-07 18:57:16 +00:00
|
|
|
{
|
|
|
|
NULL, /* equality */
|
|
|
|
NULL, /* outerObject */
|
|
|
|
NULL, /* innerObject */
|
2012-02-07 18:57:17 +00:00
|
|
|
JS_ElementIteratorStub,
|
2012-02-07 18:57:16 +00:00
|
|
|
NULL, /* unused */
|
|
|
|
false, /* isWrappedNative */
|
|
|
|
},
|
2010-06-12 16:29:04 +00:00
|
|
|
{
|
2011-10-08 22:45:04 +00:00
|
|
|
array_lookupGeneric,
|
2010-06-12 16:29:04 +00:00
|
|
|
array_lookupProperty,
|
2011-08-10 21:54:51 +00:00
|
|
|
array_lookupElement,
|
2011-08-12 18:26:48 +00:00
|
|
|
array_lookupSpecial,
|
2011-10-05 08:00:23 +00:00
|
|
|
array_defineGeneric,
|
2010-06-12 16:29:04 +00:00
|
|
|
array_defineProperty,
|
2011-08-10 21:54:51 +00:00
|
|
|
array_defineElement,
|
2011-08-12 18:26:48 +00:00
|
|
|
array_defineSpecial,
|
2011-09-15 18:44:10 +00:00
|
|
|
array_getGeneric,
|
2010-06-12 16:29:04 +00:00
|
|
|
array_getProperty,
|
2011-08-10 21:54:51 +00:00
|
|
|
array_getElement,
|
2011-11-04 16:19:00 +00:00
|
|
|
NULL, /* getElementIfPresent, because this is hard for now for
|
|
|
|
slow arrays */
|
2011-08-12 18:26:48 +00:00
|
|
|
array_getSpecial,
|
2011-10-06 00:16:25 +00:00
|
|
|
array_setGeneric,
|
2010-06-12 16:29:04 +00:00
|
|
|
array_setProperty,
|
2011-08-10 21:54:51 +00:00
|
|
|
array_setElement,
|
2011-08-12 18:26:48 +00:00
|
|
|
array_setSpecial,
|
2011-10-05 00:21:06 +00:00
|
|
|
array_getGenericAttributes,
|
|
|
|
array_getPropertyAttributes,
|
2011-08-10 21:54:51 +00:00
|
|
|
array_getElementAttributes,
|
2011-08-12 18:26:48 +00:00
|
|
|
array_getSpecialAttributes,
|
2011-10-05 00:21:06 +00:00
|
|
|
array_setGenericAttributes,
|
|
|
|
array_setPropertyAttributes,
|
2011-08-10 21:54:51 +00:00
|
|
|
array_setElementAttributes,
|
2011-08-12 18:26:48 +00:00
|
|
|
array_setSpecialAttributes,
|
2010-06-12 16:29:04 +00:00
|
|
|
array_deleteProperty,
|
2011-08-10 21:54:51 +00:00
|
|
|
array_deleteElement,
|
2011-08-12 18:26:48 +00:00
|
|
|
array_deleteSpecial,
|
2010-06-12 16:29:04 +00:00
|
|
|
NULL, /* enumerate */
|
|
|
|
array_typeOf,
|
|
|
|
NULL, /* thisObject */
|
|
|
|
NULL, /* clear */
|
|
|
|
}
|
2008-02-18 21:01:47 +00:00
|
|
|
};
|
|
|
|
|
2011-09-03 00:23:26 +00:00
|
|
|
Class js::SlowArrayClass = {
|
1998-03-28 02:44:41 +00:00
|
|
|
"Array",
|
2012-02-07 18:57:16 +00:00
|
|
|
JSCLASS_HAS_CACHED_PROTO(JSProto_Array) | JSCLASS_FOR_OF_ITERATION,
|
2010-06-12 16:29:04 +00:00
|
|
|
slowarray_addProperty,
|
2011-09-20 18:40:24 +00:00
|
|
|
JS_PropertyStub, /* delProperty */
|
|
|
|
JS_PropertyStub, /* getProperty */
|
|
|
|
JS_StrictPropertyStub, /* setProperty */
|
|
|
|
JS_EnumerateStub,
|
|
|
|
JS_ResolveStub,
|
2012-02-07 18:57:16 +00:00
|
|
|
JS_ConvertStub,
|
|
|
|
NULL,
|
|
|
|
NULL, /* checkAccess */
|
|
|
|
NULL, /* call */
|
|
|
|
NULL, /* construct */
|
|
|
|
NULL, /* hasInstance */
|
|
|
|
NULL, /* trace */
|
|
|
|
{
|
|
|
|
NULL, /* equality */
|
|
|
|
NULL, /* outerObject */
|
|
|
|
NULL, /* innerObject */
|
2012-02-07 18:57:17 +00:00
|
|
|
JS_ElementIteratorStub,
|
2012-02-07 18:57:16 +00:00
|
|
|
NULL, /* unused */
|
|
|
|
false, /* isWrappedNative */
|
|
|
|
}
|
1998-03-28 02:44:41 +00:00
|
|
|
};
|
|
|
|
|
2011-10-10 18:41:03 +00:00
|
|
|
bool
|
|
|
|
JSObject::allocateSlowArrayElements(JSContext *cx)
|
|
|
|
{
|
|
|
|
JS_ASSERT(hasClass(&js::SlowArrayClass));
|
|
|
|
JS_ASSERT(elements == emptyObjectElements);
|
|
|
|
|
2011-11-02 20:34:19 +00:00
|
|
|
ObjectElements *header = cx->new_<ObjectElements>(0, 0);
|
2011-10-10 18:41:03 +00:00
|
|
|
if (!header)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
elements = header->elements();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2011-02-03 19:04:14 +00:00
|
|
|
static bool
|
|
|
|
AddLengthProperty(JSContext *cx, JSObject *obj)
|
|
|
|
{
|
2011-10-10 18:41:03 +00:00
|
|
|
/*
|
|
|
|
* Add the 'length' property for a newly created or converted slow array,
|
|
|
|
* and update the elements to be an empty array owned by the object.
|
|
|
|
* The shared emptyObjectElements singleton cannot be used for slow arrays,
|
|
|
|
* as accesses to 'length' will use the elements header.
|
|
|
|
*/
|
|
|
|
|
2012-05-24 23:05:18 +00:00
|
|
|
RootedId lengthId(cx, NameToId(cx->runtime->atomState.lengthAtom));
|
2011-08-16 10:27:34 +00:00
|
|
|
JS_ASSERT(!obj->nativeLookup(cx, lengthId));
|
2011-02-03 19:04:14 +00:00
|
|
|
|
2011-10-10 18:41:03 +00:00
|
|
|
if (!obj->allocateSlowArrayElements(cx))
|
|
|
|
return false;
|
|
|
|
|
2011-02-03 19:04:14 +00:00
|
|
|
return obj->addProperty(cx, lengthId, array_length_getter, array_length_setter,
|
|
|
|
SHAPE_INVALID_SLOT, JSPROP_PERMANENT | JSPROP_SHARED, 0, 0);
|
|
|
|
}
|
|
|
|
|
2008-02-18 21:01:47 +00:00
|
|
|
/*
|
|
|
|
* Convert an array object from fast-and-dense to slow-and-flexible.
|
|
|
|
*/
|
2012-04-12 16:23:51 +00:00
|
|
|
/* static */ bool
|
|
|
|
JSObject::makeDenseArraySlow(JSContext *cx, HandleObject obj)
|
2008-02-18 21:01:47 +00:00
|
|
|
{
|
2012-04-12 16:23:51 +00:00
|
|
|
JS_ASSERT(obj->isDenseArray());
|
2008-02-18 21:01:47 +00:00
|
|
|
|
2012-04-12 16:23:51 +00:00
|
|
|
MarkTypeObjectFlags(cx, obj,
|
2011-07-15 17:14:07 +00:00
|
|
|
OBJECT_FLAG_NON_PACKED_ARRAY |
|
|
|
|
OBJECT_FLAG_NON_DENSE_ARRAY);
|
2011-04-09 02:51:40 +00:00
|
|
|
|
2012-04-12 16:23:51 +00:00
|
|
|
uint32_t arrayCapacity = obj->getDenseArrayCapacity();
|
|
|
|
uint32_t arrayInitialized = obj->getDenseArrayInitializedLength();
|
2011-04-09 02:51:40 +00:00
|
|
|
|
|
|
|
/*
|
2011-10-10 18:41:03 +00:00
|
|
|
* Get an allocated array of the existing elements, evicting from the fixed
|
|
|
|
* slots if necessary.
|
2011-04-09 02:51:40 +00:00
|
|
|
*/
|
2012-04-12 16:23:51 +00:00
|
|
|
if (!obj->hasDynamicElements()) {
|
|
|
|
if (!obj->growElements(cx, arrayCapacity))
|
2011-04-09 02:51:40 +00:00
|
|
|
return false;
|
2012-04-12 16:23:51 +00:00
|
|
|
JS_ASSERT(obj->hasDynamicElements());
|
2011-04-09 02:51:40 +00:00
|
|
|
}
|
2011-09-29 15:20:06 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Save old map now, before calling InitScopeForObject. We'll have to undo
|
|
|
|
* on error. This is gross, but a better way is not obvious. Note: the
|
|
|
|
* exact contents of the array are not preserved on error.
|
|
|
|
*/
|
2012-04-12 16:23:51 +00:00
|
|
|
js::Shape *oldShape = obj->lastProperty();
|
2011-09-29 15:20:06 +00:00
|
|
|
|
|
|
|
/* Create a native scope. */
|
2012-04-12 16:23:51 +00:00
|
|
|
gc::AllocKind kind = obj->getAllocKind();
|
|
|
|
Shape *shape = EmptyShape::getInitialShape(cx, &SlowArrayClass, obj->getProto(),
|
2011-11-19 00:22:52 +00:00
|
|
|
oldShape->getObjectParent(), kind);
|
2011-11-02 20:34:19 +00:00
|
|
|
if (!shape)
|
2011-09-29 15:20:06 +00:00
|
|
|
return false;
|
2012-04-12 16:23:51 +00:00
|
|
|
obj->shape_ = shape;
|
2011-09-29 15:20:06 +00:00
|
|
|
|
2011-10-10 18:41:03 +00:00
|
|
|
/* Take ownership of the dense elements, reset to an empty dense array. */
|
2012-04-12 16:23:51 +00:00
|
|
|
HeapSlot *elems = obj->elements;
|
|
|
|
obj->elements = emptyObjectElements;
|
2010-09-20 19:05:21 +00:00
|
|
|
|
2011-10-10 18:41:03 +00:00
|
|
|
/* Root all values in the array during conversion. */
|
2011-11-14 17:13:33 +00:00
|
|
|
AutoValueArray autoArray(cx, (Value *) elems, arrayInitialized);
|
2011-04-11 13:52:23 +00:00
|
|
|
|
2010-10-13 18:49:22 +00:00
|
|
|
/*
|
|
|
|
* Begin with the length property to share more of the property tree.
|
|
|
|
* The getter/setter here will directly access the object's private value.
|
|
|
|
*/
|
2012-04-12 16:23:51 +00:00
|
|
|
if (!AddLengthProperty(cx, obj)) {
|
|
|
|
obj->shape_ = oldShape;
|
|
|
|
if (obj->elements != emptyObjectElements)
|
|
|
|
cx->free_(obj->getElementsHeader());
|
|
|
|
obj->elements = elems;
|
2010-08-29 18:57:08 +00:00
|
|
|
return false;
|
2010-06-03 06:44:24 +00:00
|
|
|
}
|
|
|
|
|
2010-11-16 01:21:58 +00:00
|
|
|
/*
|
|
|
|
* Create new properties pointing to existing elements. Pack the array to
|
|
|
|
* remove holes, so that shapes use successive slots (as for other objects).
|
|
|
|
*/
|
Bug 708735 - Use <stdint.h> types in JSAPI and throughout SpiderMonkey. Continue to provide the {u,}int{8,16,32,64} and JS{Uint,Int}{8,16,32,64} integer types through a single header, however, for a simpler backout strategy -- and also to ease the transition for embedders. r=timeless on switching the jsd API to use the <stdint.h> types, r=luke, r=dmandelin
2011-12-09 03:54:10 +00:00
|
|
|
uint32_t next = 0;
|
|
|
|
for (uint32_t i = 0; i < arrayInitialized; i++) {
|
2011-04-09 02:51:40 +00:00
|
|
|
/* Dense array indexes can always fit in a jsid. */
|
2008-02-18 21:01:47 +00:00
|
|
|
jsid id;
|
2011-04-09 02:51:40 +00:00
|
|
|
JS_ALWAYS_TRUE(ValueToId(cx, Int32Value(i), &id));
|
2008-02-18 21:01:47 +00:00
|
|
|
|
2011-10-10 18:41:03 +00:00
|
|
|
if (elems[i].isMagic(JS_ARRAY_HOLE))
|
2008-02-18 21:01:47 +00:00
|
|
|
continue;
|
|
|
|
|
2012-04-12 16:23:51 +00:00
|
|
|
if (!obj->addDataProperty(cx, id, next, JSPROP_ENUMERATE)) {
|
|
|
|
obj->shape_ = oldShape;
|
|
|
|
cx->free_(obj->getElementsHeader());
|
|
|
|
obj->elements = elems;
|
2010-08-29 18:57:08 +00:00
|
|
|
return false;
|
|
|
|
}
|
2008-02-18 21:01:47 +00:00
|
|
|
|
2012-04-12 16:23:51 +00:00
|
|
|
obj->initSlot(next, elems[i]);
|
2011-10-10 18:41:03 +00:00
|
|
|
|
2010-11-16 01:21:58 +00:00
|
|
|
next++;
|
2008-02-18 21:01:47 +00:00
|
|
|
}
|
2010-11-05 14:37:09 +00:00
|
|
|
|
2011-10-10 18:41:03 +00:00
|
|
|
ObjectElements *oldheader = ObjectElements::fromElements(elems);
|
|
|
|
|
2012-04-12 16:23:51 +00:00
|
|
|
obj->getElementsHeader()->length = oldheader->length;
|
2011-10-10 18:41:03 +00:00
|
|
|
cx->free_(oldheader);
|
2011-04-09 02:51:40 +00:00
|
|
|
|
2010-08-29 18:57:08 +00:00
|
|
|
return true;
|
2008-02-18 21:01:47 +00:00
|
|
|
}
|
|
|
|
|
2011-03-29 21:57:56 +00:00
|
|
|
#if JS_HAS_TOSOURCE
|
|
|
|
class ArraySharpDetector
|
2009-06-30 18:29:43 +00:00
|
|
|
{
|
2011-03-29 21:57:56 +00:00
|
|
|
JSContext *cx;
|
2012-02-16 01:55:25 +00:00
|
|
|
bool success;
|
2012-01-21 07:39:37 +00:00
|
|
|
bool alreadySeen;
|
2011-03-29 21:57:56 +00:00
|
|
|
bool sharp;
|
|
|
|
|
|
|
|
public:
|
|
|
|
ArraySharpDetector(JSContext *cx)
|
|
|
|
: cx(cx),
|
2012-02-16 01:55:25 +00:00
|
|
|
success(false),
|
2012-01-21 07:39:37 +00:00
|
|
|
alreadySeen(false),
|
2011-03-29 21:57:56 +00:00
|
|
|
sharp(false)
|
|
|
|
{}
|
|
|
|
|
2012-05-01 00:10:30 +00:00
|
|
|
bool init(HandleObject obj) {
|
2012-02-16 01:55:25 +00:00
|
|
|
success = js_EnterSharpObject(cx, obj, NULL, &alreadySeen, &sharp);
|
|
|
|
if (!success)
|
2011-03-29 21:57:56 +00:00
|
|
|
return false;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool initiallySharp() const {
|
2012-01-21 07:39:37 +00:00
|
|
|
JS_ASSERT_IF(sharp, alreadySeen);
|
2011-03-29 21:57:56 +00:00
|
|
|
return sharp;
|
|
|
|
}
|
|
|
|
|
|
|
|
~ArraySharpDetector() {
|
2012-02-16 01:55:25 +00:00
|
|
|
if (success && !sharp)
|
2011-03-29 21:57:56 +00:00
|
|
|
js_LeaveSharpObject(cx, NULL);
|
|
|
|
}
|
|
|
|
};
|
2009-06-30 19:14:09 +00:00
|
|
|
|
2009-07-01 00:19:42 +00:00
|
|
|
static JSBool
|
2012-02-28 23:11:11 +00:00
|
|
|
array_toSource(JSContext *cx, unsigned argc, Value *vp)
|
2009-07-01 00:19:42 +00:00
|
|
|
{
|
2009-08-08 03:09:11 +00:00
|
|
|
JS_CHECK_RECURSION(cx, return false);
|
1998-03-28 02:44:41 +00:00
|
|
|
|
2011-09-09 04:02:26 +00:00
|
|
|
CallArgs args = CallArgsFromVp(argc, vp);
|
2012-05-24 23:05:18 +00:00
|
|
|
RootedObject obj(cx, ToObject(cx, &args.thisv()));
|
2011-01-26 21:37:45 +00:00
|
|
|
if (!obj)
|
|
|
|
return false;
|
2011-09-09 04:18:23 +00:00
|
|
|
if (!obj->isArray())
|
2011-10-04 17:48:36 +00:00
|
|
|
return HandleNonGenericMethodClassMismatch(cx, args, array_toSource, &ArrayClass);
|
1998-04-24 00:31:11 +00:00
|
|
|
|
2011-03-29 21:57:56 +00:00
|
|
|
ArraySharpDetector detector(cx);
|
|
|
|
if (!detector.init(obj))
|
2009-08-08 03:09:11 +00:00
|
|
|
return false;
|
2005-12-07 22:42:06 +00:00
|
|
|
|
2011-01-12 23:28:58 +00:00
|
|
|
StringBuffer sb(cx);
|
2009-07-01 00:19:42 +00:00
|
|
|
|
2011-03-29 21:57:56 +00:00
|
|
|
if (detector.initiallySharp()) {
|
2011-01-12 23:28:58 +00:00
|
|
|
if (!sb.append("[]"))
|
2011-03-29 21:57:56 +00:00
|
|
|
return false;
|
2009-03-17 08:51:38 +00:00
|
|
|
goto make_string;
|
|
|
|
}
|
2009-06-30 18:29:43 +00:00
|
|
|
|
2011-01-12 23:28:58 +00:00
|
|
|
if (!sb.append('['))
|
2011-03-29 21:57:56 +00:00
|
|
|
return false;
|
2009-07-01 00:19:42 +00:00
|
|
|
|
2012-03-06 23:52:55 +00:00
|
|
|
uint32_t length;
|
2009-08-08 03:09:11 +00:00
|
|
|
if (!js_GetLengthProperty(cx, obj, &length))
|
2011-03-29 21:57:56 +00:00
|
|
|
return false;
|
2009-07-01 00:19:42 +00:00
|
|
|
|
2012-03-06 23:52:55 +00:00
|
|
|
for (uint32_t index = 0; index < length; index++) {
|
2009-07-01 00:19:42 +00:00
|
|
|
JSBool hole;
|
2011-10-25 01:02:36 +00:00
|
|
|
Value elt;
|
2009-08-08 03:09:11 +00:00
|
|
|
if (!JS_CHECK_OPERATION_LIMIT(cx) ||
|
2011-10-25 01:02:36 +00:00
|
|
|
!GetElement(cx, obj, index, &hole, &elt)) {
|
2011-03-29 21:57:56 +00:00
|
|
|
return false;
|
2009-08-08 03:09:11 +00:00
|
|
|
}
|
2009-07-01 00:19:42 +00:00
|
|
|
|
|
|
|
/* Get element's character string. */
|
|
|
|
JSString *str;
|
|
|
|
if (hole) {
|
|
|
|
str = cx->runtime->emptyString;
|
2003-06-12 00:26:40 +00:00
|
|
|
} else {
|
2011-10-25 01:02:36 +00:00
|
|
|
str = js_ValueToSource(cx, elt);
|
2009-08-08 03:09:11 +00:00
|
|
|
if (!str)
|
2011-03-29 21:57:56 +00:00
|
|
|
return false;
|
2003-06-12 00:26:40 +00:00
|
|
|
}
|
2009-07-01 00:19:42 +00:00
|
|
|
|
|
|
|
/* Append element to buffer. */
|
2011-03-29 21:57:56 +00:00
|
|
|
if (!sb.append(str))
|
|
|
|
return false;
|
2009-07-01 00:19:42 +00:00
|
|
|
if (index + 1 != length) {
|
2011-01-12 23:28:58 +00:00
|
|
|
if (!sb.append(", "))
|
2011-03-29 21:57:56 +00:00
|
|
|
return false;
|
2009-07-01 00:19:42 +00:00
|
|
|
} else if (hole) {
|
2011-01-12 23:28:58 +00:00
|
|
|
if (!sb.append(','))
|
2011-03-29 21:57:56 +00:00
|
|
|
return false;
|
2003-06-12 00:26:40 +00:00
|
|
|
}
|
2009-07-01 00:19:42 +00:00
|
|
|
}
|
2009-06-30 18:29:43 +00:00
|
|
|
|
2009-07-01 00:19:42 +00:00
|
|
|
/* Finalize the buffer. */
|
2011-01-12 23:28:58 +00:00
|
|
|
if (!sb.append(']'))
|
2011-03-29 21:57:56 +00:00
|
|
|
return false;
|
2009-06-30 18:29:43 +00:00
|
|
|
|
2009-07-01 00:19:42 +00:00
|
|
|
make_string:
|
2011-03-29 21:57:56 +00:00
|
|
|
JSString *str = sb.finishString();
|
|
|
|
if (!str)
|
|
|
|
return false;
|
2009-08-08 03:09:11 +00:00
|
|
|
|
2011-09-09 04:02:26 +00:00
|
|
|
args.rval().setString(str);
|
2011-03-29 21:57:56 +00:00
|
|
|
return true;
|
2009-07-01 00:19:42 +00:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2011-03-29 22:46:51 +00:00
|
|
|
class AutoArrayCycleDetector
|
|
|
|
{
|
|
|
|
JSContext *cx;
|
|
|
|
JSObject *obj;
|
Bug 708735 - Use <stdint.h> types in JSAPI and throughout SpiderMonkey. Continue to provide the {u,}int{8,16,32,64} and JS{Uint,Int}{8,16,32,64} integer types through a single header, however, for a simpler backout strategy -- and also to ease the transition for embedders. r=timeless on switching the jsd API to use the <stdint.h> types, r=luke, r=dmandelin
2011-12-09 03:54:10 +00:00
|
|
|
uint32_t genBefore;
|
2011-03-29 22:46:51 +00:00
|
|
|
BusyArraysSet::AddPtr hashPointer;
|
|
|
|
bool cycle;
|
|
|
|
JS_DECL_USE_GUARD_OBJECT_NOTIFIER
|
|
|
|
|
|
|
|
public:
|
|
|
|
AutoArrayCycleDetector(JSContext *cx, JSObject *obj JS_GUARD_OBJECT_NOTIFIER_PARAM)
|
|
|
|
: cx(cx),
|
|
|
|
obj(obj),
|
|
|
|
cycle(true)
|
|
|
|
{
|
|
|
|
JS_GUARD_OBJECT_NOTIFIER_INIT;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool init()
|
|
|
|
{
|
|
|
|
BusyArraysSet &set = cx->busyArrays;
|
|
|
|
hashPointer = set.lookupForAdd(obj);
|
|
|
|
if (!hashPointer) {
|
|
|
|
if (!set.add(hashPointer, obj))
|
|
|
|
return false;
|
|
|
|
cycle = false;
|
|
|
|
genBefore = set.generation();
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
~AutoArrayCycleDetector()
|
|
|
|
{
|
|
|
|
if (!cycle) {
|
|
|
|
if (genBefore == cx->busyArrays.generation())
|
|
|
|
cx->busyArrays.remove(hashPointer);
|
|
|
|
else
|
|
|
|
cx->busyArrays.remove(obj);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool foundCycle() { return cycle; }
|
|
|
|
|
|
|
|
protected:
|
|
|
|
};
|
|
|
|
|
2009-07-01 00:19:42 +00:00
|
|
|
static JSBool
|
2012-05-01 00:10:30 +00:00
|
|
|
array_toString_sub(JSContext *cx, HandleObject obj, JSBool locale,
|
|
|
|
HandleString sepstr, CallArgs &args)
|
2009-07-01 00:19:42 +00:00
|
|
|
{
|
2010-12-06 18:26:58 +00:00
|
|
|
static const jschar comma = ',';
|
|
|
|
const jschar *sep;
|
|
|
|
size_t seplen;
|
|
|
|
if (sepstr) {
|
2012-05-01 00:10:30 +00:00
|
|
|
sep = NULL;
|
2010-12-06 18:26:58 +00:00
|
|
|
seplen = sepstr->length();
|
|
|
|
} else {
|
|
|
|
sep = ,
|
|
|
|
seplen = 1;
|
|
|
|
}
|
|
|
|
|
2011-03-29 22:46:51 +00:00
|
|
|
AutoArrayCycleDetector detector(cx, obj);
|
|
|
|
if (!detector.init())
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (detector.foundCycle()) {
|
2011-10-25 01:02:36 +00:00
|
|
|
args.rval().setString(cx->runtime->atomState.emptyAtom);
|
2009-08-08 03:09:11 +00:00
|
|
|
return true;
|
1998-03-28 02:44:41 +00:00
|
|
|
}
|
|
|
|
|
2012-03-06 23:52:55 +00:00
|
|
|
uint32_t length;
|
2011-03-29 22:46:51 +00:00
|
|
|
if (!js_GetLengthProperty(cx, obj, &length))
|
|
|
|
return false;
|
2009-07-01 00:19:42 +00:00
|
|
|
|
2011-01-12 23:28:58 +00:00
|
|
|
StringBuffer sb(cx);
|
2009-07-01 00:19:42 +00:00
|
|
|
|
2011-03-29 22:46:51 +00:00
|
|
|
if (!locale && !seplen && obj->isDenseArray() && !js_PrototypeHasIndexedProperties(cx, obj)) {
|
2012-01-21 12:05:53 +00:00
|
|
|
const Value *start = obj->getDenseArrayElements();
|
|
|
|
const Value *end = start + obj->getDenseArrayInitializedLength();
|
|
|
|
const Value *elem;
|
|
|
|
for (elem = start; elem < end; elem++) {
|
2011-03-29 22:46:51 +00:00
|
|
|
if (!JS_CHECK_OPERATION_LIMIT(cx))
|
|
|
|
return false;
|
2009-07-01 00:19:42 +00:00
|
|
|
|
2012-01-21 12:05:53 +00:00
|
|
|
/*
|
|
|
|
* Object stringifying is slow; delegate it to a separate loop to
|
|
|
|
* keep this one tight.
|
|
|
|
*/
|
|
|
|
if (elem->isObject())
|
|
|
|
break;
|
|
|
|
|
|
|
|
if (!elem->isMagic(JS_ARRAY_HOLE) && !elem->isNullOrUndefined()) {
|
|
|
|
if (!ValueToStringBuffer(cx, *elem, sb))
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for (uint32_t i = uint32_t(PointerRangeSize(start, elem)); i < length; i++) {
|
|
|
|
if (!JS_CHECK_OPERATION_LIMIT(cx))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
JSBool hole;
|
|
|
|
Value v;
|
|
|
|
if (!GetElement(cx, obj, i, &hole, &v))
|
|
|
|
return false;
|
|
|
|
if (!hole && !v.isNullOrUndefined()) {
|
|
|
|
if (!ValueToStringBuffer(cx, v, sb))
|
2011-03-29 22:46:51 +00:00
|
|
|
return false;
|
|
|
|
}
|
2009-08-08 03:09:11 +00:00
|
|
|
}
|
2011-03-29 22:46:51 +00:00
|
|
|
} else {
|
2012-03-06 23:52:55 +00:00
|
|
|
for (uint32_t index = 0; index < length; index++) {
|
2011-03-29 22:46:51 +00:00
|
|
|
if (!JS_CHECK_OPERATION_LIMIT(cx))
|
|
|
|
return false;
|
2009-07-01 00:19:42 +00:00
|
|
|
|
2011-03-29 22:46:51 +00:00
|
|
|
JSBool hole;
|
2011-10-25 01:02:36 +00:00
|
|
|
Value elt;
|
|
|
|
if (!GetElement(cx, obj, index, &hole, &elt))
|
2011-03-29 22:46:51 +00:00
|
|
|
return false;
|
2003-06-12 00:26:40 +00:00
|
|
|
|
2011-10-25 01:02:36 +00:00
|
|
|
if (!hole && !elt.isNullOrUndefined()) {
|
2011-03-29 22:46:51 +00:00
|
|
|
if (locale) {
|
2011-10-25 01:02:36 +00:00
|
|
|
JSObject *robj = ToObject(cx, &elt);
|
2011-03-29 22:46:51 +00:00
|
|
|
if (!robj)
|
|
|
|
return false;
|
2012-05-24 23:05:18 +00:00
|
|
|
RootedId id(cx, NameToId(cx->runtime->atomState.toLocaleStringAtom));
|
2011-10-25 01:02:36 +00:00
|
|
|
if (!robj->callMethod(cx, id, 0, NULL, &elt))
|
2011-03-29 22:46:51 +00:00
|
|
|
return false;
|
|
|
|
}
|
2011-10-25 01:02:36 +00:00
|
|
|
if (!ValueToStringBuffer(cx, elt, sb))
|
2011-03-29 22:46:51 +00:00
|
|
|
return false;
|
|
|
|
}
|
2009-06-30 19:14:09 +00:00
|
|
|
|
2011-03-29 22:46:51 +00:00
|
|
|
if (index + 1 != length) {
|
2012-05-01 00:10:30 +00:00
|
|
|
const jschar *sepchars = sep ? sep : sepstr->getChars(cx);
|
|
|
|
if (!sepchars || !sb.append(sepchars, seplen))
|
2011-03-29 22:46:51 +00:00
|
|
|
return false;
|
|
|
|
}
|
2005-11-20 01:12:58 +00:00
|
|
|
}
|
1998-03-28 02:44:41 +00:00
|
|
|
}
|
|
|
|
|
2011-03-29 22:46:51 +00:00
|
|
|
JSString *str = sb.finishString();
|
2011-03-29 21:57:56 +00:00
|
|
|
if (!str)
|
2011-03-29 22:46:51 +00:00
|
|
|
return false;
|
2011-10-25 01:02:36 +00:00
|
|
|
args.rval().setString(str);
|
2011-03-29 22:46:51 +00:00
|
|
|
return true;
|
1998-04-24 00:31:11 +00:00
|
|
|
}
|
|
|
|
|
2010-07-15 17:33:33 +00:00
|
|
|
/* ES5 15.4.4.2. NB: The algorithm here differs from the one in ES3. */
|
1998-03-28 02:44:41 +00:00
|
|
|
static JSBool
|
2012-02-28 23:11:11 +00:00
|
|
|
array_toString(JSContext *cx, unsigned argc, Value *vp)
|
1998-03-28 02:44:41 +00:00
|
|
|
{
|
2011-04-18 20:50:46 +00:00
|
|
|
JS_CHECK_RECURSION(cx, return false);
|
|
|
|
|
2011-10-25 01:02:36 +00:00
|
|
|
CallArgs args = CallArgsFromVp(argc, vp);
|
2012-05-24 23:05:18 +00:00
|
|
|
RootedObject obj(cx, ToObject(cx, &args.thisv()));
|
2010-07-15 17:33:33 +00:00
|
|
|
if (!obj)
|
|
|
|
return false;
|
|
|
|
|
2011-10-25 01:02:36 +00:00
|
|
|
Value join = args.calleev();
|
2011-09-15 18:44:10 +00:00
|
|
|
if (!obj->getProperty(cx, cx->runtime->atomState.joinAtom, &join))
|
2010-07-15 17:33:33 +00:00
|
|
|
return false;
|
|
|
|
|
|
|
|
if (!js_IsCallable(join)) {
|
|
|
|
JSString *str = obj_toStringHelper(cx, obj);
|
|
|
|
if (!str)
|
|
|
|
return false;
|
2011-10-25 01:02:36 +00:00
|
|
|
args.rval().setString(str);
|
2010-07-15 17:33:33 +00:00
|
|
|
return true;
|
2008-02-18 21:01:47 +00:00
|
|
|
}
|
2009-07-01 00:19:42 +00:00
|
|
|
|
2011-10-25 01:02:36 +00:00
|
|
|
InvokeArgsGuard ag;
|
|
|
|
if (!cx->stack.pushInvokeArgs(cx, 0, &ag))
|
2010-07-15 17:33:33 +00:00
|
|
|
return false;
|
|
|
|
|
2011-10-25 01:02:36 +00:00
|
|
|
ag.calleev() = join;
|
|
|
|
ag.thisv().setObject(*obj);
|
2010-07-15 17:33:33 +00:00
|
|
|
|
|
|
|
/* Do the call. */
|
2011-10-25 01:02:36 +00:00
|
|
|
if (!Invoke(cx, ag))
|
2010-07-15 17:33:33 +00:00
|
|
|
return false;
|
2011-10-25 01:02:36 +00:00
|
|
|
args.rval() = ag.rval();
|
2010-07-15 17:33:33 +00:00
|
|
|
return true;
|
2000-08-09 21:46:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static JSBool
|
2012-02-28 23:11:11 +00:00
|
|
|
array_toLocaleString(JSContext *cx, unsigned argc, Value *vp)
|
2000-08-09 21:46:03 +00:00
|
|
|
{
|
2011-04-18 20:50:46 +00:00
|
|
|
JS_CHECK_RECURSION(cx, return false);
|
|
|
|
|
2011-10-25 01:02:36 +00:00
|
|
|
CallArgs args = CallArgsFromVp(argc, vp);
|
2012-05-24 23:05:18 +00:00
|
|
|
RootedObject obj(cx, ToObject(cx, &args.thisv()));
|
2010-07-15 17:33:33 +00:00
|
|
|
if (!obj)
|
|
|
|
return false;
|
2007-07-10 05:07:20 +00:00
|
|
|
|
2000-08-09 21:46:03 +00:00
|
|
|
/*
|
2001-03-10 00:20:42 +00:00
|
|
|
* Passing comma here as the separator. Need a way to get a
|
2001-01-04 10:13:18 +00:00
|
|
|
* locale-specific version.
|
2000-08-09 21:46:03 +00:00
|
|
|
*/
|
2012-05-24 23:05:18 +00:00
|
|
|
return array_toString_sub(cx, obj, JS_TRUE, RootedString(cx), args);
|
1998-03-28 02:44:41 +00:00
|
|
|
}
|
|
|
|
|
2011-03-06 01:13:40 +00:00
|
|
|
static inline bool
|
|
|
|
InitArrayTypes(JSContext *cx, TypeObject *type, const Value *vector, unsigned count)
|
|
|
|
{
|
2011-04-06 01:12:03 +00:00
|
|
|
if (cx->typeInferenceEnabled() && !type->unknownProperties()) {
|
2011-03-06 01:13:40 +00:00
|
|
|
AutoEnterTypeInference enter(cx);
|
|
|
|
|
|
|
|
TypeSet *types = type->getProperty(cx, JSID_VOID, true);
|
|
|
|
if (!types)
|
2011-04-22 14:59:45 +00:00
|
|
|
return false;
|
2011-03-06 01:13:40 +00:00
|
|
|
|
|
|
|
for (unsigned i = 0; i < count; i++) {
|
|
|
|
if (vector[i].isMagic(JS_ARRAY_HOLE))
|
|
|
|
continue;
|
2011-07-15 17:14:07 +00:00
|
|
|
Type valtype = GetValueType(cx, vector[i]);
|
2011-03-06 01:13:40 +00:00
|
|
|
types->addType(cx, valtype);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2011-11-08 22:54:57 +00:00
|
|
|
enum ShouldUpdateTypes
|
|
|
|
{
|
|
|
|
UpdateTypes = true,
|
|
|
|
DontUpdateTypes = false
|
|
|
|
};
|
|
|
|
|
|
|
|
static bool
|
2012-04-12 16:23:51 +00:00
|
|
|
InitArrayElements(JSContext *cx, HandleObject obj, uint32_t start, uint32_t count, const Value *vector, ShouldUpdateTypes updateTypes)
|
2002-03-14 00:10:31 +00:00
|
|
|
{
|
2011-08-05 22:37:54 +00:00
|
|
|
JS_ASSERT(count <= MAX_ARRAY_INDEX);
|
2009-05-11 21:57:18 +00:00
|
|
|
|
2010-11-05 14:37:09 +00:00
|
|
|
if (count == 0)
|
2011-11-08 22:54:57 +00:00
|
|
|
return true;
|
2010-11-05 14:37:09 +00:00
|
|
|
|
2011-07-15 17:14:07 +00:00
|
|
|
if (updateTypes && !InitArrayTypes(cx, obj->getType(cx), vector, count))
|
2011-11-08 22:54:57 +00:00
|
|
|
return false;
|
2011-03-06 01:13:40 +00:00
|
|
|
|
2009-01-12 21:07:48 +00:00
|
|
|
/*
|
|
|
|
* Optimize for dense arrays so long as adding the given set of elements
|
|
|
|
* wouldn't otherwise make the array slow.
|
|
|
|
*/
|
2010-10-14 14:12:19 +00:00
|
|
|
do {
|
|
|
|
if (!obj->isDenseArray())
|
|
|
|
break;
|
|
|
|
if (js_PrototypeHasIndexedProperties(cx, obj))
|
|
|
|
break;
|
2009-05-11 21:57:18 +00:00
|
|
|
|
2010-10-14 14:12:19 +00:00
|
|
|
JSObject::EnsureDenseResult result = obj->ensureDenseArrayElements(cx, start, count);
|
|
|
|
if (result != JSObject::ED_OK) {
|
|
|
|
if (result == JSObject::ED_FAILED)
|
|
|
|
return false;
|
|
|
|
JS_ASSERT(result == JSObject::ED_SPARSE);
|
|
|
|
break;
|
|
|
|
}
|
2012-03-06 23:52:55 +00:00
|
|
|
uint32_t newlen = start + count;
|
2010-04-06 01:32:16 +00:00
|
|
|
if (newlen > obj->getArrayLength())
|
2011-03-03 22:07:48 +00:00
|
|
|
obj->setDenseArrayLength(newlen);
|
2008-02-18 21:01:47 +00:00
|
|
|
|
2011-09-23 19:13:11 +00:00
|
|
|
JS_ASSERT(count < UINT32_MAX / sizeof(Value));
|
2011-07-13 22:43:33 +00:00
|
|
|
obj->copyDenseArrayElements(start, vector, count);
|
2010-07-15 06:19:36 +00:00
|
|
|
JS_ASSERT_IF(count != 0, !obj->getDenseArrayElement(newlen - 1).isMagic(JS_ARRAY_HOLE));
|
2010-10-14 14:12:19 +00:00
|
|
|
return true;
|
|
|
|
} while (false);
|
2008-02-18 21:01:47 +00:00
|
|
|
|
2011-09-23 19:13:11 +00:00
|
|
|
const Value* end = vector + count;
|
|
|
|
while (vector < end && start <= MAX_ARRAY_INDEX) {
|
2009-02-10 22:07:01 +00:00
|
|
|
if (!JS_CHECK_OPERATION_LIMIT(cx) ||
|
2006-12-24 11:31:37 +00:00
|
|
|
!SetArrayElement(cx, obj, start++, *vector++)) {
|
2011-11-08 22:54:57 +00:00
|
|
|
return false;
|
2006-12-24 11:31:37 +00:00
|
|
|
}
|
2002-03-14 00:10:31 +00:00
|
|
|
}
|
2009-01-12 21:07:48 +00:00
|
|
|
|
|
|
|
if (vector == end)
|
2011-11-08 22:54:57 +00:00
|
|
|
return true;
|
2009-01-12 21:07:48 +00:00
|
|
|
|
|
|
|
/* Finish out any remaining elements past the max array index. */
|
2012-04-12 16:23:51 +00:00
|
|
|
if (obj->isDenseArray() && !JSObject::makeDenseArraySlow(cx, obj))
|
2011-11-08 22:54:57 +00:00
|
|
|
return false;
|
2009-01-12 21:07:48 +00:00
|
|
|
|
2011-08-05 22:37:54 +00:00
|
|
|
JS_ASSERT(start == MAX_ARRAY_INDEX + 1);
|
2012-05-24 23:05:18 +00:00
|
|
|
RootedValue value(cx);
|
|
|
|
RootedId id(cx);
|
2011-08-05 22:37:54 +00:00
|
|
|
Value idval = DoubleValue(MAX_ARRAY_INDEX + 1);
|
2009-01-12 21:07:48 +00:00
|
|
|
do {
|
2012-05-01 00:10:30 +00:00
|
|
|
value = *vector++;
|
2012-05-06 20:45:19 +00:00
|
|
|
if (!ValueToId(cx, idval, id.address()) ||
|
2012-05-01 00:10:30 +00:00
|
|
|
!obj->setGeneric(cx, id, value.address(), true)) {
|
2011-11-08 22:54:57 +00:00
|
|
|
return false;
|
2009-01-12 21:07:48 +00:00
|
|
|
}
|
2010-07-15 06:19:36 +00:00
|
|
|
idval.getDoubleRef() += 1;
|
2009-01-12 21:07:48 +00:00
|
|
|
} while (vector != end);
|
|
|
|
|
2011-11-08 22:54:57 +00:00
|
|
|
return true;
|
2002-03-14 00:10:31 +00:00
|
|
|
}
|
|
|
|
|
2011-09-23 19:13:11 +00:00
|
|
|
#if 0
|
1998-03-28 02:44:41 +00:00
|
|
|
static JSBool
|
2012-03-06 23:52:55 +00:00
|
|
|
InitArrayObject(JSContext *cx, JSObject *obj, uint32_t length, const Value *vector)
|
1998-03-28 02:44:41 +00:00
|
|
|
{
|
2010-03-05 04:44:09 +00:00
|
|
|
JS_ASSERT(obj->isArray());
|
2008-02-15 09:48:53 +00:00
|
|
|
|
2010-07-23 22:29:02 +00:00
|
|
|
JS_ASSERT(obj->isDenseArray());
|
2011-05-16 23:15:37 +00:00
|
|
|
obj->setArrayLength(cx, length);
|
2010-07-23 22:29:02 +00:00
|
|
|
if (!vector || !length)
|
2010-07-27 23:42:58 +00:00
|
|
|
return true;
|
2010-10-14 14:12:19 +00:00
|
|
|
|
2011-07-15 17:14:07 +00:00
|
|
|
if (!InitArrayTypes(cx, obj->getType(cx), vector, length))
|
2011-03-06 01:13:40 +00:00
|
|
|
return false;
|
|
|
|
|
2010-10-14 14:12:19 +00:00
|
|
|
/* Avoid ensureDenseArrayElements to skip sparse array checks there. */
|
2011-10-10 18:41:03 +00:00
|
|
|
if (!obj->ensureElements(cx, length))
|
2010-07-23 22:29:02 +00:00
|
|
|
return false;
|
2011-04-08 00:14:15 +00:00
|
|
|
|
2011-10-10 18:41:03 +00:00
|
|
|
obj->setDenseArrayInitializedLength(length);
|
2011-04-08 00:14:15 +00:00
|
|
|
|
2011-03-03 22:07:48 +00:00
|
|
|
bool hole = false;
|
2012-03-06 23:52:55 +00:00
|
|
|
for (uint32_t i = 0; i < length; i++) {
|
2010-11-05 14:37:09 +00:00
|
|
|
obj->setDenseArrayElement(i, vector[i]);
|
2011-03-03 22:07:48 +00:00
|
|
|
hole |= vector[i].isMagic(JS_ARRAY_HOLE);
|
2010-11-05 14:37:09 +00:00
|
|
|
}
|
2011-05-09 14:12:47 +00:00
|
|
|
if (hole)
|
2011-06-01 18:15:51 +00:00
|
|
|
obj->markDenseArrayNotPacked(cx);
|
2011-04-08 00:14:15 +00:00
|
|
|
|
2010-07-23 22:29:02 +00:00
|
|
|
return true;
|
1998-03-28 02:44:41 +00:00
|
|
|
}
|
2011-09-23 19:13:11 +00:00
|
|
|
#endif
|
1998-03-28 02:44:41 +00:00
|
|
|
|
2003-06-12 00:26:40 +00:00
|
|
|
/*
|
|
|
|
* Perl-inspired join, reverse, and sort.
|
|
|
|
*/
|
2008-10-08 22:08:33 +00:00
|
|
|
static JSBool
|
2012-02-28 23:11:11 +00:00
|
|
|
array_join(JSContext *cx, unsigned argc, Value *vp)
|
2003-06-12 00:26:40 +00:00
|
|
|
{
|
2011-04-18 20:50:46 +00:00
|
|
|
JS_CHECK_RECURSION(cx, return false);
|
|
|
|
|
2011-10-25 01:02:36 +00:00
|
|
|
CallArgs args = CallArgsFromVp(argc, vp);
|
2012-05-24 23:05:18 +00:00
|
|
|
RootedString str(cx);
|
2012-03-01 18:48:52 +00:00
|
|
|
if (args.hasDefined(0)) {
|
2011-12-02 03:35:44 +00:00
|
|
|
str = ToString(cx, args[0]);
|
2005-11-20 01:12:58 +00:00
|
|
|
if (!str)
|
|
|
|
return JS_FALSE;
|
2011-10-25 01:02:36 +00:00
|
|
|
args[0].setString(str);
|
2012-03-01 18:48:52 +00:00
|
|
|
} else {
|
|
|
|
str = NULL;
|
2005-11-20 01:12:58 +00:00
|
|
|
}
|
2012-05-24 23:05:18 +00:00
|
|
|
RootedObject obj(cx, ToObject(cx, &args.thisv()));
|
2011-01-26 21:37:45 +00:00
|
|
|
if (!obj)
|
|
|
|
return false;
|
2011-10-25 01:02:36 +00:00
|
|
|
return array_toString_sub(cx, obj, JS_FALSE, str, args);
|
2003-06-12 00:26:40 +00:00
|
|
|
}
|
|
|
|
|
1998-03-28 02:44:41 +00:00
|
|
|
static JSBool
|
2012-02-28 23:11:11 +00:00
|
|
|
array_reverse(JSContext *cx, unsigned argc, Value *vp)
|
1998-03-28 02:44:41 +00:00
|
|
|
{
|
2011-10-25 01:02:36 +00:00
|
|
|
CallArgs args = CallArgsFromVp(argc, vp);
|
2012-05-24 23:05:18 +00:00
|
|
|
RootedObject obj(cx, ToObject(cx, &args.thisv()));
|
2011-01-26 21:37:45 +00:00
|
|
|
if (!obj)
|
|
|
|
return false;
|
|
|
|
|
2012-03-06 23:52:55 +00:00
|
|
|
uint32_t len;
|
2011-01-26 21:37:45 +00:00
|
|
|
if (!js_GetLengthProperty(cx, obj, &len))
|
|
|
|
return false;
|
2009-05-11 21:57:18 +00:00
|
|
|
|
2010-10-14 14:12:19 +00:00
|
|
|
do {
|
|
|
|
if (!obj->isDenseArray())
|
|
|
|
break;
|
|
|
|
if (js_PrototypeHasIndexedProperties(cx, obj))
|
|
|
|
break;
|
2011-04-11 08:38:27 +00:00
|
|
|
|
2009-05-11 21:57:18 +00:00
|
|
|
/* An empty array or an array with no elements is already reversed. */
|
2011-10-25 01:02:36 +00:00
|
|
|
if (len == 0 || obj->getDenseArrayCapacity() == 0) {
|
|
|
|
args.rval().setObject(*obj);
|
2011-01-26 21:37:45 +00:00
|
|
|
return true;
|
2011-10-25 01:02:36 +00:00
|
|
|
}
|
2009-05-11 21:57:18 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* It's actually surprisingly complicated to reverse an array due to the
|
|
|
|
* orthogonality of array length and array capacity while handling
|
|
|
|
* leading and trailing holes correctly. Reversing seems less likely to
|
|
|
|
* be a common operation than other array mass-mutation methods, so for
|
|
|
|
* now just take a probably-small memory hit (in the absence of too many
|
|
|
|
* holes in the array at its start) and ensure that the capacity is
|
|
|
|
* sufficient to hold all the elements in the array if it were full.
|
|
|
|
*/
|
2010-10-14 14:12:19 +00:00
|
|
|
JSObject::EnsureDenseResult result = obj->ensureDenseArrayElements(cx, len, 0);
|
|
|
|
if (result != JSObject::ED_OK) {
|
|
|
|
if (result == JSObject::ED_FAILED)
|
|
|
|
return false;
|
|
|
|
JS_ASSERT(result == JSObject::ED_SPARSE);
|
|
|
|
break;
|
|
|
|
}
|
2009-05-11 21:57:18 +00:00
|
|
|
|
2010-11-05 14:37:09 +00:00
|
|
|
/* Fill out the array's initialized length to its proper length. */
|
2011-06-01 18:15:51 +00:00
|
|
|
obj->ensureDenseArrayInitializedLength(cx, len, 0);
|
2010-11-05 14:37:09 +00:00
|
|
|
|
Bug 708735 - Use <stdint.h> types in JSAPI and throughout SpiderMonkey. Continue to provide the {u,}int{8,16,32,64} and JS{Uint,Int}{8,16,32,64} integer types through a single header, however, for a simpler backout strategy -- and also to ease the transition for embedders. r=timeless on switching the jsd API to use the <stdint.h> types, r=luke, r=dmandelin
2011-12-09 03:54:10 +00:00
|
|
|
uint32_t lo = 0, hi = len - 1;
|
2009-05-11 21:57:18 +00:00
|
|
|
for (; lo < hi; lo++, hi--) {
|
2011-01-11 02:39:46 +00:00
|
|
|
Value origlo = obj->getDenseArrayElement(lo);
|
|
|
|
Value orighi = obj->getDenseArrayElement(hi);
|
|
|
|
obj->setDenseArrayElement(lo, orighi);
|
|
|
|
if (orighi.isMagic(JS_ARRAY_HOLE) &&
|
|
|
|
!js_SuppressDeletedProperty(cx, obj, INT_TO_JSID(lo))) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
obj->setDenseArrayElement(hi, origlo);
|
|
|
|
if (origlo.isMagic(JS_ARRAY_HOLE) &&
|
|
|
|
!js_SuppressDeletedProperty(cx, obj, INT_TO_JSID(hi))) {
|
|
|
|
return false;
|
|
|
|
}
|
2009-05-11 21:57:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Per ECMA-262, don't update the length of the array, even if the new
|
|
|
|
* array has trailing holes (and thus the original array began with
|
|
|
|
* holes).
|
|
|
|
*/
|
2011-10-25 01:02:36 +00:00
|
|
|
args.rval().setObject(*obj);
|
2011-01-11 02:39:46 +00:00
|
|
|
return true;
|
2010-10-14 14:12:19 +00:00
|
|
|
} while (false);
|
1998-03-28 02:44:41 +00:00
|
|
|
|
2011-10-25 01:02:36 +00:00
|
|
|
Value lowval, hival;
|
2012-03-06 23:52:55 +00:00
|
|
|
for (uint32_t i = 0, half = len / 2; i < half; i++) {
|
2009-09-25 12:30:11 +00:00
|
|
|
JSBool hole, hole2;
|
|
|
|
if (!JS_CHECK_OPERATION_LIMIT(cx) ||
|
2011-10-25 01:02:36 +00:00
|
|
|
!GetElement(cx, obj, i, &hole, &lowval) ||
|
|
|
|
!GetElement(cx, obj, len - i - 1, &hole2, &hival) ||
|
|
|
|
!SetOrDeleteArrayElement(cx, obj, len - i - 1, hole, lowval) ||
|
|
|
|
!SetOrDeleteArrayElement(cx, obj, i, hole2, hival)) {
|
2009-09-25 12:30:11 +00:00
|
|
|
return false;
|
|
|
|
}
|
1998-03-28 02:44:41 +00:00
|
|
|
}
|
2011-10-25 01:02:36 +00:00
|
|
|
args.rval().setObject(*obj);
|
2009-09-25 12:30:11 +00:00
|
|
|
return true;
|
1998-03-28 02:44:41 +00:00
|
|
|
}
|
|
|
|
|
2011-11-16 14:00:32 +00:00
|
|
|
namespace {
|
1998-03-28 02:44:41 +00:00
|
|
|
|
2011-11-16 14:00:32 +00:00
|
|
|
inline bool
|
|
|
|
CompareStringValues(JSContext *cx, const Value &a, const Value &b, bool *lessOrEqualp)
|
|
|
|
{
|
|
|
|
if (!JS_CHECK_OPERATION_LIMIT(cx))
|
|
|
|
return false;
|
2001-01-04 10:13:18 +00:00
|
|
|
|
2011-11-16 14:00:32 +00:00
|
|
|
JSString *astr = a.toString();
|
|
|
|
JSString *bstr = b.toString();
|
Bug 708735 - Use <stdint.h> types in JSAPI and throughout SpiderMonkey. Continue to provide the {u,}int{8,16,32,64} and JS{Uint,Int}{8,16,32,64} integer types through a single header, however, for a simpler backout strategy -- and also to ease the transition for embedders. r=timeless on switching the jsd API to use the <stdint.h> types, r=luke, r=dmandelin
2011-12-09 03:54:10 +00:00
|
|
|
int32_t result;
|
2011-11-16 14:00:32 +00:00
|
|
|
if (!CompareStrings(cx, astr, bstr, &result))
|
|
|
|
return false;
|
2006-10-05 23:28:51 +00:00
|
|
|
|
2011-11-16 14:00:32 +00:00
|
|
|
*lessOrEqualp = (result <= 0);
|
|
|
|
return true;
|
|
|
|
}
|
2002-03-13 01:50:13 +00:00
|
|
|
|
2012-05-02 14:11:00 +00:00
|
|
|
static uint64_t const powersOf10[] = {
|
|
|
|
1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000, 1000000000000ULL
|
2012-01-23 22:06:02 +00:00
|
|
|
};
|
|
|
|
|
2012-01-25 16:54:28 +00:00
|
|
|
static inline unsigned
|
|
|
|
NumDigitsBase10(uint32_t n)
|
2012-01-23 22:06:02 +00:00
|
|
|
{
|
|
|
|
/*
|
|
|
|
* This is just floor_log10(n) + 1
|
|
|
|
* Algorithm taken from
|
|
|
|
* http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog10
|
|
|
|
*/
|
2012-01-25 16:54:28 +00:00
|
|
|
uint32_t log2, t;
|
2012-01-23 22:06:02 +00:00
|
|
|
JS_CEILING_LOG2(log2, n);
|
|
|
|
t = log2 * 1233 >> 12;
|
2012-01-25 16:54:28 +00:00
|
|
|
return t - (n < powersOf10[t]) + 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static JS_ALWAYS_INLINE uint32_t
|
|
|
|
NegateNegativeInt32(int32_t i)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* We cannot simply return '-i' because this is undefined for INT32_MIN.
|
|
|
|
* 2s complement does actually give us what we want, however. That is,
|
|
|
|
* ~0x80000000 + 1 = 0x80000000 which is correct when interpreted as a
|
|
|
|
* uint32_t. To avoid undefined behavior, we write out 2s complement
|
|
|
|
* explicitly and rely on the peephole optimizer to generate 'neg'.
|
|
|
|
*/
|
|
|
|
return ~uint32_t(i) + 1;
|
2012-01-23 22:06:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
inline bool
|
|
|
|
CompareLexicographicInt32(JSContext *cx, const Value &a, const Value &b, bool *lessOrEqualp)
|
|
|
|
{
|
|
|
|
int32_t aint = a.toInt32();
|
|
|
|
int32_t bint = b.toInt32();
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If both numbers are equal ... trivial
|
|
|
|
* If only one of both is negative --> arithmetic comparison as char code
|
|
|
|
* of '-' is always less than any other digit
|
|
|
|
* If both numbers are negative convert them to positive and continue
|
|
|
|
* handling ...
|
|
|
|
*/
|
|
|
|
if (aint == bint) {
|
|
|
|
*lessOrEqualp = true;
|
|
|
|
} else if ((aint < 0) && (bint >= 0)) {
|
|
|
|
*lessOrEqualp = true;
|
|
|
|
} else if ((aint >= 0) && (bint < 0)) {
|
|
|
|
*lessOrEqualp = false;
|
|
|
|
} else {
|
2012-01-25 16:54:28 +00:00
|
|
|
uint32_t auint, buint;
|
|
|
|
if (aint >= 0) {
|
|
|
|
auint = aint;
|
|
|
|
buint = bint;
|
|
|
|
} else {
|
|
|
|
auint = NegateNegativeInt32(aint);
|
|
|
|
buint = NegateNegativeInt32(bint);
|
2012-01-23 22:06:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* ... get number of digits of both integers.
|
|
|
|
* If they have the same number of digits --> arithmetic comparison.
|
|
|
|
* If digits_a > digits_b: a < b*10e(digits_a - digits_b).
|
|
|
|
* If digits_b > digits_a: a*10e(digits_b - digits_a) <= b.
|
|
|
|
*/
|
2012-01-25 16:54:28 +00:00
|
|
|
unsigned digitsa = NumDigitsBase10(auint);
|
|
|
|
unsigned digitsb = NumDigitsBase10(buint);
|
2012-05-02 14:11:00 +00:00
|
|
|
if (digitsa == digitsb) {
|
2012-01-25 16:54:28 +00:00
|
|
|
*lessOrEqualp = (auint <= buint);
|
2012-05-02 14:11:00 +00:00
|
|
|
} else if (digitsa > digitsb) {
|
|
|
|
JS_ASSERT((digitsa - digitsb) < ArrayLength(powersOf10));
|
2012-01-25 16:54:28 +00:00
|
|
|
*lessOrEqualp = (uint64_t(auint) < uint64_t(buint) * powersOf10[digitsa - digitsb]);
|
2012-05-02 14:11:00 +00:00
|
|
|
} else { /* if (digitsb > digitsa) */
|
|
|
|
JS_ASSERT((digitsb - digitsa) < ArrayLength(powersOf10));
|
2012-01-25 16:54:28 +00:00
|
|
|
*lessOrEqualp = (uint64_t(auint) * powersOf10[digitsb - digitsa] <= uint64_t(buint));
|
2012-05-02 14:11:00 +00:00
|
|
|
}
|
2012-01-23 22:06:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline bool
|
|
|
|
CompareSubStringValues(JSContext *cx, const jschar *s1, size_t l1,
|
|
|
|
const jschar *s2, size_t l2, bool *lessOrEqualp)
|
|
|
|
{
|
|
|
|
if (!JS_CHECK_OPERATION_LIMIT(cx))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
int32_t result;
|
|
|
|
if (!s1 || !s2 || !CompareChars(s1, l1, s2, l2, &result))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
*lessOrEqualp = (result <= 0);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct SortComparatorStrings
|
|
|
|
{
|
2011-11-16 14:00:32 +00:00
|
|
|
JSContext *const cx;
|
2005-11-16 10:02:57 +00:00
|
|
|
|
2011-11-16 14:00:32 +00:00
|
|
|
SortComparatorStrings(JSContext *cx)
|
|
|
|
: cx(cx) {}
|
1998-03-28 02:44:41 +00:00
|
|
|
|
2011-11-16 14:00:32 +00:00
|
|
|
bool operator()(const Value &a, const Value &b, bool *lessOrEqualp) {
|
|
|
|
return CompareStringValues(cx, a, b, lessOrEqualp);
|
|
|
|
}
|
|
|
|
};
|
2006-10-05 23:28:51 +00:00
|
|
|
|
2012-01-23 22:06:02 +00:00
|
|
|
struct SortComparatorLexicographicInt32
|
|
|
|
{
|
2011-11-16 14:00:32 +00:00
|
|
|
JSContext *const cx;
|
2006-10-05 23:28:51 +00:00
|
|
|
|
2012-01-23 22:06:02 +00:00
|
|
|
SortComparatorLexicographicInt32(JSContext *cx)
|
2011-11-16 14:00:32 +00:00
|
|
|
: cx(cx) {}
|
2006-10-05 23:28:51 +00:00
|
|
|
|
2012-01-23 22:06:02 +00:00
|
|
|
bool operator()(const Value &a, const Value &b, bool *lessOrEqualp) {
|
|
|
|
return CompareLexicographicInt32(cx, a, b, lessOrEqualp);
|
2005-11-16 10:02:57 +00:00
|
|
|
}
|
2011-11-16 14:00:32 +00:00
|
|
|
};
|
2005-11-16 10:02:57 +00:00
|
|
|
|
2012-01-23 22:06:02 +00:00
|
|
|
struct StringifiedElement
|
|
|
|
{
|
|
|
|
size_t charsBegin;
|
|
|
|
size_t charsEnd;
|
|
|
|
size_t elementIndex;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct SortComparatorStringifiedElements
|
|
|
|
{
|
|
|
|
JSContext *const cx;
|
|
|
|
const StringBuffer &sb;
|
|
|
|
|
|
|
|
SortComparatorStringifiedElements(JSContext *cx, const StringBuffer &sb)
|
|
|
|
: cx(cx), sb(sb) {}
|
|
|
|
|
|
|
|
bool operator()(const StringifiedElement &a, const StringifiedElement &b, bool *lessOrEqualp) {
|
|
|
|
return CompareSubStringValues(cx, sb.begin() + a.charsBegin, a.charsEnd - a.charsBegin,
|
|
|
|
sb.begin() + b.charsBegin, b.charsEnd - b.charsBegin,
|
|
|
|
lessOrEqualp);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
struct SortComparatorFunction
|
|
|
|
{
|
2011-11-16 14:00:32 +00:00
|
|
|
JSContext *const cx;
|
|
|
|
const Value &fval;
|
|
|
|
InvokeArgsGuard &ag;
|
1998-03-28 02:44:41 +00:00
|
|
|
|
2011-11-16 14:00:32 +00:00
|
|
|
SortComparatorFunction(JSContext *cx, const Value &fval, InvokeArgsGuard &ag)
|
|
|
|
: cx(cx), fval(fval), ag(ag) { }
|
2010-03-04 01:52:26 +00:00
|
|
|
|
2011-12-21 01:31:28 +00:00
|
|
|
bool operator()(const Value &a, const Value &b, bool *lessOrEqualp);
|
2010-03-04 01:52:26 +00:00
|
|
|
};
|
1998-03-28 02:44:41 +00:00
|
|
|
|
2011-11-16 14:00:32 +00:00
|
|
|
bool
|
|
|
|
SortComparatorFunction::operator()(const Value &a, const Value &b, bool *lessOrEqualp)
|
1998-03-28 02:44:41 +00:00
|
|
|
{
|
2010-03-04 01:52:26 +00:00
|
|
|
/*
|
2006-03-15 20:49:09 +00:00
|
|
|
* array_sort deals with holes and undefs on its own and they should not
|
|
|
|
* come here.
|
2005-06-08 16:38:38 +00:00
|
|
|
*/
|
2011-11-16 14:00:32 +00:00
|
|
|
JS_ASSERT(!a.isMagic() && !a.isUndefined());
|
|
|
|
JS_ASSERT(!a.isMagic() && !b.isUndefined());
|
2005-06-08 16:38:38 +00:00
|
|
|
|
2009-02-10 22:07:01 +00:00
|
|
|
if (!JS_CHECK_OPERATION_LIMIT(cx))
|
2011-11-16 14:00:32 +00:00
|
|
|
return false;
|
2006-12-24 11:31:37 +00:00
|
|
|
|
2011-10-25 01:02:36 +00:00
|
|
|
if (!ag.pushed() && !cx->stack.pushInvokeArgs(cx, 2, &ag))
|
2011-11-16 14:00:32 +00:00
|
|
|
return false;
|
|
|
|
|
|
|
|
ag.setCallee(fval);
|
2011-10-25 01:02:36 +00:00
|
|
|
ag.thisv() = UndefinedValue();
|
2011-11-16 14:00:32 +00:00
|
|
|
ag[0] = a;
|
|
|
|
ag[1] = b;
|
2007-11-29 07:09:21 +00:00
|
|
|
|
2011-10-25 01:02:36 +00:00
|
|
|
if (!Invoke(cx, ag))
|
2011-11-16 14:00:32 +00:00
|
|
|
return false;
|
2008-03-06 23:24:08 +00:00
|
|
|
|
2012-02-24 22:19:52 +00:00
|
|
|
double cmp;
|
2011-10-25 01:02:36 +00:00
|
|
|
if (!ToNumber(cx, ag.rval(), &cmp))
|
2011-11-16 14:00:32 +00:00
|
|
|
return false;
|
2003-06-12 00:26:40 +00:00
|
|
|
|
2007-11-29 07:09:21 +00:00
|
|
|
/*
|
2011-11-16 14:00:32 +00:00
|
|
|
* XXX eport some kind of error here if cmp is NaN? ECMA talks about
|
|
|
|
* 'consistent compare functions' that don't return NaN, but is silent
|
|
|
|
* about what the result should be. So we currently ignore it.
|
2007-11-29 07:09:21 +00:00
|
|
|
*/
|
2012-01-23 11:43:16 +00:00
|
|
|
*lessOrEqualp = (MOZ_DOUBLE_IS_NaN(cmp) || cmp <= 0);
|
2011-11-16 14:00:32 +00:00
|
|
|
return true;
|
2009-06-25 19:12:19 +00:00
|
|
|
}
|
|
|
|
|
2011-11-16 14:00:32 +00:00
|
|
|
} /* namespace anonymous */
|
2002-05-27 05:53:57 +00:00
|
|
|
|
2010-07-23 21:41:56 +00:00
|
|
|
JSBool
|
2012-02-28 23:11:11 +00:00
|
|
|
js::array_sort(JSContext *cx, unsigned argc, Value *vp)
|
1998-03-28 02:44:41 +00:00
|
|
|
{
|
2011-10-25 01:02:36 +00:00
|
|
|
CallArgs args = CallArgsFromVp(argc, vp);
|
2012-05-24 15:52:21 +00:00
|
|
|
|
2012-05-24 23:05:18 +00:00
|
|
|
RootedValue fvalRoot(cx);
|
2012-05-24 15:52:21 +00:00
|
|
|
Value &fval = fvalRoot.reference();
|
|
|
|
|
2012-03-01 18:48:52 +00:00
|
|
|
if (args.hasDefined(0)) {
|
2011-10-25 01:02:36 +00:00
|
|
|
if (args[0].isPrimitive()) {
|
2010-03-29 07:02:13 +00:00
|
|
|
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_SORT_ARG);
|
|
|
|
return false;
|
2003-06-12 00:26:40 +00:00
|
|
|
}
|
2011-10-25 01:02:36 +00:00
|
|
|
fval = args[0]; /* non-default compare function */
|
1998-03-28 02:44:41 +00:00
|
|
|
} else {
|
2010-07-15 06:19:36 +00:00
|
|
|
fval.setNull();
|
1998-03-28 02:44:41 +00:00
|
|
|
}
|
|
|
|
|
2012-05-24 23:05:18 +00:00
|
|
|
RootedObject obj(cx, ToObject(cx, &args.thisv()));
|
2011-01-26 21:37:45 +00:00
|
|
|
if (!obj)
|
|
|
|
return false;
|
2011-11-16 14:00:32 +00:00
|
|
|
|
2012-03-06 23:52:55 +00:00
|
|
|
uint32_t len;
|
2011-01-26 21:37:45 +00:00
|
|
|
if (!js_GetLengthProperty(cx, obj, &len))
|
2010-03-29 07:02:13 +00:00
|
|
|
return false;
|
2002-11-07 10:51:23 +00:00
|
|
|
if (len == 0) {
|
2011-10-25 01:02:36 +00:00
|
|
|
args.rval().setObject(*obj);
|
2010-03-29 07:02:13 +00:00
|
|
|
return true;
|
2002-11-07 10:51:23 +00:00
|
|
|
}
|
2002-07-31 21:42:12 +00:00
|
|
|
|
2005-10-09 06:09:21 +00:00
|
|
|
/*
|
2010-07-15 06:19:36 +00:00
|
|
|
* We need a temporary array of 2 * len Value to hold the array elements
|
2007-12-13 19:55:21 +00:00
|
|
|
* and the scratch space for merge sort. Check that its size does not
|
|
|
|
* overflow size_t, which would allow for indexing beyond the end of the
|
|
|
|
* malloc'd vector.
|
2005-10-09 06:09:21 +00:00
|
|
|
*/
|
2008-01-07 08:41:06 +00:00
|
|
|
#if JS_BITS_PER_WORD == 32
|
2010-07-15 06:19:36 +00:00
|
|
|
if (size_t(len) > size_t(-1) / (2 * sizeof(Value))) {
|
2008-03-12 23:07:47 +00:00
|
|
|
js_ReportAllocationOverflow(cx);
|
2010-03-29 07:02:13 +00:00
|
|
|
return false;
|
2002-07-31 21:42:12 +00:00
|
|
|
}
|
2008-01-07 08:41:06 +00:00
|
|
|
#endif
|
1998-03-28 02:44:41 +00:00
|
|
|
|
2006-03-17 22:09:46 +00:00
|
|
|
/*
|
|
|
|
* Initialize vec as a root. We will clear elements of vec one by
|
2010-03-29 07:02:13 +00:00
|
|
|
* one while increasing the rooted amount of vec when we know that the
|
|
|
|
* property at the corresponding index exists and its value must be rooted.
|
2006-03-17 22:09:46 +00:00
|
|
|
*
|
2006-07-01 19:52:32 +00:00
|
|
|
* In this way when sorting a huge mostly sparse array we will not
|
2006-03-17 22:09:46 +00:00
|
|
|
* access the tail of vec corresponding to properties that do not
|
2006-08-12 08:41:54 +00:00
|
|
|
* exist, allowing OS to avoiding committing RAM. See bug 330812.
|
2006-03-17 22:09:46 +00:00
|
|
|
*/
|
2011-11-16 14:00:32 +00:00
|
|
|
size_t n, undefs;
|
2010-03-29 07:02:13 +00:00
|
|
|
{
|
2011-11-16 14:00:32 +00:00
|
|
|
AutoValueVector vec(cx);
|
|
|
|
if (!vec.reserve(2 * size_t(len)))
|
2010-03-29 07:02:13 +00:00
|
|
|
return false;
|
2006-12-24 11:31:37 +00:00
|
|
|
|
2010-03-29 07:02:13 +00:00
|
|
|
/*
|
|
|
|
* By ECMA 262, 15.4.4.11, a property that does not exist (which we
|
|
|
|
* call a "hole") is always greater than an existing property with
|
|
|
|
* value undefined and that is always greater than any other property.
|
|
|
|
* Thus to sort holes and undefs we simply count them, sort the rest
|
|
|
|
* of elements, append undefs after them and then make holes after
|
|
|
|
* undefs.
|
|
|
|
*/
|
|
|
|
undefs = 0;
|
|
|
|
bool allStrings = true;
|
2012-01-23 22:06:02 +00:00
|
|
|
bool allInts = true;
|
2012-03-06 23:52:55 +00:00
|
|
|
for (uint32_t i = 0; i < len; i++) {
|
2010-03-29 07:02:13 +00:00
|
|
|
if (!JS_CHECK_OPERATION_LIMIT(cx))
|
|
|
|
return false;
|
2010-01-11 17:52:21 +00:00
|
|
|
|
2010-03-29 07:02:13 +00:00
|
|
|
/* Clear vec[newlen] before including it in the rooted set. */
|
|
|
|
JSBool hole;
|
2011-11-16 14:00:32 +00:00
|
|
|
Value v;
|
|
|
|
if (!GetElement(cx, obj, i, &hole, &v))
|
2010-03-29 07:02:13 +00:00
|
|
|
return false;
|
|
|
|
if (hole)
|
|
|
|
continue;
|
2011-11-16 14:00:32 +00:00
|
|
|
if (v.isUndefined()) {
|
2010-03-29 07:02:13 +00:00
|
|
|
++undefs;
|
|
|
|
continue;
|
|
|
|
}
|
2011-11-16 14:00:32 +00:00
|
|
|
vec.infallibleAppend(v);
|
|
|
|
allStrings = allStrings && v.isString();
|
2012-01-23 22:06:02 +00:00
|
|
|
allInts = allInts && v.isInt32();
|
2010-03-29 07:02:13 +00:00
|
|
|
}
|
|
|
|
|
2011-11-16 14:00:32 +00:00
|
|
|
n = vec.length();
|
|
|
|
if (n == 0) {
|
2011-10-25 01:02:36 +00:00
|
|
|
args.rval().setObject(*obj);
|
2010-03-29 07:02:13 +00:00
|
|
|
return true; /* The array has only holes and undefs. */
|
2010-11-30 18:25:07 +00:00
|
|
|
}
|
2006-10-05 23:28:51 +00:00
|
|
|
|
2011-11-16 14:00:32 +00:00
|
|
|
JS_ALWAYS_TRUE(vec.resize(n * 2));
|
2010-03-29 07:02:13 +00:00
|
|
|
|
2011-11-16 14:00:32 +00:00
|
|
|
/* Here len == n + undefs + number_of_holes. */
|
2012-01-23 22:06:02 +00:00
|
|
|
Value *result = vec.begin();
|
2010-07-15 06:19:36 +00:00
|
|
|
if (fval.isNull()) {
|
2007-12-13 19:55:21 +00:00
|
|
|
/*
|
2010-03-29 07:02:13 +00:00
|
|
|
* Sort using the default comparator converting all elements to
|
|
|
|
* strings.
|
2007-12-13 19:55:21 +00:00
|
|
|
*/
|
2010-03-29 07:02:13 +00:00
|
|
|
if (allStrings) {
|
2011-11-16 14:00:32 +00:00
|
|
|
if (!MergeSort(vec.begin(), n, vec.begin() + n, SortComparatorStrings(cx)))
|
|
|
|
return false;
|
2012-01-23 22:06:02 +00:00
|
|
|
} else if (allInts) {
|
|
|
|
if (!MergeSort(vec.begin(), n, vec.begin() + n,
|
|
|
|
SortComparatorLexicographicInt32(cx))) {
|
|
|
|
return false;
|
|
|
|
}
|
2010-03-29 07:02:13 +00:00
|
|
|
} else {
|
|
|
|
/*
|
2012-01-23 22:06:02 +00:00
|
|
|
* Convert all elements to a jschar array in StringBuffer.
|
|
|
|
* Store the index and length of each stringified element with
|
|
|
|
* the corresponding index of the element in the array. Sort
|
|
|
|
* the stringified elements and with this result order the
|
|
|
|
* original array.
|
2010-03-29 07:02:13 +00:00
|
|
|
*/
|
2012-01-23 22:06:02 +00:00
|
|
|
StringBuffer sb(cx);
|
|
|
|
Vector<StringifiedElement, 0, TempAllocPolicy> strElements(cx);
|
|
|
|
if (!strElements.reserve(2 * n))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
int cursor = 0;
|
|
|
|
for (size_t i = 0; i < n; i++) {
|
2010-03-29 07:02:13 +00:00
|
|
|
if (!JS_CHECK_OPERATION_LIMIT(cx))
|
|
|
|
return false;
|
2012-01-23 22:06:02 +00:00
|
|
|
|
|
|
|
if (!ValueToStringBuffer(cx, vec[i], sb))
|
2010-03-29 07:02:13 +00:00
|
|
|
return false;
|
2011-11-16 14:00:32 +00:00
|
|
|
|
2012-01-23 22:06:02 +00:00
|
|
|
StringifiedElement el = { cursor, sb.length(), i };
|
|
|
|
strElements.infallibleAppend(el);
|
|
|
|
cursor = sb.length();
|
|
|
|
}
|
2010-03-29 07:02:13 +00:00
|
|
|
|
2012-01-23 22:06:02 +00:00
|
|
|
/* Resize strElements so we can perform the sorting */
|
|
|
|
JS_ALWAYS_TRUE(strElements.resize(2 * n));
|
|
|
|
|
|
|
|
if (!MergeSort(strElements.begin(), n, strElements.begin() + n,
|
|
|
|
SortComparatorStringifiedElements(cx, sb))) {
|
2010-03-29 07:02:13 +00:00
|
|
|
return false;
|
2007-12-13 19:55:21 +00:00
|
|
|
}
|
2011-11-16 14:00:32 +00:00
|
|
|
|
2012-01-23 22:06:02 +00:00
|
|
|
/* Order vec[n:2n-1] using strElements.index */
|
|
|
|
for (size_t i = 0; i < n; i ++)
|
|
|
|
vec[n + i] = vec[strElements[i].elementIndex];
|
|
|
|
|
|
|
|
result = vec.begin() + n;
|
2010-03-29 07:02:13 +00:00
|
|
|
}
|
|
|
|
} else {
|
2011-11-16 14:00:32 +00:00
|
|
|
InvokeArgsGuard args;
|
|
|
|
if (!MergeSort(vec.begin(), n, vec.begin() + n,
|
2012-01-23 22:06:02 +00:00
|
|
|
SortComparatorFunction(cx, fval, args))) {
|
2010-03-29 07:02:13 +00:00
|
|
|
return false;
|
2010-03-04 01:52:26 +00:00
|
|
|
}
|
2007-11-21 05:51:46 +00:00
|
|
|
}
|
2005-11-16 10:02:57 +00:00
|
|
|
|
2012-03-06 23:52:55 +00:00
|
|
|
if (!InitArrayElements(cx, obj, 0, uint32_t(n), result, DontUpdateTypes))
|
2010-03-29 07:02:13 +00:00
|
|
|
return false;
|
|
|
|
}
|
2010-03-27 01:01:54 +00:00
|
|
|
|
2006-08-12 08:41:54 +00:00
|
|
|
/* Set undefs that sorted after the rest of elements. */
|
|
|
|
while (undefs != 0) {
|
|
|
|
--undefs;
|
2011-11-16 14:00:32 +00:00
|
|
|
if (!JS_CHECK_OPERATION_LIMIT(cx) || !SetArrayElement(cx, obj, n++, UndefinedValue()))
|
2010-03-29 07:02:13 +00:00
|
|
|
return false;
|
2006-08-12 08:41:54 +00:00
|
|
|
}
|
|
|
|
|
2006-07-01 19:52:32 +00:00
|
|
|
/* Re-create any holes that sorted to the end of the array. */
|
2011-11-16 14:00:32 +00:00
|
|
|
while (len > n) {
|
2011-02-09 19:31:40 +00:00
|
|
|
if (!JS_CHECK_OPERATION_LIMIT(cx) || DeleteArrayElement(cx, obj, --len, true) < 0)
|
2010-09-15 20:43:55 +00:00
|
|
|
return false;
|
2006-07-01 19:52:32 +00:00
|
|
|
}
|
2011-10-25 01:02:36 +00:00
|
|
|
args.rval().setObject(*obj);
|
2010-03-29 07:02:13 +00:00
|
|
|
return true;
|
1998-03-28 02:44:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2003-06-12 00:26:40 +00:00
|
|
|
* Perl-inspired push, pop, shift, unshift, and splice methods.
|
1998-03-28 02:44:41 +00:00
|
|
|
*/
|
2011-10-25 01:02:36 +00:00
|
|
|
static bool
|
2012-04-12 16:23:51 +00:00
|
|
|
array_push_slowly(JSContext *cx, HandleObject obj, CallArgs &args)
|
1998-03-28 02:44:41 +00:00
|
|
|
{
|
2012-03-06 23:52:55 +00:00
|
|
|
uint32_t length;
|
1998-03-28 02:44:41 +00:00
|
|
|
|
1998-04-24 00:31:11 +00:00
|
|
|
if (!js_GetLengthProperty(cx, obj, &length))
|
2011-10-25 01:02:36 +00:00
|
|
|
return false;
|
2011-11-08 22:54:57 +00:00
|
|
|
if (!InitArrayElements(cx, obj, length, args.length(), args.array(), UpdateTypes))
|
2011-10-25 01:02:36 +00:00
|
|
|
return false;
|
1998-03-28 02:44:41 +00:00
|
|
|
|
2006-04-26 21:33:01 +00:00
|
|
|
/* Per ECMA-262, return the new array length. */
|
2012-02-24 22:19:52 +00:00
|
|
|
double newlength = length + double(args.length());
|
2011-10-25 01:02:36 +00:00
|
|
|
args.rval().setNumber(newlength);
|
2006-08-12 08:41:54 +00:00
|
|
|
return js_SetLengthProperty(cx, obj, newlength);
|
1998-03-28 02:44:41 +00:00
|
|
|
}
|
|
|
|
|
2011-10-25 01:02:36 +00:00
|
|
|
static bool
|
2012-04-12 16:23:51 +00:00
|
|
|
array_push1_dense(JSContext* cx, HandleObject obj, CallArgs &args)
|
2007-08-02 04:33:52 +00:00
|
|
|
{
|
2011-10-25 01:02:36 +00:00
|
|
|
JS_ASSERT(args.length() == 1);
|
2007-08-02 04:33:52 +00:00
|
|
|
|
Bug 708735 - Use <stdint.h> types in JSAPI and throughout SpiderMonkey. Continue to provide the {u,}int{8,16,32,64} and JS{Uint,Int}{8,16,32,64} integer types through a single header, however, for a simpler backout strategy -- and also to ease the transition for embedders. r=timeless on switching the jsd API to use the <stdint.h> types, r=luke, r=dmandelin
2011-12-09 03:54:10 +00:00
|
|
|
uint32_t length = obj->getArrayLength();
|
2011-10-25 01:02:36 +00:00
|
|
|
JSObject::EnsureDenseResult result = obj->ensureDenseArrayElements(cx, length, 1);
|
|
|
|
if (result != JSObject::ED_OK) {
|
|
|
|
if (result == JSObject::ED_FAILED)
|
|
|
|
return false;
|
|
|
|
JS_ASSERT(result == JSObject::ED_SPARSE);
|
2012-04-12 16:23:51 +00:00
|
|
|
if (!JSObject::makeDenseArraySlow(cx, obj))
|
2011-10-25 01:02:36 +00:00
|
|
|
return false;
|
|
|
|
return array_push_slowly(cx, obj, args);
|
|
|
|
}
|
2008-02-18 21:01:47 +00:00
|
|
|
|
2011-10-25 01:02:36 +00:00
|
|
|
obj->setDenseArrayLength(length + 1);
|
|
|
|
obj->setDenseArrayElementWithType(cx, length, args[0]);
|
|
|
|
args.rval().setNumber(obj->getArrayLength());
|
|
|
|
return true;
|
2007-08-02 04:33:52 +00:00
|
|
|
}
|
|
|
|
|
2010-07-15 06:19:36 +00:00
|
|
|
JS_ALWAYS_INLINE JSBool
|
2012-05-19 22:03:45 +00:00
|
|
|
NewbornArrayPushImpl(JSContext *cx, HandleObject obj, const Value &v)
|
2009-02-06 19:19:06 +00:00
|
|
|
{
|
2011-06-28 17:05:40 +00:00
|
|
|
JS_ASSERT(!v.isMagic());
|
|
|
|
|
Bug 708735 - Use <stdint.h> types in JSAPI and throughout SpiderMonkey. Continue to provide the {u,}int{8,16,32,64} and JS{Uint,Int}{8,16,32,64} integer types through a single header, however, for a simpler backout strategy -- and also to ease the transition for embedders. r=timeless on switching the jsd API to use the <stdint.h> types, r=luke, r=dmandelin
2011-12-09 03:54:10 +00:00
|
|
|
uint32_t length = obj->getArrayLength();
|
2011-02-17 22:10:10 +00:00
|
|
|
if (obj->isSlowArray()) {
|
|
|
|
/* This can happen in one evil case. See bug 630377. */
|
2012-05-24 23:05:18 +00:00
|
|
|
RootedId id(cx);
|
2012-05-19 22:03:45 +00:00
|
|
|
return IndexToId(cx, length, id.address()) &&
|
|
|
|
baseops::DefineProperty(cx, obj, id, &v, NULL, NULL, JSPROP_ENUMERATE);
|
2011-02-17 22:10:10 +00:00
|
|
|
}
|
|
|
|
|
2010-03-05 04:44:09 +00:00
|
|
|
JS_ASSERT(obj->isDenseArray());
|
2010-04-27 01:33:36 +00:00
|
|
|
JS_ASSERT(length <= obj->getDenseArrayCapacity());
|
2009-02-06 19:19:06 +00:00
|
|
|
|
2011-10-10 18:41:03 +00:00
|
|
|
if (!obj->ensureElements(cx, length + 1))
|
2011-06-28 17:05:40 +00:00
|
|
|
return false;
|
2011-04-08 00:14:15 +00:00
|
|
|
|
2011-10-10 18:41:03 +00:00
|
|
|
obj->setDenseArrayInitializedLength(length + 1);
|
2011-03-03 22:07:48 +00:00
|
|
|
obj->setDenseArrayLength(length + 1);
|
2011-10-25 23:07:42 +00:00
|
|
|
obj->initDenseArrayElementWithType(cx, length, v);
|
2011-02-17 22:10:10 +00:00
|
|
|
return true;
|
2009-02-06 19:19:06 +00:00
|
|
|
}
|
2010-07-15 06:19:36 +00:00
|
|
|
|
|
|
|
JSBool
|
2012-05-19 22:03:45 +00:00
|
|
|
js_NewbornArrayPush(JSContext *cx, HandleObject obj, const Value &vp)
|
2010-07-15 06:19:36 +00:00
|
|
|
{
|
2011-06-28 17:05:40 +00:00
|
|
|
return NewbornArrayPushImpl(cx, obj, vp);
|
2010-07-15 06:19:36 +00:00
|
|
|
}
|
|
|
|
|
2011-05-11 06:33:30 +00:00
|
|
|
JSBool
|
2012-02-28 23:11:11 +00:00
|
|
|
js::array_push(JSContext *cx, unsigned argc, Value *vp)
|
1998-03-28 02:44:41 +00:00
|
|
|
{
|
2011-10-25 01:02:36 +00:00
|
|
|
CallArgs args = CallArgsFromVp(argc, vp);
|
2012-05-24 23:05:18 +00:00
|
|
|
RootedObject obj(cx, ToObject(cx, &args.thisv()));
|
2008-02-18 21:01:47 +00:00
|
|
|
if (!obj)
|
2011-01-26 21:37:45 +00:00
|
|
|
return false;
|
2010-11-09 22:40:10 +00:00
|
|
|
|
2011-01-26 21:37:45 +00:00
|
|
|
/* Insist on one argument and obj of the expected class. */
|
2011-10-25 01:02:36 +00:00
|
|
|
if (args.length() != 1 || !obj->isDenseArray())
|
|
|
|
return array_push_slowly(cx, obj, args);
|
2008-09-17 00:07:59 +00:00
|
|
|
|
2011-10-25 01:02:36 +00:00
|
|
|
return array_push1_dense(cx, obj, args);
|
2008-09-17 00:07:59 +00:00
|
|
|
}
|
|
|
|
|
2008-10-08 22:08:33 +00:00
|
|
|
static JSBool
|
2012-04-12 16:23:51 +00:00
|
|
|
array_pop_slowly(JSContext *cx, HandleObject obj, CallArgs &args)
|
2008-09-17 00:07:59 +00:00
|
|
|
{
|
2012-03-06 23:52:55 +00:00
|
|
|
uint32_t index;
|
2008-02-18 21:01:47 +00:00
|
|
|
if (!js_GetLengthProperty(cx, obj, &index))
|
2011-10-25 01:02:36 +00:00
|
|
|
return false;
|
1998-03-28 02:44:41 +00:00
|
|
|
|
2011-10-25 01:02:36 +00:00
|
|
|
if (index == 0) {
|
|
|
|
args.rval().setUndefined();
|
|
|
|
return js_SetLengthProperty(cx, obj, index);
|
1998-03-28 02:44:41 +00:00
|
|
|
}
|
2011-10-25 01:02:36 +00:00
|
|
|
|
|
|
|
index--;
|
|
|
|
|
|
|
|
JSBool hole;
|
2012-05-24 23:05:18 +00:00
|
|
|
RootedValue elt(cx);
|
2012-05-01 00:10:30 +00:00
|
|
|
if (!GetElement(cx, obj, index, &hole, elt.address()))
|
2011-10-25 01:02:36 +00:00
|
|
|
return false;
|
|
|
|
|
|
|
|
if (!hole && DeleteArrayElement(cx, obj, index, true) < 0)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
args.rval() = elt;
|
1998-04-24 00:31:11 +00:00
|
|
|
return js_SetLengthProperty(cx, obj, index);
|
1998-03-28 02:44:41 +00:00
|
|
|
}
|
|
|
|
|
2008-10-08 22:08:33 +00:00
|
|
|
static JSBool
|
2012-04-12 16:23:51 +00:00
|
|
|
array_pop_dense(JSContext *cx, HandleObject obj, CallArgs &args)
|
2008-09-17 00:07:59 +00:00
|
|
|
{
|
2012-03-06 23:52:55 +00:00
|
|
|
uint32_t index = obj->getArrayLength();
|
2008-09-17 00:07:59 +00:00
|
|
|
if (index == 0) {
|
2011-10-25 01:02:36 +00:00
|
|
|
args.rval().setUndefined();
|
2012-06-12 21:04:33 +00:00
|
|
|
return true;
|
2008-09-17 00:07:59 +00:00
|
|
|
}
|
2011-10-25 01:02:36 +00:00
|
|
|
|
2008-09-17 00:07:59 +00:00
|
|
|
index--;
|
2011-11-16 14:00:32 +00:00
|
|
|
|
2011-10-25 01:02:36 +00:00
|
|
|
JSBool hole;
|
2012-05-24 23:05:18 +00:00
|
|
|
RootedValue elt(cx);
|
2012-05-01 00:10:30 +00:00
|
|
|
if (!GetElement(cx, obj, index, &hole, elt.address()))
|
2012-06-12 21:04:33 +00:00
|
|
|
return false;
|
2011-10-25 01:02:36 +00:00
|
|
|
|
2011-02-09 19:31:40 +00:00
|
|
|
if (!hole && DeleteArrayElement(cx, obj, index, true) < 0)
|
2012-06-12 21:04:33 +00:00
|
|
|
return false;
|
2011-10-25 01:02:36 +00:00
|
|
|
|
|
|
|
args.rval() = elt;
|
2012-06-12 21:04:33 +00:00
|
|
|
|
|
|
|
// obj may not be a dense array any more, e.g. if the element was a missing
|
|
|
|
// and a getter supplied by the prototype modified the object.
|
|
|
|
if (obj->isDenseArray()) {
|
|
|
|
if (obj->getDenseArrayInitializedLength() > index)
|
|
|
|
obj->setDenseArrayInitializedLength(index);
|
|
|
|
|
|
|
|
obj->setArrayLength(cx, index);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return js_SetLengthProperty(cx, obj, index);
|
2008-09-17 00:07:59 +00:00
|
|
|
}
|
|
|
|
|
2011-05-11 06:33:30 +00:00
|
|
|
JSBool
|
2012-02-28 23:11:11 +00:00
|
|
|
js::array_pop(JSContext *cx, unsigned argc, Value *vp)
|
2008-09-17 00:07:59 +00:00
|
|
|
{
|
2011-10-25 01:02:36 +00:00
|
|
|
CallArgs args = CallArgsFromVp(argc, vp);
|
2012-05-24 23:05:18 +00:00
|
|
|
RootedObject obj(cx, ToObject(cx, &args.thisv()));
|
2008-09-17 00:07:59 +00:00
|
|
|
if (!obj)
|
2011-01-26 21:37:45 +00:00
|
|
|
return false;
|
2010-03-05 04:44:09 +00:00
|
|
|
if (obj->isDenseArray())
|
2011-10-25 01:02:36 +00:00
|
|
|
return array_pop_dense(cx, obj, args);
|
|
|
|
return array_pop_slowly(cx, obj, args);
|
2008-09-17 00:07:59 +00:00
|
|
|
}
|
|
|
|
|
2011-10-18 18:08:52 +00:00
|
|
|
#ifdef JS_METHODJIT
|
2011-10-18 21:50:35 +00:00
|
|
|
void JS_FASTCALL
|
2011-10-18 18:08:52 +00:00
|
|
|
mjit::stubs::ArrayShift(VMFrame &f)
|
|
|
|
{
|
|
|
|
JSObject *obj = &f.regs.sp[-1].toObject();
|
|
|
|
JS_ASSERT(obj->isDenseArray());
|
|
|
|
|
|
|
|
/*
|
|
|
|
* At this point the length and initialized length have already been
|
|
|
|
* decremented and the result fetched, so just shift the array elements
|
|
|
|
* themselves.
|
|
|
|
*/
|
Bug 708735 - Use <stdint.h> types in JSAPI and throughout SpiderMonkey. Continue to provide the {u,}int{8,16,32,64} and JS{Uint,Int}{8,16,32,64} integer types through a single header, however, for a simpler backout strategy -- and also to ease the transition for embedders. r=timeless on switching the jsd API to use the <stdint.h> types, r=luke, r=dmandelin
2011-12-09 03:54:10 +00:00
|
|
|
uint32_t initlen = obj->getDenseArrayInitializedLength();
|
2012-01-31 01:13:07 +00:00
|
|
|
obj->moveDenseArrayElementsUnbarriered(0, 1, initlen);
|
2011-10-18 18:08:52 +00:00
|
|
|
}
|
|
|
|
#endif /* JS_METHODJIT */
|
|
|
|
|
|
|
|
JSBool
|
2012-02-28 23:11:11 +00:00
|
|
|
js::array_shift(JSContext *cx, unsigned argc, Value *vp)
|
1998-03-28 02:44:41 +00:00
|
|
|
{
|
2011-10-25 01:02:36 +00:00
|
|
|
CallArgs args = CallArgsFromVp(argc, vp);
|
2012-05-24 23:05:18 +00:00
|
|
|
RootedObject obj(cx, ToObject(cx, &args.thisv()));
|
2011-01-26 21:37:45 +00:00
|
|
|
if (!obj)
|
|
|
|
return JS_FALSE;
|
1998-04-24 00:31:11 +00:00
|
|
|
|
2012-03-06 23:52:55 +00:00
|
|
|
uint32_t length;
|
2011-01-26 21:37:45 +00:00
|
|
|
if (!js_GetLengthProperty(cx, obj, &length))
|
2003-06-12 00:26:40 +00:00
|
|
|
return JS_FALSE;
|
2010-04-12 05:38:55 +00:00
|
|
|
|
2006-08-12 08:41:54 +00:00
|
|
|
if (length == 0) {
|
2011-10-25 01:02:36 +00:00
|
|
|
args.rval().setUndefined();
|
2006-08-12 08:41:54 +00:00
|
|
|
} else {
|
2003-06-12 00:26:40 +00:00
|
|
|
length--;
|
|
|
|
|
2011-04-08 00:14:15 +00:00
|
|
|
if (obj->isDenseArray() && !js_PrototypeHasIndexedProperties(cx, obj) &&
|
|
|
|
length < obj->getDenseArrayCapacity() &&
|
|
|
|
0 < obj->getDenseArrayInitializedLength()) {
|
2011-10-25 01:02:36 +00:00
|
|
|
args.rval() = obj->getDenseArrayElement(0);
|
|
|
|
if (args.rval().isMagic(JS_ARRAY_HOLE))
|
|
|
|
args.rval().setUndefined();
|
2012-01-31 01:13:07 +00:00
|
|
|
obj->moveDenseArrayElements(0, 1, obj->getDenseArrayInitializedLength() - 1);
|
2011-10-10 18:41:03 +00:00
|
|
|
obj->setDenseArrayInitializedLength(obj->getDenseArrayInitializedLength() - 1);
|
2011-05-16 23:15:37 +00:00
|
|
|
obj->setArrayLength(cx, length);
|
2011-01-11 02:39:46 +00:00
|
|
|
if (!js_SuppressDeletedProperty(cx, obj, INT_TO_JSID(length)))
|
|
|
|
return JS_FALSE;
|
2010-04-12 05:38:55 +00:00
|
|
|
return JS_TRUE;
|
|
|
|
}
|
2003-06-12 00:26:40 +00:00
|
|
|
|
2011-01-26 21:37:45 +00:00
|
|
|
JSBool hole;
|
2011-11-04 16:18:52 +00:00
|
|
|
if (!GetElement(cx, obj, 0u, &hole, &args.rval()))
|
2010-04-12 05:38:55 +00:00
|
|
|
return JS_FALSE;
|
2003-06-12 00:26:40 +00:00
|
|
|
|
2010-04-12 05:38:55 +00:00
|
|
|
/* Slide down the array above the first element. */
|
2012-05-24 23:05:18 +00:00
|
|
|
RootedValue value(cx);
|
2012-03-06 23:52:55 +00:00
|
|
|
for (uint32_t i = 0; i < length; i++) {
|
2010-04-12 05:38:55 +00:00
|
|
|
if (!JS_CHECK_OPERATION_LIMIT(cx) ||
|
2012-05-01 00:10:30 +00:00
|
|
|
!GetElement(cx, obj, i + 1, &hole, value.address()) ||
|
|
|
|
!SetOrDeleteArrayElement(cx, obj, i, hole, value)) {
|
2009-05-11 21:57:18 +00:00
|
|
|
return JS_FALSE;
|
2010-04-12 05:38:55 +00:00
|
|
|
}
|
2009-05-11 21:57:18 +00:00
|
|
|
}
|
2010-04-12 05:38:55 +00:00
|
|
|
|
|
|
|
/* Delete the only or last element when it exists. */
|
2011-02-09 19:31:40 +00:00
|
|
|
if (!hole && DeleteArrayElement(cx, obj, length, true) < 0)
|
2010-04-12 05:38:55 +00:00
|
|
|
return JS_FALSE;
|
1998-03-28 02:44:41 +00:00
|
|
|
}
|
1998-04-24 00:31:11 +00:00
|
|
|
return js_SetLengthProperty(cx, obj, length);
|
1998-03-28 02:44:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static JSBool
|
2012-02-28 23:11:11 +00:00
|
|
|
array_unshift(JSContext *cx, unsigned argc, Value *vp)
|
1998-03-28 02:44:41 +00:00
|
|
|
{
|
2011-10-25 01:02:36 +00:00
|
|
|
CallArgs args = CallArgsFromVp(argc, vp);
|
2012-05-24 23:05:18 +00:00
|
|
|
RootedObject obj(cx, ToObject(cx, &args.thisv()));
|
2011-01-26 21:37:45 +00:00
|
|
|
if (!obj)
|
|
|
|
return false;
|
|
|
|
|
2012-03-06 23:52:55 +00:00
|
|
|
uint32_t length;
|
2011-01-26 21:37:45 +00:00
|
|
|
if (!js_GetLengthProperty(cx, obj, &length))
|
2003-06-12 00:26:40 +00:00
|
|
|
return JS_FALSE;
|
2010-11-09 22:40:10 +00:00
|
|
|
|
2012-02-24 22:19:52 +00:00
|
|
|
double newlen = length;
|
2011-10-25 01:02:36 +00:00
|
|
|
if (args.length() > 0) {
|
|
|
|
/* Slide up the array to make room for all args at the bottom. */
|
2003-06-12 00:26:40 +00:00
|
|
|
if (length > 0) {
|
2010-10-14 14:12:19 +00:00
|
|
|
bool optimized = false;
|
|
|
|
do {
|
|
|
|
if (!obj->isDenseArray())
|
|
|
|
break;
|
|
|
|
if (js_PrototypeHasIndexedProperties(cx, obj))
|
|
|
|
break;
|
2011-10-25 01:02:36 +00:00
|
|
|
JSObject::EnsureDenseResult result = obj->ensureDenseArrayElements(cx, length, args.length());
|
2010-10-14 14:12:19 +00:00
|
|
|
if (result != JSObject::ED_OK) {
|
|
|
|
if (result == JSObject::ED_FAILED)
|
|
|
|
return false;
|
|
|
|
JS_ASSERT(result == JSObject::ED_SPARSE);
|
|
|
|
break;
|
|
|
|
}
|
2011-10-25 01:02:36 +00:00
|
|
|
obj->moveDenseArrayElements(args.length(), 0, length);
|
Bug 708735 - Use <stdint.h> types in JSAPI and throughout SpiderMonkey. Continue to provide the {u,}int{8,16,32,64} and JS{Uint,Int}{8,16,32,64} integer types through a single header, however, for a simpler backout strategy -- and also to ease the transition for embedders. r=timeless on switching the jsd API to use the <stdint.h> types, r=luke, r=dmandelin
2011-12-09 03:54:10 +00:00
|
|
|
for (uint32_t i = 0; i < args.length(); i++)
|
2010-07-15 06:19:36 +00:00
|
|
|
obj->setDenseArrayElement(i, MagicValue(JS_ARRAY_HOLE));
|
2010-10-14 14:12:19 +00:00
|
|
|
optimized = true;
|
|
|
|
} while (false);
|
|
|
|
|
|
|
|
if (!optimized) {
|
2012-02-24 22:19:52 +00:00
|
|
|
double last = length;
|
|
|
|
double upperIndex = last + args.length();
|
2012-05-24 23:05:18 +00:00
|
|
|
RootedValue value(cx);
|
2009-05-11 21:57:18 +00:00
|
|
|
do {
|
|
|
|
--last, --upperIndex;
|
2011-10-25 01:02:36 +00:00
|
|
|
JSBool hole;
|
2009-05-11 21:57:18 +00:00
|
|
|
if (!JS_CHECK_OPERATION_LIMIT(cx) ||
|
2012-05-01 00:10:30 +00:00
|
|
|
!GetElement(cx, obj, last, &hole, value.address()) ||
|
|
|
|
!SetOrDeleteArrayElement(cx, obj, upperIndex, hole, value)) {
|
2009-05-11 21:57:18 +00:00
|
|
|
return JS_FALSE;
|
|
|
|
}
|
|
|
|
} while (last != 0);
|
|
|
|
}
|
2003-06-12 00:26:40 +00:00
|
|
|
}
|
|
|
|
|
2011-10-25 01:02:36 +00:00
|
|
|
/* Copy from args to the bottom of the array. */
|
2011-11-08 22:54:57 +00:00
|
|
|
if (!InitArrayElements(cx, obj, 0, args.length(), args.array(), UpdateTypes))
|
2006-08-12 08:41:54 +00:00
|
|
|
return JS_FALSE;
|
2003-06-12 00:26:40 +00:00
|
|
|
|
2011-10-25 01:02:36 +00:00
|
|
|
newlen += args.length();
|
1998-03-28 02:44:41 +00:00
|
|
|
}
|
2010-11-24 22:22:44 +00:00
|
|
|
if (!js_SetLengthProperty(cx, obj, newlen))
|
|
|
|
return JS_FALSE;
|
2006-08-12 08:41:54 +00:00
|
|
|
|
|
|
|
/* Follow Perl by returning the new array length. */
|
2011-10-25 01:02:36 +00:00
|
|
|
args.rval().setNumber(newlen);
|
2010-07-15 06:19:36 +00:00
|
|
|
return JS_TRUE;
|
1998-03-28 02:44:41 +00:00
|
|
|
}
|
|
|
|
|
2011-09-18 14:36:51 +00:00
|
|
|
static inline void
|
|
|
|
TryReuseArrayType(JSObject *obj, JSObject *nobj)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* Try to change the type of a newly created array nobj to the same type
|
|
|
|
* as obj. This can only be performed if the original object is an array
|
|
|
|
* and has the same prototype.
|
|
|
|
*/
|
|
|
|
JS_ASSERT(nobj->isDenseArray());
|
2011-10-08 03:09:09 +00:00
|
|
|
JS_ASSERT(nobj->getProto()->hasNewType(nobj->type()));
|
2011-09-18 14:36:51 +00:00
|
|
|
|
|
|
|
if (obj->isArray() && !obj->hasSingletonType() && obj->getProto() == nobj->getProto())
|
|
|
|
nobj->setType(obj->type());
|
|
|
|
}
|
|
|
|
|
2011-09-23 19:13:11 +00:00
|
|
|
/*
|
|
|
|
* Returns true if this is a dense array whose |count| properties starting from
|
|
|
|
* |startingIndex| may be accessed (get, set, delete) directly through its
|
|
|
|
* contiguous vector of elements without fear of getters, setters, etc. along
|
2011-10-17 18:10:43 +00:00
|
|
|
* the prototype chain, or of enumerators requiring notification of
|
|
|
|
* modifications.
|
2011-09-23 19:13:11 +00:00
|
|
|
*/
|
|
|
|
static inline bool
|
Bug 708735 - Use <stdint.h> types in JSAPI and throughout SpiderMonkey. Continue to provide the {u,}int{8,16,32,64} and JS{Uint,Int}{8,16,32,64} integer types through a single header, however, for a simpler backout strategy -- and also to ease the transition for embedders. r=timeless on switching the jsd API to use the <stdint.h> types, r=luke, r=dmandelin
2011-12-09 03:54:10 +00:00
|
|
|
CanOptimizeForDenseStorage(JSObject *arr, uint32_t startingIndex, uint32_t count, JSContext *cx)
|
2011-09-23 19:13:11 +00:00
|
|
|
{
|
2011-10-17 18:10:43 +00:00
|
|
|
/* If the desired properties overflow dense storage, we can't optimize. */
|
|
|
|
if (UINT32_MAX - startingIndex < count)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
/* There's no optimizing possible if it's not a dense array. */
|
|
|
|
if (!arr->isDenseArray())
|
|
|
|
return false;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Don't optimize if the array might be in the midst of iteration. We
|
|
|
|
* rely on this to be able to safely move dense array elements around with
|
|
|
|
* just a memmove (see JSObject::moveDenseArrayElements), without worrying
|
|
|
|
* about updating any in-progress enumerators for properties implicitly
|
|
|
|
* deleted if a hole is moved from one location to another location not yet
|
|
|
|
* visited. See bug 690622.
|
|
|
|
*
|
|
|
|
* Another potential wrinkle: what if the enumeration is happening on an
|
|
|
|
* object which merely has |arr| on its prototype chain? It turns out this
|
|
|
|
* case can't happen, because any dense array used as the prototype of
|
|
|
|
* another object is first slowified, for type inference's sake.
|
|
|
|
*/
|
|
|
|
if (JS_UNLIKELY(arr->getType(cx)->hasAllFlags(OBJECT_FLAG_ITERATED)))
|
|
|
|
return false;
|
2011-09-23 19:13:11 +00:00
|
|
|
|
2011-10-17 18:10:43 +00:00
|
|
|
/* Now just watch out for getters and setters along the prototype chain. */
|
|
|
|
return !js_PrototypeHasIndexedProperties(cx, arr) &&
|
|
|
|
startingIndex + count <= arr->getDenseArrayInitializedLength();
|
2011-09-23 19:13:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* ES5 15.4.4.12. */
|
1998-03-28 02:44:41 +00:00
|
|
|
static JSBool
|
2012-02-28 23:11:11 +00:00
|
|
|
array_splice(JSContext *cx, unsigned argc, Value *vp)
|
1998-03-28 02:44:41 +00:00
|
|
|
{
|
2011-09-23 19:13:11 +00:00
|
|
|
CallArgs args = CallArgsFromVp(argc, vp);
|
|
|
|
|
|
|
|
/* Step 1. */
|
2012-05-24 23:05:18 +00:00
|
|
|
RootedObject obj(cx, ToObject(cx, &args.thisv()));
|
2011-01-26 21:37:45 +00:00
|
|
|
if (!obj)
|
|
|
|
return false;
|
|
|
|
|
2011-09-23 19:13:11 +00:00
|
|
|
/* Steps 3-4. */
|
Bug 708735 - Use <stdint.h> types in JSAPI and throughout SpiderMonkey. Continue to provide the {u,}int{8,16,32,64} and JS{Uint,Int}{8,16,32,64} integer types through a single header, however, for a simpler backout strategy -- and also to ease the transition for embedders. r=timeless on switching the jsd API to use the <stdint.h> types, r=luke, r=dmandelin
2011-12-09 03:54:10 +00:00
|
|
|
uint32_t len;
|
2011-09-23 19:13:11 +00:00
|
|
|
if (!js_GetLengthProperty(cx, obj, &len))
|
|
|
|
return false;
|
1998-03-28 02:44:41 +00:00
|
|
|
|
2011-09-23 19:13:11 +00:00
|
|
|
/* Step 5. */
|
|
|
|
double relativeStart;
|
|
|
|
if (!ToInteger(cx, argc >= 1 ? args[0] : UndefinedValue(), &relativeStart))
|
|
|
|
return false;
|
2008-08-26 00:12:30 +00:00
|
|
|
|
2011-09-23 19:13:11 +00:00
|
|
|
/* Step 6. */
|
Bug 708735 - Use <stdint.h> types in JSAPI and throughout SpiderMonkey. Continue to provide the {u,}int{8,16,32,64} and JS{Uint,Int}{8,16,32,64} integer types through a single header, however, for a simpler backout strategy -- and also to ease the transition for embedders. r=timeless on switching the jsd API to use the <stdint.h> types, r=luke, r=dmandelin
2011-12-09 03:54:10 +00:00
|
|
|
uint32_t actualStart;
|
2011-09-23 19:13:11 +00:00
|
|
|
if (relativeStart < 0)
|
|
|
|
actualStart = JS_MAX(len + relativeStart, 0);
|
|
|
|
else
|
|
|
|
actualStart = JS_MIN(relativeStart, len);
|
1998-03-28 02:44:41 +00:00
|
|
|
|
2011-09-23 19:13:11 +00:00
|
|
|
/* Step 7. */
|
Bug 708735 - Use <stdint.h> types in JSAPI and throughout SpiderMonkey. Continue to provide the {u,}int{8,16,32,64} and JS{Uint,Int}{8,16,32,64} integer types through a single header, however, for a simpler backout strategy -- and also to ease the transition for embedders. r=timeless on switching the jsd API to use the <stdint.h> types, r=luke, r=dmandelin
2011-12-09 03:54:10 +00:00
|
|
|
uint32_t actualDeleteCount;
|
2011-09-23 19:13:11 +00:00
|
|
|
if (argc != 1) {
|
2012-02-24 22:19:52 +00:00
|
|
|
double deleteCountDouble;
|
2011-09-23 19:13:11 +00:00
|
|
|
if (!ToInteger(cx, argc >= 2 ? args[1] : Int32Value(0), &deleteCountDouble))
|
|
|
|
return false;
|
|
|
|
actualDeleteCount = JS_MIN(JS_MAX(deleteCountDouble, 0), len - actualStart);
|
1998-03-28 02:44:41 +00:00
|
|
|
} else {
|
2011-09-23 19:13:11 +00:00
|
|
|
/*
|
|
|
|
* Non-standard: if start was specified but deleteCount was omitted,
|
|
|
|
* delete to the end of the array. See bug 668024 for discussion.
|
|
|
|
*/
|
|
|
|
actualDeleteCount = len - actualStart;
|
|
|
|
}
|
|
|
|
|
|
|
|
JS_ASSERT(len - actualStart >= actualDeleteCount);
|
|
|
|
|
|
|
|
/* Steps 2, 8-9. */
|
2012-05-24 23:05:18 +00:00
|
|
|
RootedObject arr(cx);
|
2011-09-23 19:13:11 +00:00
|
|
|
if (CanOptimizeForDenseStorage(obj, actualStart, actualDeleteCount, cx)) {
|
|
|
|
arr = NewDenseCopiedArray(cx, actualDeleteCount,
|
|
|
|
obj->getDenseArrayElements() + actualStart);
|
|
|
|
if (!arr)
|
2011-04-02 18:33:20 +00:00
|
|
|
return false;
|
2011-09-23 19:13:11 +00:00
|
|
|
TryReuseArrayType(obj, arr);
|
|
|
|
} else {
|
|
|
|
arr = NewDenseAllocatedArray(cx, actualDeleteCount);
|
|
|
|
if (!arr)
|
|
|
|
return false;
|
|
|
|
TryReuseArrayType(obj, arr);
|
|
|
|
|
Bug 708735 - Use <stdint.h> types in JSAPI and throughout SpiderMonkey. Continue to provide the {u,}int{8,16,32,64} and JS{Uint,Int}{8,16,32,64} integer types through a single header, however, for a simpler backout strategy -- and also to ease the transition for embedders. r=timeless on switching the jsd API to use the <stdint.h> types, r=luke, r=dmandelin
2011-12-09 03:54:10 +00:00
|
|
|
for (uint32_t k = 0; k < actualDeleteCount; k++) {
|
2011-09-23 19:13:11 +00:00
|
|
|
JSBool hole;
|
|
|
|
Value fromValue;
|
|
|
|
if (!JS_CHECK_OPERATION_LIMIT(cx) ||
|
|
|
|
!GetElement(cx, obj, actualStart + k, &hole, &fromValue) ||
|
|
|
|
(!hole && !arr->defineElement(cx, k, fromValue)))
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
1998-03-28 02:44:41 +00:00
|
|
|
}
|
|
|
|
|
2011-09-23 19:13:11 +00:00
|
|
|
/* Step 11. */
|
Bug 708735 - Use <stdint.h> types in JSAPI and throughout SpiderMonkey. Continue to provide the {u,}int{8,16,32,64} and JS{Uint,Int}{8,16,32,64} integer types through a single header, however, for a simpler backout strategy -- and also to ease the transition for embedders. r=timeless on switching the jsd API to use the <stdint.h> types, r=luke, r=dmandelin
2011-12-09 03:54:10 +00:00
|
|
|
uint32_t itemCount = (argc >= 2) ? (argc - 2) : 0;
|
2007-10-13 20:09:48 +00:00
|
|
|
|
2011-09-23 19:13:11 +00:00
|
|
|
if (itemCount < actualDeleteCount) {
|
|
|
|
/* Step 12: the array is being shrunk. */
|
Bug 708735 - Use <stdint.h> types in JSAPI and throughout SpiderMonkey. Continue to provide the {u,}int{8,16,32,64} and JS{Uint,Int}{8,16,32,64} integer types through a single header, however, for a simpler backout strategy -- and also to ease the transition for embedders. r=timeless on switching the jsd API to use the <stdint.h> types, r=luke, r=dmandelin
2011-12-09 03:54:10 +00:00
|
|
|
uint32_t sourceIndex = actualStart + actualDeleteCount;
|
|
|
|
uint32_t targetIndex = actualStart + itemCount;
|
|
|
|
uint32_t finalLength = len - actualDeleteCount + itemCount;
|
2011-09-23 19:13:11 +00:00
|
|
|
|
|
|
|
if (CanOptimizeForDenseStorage(obj, 0, len, cx)) {
|
|
|
|
/* Steps 12(a)-(b). */
|
|
|
|
obj->moveDenseArrayElements(targetIndex, sourceIndex, len - sourceIndex);
|
|
|
|
|
|
|
|
/*
|
2011-10-25 23:07:42 +00:00
|
|
|
* Update the initialized length. Do so before shrinking so that we
|
|
|
|
* can apply the write barrier to the old slots.
|
2011-09-23 19:13:11 +00:00
|
|
|
*/
|
|
|
|
if (cx->typeInferenceEnabled())
|
|
|
|
obj->setDenseArrayInitializedLength(finalLength);
|
|
|
|
|
2011-10-25 23:07:42 +00:00
|
|
|
/* Steps 12(c)-(d). */
|
2011-11-14 17:13:33 +00:00
|
|
|
obj->shrinkElements(cx, finalLength);
|
2011-10-25 23:07:42 +00:00
|
|
|
|
2011-09-23 19:13:11 +00:00
|
|
|
/* Fix running enumerators for the deleted items. */
|
|
|
|
if (!js_SuppressDeletedElements(cx, obj, finalLength, len))
|
|
|
|
return false;
|
2009-05-11 21:57:18 +00:00
|
|
|
} else {
|
2011-09-23 19:13:11 +00:00
|
|
|
/*
|
|
|
|
* This is all very slow if the length is very large. We don't yet
|
|
|
|
* have the ability to iterate in sorted order, so we just do the
|
|
|
|
* pessimistic thing and let JS_CHECK_OPERATION_LIMIT handle the
|
|
|
|
* fallout.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* Steps 12(a)-(b). */
|
Bug 708735 - Use <stdint.h> types in JSAPI and throughout SpiderMonkey. Continue to provide the {u,}int{8,16,32,64} and JS{Uint,Int}{8,16,32,64} integer types through a single header, however, for a simpler backout strategy -- and also to ease the transition for embedders. r=timeless on switching the jsd API to use the <stdint.h> types, r=luke, r=dmandelin
2011-12-09 03:54:10 +00:00
|
|
|
for (uint32_t from = sourceIndex, to = targetIndex; from < len; from++, to++) {
|
2011-09-23 19:13:11 +00:00
|
|
|
JSBool hole;
|
|
|
|
Value fromValue;
|
2009-05-11 21:57:18 +00:00
|
|
|
if (!JS_CHECK_OPERATION_LIMIT(cx) ||
|
2011-09-23 19:13:11 +00:00
|
|
|
!GetElement(cx, obj, from, &hole, &fromValue) ||
|
|
|
|
!SetOrDeleteArrayElement(cx, obj, to, hole, fromValue))
|
|
|
|
{
|
|
|
|
return false;
|
2009-05-11 21:57:18 +00:00
|
|
|
}
|
2007-10-13 20:09:48 +00:00
|
|
|
}
|
2006-04-28 00:20:44 +00:00
|
|
|
|
2011-09-23 19:13:11 +00:00
|
|
|
/* Steps 12(c)-(d). */
|
Bug 708735 - Use <stdint.h> types in JSAPI and throughout SpiderMonkey. Continue to provide the {u,}int{8,16,32,64} and JS{Uint,Int}{8,16,32,64} integer types through a single header, however, for a simpler backout strategy -- and also to ease the transition for embedders. r=timeless on switching the jsd API to use the <stdint.h> types, r=luke, r=dmandelin
2011-12-09 03:54:10 +00:00
|
|
|
for (uint32_t k = len; k > finalLength; k--) {
|
2011-09-23 19:13:11 +00:00
|
|
|
if (DeleteArrayElement(cx, obj, k - 1, true) < 0)
|
2010-10-14 14:12:19 +00:00
|
|
|
return false;
|
|
|
|
}
|
2011-09-23 19:13:11 +00:00
|
|
|
}
|
|
|
|
} else if (itemCount > actualDeleteCount) {
|
|
|
|
/* Step 13. */
|
2010-07-21 03:27:15 +00:00
|
|
|
|
2011-09-23 19:13:11 +00:00
|
|
|
/*
|
|
|
|
* Optimize only if the array is already dense and we can extend it to
|
|
|
|
* its new length.
|
|
|
|
*/
|
|
|
|
if (obj->isDenseArray()) {
|
|
|
|
JSObject::EnsureDenseResult res =
|
|
|
|
obj->ensureDenseArrayElements(cx, obj->getArrayLength(),
|
|
|
|
itemCount - actualDeleteCount);
|
|
|
|
if (res == JSObject::ED_FAILED)
|
|
|
|
return false;
|
2010-10-14 14:12:19 +00:00
|
|
|
|
2011-09-23 19:13:11 +00:00
|
|
|
if (res == JSObject::ED_SPARSE) {
|
2012-04-12 16:23:51 +00:00
|
|
|
if (!JSObject::makeDenseArraySlow(cx, obj))
|
2011-09-23 19:13:11 +00:00
|
|
|
return false;
|
|
|
|
} else {
|
|
|
|
JS_ASSERT(res == JSObject::ED_OK);
|
2009-05-11 21:57:18 +00:00
|
|
|
}
|
2003-06-12 00:26:40 +00:00
|
|
|
}
|
2010-07-21 03:27:15 +00:00
|
|
|
|
2011-09-23 19:13:11 +00:00
|
|
|
if (CanOptimizeForDenseStorage(obj, len, itemCount - actualDeleteCount, cx)) {
|
|
|
|
obj->moveDenseArrayElements(actualStart + itemCount,
|
|
|
|
actualStart + actualDeleteCount,
|
|
|
|
len - (actualStart + actualDeleteCount));
|
|
|
|
|
|
|
|
if (cx->typeInferenceEnabled())
|
|
|
|
obj->setDenseArrayInitializedLength(len + itemCount - actualDeleteCount);
|
2009-05-11 21:57:18 +00:00
|
|
|
} else {
|
2012-02-24 22:19:52 +00:00
|
|
|
for (double k = len - actualDeleteCount; k > actualStart; k--) {
|
|
|
|
double from = k + actualDeleteCount - 1;
|
|
|
|
double to = k + itemCount - 1;
|
2011-09-23 19:13:11 +00:00
|
|
|
|
|
|
|
JSBool hole;
|
|
|
|
Value fromValue;
|
2009-05-11 21:57:18 +00:00
|
|
|
if (!JS_CHECK_OPERATION_LIMIT(cx) ||
|
2011-09-23 19:13:11 +00:00
|
|
|
!GetElement(cx, obj, from, &hole, &fromValue) ||
|
|
|
|
!SetOrDeleteArrayElement(cx, obj, to, hole, fromValue))
|
|
|
|
{
|
|
|
|
return false;
|
2009-05-11 21:57:18 +00:00
|
|
|
}
|
|
|
|
}
|
2003-06-12 00:26:40 +00:00
|
|
|
}
|
1998-03-28 02:44:41 +00:00
|
|
|
}
|
|
|
|
|
2011-09-23 19:13:11 +00:00
|
|
|
/* Step 10. */
|
|
|
|
Value *items = args.array() + 2;
|
2010-10-01 18:12:01 +00:00
|
|
|
|
2011-09-23 19:13:11 +00:00
|
|
|
/* Steps 14-15. */
|
Bug 708735 - Use <stdint.h> types in JSAPI and throughout SpiderMonkey. Continue to provide the {u,}int{8,16,32,64} and JS{Uint,Int}{8,16,32,64} integer types through a single header, however, for a simpler backout strategy -- and also to ease the transition for embedders. r=timeless on switching the jsd API to use the <stdint.h> types, r=luke, r=dmandelin
2011-12-09 03:54:10 +00:00
|
|
|
for (uint32_t k = actualStart, i = 0; i < itemCount; i++, k++) {
|
2011-09-23 19:13:11 +00:00
|
|
|
if (!SetArrayElement(cx, obj, k, items[i]))
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Step 16. */
|
2012-02-24 22:19:52 +00:00
|
|
|
double finalLength = double(len) - actualDeleteCount + itemCount;
|
2011-09-23 19:13:11 +00:00
|
|
|
if (!js_SetLengthProperty(cx, obj, finalLength))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
/* Step 17. */
|
|
|
|
args.rval().setObject(*arr);
|
|
|
|
return true;
|
1998-03-28 02:44:41 +00:00
|
|
|
}
|
|
|
|
|
2011-10-18 18:24:28 +00:00
|
|
|
#ifdef JS_METHODJIT
|
|
|
|
void JS_FASTCALL
|
|
|
|
mjit::stubs::ArrayConcatTwoArrays(VMFrame &f)
|
|
|
|
{
|
|
|
|
JSObject *result = &f.regs.sp[-3].toObject();
|
|
|
|
JSObject *obj1 = &f.regs.sp[-2].toObject();
|
|
|
|
JSObject *obj2 = &f.regs.sp[-1].toObject();
|
|
|
|
|
|
|
|
JS_ASSERT(result->isDenseArray() && obj1->isDenseArray() && obj2->isDenseArray());
|
|
|
|
|
Bug 708735 - Use <stdint.h> types in JSAPI and throughout SpiderMonkey. Continue to provide the {u,}int{8,16,32,64} and JS{Uint,Int}{8,16,32,64} integer types through a single header, however, for a simpler backout strategy -- and also to ease the transition for embedders. r=timeless on switching the jsd API to use the <stdint.h> types, r=luke, r=dmandelin
2011-12-09 03:54:10 +00:00
|
|
|
uint32_t initlen1 = obj1->getDenseArrayInitializedLength();
|
2011-10-18 18:24:28 +00:00
|
|
|
JS_ASSERT(initlen1 == obj1->getArrayLength());
|
|
|
|
|
Bug 708735 - Use <stdint.h> types in JSAPI and throughout SpiderMonkey. Continue to provide the {u,}int{8,16,32,64} and JS{Uint,Int}{8,16,32,64} integer types through a single header, however, for a simpler backout strategy -- and also to ease the transition for embedders. r=timeless on switching the jsd API to use the <stdint.h> types, r=luke, r=dmandelin
2011-12-09 03:54:10 +00:00
|
|
|
uint32_t initlen2 = obj2->getDenseArrayInitializedLength();
|
2011-10-18 18:24:28 +00:00
|
|
|
JS_ASSERT(initlen2 == obj2->getArrayLength());
|
|
|
|
|
|
|
|
/* No overflow here due to nslots limit. */
|
Bug 708735 - Use <stdint.h> types in JSAPI and throughout SpiderMonkey. Continue to provide the {u,}int{8,16,32,64} and JS{Uint,Int}{8,16,32,64} integer types through a single header, however, for a simpler backout strategy -- and also to ease the transition for embedders. r=timeless on switching the jsd API to use the <stdint.h> types, r=luke, r=dmandelin
2011-12-09 03:54:10 +00:00
|
|
|
uint32_t len = initlen1 + initlen2;
|
2011-10-18 18:24:28 +00:00
|
|
|
|
2011-10-19 21:26:08 +00:00
|
|
|
if (!result->ensureElements(f.cx, len))
|
2011-10-18 18:24:28 +00:00
|
|
|
THROW();
|
|
|
|
|
2011-10-25 23:07:42 +00:00
|
|
|
JS_ASSERT(!result->getDenseArrayInitializedLength());
|
2011-10-18 18:24:28 +00:00
|
|
|
result->setDenseArrayInitializedLength(len);
|
2011-10-25 23:07:42 +00:00
|
|
|
|
|
|
|
result->initDenseArrayElements(0, obj1->getDenseArrayElements(), initlen1);
|
|
|
|
result->initDenseArrayElements(initlen1, obj2->getDenseArrayElements(), initlen2);
|
|
|
|
|
2011-10-18 18:24:28 +00:00
|
|
|
result->setDenseArrayLength(len);
|
1998-03-28 02:44:41 +00:00
|
|
|
}
|
2011-10-18 18:24:28 +00:00
|
|
|
#endif /* JS_METHODJIT */
|
1998-03-28 02:44:41 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Python-esque sequence operations.
|
|
|
|
*/
|
2011-10-18 18:24:28 +00:00
|
|
|
JSBool
|
2012-02-28 23:11:11 +00:00
|
|
|
js::array_concat(JSContext *cx, unsigned argc, Value *vp)
|
1998-03-28 02:44:41 +00:00
|
|
|
{
|
2007-08-02 04:33:52 +00:00
|
|
|
/* Treat our |this| object as the first argument; see ECMA 15.4.4.4. */
|
2010-07-15 06:19:36 +00:00
|
|
|
Value *p = JS_ARGV(cx, vp) - 1;
|
1998-03-28 02:44:41 +00:00
|
|
|
|
2007-08-02 04:33:52 +00:00
|
|
|
/* Create a new Array object and root it using *vp. */
|
2012-05-24 23:05:18 +00:00
|
|
|
RootedObject aobj(cx, ToObject(cx, &vp[1]));
|
2011-01-26 21:37:45 +00:00
|
|
|
if (!aobj)
|
|
|
|
return false;
|
|
|
|
|
2012-05-24 23:05:18 +00:00
|
|
|
RootedObject nobj(cx);
|
2012-03-06 23:52:55 +00:00
|
|
|
uint32_t length;
|
2010-03-05 04:44:09 +00:00
|
|
|
if (aobj->isDenseArray()) {
|
2010-04-06 01:32:16 +00:00
|
|
|
length = aobj->getArrayLength();
|
2011-07-29 01:10:31 +00:00
|
|
|
const Value *vector = aobj->getDenseArrayElements();
|
2012-03-06 23:52:55 +00:00
|
|
|
uint32_t initlen = aobj->getDenseArrayInitializedLength();
|
2011-03-06 01:13:40 +00:00
|
|
|
nobj = NewDenseCopiedArray(cx, initlen, vector);
|
2008-02-18 21:01:47 +00:00
|
|
|
if (!nobj)
|
|
|
|
return JS_FALSE;
|
2011-09-18 14:36:51 +00:00
|
|
|
TryReuseArrayType(aobj, nobj);
|
2011-05-16 23:15:37 +00:00
|
|
|
nobj->setArrayLength(cx, length);
|
2010-07-15 06:19:36 +00:00
|
|
|
vp->setObject(*nobj);
|
2008-02-18 21:01:47 +00:00
|
|
|
if (argc == 0)
|
|
|
|
return JS_TRUE;
|
|
|
|
argc--;
|
2010-07-15 06:19:36 +00:00
|
|
|
p++;
|
2008-02-18 21:01:47 +00:00
|
|
|
} else {
|
2010-12-14 00:22:59 +00:00
|
|
|
nobj = NewDenseEmptyArray(cx);
|
2008-02-18 21:01:47 +00:00
|
|
|
if (!nobj)
|
|
|
|
return JS_FALSE;
|
2010-07-15 06:19:36 +00:00
|
|
|
vp->setObject(*nobj);
|
2008-02-18 21:01:47 +00:00
|
|
|
length = 0;
|
|
|
|
}
|
1998-03-28 02:44:41 +00:00
|
|
|
|
2002-09-20 18:45:05 +00:00
|
|
|
/* Loop over [0, argc] to concat args into nobj, expanding all Arrays. */
|
2012-02-28 23:11:11 +00:00
|
|
|
for (unsigned i = 0; i <= argc; i++) {
|
2009-09-25 12:30:11 +00:00
|
|
|
if (!JS_CHECK_OPERATION_LIMIT(cx))
|
|
|
|
return false;
|
2010-07-15 06:19:36 +00:00
|
|
|
const Value &v = p[i];
|
|
|
|
if (v.isObject()) {
|
2012-05-24 23:05:18 +00:00
|
|
|
RootedObject obj(cx, &v.toObject());
|
2012-05-01 00:10:30 +00:00
|
|
|
if (ObjectClassIs(*obj, ESClass_Array, cx)) {
|
2012-03-06 23:52:55 +00:00
|
|
|
uint32_t alength;
|
2012-05-01 00:10:30 +00:00
|
|
|
if (!js_GetLengthProperty(cx, obj, &alength))
|
2009-09-25 12:30:11 +00:00
|
|
|
return false;
|
Bug 708735 - Use <stdint.h> types in JSAPI and throughout SpiderMonkey. Continue to provide the {u,}int{8,16,32,64} and JS{Uint,Int}{8,16,32,64} integer types through a single header, however, for a simpler backout strategy -- and also to ease the transition for embedders. r=timeless on switching the jsd API to use the <stdint.h> types, r=luke, r=dmandelin
2011-12-09 03:54:10 +00:00
|
|
|
for (uint32_t slot = 0; slot < alength; slot++) {
|
2010-07-15 06:19:36 +00:00
|
|
|
JSBool hole;
|
2011-06-28 17:05:53 +00:00
|
|
|
Value tmp;
|
2012-05-01 00:10:30 +00:00
|
|
|
if (!JS_CHECK_OPERATION_LIMIT(cx) || !GetElement(cx, obj, slot, &hole, &tmp))
|
2009-09-25 12:30:11 +00:00
|
|
|
return false;
|
2006-07-01 19:29:34 +00:00
|
|
|
|
2006-08-12 08:41:54 +00:00
|
|
|
/*
|
2010-05-23 19:26:15 +00:00
|
|
|
* Per ECMA 262, 15.4.4.4, step 9, ignore nonexistent
|
2006-08-12 08:41:54 +00:00
|
|
|
* properties.
|
|
|
|
*/
|
2011-06-28 17:05:53 +00:00
|
|
|
if (!hole && !SetArrayElement(cx, nobj, length + slot, tmp))
|
2009-09-25 12:30:11 +00:00
|
|
|
return false;
|
2003-06-12 00:26:40 +00:00
|
|
|
}
|
|
|
|
length += alength;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-09-25 12:30:11 +00:00
|
|
|
if (!SetArrayElement(cx, nobj, length, v))
|
|
|
|
return false;
|
2003-06-12 00:26:40 +00:00
|
|
|
length++;
|
1998-03-28 02:44:41 +00:00
|
|
|
}
|
|
|
|
|
2009-09-25 12:30:11 +00:00
|
|
|
return js_SetLengthProperty(cx, nobj, length);
|
1998-03-28 02:44:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static JSBool
|
2012-02-28 23:11:11 +00:00
|
|
|
array_slice(JSContext *cx, unsigned argc, Value *vp)
|
1998-03-28 02:44:41 +00:00
|
|
|
{
|
2012-03-06 23:52:55 +00:00
|
|
|
uint32_t length, begin, end, slot;
|
2009-05-11 21:57:18 +00:00
|
|
|
JSBool hole;
|
2005-11-01 01:13:36 +00:00
|
|
|
|
2011-10-25 01:02:36 +00:00
|
|
|
CallArgs args = CallArgsFromVp(argc, vp);
|
1998-03-28 02:44:41 +00:00
|
|
|
|
2012-05-24 23:05:18 +00:00
|
|
|
RootedObject obj(cx, ToObject(cx, &args.thisv()));
|
2011-01-26 21:37:45 +00:00
|
|
|
if (!obj)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (!js_GetLengthProperty(cx, obj, &length))
|
2003-06-12 00:26:40 +00:00
|
|
|
return JS_FALSE;
|
1998-03-28 02:44:41 +00:00
|
|
|
begin = 0;
|
|
|
|
end = length;
|
|
|
|
|
2011-10-25 01:02:36 +00:00
|
|
|
if (args.length() > 0) {
|
2012-02-24 22:19:52 +00:00
|
|
|
double d;
|
2011-10-25 01:02:36 +00:00
|
|
|
if (!ToInteger(cx, args[0], &d))
|
2011-04-02 18:33:20 +00:00
|
|
|
return false;
|
2003-06-12 00:26:40 +00:00
|
|
|
if (d < 0) {
|
|
|
|
d += length;
|
|
|
|
if (d < 0)
|
|
|
|
d = 0;
|
|
|
|
} else if (d > length) {
|
|
|
|
d = length;
|
|
|
|
}
|
2012-03-06 23:52:55 +00:00
|
|
|
begin = (uint32_t)d;
|
2003-06-12 00:26:40 +00:00
|
|
|
|
2012-03-01 18:48:52 +00:00
|
|
|
if (args.hasDefined(1)) {
|
2011-10-25 01:02:36 +00:00
|
|
|
if (!ToInteger(cx, args[1], &d))
|
2011-04-02 18:33:20 +00:00
|
|
|
return false;
|
2003-06-12 00:26:40 +00:00
|
|
|
if (d < 0) {
|
|
|
|
d += length;
|
|
|
|
if (d < 0)
|
|
|
|
d = 0;
|
|
|
|
} else if (d > length) {
|
|
|
|
d = length;
|
|
|
|
}
|
2012-03-06 23:52:55 +00:00
|
|
|
end = (uint32_t)d;
|
2003-06-12 00:26:40 +00:00
|
|
|
}
|
1998-03-28 02:44:41 +00:00
|
|
|
}
|
|
|
|
|
2005-07-18 18:44:22 +00:00
|
|
|
if (begin > end)
|
|
|
|
begin = end;
|
|
|
|
|
2012-05-24 23:05:18 +00:00
|
|
|
RootedObject nobj(cx);
|
2012-04-12 16:23:51 +00:00
|
|
|
|
2011-03-10 17:56:51 +00:00
|
|
|
if (obj->isDenseArray() && end <= obj->getDenseArrayInitializedLength() &&
|
2009-05-11 21:57:18 +00:00
|
|
|
!js_PrototypeHasIndexedProperties(cx, obj)) {
|
2010-12-14 00:22:59 +00:00
|
|
|
nobj = NewDenseCopiedArray(cx, end - begin, obj->getDenseArrayElements() + begin);
|
2008-02-18 21:01:47 +00:00
|
|
|
if (!nobj)
|
|
|
|
return JS_FALSE;
|
2011-09-18 14:36:51 +00:00
|
|
|
TryReuseArrayType(obj, nobj);
|
2011-10-25 01:02:36 +00:00
|
|
|
args.rval().setObject(*nobj);
|
2008-02-18 21:01:47 +00:00
|
|
|
return JS_TRUE;
|
|
|
|
}
|
|
|
|
|
2010-12-14 00:22:59 +00:00
|
|
|
nobj = NewDenseAllocatedArray(cx, end - begin);
|
2008-02-18 21:01:47 +00:00
|
|
|
if (!nobj)
|
|
|
|
return JS_FALSE;
|
2011-09-18 14:36:51 +00:00
|
|
|
TryReuseArrayType(obj, nobj);
|
2008-02-18 21:01:47 +00:00
|
|
|
|
2012-05-24 23:05:18 +00:00
|
|
|
RootedValue value(cx);
|
1998-03-28 02:44:41 +00:00
|
|
|
for (slot = begin; slot < end; slot++) {
|
2009-05-11 21:57:18 +00:00
|
|
|
if (!JS_CHECK_OPERATION_LIMIT(cx) ||
|
2012-05-01 00:10:30 +00:00
|
|
|
!GetElement(cx, obj, slot, &hole, value.address())) {
|
2009-05-11 21:57:18 +00:00
|
|
|
return JS_FALSE;
|
2006-12-24 11:31:37 +00:00
|
|
|
}
|
2012-05-01 00:10:30 +00:00
|
|
|
if (!hole && !SetArrayElement(cx, nobj, slot - begin, value))
|
2009-05-11 21:57:18 +00:00
|
|
|
return JS_FALSE;
|
1998-03-28 02:44:41 +00:00
|
|
|
}
|
2007-10-13 20:09:48 +00:00
|
|
|
|
2011-10-25 01:02:36 +00:00
|
|
|
args.rval().setObject(*nobj);
|
2010-12-14 00:22:59 +00:00
|
|
|
return JS_TRUE;
|
1998-03-28 02:44:41 +00:00
|
|
|
}
|
|
|
|
|
2011-10-25 01:02:36 +00:00
|
|
|
enum IndexOfKind {
|
|
|
|
IndexOf,
|
|
|
|
LastIndexOf
|
|
|
|
};
|
|
|
|
|
2005-04-17 18:31:59 +00:00
|
|
|
static JSBool
|
2011-10-25 01:02:36 +00:00
|
|
|
array_indexOfHelper(JSContext *cx, IndexOfKind mode, CallArgs &args)
|
2005-04-17 18:31:59 +00:00
|
|
|
{
|
2012-03-06 23:52:55 +00:00
|
|
|
uint32_t length, i, stop;
|
2010-07-15 06:19:36 +00:00
|
|
|
Value tosearch;
|
2012-03-02 02:54:01 +00:00
|
|
|
int direction;
|
2006-08-12 08:41:54 +00:00
|
|
|
JSBool hole;
|
2005-05-04 02:43:13 +00:00
|
|
|
|
2011-10-25 01:02:36 +00:00
|
|
|
JSObject *obj = ToObject(cx, &args.thisv());
|
2011-01-26 21:37:45 +00:00
|
|
|
if (!obj)
|
|
|
|
return false;
|
|
|
|
if (!js_GetLengthProperty(cx, obj, &length))
|
2005-04-17 18:31:59 +00:00
|
|
|
return JS_FALSE;
|
2005-10-02 06:27:07 +00:00
|
|
|
if (length == 0)
|
|
|
|
goto not_found;
|
|
|
|
|
2011-10-25 01:02:36 +00:00
|
|
|
if (args.length() <= 1) {
|
|
|
|
i = (mode == LastIndexOf) ? length - 1 : 0;
|
|
|
|
tosearch = (args.length() != 0) ? args[0] : UndefinedValue();
|
2005-10-02 06:27:07 +00:00
|
|
|
} else {
|
2012-02-24 22:19:52 +00:00
|
|
|
double start;
|
2005-10-02 06:27:07 +00:00
|
|
|
|
2011-10-25 01:02:36 +00:00
|
|
|
tosearch = args[0];
|
|
|
|
if (!ToInteger(cx, args[1], &start))
|
2011-04-02 18:33:20 +00:00
|
|
|
return false;
|
2005-05-04 02:43:13 +00:00
|
|
|
if (start < 0) {
|
|
|
|
start += length;
|
2006-12-18 06:43:02 +00:00
|
|
|
if (start < 0) {
|
2011-10-25 01:02:36 +00:00
|
|
|
if (mode == LastIndexOf)
|
2006-12-18 06:43:02 +00:00
|
|
|
goto not_found;
|
|
|
|
i = 0;
|
|
|
|
} else {
|
2012-03-06 23:52:55 +00:00
|
|
|
i = (uint32_t)start;
|
2006-12-18 06:43:02 +00:00
|
|
|
}
|
2005-10-02 06:27:07 +00:00
|
|
|
} else if (start >= length) {
|
2011-10-25 01:02:36 +00:00
|
|
|
if (mode == IndexOf)
|
2006-12-18 06:43:02 +00:00
|
|
|
goto not_found;
|
2005-10-02 06:27:07 +00:00
|
|
|
i = length - 1;
|
|
|
|
} else {
|
2012-03-06 23:52:55 +00:00
|
|
|
i = (uint32_t)start;
|
2005-05-04 02:43:13 +00:00
|
|
|
}
|
|
|
|
}
|
2005-10-02 06:27:07 +00:00
|
|
|
|
2011-10-25 01:02:36 +00:00
|
|
|
if (mode == LastIndexOf) {
|
2005-10-02 06:27:07 +00:00
|
|
|
stop = 0;
|
|
|
|
direction = -1;
|
|
|
|
} else {
|
|
|
|
stop = length - 1;
|
|
|
|
direction = 1;
|
|
|
|
}
|
|
|
|
|
2005-10-09 06:09:21 +00:00
|
|
|
for (;;) {
|
2011-10-25 01:02:36 +00:00
|
|
|
Value elt;
|
2009-02-10 22:07:01 +00:00
|
|
|
if (!JS_CHECK_OPERATION_LIMIT(cx) ||
|
2012-03-06 23:52:55 +00:00
|
|
|
!GetElement(cx, obj, (uint32_t)i, &hole, &elt)) {
|
2005-04-17 18:31:59 +00:00
|
|
|
return JS_FALSE;
|
2006-12-24 11:31:37 +00:00
|
|
|
}
|
2010-12-06 18:26:58 +00:00
|
|
|
if (!hole) {
|
2012-01-24 18:29:55 +00:00
|
|
|
bool equal;
|
2011-10-25 01:02:36 +00:00
|
|
|
if (!StrictlyEqual(cx, elt, tosearch, &equal))
|
2012-01-24 18:29:55 +00:00
|
|
|
return false;
|
2010-12-06 18:26:58 +00:00
|
|
|
if (equal) {
|
2011-10-25 01:02:36 +00:00
|
|
|
args.rval().setNumber(i);
|
2012-01-24 18:29:55 +00:00
|
|
|
return true;
|
2010-12-06 18:26:58 +00:00
|
|
|
}
|
2010-07-15 06:19:36 +00:00
|
|
|
}
|
2005-10-02 06:27:07 +00:00
|
|
|
if (i == stop)
|
|
|
|
goto not_found;
|
2005-10-09 06:09:21 +00:00
|
|
|
i += direction;
|
2005-04-17 18:31:59 +00:00
|
|
|
}
|
|
|
|
|
2005-10-02 06:27:07 +00:00
|
|
|
not_found:
|
2011-10-25 01:02:36 +00:00
|
|
|
args.rval().setInt32(-1);
|
2005-05-04 02:43:13 +00:00
|
|
|
return JS_TRUE;
|
|
|
|
}
|
|
|
|
|
2005-10-02 06:27:07 +00:00
|
|
|
static JSBool
|
2012-02-28 23:11:11 +00:00
|
|
|
array_indexOf(JSContext *cx, unsigned argc, Value *vp)
|
2005-10-02 06:27:07 +00:00
|
|
|
{
|
2011-10-25 01:02:36 +00:00
|
|
|
CallArgs args = CallArgsFromVp(argc, vp);
|
|
|
|
return array_indexOfHelper(cx, IndexOf, args);
|
2005-10-02 06:27:07 +00:00
|
|
|
}
|
|
|
|
|
2005-05-04 02:43:13 +00:00
|
|
|
static JSBool
|
2012-02-28 23:11:11 +00:00
|
|
|
array_lastIndexOf(JSContext *cx, unsigned argc, Value *vp)
|
2005-05-04 02:43:13 +00:00
|
|
|
{
|
2011-10-25 01:02:36 +00:00
|
|
|
CallArgs args = CallArgsFromVp(argc, vp);
|
|
|
|
return array_indexOfHelper(cx, LastIndexOf, args);
|
2005-04-17 18:31:59 +00:00
|
|
|
}
|
|
|
|
|
2011-11-04 22:56:40 +00:00
|
|
|
/* ECMA 15.4.4.16-15.4.4.18. */
|
|
|
|
class ArrayForEachBehavior
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
static bool shouldExit(Value &callval, Value *rval) { return false; }
|
|
|
|
static Value lateExitValue() { return UndefinedValue(); }
|
|
|
|
};
|
2005-04-17 18:31:59 +00:00
|
|
|
|
2011-11-04 22:56:40 +00:00
|
|
|
class ArrayEveryBehavior
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
static bool shouldExit(Value &callval, Value *rval)
|
|
|
|
{
|
|
|
|
if (!js_ValueToBoolean(callval)) {
|
|
|
|
*rval = BooleanValue(false);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
static Value lateExitValue() { return BooleanValue(true); }
|
|
|
|
};
|
2007-01-10 01:47:58 +00:00
|
|
|
|
2011-11-04 22:56:40 +00:00
|
|
|
class ArraySomeBehavior
|
2005-04-17 18:31:59 +00:00
|
|
|
{
|
2011-11-04 22:56:40 +00:00
|
|
|
public:
|
|
|
|
static bool shouldExit(Value &callval, Value *rval)
|
|
|
|
{
|
|
|
|
if (js_ValueToBoolean(callval)) {
|
|
|
|
*rval = BooleanValue(true);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
static Value lateExitValue() { return BooleanValue(false); }
|
|
|
|
};
|
|
|
|
|
|
|
|
template <class Behavior>
|
|
|
|
static inline bool
|
|
|
|
array_readonlyCommon(JSContext *cx, CallArgs &args)
|
|
|
|
{
|
|
|
|
/* Step 1. */
|
2012-05-24 23:05:18 +00:00
|
|
|
RootedObject obj(cx, ToObject(cx, &args.thisv()));
|
2011-01-26 21:37:45 +00:00
|
|
|
if (!obj)
|
|
|
|
return false;
|
|
|
|
|
2011-11-04 22:56:40 +00:00
|
|
|
/* Step 2-3. */
|
Bug 708735 - Use <stdint.h> types in JSAPI and throughout SpiderMonkey. Continue to provide the {u,}int{8,16,32,64} and JS{Uint,Int}{8,16,32,64} integer types through a single header, however, for a simpler backout strategy -- and also to ease the transition for embedders. r=timeless on switching the jsd API to use the <stdint.h> types, r=luke, r=dmandelin
2011-12-09 03:54:10 +00:00
|
|
|
uint32_t len;
|
2011-11-04 22:56:40 +00:00
|
|
|
if (!js_GetLengthProperty(cx, obj, &len))
|
|
|
|
return false;
|
2005-04-17 18:31:59 +00:00
|
|
|
|
2011-11-04 22:56:40 +00:00
|
|
|
/* Step 4. */
|
2011-10-25 01:02:36 +00:00
|
|
|
if (args.length() == 0) {
|
|
|
|
js_ReportMissingArg(cx, args.calleev(), 0);
|
2011-11-04 22:56:40 +00:00
|
|
|
return false;
|
2008-08-08 16:02:50 +00:00
|
|
|
}
|
2012-05-24 23:05:18 +00:00
|
|
|
RootedObject callable(cx, js_ValueToCallableObject(cx, &args[0], JSV2F_SEARCH_STACK));
|
2005-10-25 08:00:30 +00:00
|
|
|
if (!callable)
|
2011-11-04 22:56:40 +00:00
|
|
|
return false;
|
2005-04-17 18:31:59 +00:00
|
|
|
|
2011-11-04 22:56:40 +00:00
|
|
|
/* Step 5. */
|
|
|
|
Value thisv = args.length() >= 2 ? args[1] : UndefinedValue();
|
2010-03-04 01:52:26 +00:00
|
|
|
|
2011-11-04 22:56:40 +00:00
|
|
|
/* Step 6. */
|
Bug 708735 - Use <stdint.h> types in JSAPI and throughout SpiderMonkey. Continue to provide the {u,}int{8,16,32,64} and JS{Uint,Int}{8,16,32,64} integer types through a single header, however, for a simpler backout strategy -- and also to ease the transition for embedders. r=timeless on switching the jsd API to use the <stdint.h> types, r=luke, r=dmandelin
2011-12-09 03:54:10 +00:00
|
|
|
uint32_t k = 0;
|
2005-04-17 18:31:59 +00:00
|
|
|
|
2011-11-04 22:56:40 +00:00
|
|
|
/* Step 7. */
|
2011-10-25 01:02:36 +00:00
|
|
|
InvokeArgsGuard ag;
|
2011-11-04 22:56:40 +00:00
|
|
|
while (k < len) {
|
|
|
|
if (!JS_CHECK_OPERATION_LIMIT(cx))
|
2011-09-06 16:06:07 +00:00
|
|
|
return false;
|
|
|
|
|
2011-11-04 22:56:40 +00:00
|
|
|
/* Step a, b, and c.i. */
|
|
|
|
Value kValue;
|
|
|
|
JSBool kNotPresent;
|
|
|
|
if (!GetElement(cx, obj, k, &kNotPresent, &kValue))
|
|
|
|
return false;
|
2010-09-28 22:23:43 +00:00
|
|
|
|
2011-11-04 22:56:40 +00:00
|
|
|
/* Step c.ii-iii. */
|
|
|
|
if (!kNotPresent) {
|
|
|
|
if (!ag.pushed() && !cx->stack.pushInvokeArgs(cx, 3, &ag))
|
|
|
|
return false;
|
2011-11-08 18:17:25 +00:00
|
|
|
ag.setCallee(ObjectValue(*callable));
|
2011-11-04 22:56:40 +00:00
|
|
|
ag.thisv() = thisv;
|
|
|
|
ag[0] = kValue;
|
|
|
|
ag[1] = NumberValue(k);
|
|
|
|
ag[2] = ObjectValue(*obj);
|
|
|
|
if (!Invoke(cx, ag))
|
|
|
|
return false;
|
2005-04-17 18:31:59 +00:00
|
|
|
|
2011-11-04 22:56:40 +00:00
|
|
|
if (Behavior::shouldExit(ag.rval(), &args.rval()))
|
|
|
|
return true;
|
2005-04-17 18:31:59 +00:00
|
|
|
}
|
|
|
|
|
2011-11-04 22:56:40 +00:00
|
|
|
/* Step d. */
|
|
|
|
k++;
|
|
|
|
}
|
2005-04-17 18:31:59 +00:00
|
|
|
|
2011-11-04 22:56:40 +00:00
|
|
|
/* Step 8. */
|
|
|
|
args.rval() = Behavior::lateExitValue();
|
|
|
|
return true;
|
|
|
|
}
|
2011-11-16 14:00:32 +00:00
|
|
|
|
2011-11-04 22:56:40 +00:00
|
|
|
/* ES5 15.4.4.16. */
|
2009-06-25 19:12:19 +00:00
|
|
|
static JSBool
|
2012-02-28 23:11:11 +00:00
|
|
|
array_every(JSContext *cx, unsigned argc, Value *vp)
|
2005-04-17 18:31:59 +00:00
|
|
|
{
|
2011-10-25 01:02:36 +00:00
|
|
|
CallArgs args = CallArgsFromVp(argc, vp);
|
2011-11-04 22:56:40 +00:00
|
|
|
return array_readonlyCommon<ArrayEveryBehavior>(cx, args);
|
2005-04-17 18:31:59 +00:00
|
|
|
}
|
|
|
|
|
2011-11-04 22:56:40 +00:00
|
|
|
/* ES5 15.4.4.17. */
|
2009-06-25 19:12:19 +00:00
|
|
|
static JSBool
|
2012-02-28 23:11:11 +00:00
|
|
|
array_some(JSContext *cx, unsigned argc, Value *vp)
|
2005-04-17 18:31:59 +00:00
|
|
|
{
|
2011-10-25 01:02:36 +00:00
|
|
|
CallArgs args = CallArgsFromVp(argc, vp);
|
2011-11-04 22:56:40 +00:00
|
|
|
return array_readonlyCommon<ArraySomeBehavior>(cx, args);
|
2005-04-17 18:31:59 +00:00
|
|
|
}
|
|
|
|
|
2011-11-04 22:56:40 +00:00
|
|
|
/* ES5 15.4.4.18. */
|
2009-06-25 19:12:19 +00:00
|
|
|
static JSBool
|
2012-02-28 23:11:11 +00:00
|
|
|
array_forEach(JSContext *cx, unsigned argc, Value *vp)
|
2007-01-10 01:47:58 +00:00
|
|
|
{
|
2011-10-25 01:02:36 +00:00
|
|
|
CallArgs args = CallArgsFromVp(argc, vp);
|
2011-11-04 22:56:40 +00:00
|
|
|
return array_readonlyCommon<ArrayForEachBehavior>(cx, args);
|
2007-01-10 01:47:58 +00:00
|
|
|
}
|
|
|
|
|
2011-11-04 22:56:40 +00:00
|
|
|
/* ES5 15.4.4.19. */
|
2009-06-25 19:12:19 +00:00
|
|
|
static JSBool
|
2012-02-28 23:11:11 +00:00
|
|
|
array_map(JSContext *cx, unsigned argc, Value *vp)
|
2007-01-10 01:47:58 +00:00
|
|
|
{
|
2011-10-25 01:02:36 +00:00
|
|
|
CallArgs args = CallArgsFromVp(argc, vp);
|
2011-11-04 22:56:40 +00:00
|
|
|
|
|
|
|
/* Step 1. */
|
2012-05-24 23:05:18 +00:00
|
|
|
RootedObject obj(cx, ToObject(cx, &args.thisv()));
|
2011-11-04 22:56:40 +00:00
|
|
|
if (!obj)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
/* Step 2-3. */
|
Bug 708735 - Use <stdint.h> types in JSAPI and throughout SpiderMonkey. Continue to provide the {u,}int{8,16,32,64} and JS{Uint,Int}{8,16,32,64} integer types through a single header, however, for a simpler backout strategy -- and also to ease the transition for embedders. r=timeless on switching the jsd API to use the <stdint.h> types, r=luke, r=dmandelin
2011-12-09 03:54:10 +00:00
|
|
|
uint32_t len;
|
2011-11-04 22:56:40 +00:00
|
|
|
if (!js_GetLengthProperty(cx, obj, &len))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
/* Step 4. */
|
|
|
|
if (args.length() == 0) {
|
|
|
|
js_ReportMissingArg(cx, args.calleev(), 0);
|
|
|
|
return false;
|
|
|
|
}
|
2012-05-24 23:05:18 +00:00
|
|
|
RootedObject callable(cx, js_ValueToCallableObject(cx, &args[0], JSV2F_SEARCH_STACK));
|
2011-11-04 22:56:40 +00:00
|
|
|
if (!callable)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
/* Step 5. */
|
|
|
|
Value thisv = args.length() >= 2 ? args[1] : UndefinedValue();
|
|
|
|
|
|
|
|
/* Step 6. */
|
2012-05-24 23:05:18 +00:00
|
|
|
RootedObject arr(cx, NewDenseAllocatedArray(cx, len));
|
2011-11-04 22:56:40 +00:00
|
|
|
if (!arr)
|
|
|
|
return false;
|
|
|
|
TypeObject *newtype = GetTypeCallerInitObject(cx, JSProto_Array);
|
|
|
|
if (!newtype)
|
|
|
|
return false;
|
|
|
|
arr->setType(newtype);
|
|
|
|
|
|
|
|
/* Step 7. */
|
Bug 708735 - Use <stdint.h> types in JSAPI and throughout SpiderMonkey. Continue to provide the {u,}int{8,16,32,64} and JS{Uint,Int}{8,16,32,64} integer types through a single header, however, for a simpler backout strategy -- and also to ease the transition for embedders. r=timeless on switching the jsd API to use the <stdint.h> types, r=luke, r=dmandelin
2011-12-09 03:54:10 +00:00
|
|
|
uint32_t k = 0;
|
2011-11-04 22:56:40 +00:00
|
|
|
|
|
|
|
/* Step 8. */
|
|
|
|
InvokeArgsGuard ag;
|
|
|
|
while (k < len) {
|
|
|
|
if (!JS_CHECK_OPERATION_LIMIT(cx))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
/* Step a, b, and c.i. */
|
|
|
|
JSBool kNotPresent;
|
|
|
|
Value kValue;
|
|
|
|
if (!GetElement(cx, obj, k, &kNotPresent, &kValue))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
/* Step c.ii-iii. */
|
|
|
|
if (!kNotPresent) {
|
|
|
|
if (!ag.pushed() && !cx->stack.pushInvokeArgs(cx, 3, &ag))
|
|
|
|
return false;
|
2011-11-08 18:17:25 +00:00
|
|
|
ag.setCallee(ObjectValue(*callable));
|
2011-11-04 22:56:40 +00:00
|
|
|
ag.thisv() = thisv;
|
|
|
|
ag[0] = kValue;
|
|
|
|
ag[1] = NumberValue(k);
|
|
|
|
ag[2] = ObjectValue(*obj);
|
|
|
|
if (!Invoke(cx, ag))
|
|
|
|
return false;
|
|
|
|
if(!SetArrayElement(cx, arr, k, ag.rval()))
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Step d. */
|
|
|
|
k++;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Step 9. */
|
|
|
|
args.rval().setObject(*arr);
|
|
|
|
return true;
|
2007-01-10 01:47:58 +00:00
|
|
|
}
|
|
|
|
|
2011-11-04 22:56:40 +00:00
|
|
|
/* ES5 15.4.4.20. */
|
2009-06-25 19:12:19 +00:00
|
|
|
static JSBool
|
2012-02-28 23:11:11 +00:00
|
|
|
array_filter(JSContext *cx, unsigned argc, Value *vp)
|
2005-04-17 18:31:59 +00:00
|
|
|
{
|
2011-10-25 01:02:36 +00:00
|
|
|
CallArgs args = CallArgsFromVp(argc, vp);
|
2011-11-04 22:56:40 +00:00
|
|
|
|
|
|
|
/* Step 1. */
|
2012-05-24 23:05:18 +00:00
|
|
|
RootedObject obj(cx, ToObject(cx, &args.thisv()));
|
2011-11-04 22:56:40 +00:00
|
|
|
if (!obj)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
/* Step 2-3. */
|
Bug 708735 - Use <stdint.h> types in JSAPI and throughout SpiderMonkey. Continue to provide the {u,}int{8,16,32,64} and JS{Uint,Int}{8,16,32,64} integer types through a single header, however, for a simpler backout strategy -- and also to ease the transition for embedders. r=timeless on switching the jsd API to use the <stdint.h> types, r=luke, r=dmandelin
2011-12-09 03:54:10 +00:00
|
|
|
uint32_t len;
|
2011-11-04 22:56:40 +00:00
|
|
|
if (!js_GetLengthProperty(cx, obj, &len))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
/* Step 4. */
|
|
|
|
if (args.length() == 0) {
|
|
|
|
js_ReportMissingArg(cx, args.calleev(), 0);
|
|
|
|
return false;
|
|
|
|
}
|
2012-05-24 23:05:18 +00:00
|
|
|
RootedObject callable(cx, js_ValueToCallableObject(cx, &args[0], JSV2F_SEARCH_STACK));
|
2011-11-04 22:56:40 +00:00
|
|
|
if (!callable)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
/* Step 5. */
|
|
|
|
Value thisv = args.length() >= 2 ? args[1] : UndefinedValue();
|
|
|
|
|
|
|
|
/* Step 6. */
|
2012-05-24 23:05:18 +00:00
|
|
|
RootedObject arr(cx, NewDenseAllocatedArray(cx, 0));
|
2011-11-04 22:56:40 +00:00
|
|
|
if (!arr)
|
|
|
|
return false;
|
|
|
|
TypeObject *newtype = GetTypeCallerInitObject(cx, JSProto_Array);
|
|
|
|
if (!newtype)
|
|
|
|
return false;
|
|
|
|
arr->setType(newtype);
|
|
|
|
|
|
|
|
/* Step 7. */
|
Bug 708735 - Use <stdint.h> types in JSAPI and throughout SpiderMonkey. Continue to provide the {u,}int{8,16,32,64} and JS{Uint,Int}{8,16,32,64} integer types through a single header, however, for a simpler backout strategy -- and also to ease the transition for embedders. r=timeless on switching the jsd API to use the <stdint.h> types, r=luke, r=dmandelin
2011-12-09 03:54:10 +00:00
|
|
|
uint32_t k = 0;
|
2011-11-04 22:56:40 +00:00
|
|
|
|
|
|
|
/* Step 8. */
|
Bug 708735 - Use <stdint.h> types in JSAPI and throughout SpiderMonkey. Continue to provide the {u,}int{8,16,32,64} and JS{Uint,Int}{8,16,32,64} integer types through a single header, however, for a simpler backout strategy -- and also to ease the transition for embedders. r=timeless on switching the jsd API to use the <stdint.h> types, r=luke, r=dmandelin
2011-12-09 03:54:10 +00:00
|
|
|
uint32_t to = 0;
|
2011-11-04 22:56:40 +00:00
|
|
|
|
|
|
|
/* Step 9. */
|
|
|
|
InvokeArgsGuard ag;
|
|
|
|
while (k < len) {
|
|
|
|
if (!JS_CHECK_OPERATION_LIMIT(cx))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
/* Step a, b, and c.i. */
|
|
|
|
JSBool kNotPresent;
|
|
|
|
Value kValue;
|
|
|
|
if (!GetElement(cx, obj, k, &kNotPresent, &kValue))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
/* Step c.ii-iii. */
|
|
|
|
if (!kNotPresent) {
|
|
|
|
if (!ag.pushed() && !cx->stack.pushInvokeArgs(cx, 3, &ag))
|
|
|
|
return false;
|
2011-11-08 18:17:25 +00:00
|
|
|
ag.setCallee(ObjectValue(*callable));
|
2011-11-04 22:56:40 +00:00
|
|
|
ag.thisv() = thisv;
|
|
|
|
ag[0] = kValue;
|
|
|
|
ag[1] = NumberValue(k);
|
|
|
|
ag[2] = ObjectValue(*obj);
|
|
|
|
if (!Invoke(cx, ag))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (js_ValueToBoolean(ag.rval())) {
|
|
|
|
if(!SetArrayElement(cx, arr, to, kValue))
|
|
|
|
return false;
|
|
|
|
to++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Step d. */
|
|
|
|
k++;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Step 10. */
|
|
|
|
args.rval().setObject(*arr);
|
|
|
|
return true;
|
2005-04-17 18:31:59 +00:00
|
|
|
}
|
|
|
|
|
2011-11-04 22:56:40 +00:00
|
|
|
/* ES5 15.4.4.21-15.4.4.22. */
|
|
|
|
class ArrayReduceBehavior
|
|
|
|
{
|
|
|
|
public:
|
Bug 708735 - Use <stdint.h> types in JSAPI and throughout SpiderMonkey. Continue to provide the {u,}int{8,16,32,64} and JS{Uint,Int}{8,16,32,64} integer types through a single header, however, for a simpler backout strategy -- and also to ease the transition for embedders. r=timeless on switching the jsd API to use the <stdint.h> types, r=luke, r=dmandelin
2011-12-09 03:54:10 +00:00
|
|
|
static void initialize(uint32_t len, uint32_t *start, uint32_t *end, int32_t *step)
|
2011-11-04 22:56:40 +00:00
|
|
|
{
|
|
|
|
*start = 0;
|
|
|
|
*step = 1;
|
|
|
|
*end = len;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
class ArrayReduceRightBehavior
|
|
|
|
{
|
|
|
|
public:
|
Bug 708735 - Use <stdint.h> types in JSAPI and throughout SpiderMonkey. Continue to provide the {u,}int{8,16,32,64} and JS{Uint,Int}{8,16,32,64} integer types through a single header, however, for a simpler backout strategy -- and also to ease the transition for embedders. r=timeless on switching the jsd API to use the <stdint.h> types, r=luke, r=dmandelin
2011-12-09 03:54:10 +00:00
|
|
|
static void initialize(uint32_t len, uint32_t *start, uint32_t *end, int32_t *step)
|
2011-11-04 22:56:40 +00:00
|
|
|
{
|
|
|
|
*start = len - 1;
|
|
|
|
*step = -1;
|
2011-11-16 14:00:32 +00:00
|
|
|
/*
|
2011-11-04 22:56:40 +00:00
|
|
|
* We rely on (well defined) unsigned integer underflow to check our
|
|
|
|
* end condition after visiting the full range (including 0).
|
|
|
|
*/
|
Bug 708735 - Use <stdint.h> types in JSAPI and throughout SpiderMonkey. Continue to provide the {u,}int{8,16,32,64} and JS{Uint,Int}{8,16,32,64} integer types through a single header, however, for a simpler backout strategy -- and also to ease the transition for embedders. r=timeless on switching the jsd API to use the <stdint.h> types, r=luke, r=dmandelin
2011-12-09 03:54:10 +00:00
|
|
|
*end = UINT32_MAX;
|
2011-11-04 22:56:40 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
template<class Behavior>
|
|
|
|
static inline bool
|
|
|
|
array_reduceCommon(JSContext *cx, CallArgs &args)
|
|
|
|
{
|
|
|
|
/* Step 1. */
|
|
|
|
JSObject *obj = ToObject(cx, &args.thisv());
|
|
|
|
if (!obj)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
/* Step 2-3. */
|
Bug 708735 - Use <stdint.h> types in JSAPI and throughout SpiderMonkey. Continue to provide the {u,}int{8,16,32,64} and JS{Uint,Int}{8,16,32,64} integer types through a single header, however, for a simpler backout strategy -- and also to ease the transition for embedders. r=timeless on switching the jsd API to use the <stdint.h> types, r=luke, r=dmandelin
2011-12-09 03:54:10 +00:00
|
|
|
uint32_t len;
|
2011-11-04 22:56:40 +00:00
|
|
|
if (!js_GetLengthProperty(cx, obj, &len))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
/* Step 4. */
|
|
|
|
if (args.length() == 0) {
|
|
|
|
js_ReportMissingArg(cx, args.calleev(), 0);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
JSObject *callable = js_ValueToCallableObject(cx, &args[0], JSV2F_SEARCH_STACK);
|
|
|
|
if (!callable)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
/* Step 5. */
|
|
|
|
if (len == 0 && args.length() < 2) {
|
|
|
|
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_EMPTY_ARRAY_REDUCE);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Step 6. */
|
Bug 708735 - Use <stdint.h> types in JSAPI and throughout SpiderMonkey. Continue to provide the {u,}int{8,16,32,64} and JS{Uint,Int}{8,16,32,64} integer types through a single header, however, for a simpler backout strategy -- and also to ease the transition for embedders. r=timeless on switching the jsd API to use the <stdint.h> types, r=luke, r=dmandelin
2011-12-09 03:54:10 +00:00
|
|
|
uint32_t k, end;
|
|
|
|
int32_t step;
|
2011-11-04 22:56:40 +00:00
|
|
|
Behavior::initialize(len, &k, &end, &step);
|
|
|
|
|
|
|
|
/* Step 7-8. */
|
|
|
|
Value accumulator;
|
|
|
|
if (args.length() >= 2) {
|
|
|
|
accumulator = args[1];
|
|
|
|
} else {
|
|
|
|
JSBool kNotPresent = true;
|
|
|
|
while (kNotPresent && k != end) {
|
|
|
|
if (!GetElement(cx, obj, k, &kNotPresent, &accumulator))
|
|
|
|
return false;
|
|
|
|
k += step;
|
|
|
|
}
|
|
|
|
if (kNotPresent) {
|
|
|
|
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_EMPTY_ARRAY_REDUCE);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Step 9. */
|
|
|
|
InvokeArgsGuard ag;
|
|
|
|
while (k != end) {
|
|
|
|
if (!JS_CHECK_OPERATION_LIMIT(cx))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
/* Step a, b, and c.i. */
|
|
|
|
JSBool kNotPresent;
|
|
|
|
Value kValue;
|
|
|
|
if (!GetElement(cx, obj, k, &kNotPresent, &kValue))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
/* Step c.ii. */
|
|
|
|
if (!kNotPresent) {
|
|
|
|
if (!ag.pushed() && !cx->stack.pushInvokeArgs(cx, 4, &ag))
|
|
|
|
return false;
|
2011-11-08 18:17:25 +00:00
|
|
|
ag.setCallee(ObjectValue(*callable));
|
2011-11-04 22:56:40 +00:00
|
|
|
ag.thisv() = UndefinedValue();
|
|
|
|
ag[0] = accumulator;
|
|
|
|
ag[1] = kValue;
|
|
|
|
ag[2] = NumberValue(k);
|
|
|
|
ag[3] = ObjectValue(*obj);
|
|
|
|
if (!Invoke(cx, ag))
|
|
|
|
return false;
|
|
|
|
accumulator = ag.rval();
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Step d. */
|
|
|
|
k += step;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Step 10. */
|
|
|
|
args.rval() = accumulator;
|
|
|
|
return true;
|
2005-04-17 18:31:59 +00:00
|
|
|
}
|
|
|
|
|
2011-11-04 22:56:40 +00:00
|
|
|
/* ES5 15.4.4.21. */
|
2009-06-25 19:12:19 +00:00
|
|
|
static JSBool
|
2012-02-28 23:11:11 +00:00
|
|
|
array_reduce(JSContext *cx, unsigned argc, Value *vp)
|
2005-04-17 18:31:59 +00:00
|
|
|
{
|
2011-10-25 01:02:36 +00:00
|
|
|
CallArgs args = CallArgsFromVp(argc, vp);
|
2011-11-04 22:56:40 +00:00
|
|
|
return array_reduceCommon<ArrayReduceBehavior>(cx, args);
|
2005-04-17 18:31:59 +00:00
|
|
|
}
|
|
|
|
|
2011-11-04 22:56:40 +00:00
|
|
|
/* ES5 15.4.4.22. */
|
2009-06-25 19:12:19 +00:00
|
|
|
static JSBool
|
2012-02-28 23:11:11 +00:00
|
|
|
array_reduceRight(JSContext *cx, unsigned argc, Value *vp)
|
2005-04-17 18:31:59 +00:00
|
|
|
{
|
2011-10-25 01:02:36 +00:00
|
|
|
CallArgs args = CallArgsFromVp(argc, vp);
|
2011-11-04 22:56:40 +00:00
|
|
|
return array_reduceCommon<ArrayReduceRightBehavior>(cx, args);
|
2005-04-17 18:31:59 +00:00
|
|
|
}
|
|
|
|
|
2009-08-14 10:23:07 +00:00
|
|
|
static JSBool
|
2012-02-28 23:11:11 +00:00
|
|
|
array_isArray(JSContext *cx, unsigned argc, Value *vp)
|
2009-08-14 10:23:07 +00:00
|
|
|
{
|
2011-09-20 23:48:50 +00:00
|
|
|
CallArgs args = CallArgsFromVp(argc, vp);
|
2012-02-01 21:36:48 +00:00
|
|
|
bool isArray = args.length() > 0 && IsObjectWithClass(args[0], ESClass_Array, cx);
|
2011-09-20 23:48:50 +00:00
|
|
|
args.rval().setBoolean(isArray);
|
2010-10-22 22:40:11 +00:00
|
|
|
return true;
|
2009-08-14 10:23:07 +00:00
|
|
|
}
|
|
|
|
|
2010-10-29 15:05:55 +00:00
|
|
|
#define GENERIC JSFUN_GENERIC_NATIVE
|
|
|
|
|
1998-03-28 02:44:41 +00:00
|
|
|
static JSFunctionSpec array_methods[] = {
|
1998-04-24 00:31:11 +00:00
|
|
|
#if JS_HAS_TOSOURCE
|
2011-06-11 02:03:57 +00:00
|
|
|
JS_FN(js_toSource_str, array_toSource, 0,0),
|
1998-04-24 00:31:11 +00:00
|
|
|
#endif
|
2011-06-11 02:03:57 +00:00
|
|
|
JS_FN(js_toString_str, array_toString, 0,0),
|
|
|
|
JS_FN(js_toLocaleString_str,array_toLocaleString,0,0),
|
1998-03-28 02:44:41 +00:00
|
|
|
|
|
|
|
/* Perl-ish methods. */
|
2011-06-11 02:03:57 +00:00
|
|
|
JS_FN("join", array_join, 1,JSFUN_GENERIC_NATIVE),
|
|
|
|
JS_FN("reverse", array_reverse, 0,JSFUN_GENERIC_NATIVE),
|
|
|
|
JS_FN("sort", array_sort, 1,JSFUN_GENERIC_NATIVE),
|
|
|
|
JS_FN("push", array_push, 1,JSFUN_GENERIC_NATIVE),
|
|
|
|
JS_FN("pop", array_pop, 0,JSFUN_GENERIC_NATIVE),
|
|
|
|
JS_FN("shift", array_shift, 0,JSFUN_GENERIC_NATIVE),
|
|
|
|
JS_FN("unshift", array_unshift, 1,JSFUN_GENERIC_NATIVE),
|
|
|
|
JS_FN("splice", array_splice, 2,JSFUN_GENERIC_NATIVE),
|
1998-03-28 02:44:41 +00:00
|
|
|
|
2008-02-18 21:01:47 +00:00
|
|
|
/* Pythonic sequence methods. */
|
2011-06-11 02:03:57 +00:00
|
|
|
JS_FN("concat", array_concat, 1,JSFUN_GENERIC_NATIVE),
|
|
|
|
JS_FN("slice", array_slice, 2,JSFUN_GENERIC_NATIVE),
|
1998-03-28 02:44:41 +00:00
|
|
|
|
2011-06-11 02:03:57 +00:00
|
|
|
JS_FN("indexOf", array_indexOf, 1,JSFUN_GENERIC_NATIVE),
|
|
|
|
JS_FN("lastIndexOf", array_lastIndexOf, 1,JSFUN_GENERIC_NATIVE),
|
|
|
|
JS_FN("forEach", array_forEach, 1,JSFUN_GENERIC_NATIVE),
|
|
|
|
JS_FN("map", array_map, 1,JSFUN_GENERIC_NATIVE),
|
|
|
|
JS_FN("reduce", array_reduce, 1,JSFUN_GENERIC_NATIVE),
|
|
|
|
JS_FN("reduceRight", array_reduceRight, 1,JSFUN_GENERIC_NATIVE),
|
|
|
|
JS_FN("filter", array_filter, 1,JSFUN_GENERIC_NATIVE),
|
|
|
|
JS_FN("some", array_some, 1,JSFUN_GENERIC_NATIVE),
|
|
|
|
JS_FN("every", array_every, 1,JSFUN_GENERIC_NATIVE),
|
2005-04-17 18:31:59 +00:00
|
|
|
|
2007-08-02 04:33:52 +00:00
|
|
|
JS_FS_END
|
1998-03-28 02:44:41 +00:00
|
|
|
};
|
|
|
|
|
2009-08-14 10:23:07 +00:00
|
|
|
static JSFunctionSpec array_static_methods[] = {
|
2011-06-11 02:03:57 +00:00
|
|
|
JS_FN("isArray", array_isArray, 1,0),
|
2009-08-14 10:23:07 +00:00
|
|
|
JS_FS_END
|
|
|
|
};
|
|
|
|
|
2011-06-28 17:05:53 +00:00
|
|
|
/* ES5 15.4.2 */
|
2008-08-21 07:50:20 +00:00
|
|
|
JSBool
|
2012-02-28 23:11:11 +00:00
|
|
|
js_Array(JSContext *cx, unsigned argc, Value *vp)
|
1998-03-28 02:44:41 +00:00
|
|
|
{
|
2011-10-25 01:02:36 +00:00
|
|
|
CallArgs args = CallArgsFromVp(argc, vp);
|
2012-05-24 23:05:18 +00:00
|
|
|
RootedTypeObject type(cx, GetTypeCallerInitObject(cx, JSProto_Array));
|
2010-12-19 20:21:15 +00:00
|
|
|
if (!type)
|
|
|
|
return JS_FALSE;
|
2010-10-29 15:05:55 +00:00
|
|
|
|
2011-10-25 01:02:36 +00:00
|
|
|
if (args.length() != 1 || !args[0].isNumber()) {
|
|
|
|
if (!InitArrayTypes(cx, type, args.array(), args.length()))
|
2011-03-06 01:13:40 +00:00
|
|
|
return false;
|
2011-10-25 01:02:36 +00:00
|
|
|
JSObject *obj = (args.length() == 0)
|
2011-06-28 17:05:53 +00:00
|
|
|
? NewDenseEmptyArray(cx)
|
2011-10-25 01:02:36 +00:00
|
|
|
: NewDenseCopiedArray(cx, args.length(), args.array());
|
2011-06-28 17:05:53 +00:00
|
|
|
if (!obj)
|
|
|
|
return false;
|
2011-07-01 23:24:32 +00:00
|
|
|
obj->setType(type);
|
2011-10-25 01:02:36 +00:00
|
|
|
args.rval().setObject(*obj);
|
2011-06-28 17:05:53 +00:00
|
|
|
return true;
|
|
|
|
}
|
1998-04-24 00:31:11 +00:00
|
|
|
|
Bug 708735 - Use <stdint.h> types in JSAPI and throughout SpiderMonkey. Continue to provide the {u,}int{8,16,32,64} and JS{Uint,Int}{8,16,32,64} integer types through a single header, however, for a simpler backout strategy -- and also to ease the transition for embedders. r=timeless on switching the jsd API to use the <stdint.h> types, r=luke, r=dmandelin
2011-12-09 03:54:10 +00:00
|
|
|
uint32_t length;
|
2011-10-25 01:02:36 +00:00
|
|
|
if (args[0].isInt32()) {
|
Bug 708735 - Use <stdint.h> types in JSAPI and throughout SpiderMonkey. Continue to provide the {u,}int{8,16,32,64} and JS{Uint,Int}{8,16,32,64} integer types through a single header, however, for a simpler backout strategy -- and also to ease the transition for embedders. r=timeless on switching the jsd API to use the <stdint.h> types, r=luke, r=dmandelin
2011-12-09 03:54:10 +00:00
|
|
|
int32_t i = args[0].toInt32();
|
2011-06-28 17:05:53 +00:00
|
|
|
if (i < 0) {
|
|
|
|
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_ARRAY_LENGTH);
|
|
|
|
return false;
|
|
|
|
}
|
Bug 708735 - Use <stdint.h> types in JSAPI and throughout SpiderMonkey. Continue to provide the {u,}int{8,16,32,64} and JS{Uint,Int}{8,16,32,64} integer types through a single header, however, for a simpler backout strategy -- and also to ease the transition for embedders. r=timeless on switching the jsd API to use the <stdint.h> types, r=luke, r=dmandelin
2011-12-09 03:54:10 +00:00
|
|
|
length = uint32_t(i);
|
1998-03-28 02:44:41 +00:00
|
|
|
} else {
|
2012-02-24 22:19:52 +00:00
|
|
|
double d = args[0].toDouble();
|
2012-04-19 23:18:24 +00:00
|
|
|
length = ToUint32(d);
|
2012-02-24 22:19:52 +00:00
|
|
|
if (d != double(length)) {
|
2011-06-28 17:05:53 +00:00
|
|
|
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_ARRAY_LENGTH);
|
|
|
|
return false;
|
|
|
|
}
|
1998-03-28 02:44:41 +00:00
|
|
|
}
|
2010-07-31 01:24:03 +00:00
|
|
|
|
2011-06-28 17:05:53 +00:00
|
|
|
JSObject *obj = NewDenseUnallocatedArray(cx, length);
|
2010-10-13 18:49:22 +00:00
|
|
|
if (!obj)
|
2011-06-28 17:05:53 +00:00
|
|
|
return false;
|
2009-11-24 00:09:02 +00:00
|
|
|
|
2010-12-20 17:06:43 +00:00
|
|
|
obj->setType(type);
|
2010-10-14 14:12:19 +00:00
|
|
|
|
2010-12-21 15:32:21 +00:00
|
|
|
/* If the length calculation overflowed, make sure that is marked for the new type. */
|
2011-05-16 23:15:37 +00:00
|
|
|
if (obj->getArrayLength() > INT32_MAX)
|
|
|
|
obj->setArrayLength(cx, obj->getArrayLength());
|
2010-12-21 15:32:21 +00:00
|
|
|
|
2011-10-25 01:02:36 +00:00
|
|
|
args.rval().setObject(*obj);
|
2011-06-28 17:05:53 +00:00
|
|
|
return true;
|
2008-11-05 13:29:38 +00:00
|
|
|
}
|
2008-10-08 22:08:33 +00:00
|
|
|
|
1998-03-28 02:44:41 +00:00
|
|
|
JSObject *
|
|
|
|
js_InitArrayClass(JSContext *cx, JSObject *obj)
|
|
|
|
{
|
2011-05-02 18:53:24 +00:00
|
|
|
JS_ASSERT(obj->isNative());
|
|
|
|
|
2012-05-24 23:05:18 +00:00
|
|
|
Rooted<GlobalObject*> global(cx);
|
2012-01-02 23:02:05 +00:00
|
|
|
global = &obj->asGlobal();
|
2011-05-02 18:53:24 +00:00
|
|
|
|
2012-05-24 23:05:18 +00:00
|
|
|
RootedObject arrayProto(cx);
|
2011-12-31 14:32:04 +00:00
|
|
|
arrayProto = global->createBlankPrototype(cx, &SlowArrayClass);
|
2011-05-02 18:53:24 +00:00
|
|
|
if (!arrayProto || !AddLengthProperty(cx, arrayProto))
|
2003-06-12 00:26:40 +00:00
|
|
|
return NULL;
|
2011-07-22 01:53:37 +00:00
|
|
|
arrayProto->setArrayLength(cx, 0);
|
2010-07-23 22:29:02 +00:00
|
|
|
|
2012-05-24 23:05:18 +00:00
|
|
|
RootedFunction ctor(cx);
|
2012-05-06 20:45:19 +00:00
|
|
|
ctor = global->createConstructor(cx, js_Array, CLASS_NAME(cx, Array), 1);
|
2011-05-02 18:53:24 +00:00
|
|
|
if (!ctor)
|
|
|
|
return NULL;
|
2010-12-19 04:44:51 +00:00
|
|
|
|
2011-11-18 21:59:48 +00:00
|
|
|
/*
|
|
|
|
* The default 'new' type of Array.prototype is required by type inference
|
|
|
|
* to have unknown properties, to simplify handling of e.g. heterogenous
|
|
|
|
* arrays in JSON and script literals and allows setDenseArrayElement to
|
|
|
|
* be used without updating the indexed type set for such default arrays.
|
|
|
|
*/
|
2011-11-09 02:34:11 +00:00
|
|
|
if (!arrayProto->setNewTypeUnknown(cx))
|
|
|
|
return NULL;
|
2011-07-22 01:53:37 +00:00
|
|
|
|
2011-05-02 18:53:24 +00:00
|
|
|
if (!LinkConstructorAndPrototype(cx, ctor, arrayProto))
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
if (!DefinePropertiesAndBrand(cx, arrayProto, NULL, array_methods) ||
|
|
|
|
!DefinePropertiesAndBrand(cx, ctor, NULL, array_static_methods))
|
|
|
|
{
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!DefineConstructorAndPrototype(cx, global, JSProto_Array, ctor, arrayProto))
|
|
|
|
return NULL;
|
2010-12-19 04:44:51 +00:00
|
|
|
|
2011-05-02 18:53:24 +00:00
|
|
|
return arrayProto;
|
1998-03-28 02:44:41 +00:00
|
|
|
}
|
|
|
|
|
2010-12-14 00:22:59 +00:00
|
|
|
/*
|
|
|
|
* Array allocation functions.
|
|
|
|
*/
|
|
|
|
namespace js {
|
|
|
|
|
2011-11-03 16:57:12 +00:00
|
|
|
static inline bool
|
2012-03-06 23:52:55 +00:00
|
|
|
EnsureNewArrayElements(JSContext *cx, JSObject *obj, uint32_t length)
|
2011-11-03 16:57:12 +00:00
|
|
|
{
|
|
|
|
/*
|
|
|
|
* If ensureElements creates dynamically allocated slots, then having
|
|
|
|
* fixedSlots is a waste.
|
|
|
|
*/
|
Bug 708735 - Use <stdint.h> types in JSAPI and throughout SpiderMonkey. Continue to provide the {u,}int{8,16,32,64} and JS{Uint,Int}{8,16,32,64} integer types through a single header, however, for a simpler backout strategy -- and also to ease the transition for embedders. r=timeless on switching the jsd API to use the <stdint.h> types, r=luke, r=dmandelin
2011-12-09 03:54:10 +00:00
|
|
|
DebugOnly<uint32_t> cap = obj->getDenseArrayCapacity();
|
2011-11-03 16:57:12 +00:00
|
|
|
|
|
|
|
if (!obj->ensureElements(cx, length))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
JS_ASSERT_IF(cap, !obj->hasDynamicElements());
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2010-12-14 00:22:59 +00:00
|
|
|
template<bool allocateCapacity>
|
|
|
|
static JS_ALWAYS_INLINE JSObject *
|
2012-05-24 15:52:21 +00:00
|
|
|
NewArray(JSContext *cx, uint32_t length, JSObject *proto_)
|
1998-03-28 02:44:41 +00:00
|
|
|
{
|
2011-10-10 18:41:03 +00:00
|
|
|
gc::AllocKind kind = GuessArrayGCKind(length);
|
2011-11-02 20:34:19 +00:00
|
|
|
JS_ASSERT(CanBeFinalizedInBackground(kind, &ArrayClass));
|
|
|
|
kind = GetBackgroundAllocKind(kind);
|
|
|
|
|
2012-05-24 15:52:21 +00:00
|
|
|
GlobalObject *parent_ = GetCurrentGlobal(cx);
|
2011-11-03 16:57:12 +00:00
|
|
|
|
2012-05-03 07:12:47 +00:00
|
|
|
NewObjectCache &cache = cx->runtime->newObjectCache;
|
2011-11-18 22:40:14 +00:00
|
|
|
|
|
|
|
NewObjectCache::EntryIndex entry = -1;
|
2012-05-24 15:52:21 +00:00
|
|
|
if (cache.lookupGlobal(&ArrayClass, parent_, kind, &entry)) {
|
2011-11-18 22:40:14 +00:00
|
|
|
JSObject *obj = cache.newObjectFromHit(cx, entry);
|
2011-11-03 16:57:12 +00:00
|
|
|
if (!obj)
|
|
|
|
return NULL;
|
|
|
|
/* Fixup the elements pointer and length, which may be incorrect. */
|
|
|
|
obj->setFixedElements();
|
2011-11-03 21:20:44 +00:00
|
|
|
obj->setArrayLength(cx, length);
|
2011-11-03 16:57:12 +00:00
|
|
|
if (allocateCapacity && !EnsureNewArrayElements(cx, obj, length))
|
|
|
|
return NULL;
|
|
|
|
return obj;
|
|
|
|
}
|
|
|
|
|
2012-05-24 23:05:18 +00:00
|
|
|
Rooted<GlobalObject*> parent(cx, parent_);
|
2011-12-31 14:32:04 +00:00
|
|
|
|
2012-05-24 15:52:21 +00:00
|
|
|
if (!proto_ && !FindProto(cx, &ArrayClass, parent, &proto_))
|
2011-11-03 16:57:12 +00:00
|
|
|
return NULL;
|
|
|
|
|
2012-05-24 23:05:18 +00:00
|
|
|
RootedObject proto(cx, proto_);
|
|
|
|
RootedTypeObject type(cx);
|
2011-12-31 14:32:04 +00:00
|
|
|
|
|
|
|
type = proto->getNewType(cx);
|
2011-11-02 20:34:19 +00:00
|
|
|
if (!type)
|
|
|
|
return NULL;
|
|
|
|
|
2011-11-22 00:20:39 +00:00
|
|
|
/*
|
|
|
|
* Get a shape with zero fixed slots, regardless of the size class.
|
|
|
|
* See JSObject::createDenseArray.
|
|
|
|
*/
|
2012-05-24 23:05:18 +00:00
|
|
|
RootedShape shape(cx);
|
2011-12-31 14:32:04 +00:00
|
|
|
shape = EmptyShape::getInitialShape(cx, &ArrayClass, proto,
|
|
|
|
parent, gc::FINALIZE_OBJECT0);
|
2011-11-02 20:34:19 +00:00
|
|
|
if (!shape)
|
|
|
|
return NULL;
|
|
|
|
|
2011-11-18 22:59:31 +00:00
|
|
|
JSObject* obj = JSObject::createDenseArray(cx, kind, shape, type, length);
|
2011-01-08 02:55:35 +00:00
|
|
|
if (!obj)
|
|
|
|
return NULL;
|
2010-12-14 00:22:59 +00:00
|
|
|
|
2011-11-18 22:40:14 +00:00
|
|
|
if (entry != -1)
|
|
|
|
cache.fillGlobal(entry, &ArrayClass, parent, kind, obj);
|
2011-09-23 19:13:11 +00:00
|
|
|
|
2011-11-03 16:57:12 +00:00
|
|
|
if (allocateCapacity && !EnsureNewArrayElements(cx, obj, length))
|
|
|
|
return NULL;
|
2011-04-02 00:26:34 +00:00
|
|
|
|
2011-11-02 20:34:19 +00:00
|
|
|
Probes::createObject(cx, obj);
|
2010-12-14 00:22:59 +00:00
|
|
|
return obj;
|
|
|
|
}
|
|
|
|
|
|
|
|
JSObject * JS_FASTCALL
|
|
|
|
NewDenseEmptyArray(JSContext *cx, JSObject *proto)
|
|
|
|
{
|
|
|
|
return NewArray<false>(cx, 0, proto);
|
|
|
|
}
|
2009-10-23 19:40:36 +00:00
|
|
|
|
2010-12-14 00:22:59 +00:00
|
|
|
JSObject * JS_FASTCALL
|
Bug 708735 - Use <stdint.h> types in JSAPI and throughout SpiderMonkey. Continue to provide the {u,}int{8,16,32,64} and JS{Uint,Int}{8,16,32,64} integer types through a single header, however, for a simpler backout strategy -- and also to ease the transition for embedders. r=timeless on switching the jsd API to use the <stdint.h> types, r=luke, r=dmandelin
2011-12-09 03:54:10 +00:00
|
|
|
NewDenseAllocatedArray(JSContext *cx, uint32_t length, JSObject *proto)
|
2010-12-14 00:22:59 +00:00
|
|
|
{
|
|
|
|
return NewArray<true>(cx, length, proto);
|
|
|
|
}
|
|
|
|
|
2010-12-20 17:06:43 +00:00
|
|
|
JSObject * JS_FASTCALL
|
Bug 708735 - Use <stdint.h> types in JSAPI and throughout SpiderMonkey. Continue to provide the {u,}int{8,16,32,64} and JS{Uint,Int}{8,16,32,64} integer types through a single header, however, for a simpler backout strategy -- and also to ease the transition for embedders. r=timeless on switching the jsd API to use the <stdint.h> types, r=luke, r=dmandelin
2011-12-09 03:54:10 +00:00
|
|
|
NewDenseAllocatedEmptyArray(JSContext *cx, uint32_t length, JSObject *proto)
|
2010-12-20 17:06:43 +00:00
|
|
|
{
|
2011-04-02 00:26:34 +00:00
|
|
|
return NewArray<true>(cx, length, proto);
|
2010-12-20 17:06:43 +00:00
|
|
|
}
|
2007-03-02 17:35:29 +00:00
|
|
|
|
2010-12-14 00:22:59 +00:00
|
|
|
JSObject * JS_FASTCALL
|
Bug 708735 - Use <stdint.h> types in JSAPI and throughout SpiderMonkey. Continue to provide the {u,}int{8,16,32,64} and JS{Uint,Int}{8,16,32,64} integer types through a single header, however, for a simpler backout strategy -- and also to ease the transition for embedders. r=timeless on switching the jsd API to use the <stdint.h> types, r=luke, r=dmandelin
2011-12-09 03:54:10 +00:00
|
|
|
NewDenseUnallocatedArray(JSContext *cx, uint32_t length, JSObject *proto)
|
2010-12-14 00:22:59 +00:00
|
|
|
{
|
|
|
|
return NewArray<false>(cx, length, proto);
|
1998-03-28 02:44:41 +00:00
|
|
|
}
|
2009-10-23 19:40:36 +00:00
|
|
|
|
2011-04-02 00:26:34 +00:00
|
|
|
#ifdef JS_METHODJIT
|
|
|
|
JSObject * JS_FASTCALL
|
Bug 708735 - Use <stdint.h> types in JSAPI and throughout SpiderMonkey. Continue to provide the {u,}int{8,16,32,64} and JS{Uint,Int}{8,16,32,64} integer types through a single header, however, for a simpler backout strategy -- and also to ease the transition for embedders. r=timeless on switching the jsd API to use the <stdint.h> types, r=luke, r=dmandelin
2011-12-09 03:54:10 +00:00
|
|
|
mjit::stubs::NewDenseUnallocatedArray(VMFrame &f, uint32_t length)
|
2011-04-02 00:26:34 +00:00
|
|
|
{
|
|
|
|
JSObject *proto = (JSObject *) f.scratch;
|
|
|
|
JSObject *obj = NewArray<false>(f.cx, length, proto);
|
2012-03-10 20:52:28 +00:00
|
|
|
if (!obj)
|
2011-04-02 00:26:34 +00:00
|
|
|
THROWV(NULL);
|
2012-03-10 20:52:28 +00:00
|
|
|
|
2011-04-02 00:26:34 +00:00
|
|
|
return obj;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2008-02-18 21:01:47 +00:00
|
|
|
JSObject *
|
Bug 708735 - Use <stdint.h> types in JSAPI and throughout SpiderMonkey. Continue to provide the {u,}int{8,16,32,64} and JS{Uint,Int}{8,16,32,64} integer types through a single header, however, for a simpler backout strategy -- and also to ease the transition for embedders. r=timeless on switching the jsd API to use the <stdint.h> types, r=luke, r=dmandelin
2011-12-09 03:54:10 +00:00
|
|
|
NewDenseCopiedArray(JSContext *cx, uint32_t length, const Value *vp, JSObject *proto /* = NULL */)
|
2010-12-14 00:22:59 +00:00
|
|
|
{
|
2012-05-01 00:10:30 +00:00
|
|
|
// XXX vp may be an internal pointer to an object's dense array elements.
|
|
|
|
SkipRoot skip(cx, &vp);
|
|
|
|
|
2010-12-14 00:22:59 +00:00
|
|
|
JSObject* obj = NewArray<true>(cx, length, proto);
|
2011-01-08 02:55:35 +00:00
|
|
|
if (!obj)
|
|
|
|
return NULL;
|
|
|
|
|
2010-12-14 00:22:59 +00:00
|
|
|
JS_ASSERT(obj->getDenseArrayCapacity() >= length);
|
|
|
|
|
2011-10-10 18:41:03 +00:00
|
|
|
obj->setDenseArrayInitializedLength(vp ? length : 0);
|
2011-07-29 01:10:31 +00:00
|
|
|
|
2010-12-14 00:22:59 +00:00
|
|
|
if (vp)
|
2011-10-25 23:07:42 +00:00
|
|
|
obj->initDenseArrayElements(0, vp, length);
|
2010-12-14 00:22:59 +00:00
|
|
|
|
|
|
|
return obj;
|
1998-03-28 02:44:41 +00:00
|
|
|
}
|
2008-02-18 21:01:47 +00:00
|
|
|
|
|
|
|
JSObject *
|
2010-12-14 00:22:59 +00:00
|
|
|
NewSlowEmptyArray(JSContext *cx)
|
2008-02-18 21:01:47 +00:00
|
|
|
{
|
2012-05-24 23:05:18 +00:00
|
|
|
RootedObject obj(cx, NewBuiltinClassInstance(cx, &SlowArrayClass));
|
2011-02-03 19:04:14 +00:00
|
|
|
if (!obj || !AddLengthProperty(cx, obj))
|
2010-12-14 00:22:59 +00:00
|
|
|
return NULL;
|
|
|
|
|
2011-05-16 23:15:37 +00:00
|
|
|
obj->setArrayLength(cx, 0);
|
2008-02-18 21:01:47 +00:00
|
|
|
return obj;
|
|
|
|
}
|
|
|
|
|
2010-12-14 00:22:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-09-20 19:43:52 +00:00
|
|
|
#ifdef DEBUG
|
2008-02-18 21:01:47 +00:00
|
|
|
JSBool
|
2012-02-28 23:11:11 +00:00
|
|
|
js_ArrayInfo(JSContext *cx, unsigned argc, jsval *vp)
|
2008-02-18 21:01:47 +00:00
|
|
|
{
|
2011-10-25 01:02:36 +00:00
|
|
|
CallArgs args = CallArgsFromVp(argc, vp);
|
2008-02-18 21:01:47 +00:00
|
|
|
JSObject *array;
|
|
|
|
|
2012-02-28 23:11:11 +00:00
|
|
|
for (unsigned i = 0; i < args.length(); i++) {
|
2011-10-25 01:02:36 +00:00
|
|
|
Value arg = args[i];
|
2008-03-02 17:45:33 +00:00
|
|
|
|
2010-09-20 19:43:52 +00:00
|
|
|
char *bytes = DecompileValueGenerator(cx, JSDVG_SEARCH_STACK, arg, NULL);
|
2008-02-18 21:01:47 +00:00
|
|
|
if (!bytes)
|
|
|
|
return JS_FALSE;
|
2010-09-20 19:43:52 +00:00
|
|
|
if (arg.isPrimitive() ||
|
|
|
|
!(array = arg.toObjectOrNull())->isArray()) {
|
2008-02-18 21:01:47 +00:00
|
|
|
fprintf(stderr, "%s: not array\n", bytes);
|
2011-03-31 08:14:12 +00:00
|
|
|
cx->free_(bytes);
|
2008-02-18 21:01:47 +00:00
|
|
|
continue;
|
|
|
|
}
|
2010-09-20 19:43:52 +00:00
|
|
|
fprintf(stderr, "%s: %s (len %u", bytes,
|
|
|
|
array->isDenseArray() ? "dense" : "sparse",
|
2010-04-06 01:32:16 +00:00
|
|
|
array->getArrayLength());
|
2010-03-05 04:44:09 +00:00
|
|
|
if (array->isDenseArray()) {
|
2010-09-20 19:43:52 +00:00
|
|
|
fprintf(stderr, ", capacity %u",
|
2010-04-27 01:33:36 +00:00
|
|
|
array->getDenseArrayCapacity());
|
2008-02-18 21:01:47 +00:00
|
|
|
}
|
|
|
|
fputs(")\n", stderr);
|
2011-03-31 08:14:12 +00:00
|
|
|
cx->free_(bytes);
|
2008-02-18 21:01:47 +00:00
|
|
|
}
|
2010-09-20 19:43:52 +00:00
|
|
|
|
2011-10-25 01:02:36 +00:00
|
|
|
args.rval().setUndefined();
|
2010-09-20 19:43:52 +00:00
|
|
|
return true;
|
2008-02-18 21:01:47 +00:00
|
|
|
}
|
|
|
|
#endif
|