зеркало из https://github.com/mozilla/gecko-dev.git
Backed out changeset 09ffb30caa47
This commit is contained in:
Родитель
03fb86d8a2
Коммит
2e0c76a3ce
|
@ -52,8 +52,8 @@ bool checkObjectFields(JSObject *savedCopy, JSObject *obj)
|
|||
* doing memcmp.
|
||||
*/
|
||||
savedCopy->objShape = obj->objShape;
|
||||
savedCopy->slots = obj->slots;
|
||||
CHECK(!memcmp(savedCopy, obj, JSOBJECT_SIZE));
|
||||
savedCopy->dslots = obj->dslots;
|
||||
CHECK(!memcmp(savedCopy, obj, sizeof(*obj)));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -3031,6 +3031,8 @@ JS_SealObject(JSContext *cx, JSObject *obj, JSBool deep)
|
|||
/* Walk slots in obj and if any value is a non-null object, seal it. */
|
||||
for (uint32 i = 0, n = obj->slotSpan(); i != n; ++i) {
|
||||
const Value &v = obj->getSlot(i);
|
||||
if (i == JSSLOT_PRIVATE && (obj->getClass()->flags & JSCLASS_HAS_PRIVATE))
|
||||
continue;
|
||||
if (v.isPrimitive())
|
||||
continue;
|
||||
if (!JS_SealObject(cx, &v.toObject(), deep))
|
||||
|
@ -3829,7 +3831,8 @@ JS_Enumerate(JSContext *cx, JSObject *obj)
|
|||
* + native case here uses a Shape *, but that iterates in reverse!
|
||||
* + so we make non-native match, by reverse-iterating after JS_Enumerating
|
||||
*/
|
||||
const uint32 JSSLOT_ITER_INDEX = 0;
|
||||
const uint32 JSSLOT_ITER_INDEX = JSSLOT_PRIVATE + 1;
|
||||
JS_STATIC_ASSERT(JSSLOT_ITER_INDEX < JS_INITIAL_NSLOTS);
|
||||
|
||||
static void
|
||||
prop_iter_finalize(JSContext *cx, JSObject *obj)
|
||||
|
@ -3838,7 +3841,7 @@ prop_iter_finalize(JSContext *cx, JSObject *obj)
|
|||
if (!pdata)
|
||||
return;
|
||||
|
||||
if (obj->getSlot(JSSLOT_ITER_INDEX).toInt32() >= 0) {
|
||||
if (obj->fslots[JSSLOT_ITER_INDEX].toInt32() >= 0) {
|
||||
/* Non-native case: destroy the ida enumerated when obj was created. */
|
||||
JSIdArray *ida = (JSIdArray *) pdata;
|
||||
JS_DestroyIdArray(cx, ida);
|
||||
|
@ -3852,7 +3855,7 @@ prop_iter_trace(JSTracer *trc, JSObject *obj)
|
|||
if (!pdata)
|
||||
return;
|
||||
|
||||
if (obj->getSlot(JSSLOT_ITER_INDEX).toInt32() < 0) {
|
||||
if (obj->fslots[JSSLOT_ITER_INDEX].toInt32() < 0) {
|
||||
/* Native case: just mark the next property to visit. */
|
||||
((Shape *) pdata)->trace(trc);
|
||||
} else {
|
||||
|
@ -3918,7 +3921,7 @@ JS_NewPropertyIterator(JSContext *cx, JSObject *obj)
|
|||
|
||||
/* iterobj cannot escape to other threads here. */
|
||||
iterobj->setPrivate(const_cast<void *>(pdata));
|
||||
iterobj->getSlotRef(JSSLOT_ITER_INDEX).setInt32(index);
|
||||
iterobj->fslots[JSSLOT_ITER_INDEX].setInt32(index);
|
||||
return iterobj;
|
||||
}
|
||||
|
||||
|
@ -3932,7 +3935,7 @@ JS_NextProperty(JSContext *cx, JSObject *iterobj, jsid *idp)
|
|||
|
||||
CHECK_REQUEST(cx);
|
||||
assertSameCompartment(cx, iterobj);
|
||||
i = iterobj->getSlot(JSSLOT_ITER_INDEX).toInt32();
|
||||
i = iterobj->fslots[JSSLOT_ITER_INDEX].toInt32();
|
||||
if (i < 0) {
|
||||
/* Native case: private data is a property tree node pointer. */
|
||||
obj = iterobj->getParent();
|
||||
|
|
|
@ -310,6 +310,109 @@ BigIndexToId(JSContext *cx, JSObject *obj, jsuint index, JSBool createAtom,
|
|||
return JS_TRUE;
|
||||
}
|
||||
|
||||
bool
|
||||
JSObject::growDenseArrayElements(JSContext *cx, uint32 oldcap, uint32 newcap)
|
||||
{
|
||||
JS_ASSERT(isDenseArray());
|
||||
JS_ASSERT(newcap >= ARRAY_CAPACITY_MIN);
|
||||
JS_ASSERT(newcap >= oldcap);
|
||||
|
||||
if (newcap > MAX_DSLOTS_LENGTH32) {
|
||||
if (!JS_ON_TRACE(cx))
|
||||
js_ReportAllocationOverflow(cx);
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
/* dslots can be NULL during array creation. */
|
||||
Value *slots = dslots ? dslots - 1 : NULL;
|
||||
Value *newslots = (Value *) cx->realloc(slots, (size_t(newcap) + 1) * sizeof(Value));
|
||||
if (!newslots)
|
||||
return false;
|
||||
|
||||
dslots = newslots + 1;
|
||||
setDenseArrayCapacity(newcap);
|
||||
|
||||
Value *base = addressOfDenseArrayElement(0);
|
||||
for (Value *vp = base + oldcap, *end = base + newcap; vp < end; ++vp)
|
||||
vp->setMagic(JS_ARRAY_HOLE);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
JSObject::ensureDenseArrayElements(JSContext *cx, uint32 newcap)
|
||||
{
|
||||
/*
|
||||
* When a dense array with CAPACITY_DOUBLING_MAX or fewer slots needs to
|
||||
* grow, double its capacity, to push() N elements in amortized O(N) time.
|
||||
*
|
||||
* Above this limit, grow by 12.5% each time. Speed is still amortized
|
||||
* O(N), with a higher constant factor, and we waste less space.
|
||||
*/
|
||||
static const size_t CAPACITY_DOUBLING_MAX = 1024 * 1024;
|
||||
|
||||
/*
|
||||
* Round up all large allocations to a multiple of this (1MB), so as not
|
||||
* to waste space if malloc gives us 1MB-sized chunks (as jemalloc does).
|
||||
*/
|
||||
static const size_t CAPACITY_CHUNK = 1024 * 1024 / sizeof(Value);
|
||||
|
||||
uint32 oldcap = getDenseArrayCapacity();
|
||||
|
||||
if (newcap > oldcap) {
|
||||
/*
|
||||
* If this overflows uint32, newcap is very large. nextsize will end
|
||||
* up being less than newcap, the code below will thus disregard it,
|
||||
* and resizeDenseArrayElements() will fail.
|
||||
*
|
||||
* The way we use dslots[-1] forces a few +1s and -1s here. For
|
||||
* example, (oldcap * 2 + 1) produces the sequence 7, 15, 31, 63, ...
|
||||
* which makes the total allocation size (with dslots[-1]) a power
|
||||
* of two.
|
||||
*/
|
||||
uint32 nextsize = (oldcap <= CAPACITY_DOUBLING_MAX)
|
||||
? oldcap * 2 + 1
|
||||
: oldcap + (oldcap >> 3);
|
||||
|
||||
uint32 actualCapacity = JS_MAX(newcap, nextsize);
|
||||
if (actualCapacity >= CAPACITY_CHUNK)
|
||||
actualCapacity = JS_ROUNDUP(actualCapacity + 1, CAPACITY_CHUNK) - 1; /* -1 for dslots[-1] */
|
||||
else if (actualCapacity < ARRAY_CAPACITY_MIN)
|
||||
actualCapacity = ARRAY_CAPACITY_MIN;
|
||||
|
||||
if (!growDenseArrayElements(cx, oldcap, actualCapacity))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
JSObject::shrinkDenseArrayElements(JSContext *cx, uint32 newcap)
|
||||
{
|
||||
JS_ASSERT(isDenseArray());
|
||||
JS_ASSERT(newcap < getDenseArrayCapacity());
|
||||
JS_ASSERT(dslots);
|
||||
|
||||
uint32 fill = newcap;
|
||||
|
||||
if (newcap < ARRAY_CAPACITY_MIN)
|
||||
newcap = ARRAY_CAPACITY_MIN;
|
||||
|
||||
Value *newslots = (Value *) cx->realloc(dslots - 1, (size_t(newcap) + 1) * sizeof(Value));
|
||||
if (!newslots)
|
||||
return false;
|
||||
|
||||
dslots = newslots + 1;
|
||||
setDenseArrayCapacity(newcap);
|
||||
|
||||
/* we refuse to shrink below a minimum value, so we have to clear the excess space */
|
||||
Value *base = addressOfDenseArrayElement(0);
|
||||
while (fill < newcap)
|
||||
base[fill++].setMagic(JS_ARRAY_HOLE);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
ReallyBigIndexToId(JSContext* cx, jsdouble index, jsid* idp)
|
||||
{
|
||||
|
@ -426,8 +529,8 @@ js_EnsureDenseArrayCapacity(JSContext *cx, JSObject *obj, jsint i)
|
|||
return true;
|
||||
if (INDEX_TOO_SPARSE(obj, u))
|
||||
return false;
|
||||
|
||||
return obj->ensureDenseArrayElements(cx, u + 1);
|
||||
|
||||
}
|
||||
JS_DEFINE_CALLINFO_3(extern, BOOL, js_EnsureDenseArrayCapacity, CONTEXT, OBJECT, INT32, 0,
|
||||
nanojit::ACCSET_STORE_ANY)
|
||||
|
@ -556,13 +659,13 @@ array_length_setter(JSContext *cx, JSObject *obj, jsid id, Value *vp, JSBool str
|
|||
if (obj->isDenseArray()) {
|
||||
/*
|
||||
* Don't reallocate if we're not actually shrinking our slots. If we do
|
||||
* shrink slots here, ensureDenseArrayElements will fill all slots to the
|
||||
* shrink slots here, resizeDenseArrayElements will fill all slots to the
|
||||
* right of newlen with JS_ARRAY_HOLE. This permits us to disregard
|
||||
* length when reading from arrays as long we are within the capacity.
|
||||
*/
|
||||
jsuint oldcap = obj->getDenseArrayCapacity();
|
||||
if (oldcap > newlen)
|
||||
obj->shrinkDenseArrayElements(cx, newlen);
|
||||
if (oldcap > newlen && !obj->shrinkDenseArrayElements(cx, newlen))
|
||||
return false;
|
||||
obj->setArrayLength(newlen);
|
||||
} else if (oldlen - newlen < (1 << 24)) {
|
||||
do {
|
||||
|
@ -870,11 +973,20 @@ array_deleteProperty(JSContext *cx, JSObject *obj, jsid id, Value *rval, JSBool
|
|||
return JS_TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
array_finalize(JSContext *cx, JSObject *obj)
|
||||
{
|
||||
obj->freeDenseArrayElements(cx);
|
||||
}
|
||||
|
||||
static void
|
||||
array_trace(JSTracer *trc, JSObject *obj)
|
||||
{
|
||||
JS_ASSERT(obj->isDenseArray());
|
||||
|
||||
if (!obj->dslots)
|
||||
return;
|
||||
|
||||
size_t holes = 0;
|
||||
uint32 capacity = obj->getDenseArrayCapacity();
|
||||
for (uint32 i = 0; i < capacity; i++) {
|
||||
|
@ -894,7 +1006,7 @@ array_trace(JSTracer *trc, JSObject *obj)
|
|||
Class js_ArrayClass = {
|
||||
"Array",
|
||||
Class::NON_NATIVE |
|
||||
JSCLASS_HAS_PRIVATE |
|
||||
JSCLASS_HAS_RESERVED_SLOTS(JSObject::DENSE_ARRAY_CLASS_RESERVED_SLOTS) |
|
||||
JSCLASS_HAS_CACHED_PROTO(JSProto_Array),
|
||||
PropertyStub, /* addProperty */
|
||||
PropertyStub, /* delProperty */
|
||||
|
@ -903,7 +1015,7 @@ Class js_ArrayClass = {
|
|||
EnumerateStub,
|
||||
ResolveStub,
|
||||
js_TryValueOf,
|
||||
NULL,
|
||||
array_finalize,
|
||||
NULL, /* reserved0 */
|
||||
NULL, /* checkAccess */
|
||||
NULL, /* call */
|
||||
|
@ -987,18 +1099,26 @@ JSObject::makeDenseArraySlow(JSContext *cx)
|
|||
* the same initial shape.
|
||||
*/
|
||||
JSObject *arrayProto = getProto();
|
||||
if (!InitScopeForObject(cx, this, &js_SlowArrayClass, arrayProto, FINALIZE_OBJECT0))
|
||||
if (!InitScopeForObject(cx, this, &js_SlowArrayClass, arrayProto))
|
||||
return false;
|
||||
|
||||
uint32 capacity = getDenseArrayCapacity();
|
||||
uint32 capacity;
|
||||
|
||||
/*
|
||||
* Begin with the length property to share more of the property tree.
|
||||
* The getter/setter here will directly access the object's private value.
|
||||
*/
|
||||
if (dslots) {
|
||||
capacity = getDenseArrayCapacity();
|
||||
dslots[-1].setPrivateUint32(JS_INITIAL_NSLOTS + capacity);
|
||||
} else {
|
||||
/*
|
||||
* Array.prototype is constructed as a dense array, but is immediately slowified before
|
||||
* we have time to set capacity.
|
||||
*/
|
||||
capacity = 0;
|
||||
}
|
||||
|
||||
/* Begin with the length property to share more of the property tree. */
|
||||
if (!addProperty(cx, ATOM_TO_JSID(cx->runtime->atomState.lengthAtom),
|
||||
array_length_getter, NULL,
|
||||
SHAPE_INVALID_SLOT, JSPROP_PERMANENT | JSPROP_SHARED, 0, 0)) {
|
||||
JSSLOT_ARRAY_LENGTH, JSPROP_PERMANENT | JSPROP_SHARED, 0, 0)) {
|
||||
setMap(oldMap);
|
||||
return false;
|
||||
}
|
||||
|
@ -1016,12 +1136,24 @@ JSObject::makeDenseArraySlow(JSContext *cx)
|
|||
continue;
|
||||
}
|
||||
|
||||
if (!addDataProperty(cx, id, i, JSPROP_ENUMERATE)) {
|
||||
/* Assert that the length covering i fits in the alloted bits. */
|
||||
JS_ASSERT(JS_INITIAL_NSLOTS + i + 1 < NSLOTS_LIMIT);
|
||||
|
||||
if (!addDataProperty(cx, id, JS_INITIAL_NSLOTS + i, JSPROP_ENUMERATE)) {
|
||||
setMap(oldMap);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Render our formerly-reserved non-private properties GC-safe. We do not
|
||||
* need to make the length slot GC-safe because it is the private slot
|
||||
* (this is statically asserted within JSObject) where the implementation
|
||||
* can store an arbitrary value.
|
||||
*/
|
||||
JS_ASSERT(js_SlowArrayClass.flags & JSCLASS_HAS_PRIVATE);
|
||||
voidDenseOnlyArraySlots();
|
||||
|
||||
/*
|
||||
* Finally, update class. If |this| is Array.prototype, then js_InitClass
|
||||
* will create an emptyShape whose class is &js_SlowArrayClass, to ensure
|
||||
|
@ -1363,6 +1495,7 @@ InitArrayObject(JSContext *cx, JSObject *obj, jsuint length, const Value *vector
|
|||
|
||||
JS_ASSERT(obj->isDenseArray());
|
||||
obj->setArrayLength(length);
|
||||
obj->setDenseArrayCapacity(0);
|
||||
if (!vector || !length)
|
||||
return true;
|
||||
if (!obj->ensureDenseArrayElements(cx, length))
|
||||
|
@ -2321,8 +2454,10 @@ array_concat(JSContext *cx, uintN argc, Value *vp)
|
|||
/*
|
||||
* Clone aobj but pass the minimum of its length and capacity, to
|
||||
* handle a = [1,2,3]; a.length = 10000 "dense" cases efficiently. In
|
||||
* the normal case where length is <= capacity, nobj and aobj will have
|
||||
* the same capacity.
|
||||
* such a case we'll pass 8 (not 3) due to ARRAY_CAPACITY_MIN, which
|
||||
* will cause nobj to be over-allocated to 16. But in the normal case
|
||||
* where length is <= capacity, nobj and aobj will have the same
|
||||
* capacity.
|
||||
*/
|
||||
length = aobj->getArrayLength();
|
||||
jsuint capacity = aobj->getDenseArrayCapacity();
|
||||
|
@ -2842,12 +2977,10 @@ static JSFunctionSpec array_static_methods[] = {
|
|||
JS_FS_END
|
||||
};
|
||||
|
||||
/* The count here is a guess for the final capacity. */
|
||||
static inline JSObject *
|
||||
NewDenseArrayObject(JSContext *cx, jsuint count)
|
||||
NewDenseArrayObject(JSContext *cx)
|
||||
{
|
||||
JSFinalizeGCThingKind kind = GuessObjectGCKind(count);
|
||||
return NewNonFunction<WithProto::Class>(cx, &js_ArrayClass, NULL, NULL, kind);
|
||||
return NewNonFunction<WithProto::Class>(cx, &js_ArrayClass, NULL, NULL);
|
||||
}
|
||||
|
||||
JSBool
|
||||
|
@ -2856,6 +2989,12 @@ js_Array(JSContext *cx, uintN argc, Value *vp)
|
|||
jsuint length;
|
||||
const Value *vector;
|
||||
|
||||
/* Whether called with 'new' or not, use a new Array object. */
|
||||
JSObject *obj = NewDenseArrayObject(cx);
|
||||
if (!obj)
|
||||
return JS_FALSE;
|
||||
vp->setObject(*obj);
|
||||
|
||||
if (argc == 0) {
|
||||
length = 0;
|
||||
vector = NULL;
|
||||
|
@ -2872,12 +3011,6 @@ js_Array(JSContext *cx, uintN argc, Value *vp)
|
|||
vector = NULL;
|
||||
}
|
||||
|
||||
/* Whether called with 'new' or not, use a new Array object. */
|
||||
JSObject *obj = NewDenseArrayObject(cx, length);
|
||||
if (!obj)
|
||||
return JS_FALSE;
|
||||
vp->setObject(*obj);
|
||||
|
||||
return InitArrayObject(cx, obj, length, vector);
|
||||
}
|
||||
|
||||
|
@ -2889,15 +3022,15 @@ js_NewEmptyArray(JSContext* cx, JSObject* proto, int32 len)
|
|||
|
||||
JS_ASSERT(proto->isArray());
|
||||
|
||||
JSFinalizeGCThingKind kind = js_GetGCObjectKind(len);
|
||||
JSObject* obj = js_NewGCObject(cx, kind);
|
||||
JSObject* obj = js_NewGCObject(cx);
|
||||
if (!obj)
|
||||
return NULL;
|
||||
|
||||
/* Initialize all fields of JSObject. */
|
||||
obj->init(cx, &js_ArrayClass, proto, proto->getParent(),
|
||||
(void*) len, true);
|
||||
/* Initialize all fields, calling init before setting obj->map. */
|
||||
obj->init(&js_ArrayClass, proto, proto->getParent(), NullValue(), cx);
|
||||
obj->setSharedNonNativeMap();
|
||||
obj->setArrayLength(len);
|
||||
obj->setDenseArrayCapacity(0);
|
||||
return obj;
|
||||
}
|
||||
#ifdef JS_TRACER
|
||||
|
@ -2911,7 +3044,7 @@ js_NewPreallocatedArray(JSContext* cx, JSObject* proto, int32 len)
|
|||
JSObject *obj = js_NewEmptyArray(cx, proto, len);
|
||||
if (!obj)
|
||||
return NULL;
|
||||
if (!obj->ensureDenseArrayElements(cx, len))
|
||||
if (!obj->growDenseArrayElements(cx, 0, JS_MAX(len, ARRAY_CAPACITY_MIN)))
|
||||
return NULL;
|
||||
return obj;
|
||||
}
|
||||
|
@ -2932,7 +3065,7 @@ js_InitArrayClass(JSContext *cx, JSObject *obj)
|
|||
* Assert that js_InitClass used the correct (slow array, not dense array)
|
||||
* class for proto's emptyShape class.
|
||||
*/
|
||||
JS_ASSERT(proto->emptyShapes && proto->emptyShapes[0]->getClass() == proto->getClass());
|
||||
JS_ASSERT(proto->emptyShape->getClass() == proto->getClass());
|
||||
|
||||
proto->setArrayLength(0);
|
||||
return proto;
|
||||
|
@ -2941,7 +3074,7 @@ js_InitArrayClass(JSContext *cx, JSObject *obj)
|
|||
JSObject *
|
||||
js_NewArrayObject(JSContext *cx, jsuint length, const Value *vector)
|
||||
{
|
||||
JSObject *obj = NewDenseArrayObject(cx, length);
|
||||
JSObject *obj = NewDenseArrayObject(cx);
|
||||
if (!obj)
|
||||
return NULL;
|
||||
|
||||
|
@ -3062,7 +3195,7 @@ js_IsDensePrimitiveArray(JSObject *obj)
|
|||
|
||||
jsuint capacity = obj->getDenseArrayCapacity();
|
||||
for (jsuint i = 0; i < capacity; i++) {
|
||||
if (obj->getDenseArrayElement(i).isObject())
|
||||
if (obj->dslots[i].isObject())
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
|
@ -3086,9 +3219,10 @@ js_CloneDensePrimitiveArray(JSContext *cx, JSObject *obj, JSObject **clone)
|
|||
|
||||
/*
|
||||
* Must use the minimum of original array's length and capacity, to handle
|
||||
* |a = [1,2,3]; a.length = 10000| "dense" cases efficiently. In the normal
|
||||
* case where length is <= capacity, the clone and original array will have
|
||||
* the same capacity.
|
||||
* |a = [1,2,3]; a.length = 10000| "dense" cases efficiently. In such a case
|
||||
* we would use ARRAY_CAPACITY_MIN (not 3), which will cause the clone to be
|
||||
* over-allocated. In the normal case where length is <= capacity the
|
||||
* clone and original array will have the same capacity.
|
||||
*/
|
||||
jsuint jsvalCount = JS_MIN(obj->getDenseArrayCapacity(), length);
|
||||
|
||||
|
@ -3097,7 +3231,7 @@ js_CloneDensePrimitiveArray(JSContext *cx, JSObject *obj, JSObject **clone)
|
|||
return JS_FALSE;
|
||||
|
||||
for (jsuint i = 0; i < jsvalCount; i++) {
|
||||
const Value &val = obj->getDenseArrayElement(i);
|
||||
const Value &val = obj->dslots[i];
|
||||
|
||||
if (val.isString()) {
|
||||
// Strings must be made immutable before being copied to a clone.
|
||||
|
|
|
@ -46,6 +46,8 @@
|
|||
#include "jspubtd.h"
|
||||
#include "jsobj.h"
|
||||
|
||||
#define ARRAY_CAPACITY_MIN 7
|
||||
|
||||
extern JSBool
|
||||
js_StringIsIndex(JSString *str, jsuint *indexp);
|
||||
|
||||
|
@ -137,6 +139,13 @@ js_InitArrayClass(JSContext *cx, JSObject *obj);
|
|||
extern bool
|
||||
js_InitContextBusyArrayTable(JSContext *cx);
|
||||
|
||||
/*
|
||||
* Creates a new array with the given length and proto (NB: NULL is not
|
||||
* translated to Array.prototype), with len slots preallocated.
|
||||
*/
|
||||
extern JSObject * JS_FASTCALL
|
||||
js_NewArrayWithSlots(JSContext* cx, JSObject* proto, uint32 len);
|
||||
|
||||
extern JSObject *
|
||||
js_NewArrayObject(JSContext *cx, jsuint length, const js::Value *vector);
|
||||
|
||||
|
|
|
@ -302,14 +302,11 @@ js_NewNullClosure(JSContext* cx, JSObject* funobj, JSObject* proto, JSObject* pa
|
|||
JSFunction *fun = (JSFunction*) funobj;
|
||||
JS_ASSERT(GET_FUNCTION_PRIVATE(cx, funobj) == fun);
|
||||
|
||||
JSObject* closure = js_NewGCObject(cx, FINALIZE_OBJECT2);
|
||||
JSObject* closure = js_NewGCObject(cx);
|
||||
if (!closure)
|
||||
return NULL;
|
||||
|
||||
if (!closure->initSharingEmptyShape(cx, &js_FunctionClass, proto, parent,
|
||||
fun, FINALIZE_OBJECT2)) {
|
||||
return NULL;
|
||||
}
|
||||
closure->initSharingEmptyShape(&js_FunctionClass, proto, parent, fun, cx);
|
||||
return closure;
|
||||
}
|
||||
JS_DEFINE_CALLINFO_4(extern, OBJECT, js_NewNullClosure, CONTEXT, OBJECT, OBJECT, OBJECT,
|
||||
|
|
|
@ -2563,9 +2563,7 @@ JS_FRIEND_API(JSObject *)
|
|||
js_NewDateObjectMsec(JSContext *cx, jsdouble msec_time)
|
||||
{
|
||||
JSObject *obj = NewBuiltinClassInstance(cx, &js_DateClass);
|
||||
if (!obj || !obj->ensureSlots(cx, JSObject::DATE_CLASS_RESERVED_SLOTS))
|
||||
return NULL;
|
||||
if (!SetUTCTime(cx, obj, msec_time))
|
||||
if (!obj || !SetUTCTime(cx, obj, msec_time))
|
||||
return NULL;
|
||||
return obj;
|
||||
}
|
||||
|
|
|
@ -1645,7 +1645,15 @@ JS_SetDebugErrorHook(JSRuntime *rt, JSDebugErrorHook hook, void *closure)
|
|||
JS_PUBLIC_API(size_t)
|
||||
JS_GetObjectTotalSize(JSContext *cx, JSObject *obj)
|
||||
{
|
||||
return obj->slotsAndStructSize();
|
||||
size_t nbytes = (obj->isFunction() && obj->getPrivate() == obj)
|
||||
? sizeof(JSFunction)
|
||||
: sizeof *obj;
|
||||
|
||||
if (obj->dslots) {
|
||||
nbytes += (obj->dslots[-1].toPrivateUint32() - JS_INITIAL_NSLOTS + 1)
|
||||
* sizeof obj->dslots[0];
|
||||
}
|
||||
return nbytes;
|
||||
}
|
||||
|
||||
static size_t
|
||||
|
|
|
@ -235,7 +235,7 @@ UpdateDepth(JSContext *cx, JSCodeGenerator *cg, ptrdiff_t target)
|
|||
JS_ASSERT(nuses == 0);
|
||||
blockObj = cg->objectList.lastbox->object;
|
||||
JS_ASSERT(blockObj->isStaticBlock());
|
||||
JS_ASSERT(blockObj->getSlot(JSSLOT_BLOCK_DEPTH).isUndefined());
|
||||
JS_ASSERT(blockObj->fslots[JSSLOT_BLOCK_DEPTH].isUndefined());
|
||||
|
||||
OBJ_SET_BLOCK_DEPTH(cx, blockObj, cg->stackDepth);
|
||||
ndefs = OBJ_BLOCK_COUNT(cx, blockObj);
|
||||
|
@ -1599,8 +1599,9 @@ js_LexicalLookup(JSTreeContext *tc, JSAtom *atom, jsint *slotp, JSStmtInfo *stmt
|
|||
JS_ASSERT(shape->hasShortID());
|
||||
|
||||
if (slotp) {
|
||||
JS_ASSERT(obj->getSlot(JSSLOT_BLOCK_DEPTH).isInt32());
|
||||
*slotp = obj->getSlot(JSSLOT_BLOCK_DEPTH).toInt32() + shape->shortid;
|
||||
JS_ASSERT(obj->fslots[JSSLOT_BLOCK_DEPTH].isInt32());
|
||||
*slotp = obj->fslots[JSSLOT_BLOCK_DEPTH].toInt32() +
|
||||
shape->shortid;
|
||||
}
|
||||
return stmt;
|
||||
}
|
||||
|
@ -1867,12 +1868,11 @@ EmitEnterBlock(JSContext *cx, JSParseNode *pn, JSCodeGenerator *cg)
|
|||
}
|
||||
|
||||
/*
|
||||
* Clear blockObj->dslots and ensure a prompt safe crash if by accident
|
||||
* some code tries to get a slot from a compiler-created Block prototype
|
||||
* instead of from a clone.
|
||||
* Shrink slots to free blockObj->dslots and ensure a prompt safe crash if
|
||||
* by accident some code tries to get a slot from a compiler-created Block
|
||||
* prototype instead of from a clone.
|
||||
*/
|
||||
if (blockObj->hasSlotsArray())
|
||||
blockObj->removeSlotsArray(cx);
|
||||
blockObj->shrinkSlots(cx, base);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -4353,17 +4353,8 @@ EmitFunctionDefNop(JSContext *cx, JSCodeGenerator *cg, uintN index)
|
|||
static bool
|
||||
EmitNewInit(JSContext *cx, JSCodeGenerator *cg, JSProtoKey key, JSParseNode *pn, int sharpnum)
|
||||
{
|
||||
/*
|
||||
* Watch for overflow on the initializer size. This isn't problematic because
|
||||
* (a) we'll be reporting an error for the initializer shortly, and (b)
|
||||
* the count is only used as a hint for the interpreter and JITs, and does not
|
||||
* need to be correct.
|
||||
*/
|
||||
uint16 count = pn->pn_count;
|
||||
if (count >= JS_BIT(16))
|
||||
count = JS_BIT(16) - 1;
|
||||
|
||||
EMIT_UINT16PAIR_IMM_OP(JSOP_NEWINIT, (uint16) key, count);
|
||||
if (js_Emit2(cx, cg, JSOP_NEWINIT, (jsbytecode) key) < 0)
|
||||
return false;
|
||||
#if JS_HAS_SHARP_VARS
|
||||
if (cg->hasSharps()) {
|
||||
if (pn->pn_count != 0)
|
||||
|
|
109
js/src/jsfun.cpp
109
js/src/jsfun.cpp
|
@ -182,8 +182,7 @@ NewArguments(JSContext *cx, JSObject *parent, uint32 argc, JSObject &callee)
|
|||
if (!js_GetClassPrototype(cx, parent, JSProto_Object, &proto))
|
||||
return NULL;
|
||||
|
||||
JS_ASSERT(js_GetGCKindSlots(FINALIZE_OBJECT2) == JSObject::ARGS_CLASS_RESERVED_SLOTS);
|
||||
JSObject *argsobj = js_NewGCObject(cx, FINALIZE_OBJECT2);
|
||||
JSObject *argsobj = js_NewGCObject(cx);
|
||||
if (!argsobj)
|
||||
return NULL;
|
||||
|
||||
|
@ -194,10 +193,10 @@ NewArguments(JSContext *cx, JSObject *parent, uint32 argc, JSObject &callee)
|
|||
SetValueRangeToUndefined(data->slots, argc);
|
||||
|
||||
/* Can't fail from here on, so initialize everything in argsobj. */
|
||||
argsobj->init(cx, callee.getFunctionPrivate()->inStrictMode()
|
||||
argsobj->init(callee.getFunctionPrivate()->inStrictMode()
|
||||
? &StrictArgumentsClass
|
||||
: &js_ArgumentsClass,
|
||||
proto, parent, NULL, false);
|
||||
proto, parent, NULL, cx);
|
||||
|
||||
argsobj->setMap(cx->runtime->emptyArgumentsShape);
|
||||
|
||||
|
@ -965,20 +964,15 @@ CalleeGetter(JSContext *cx, JSObject *obj, jsid id, Value *vp)
|
|||
static JSObject *
|
||||
NewCallObject(JSContext *cx, JSFunction *fun, JSObject &scopeChain, JSObject &callee)
|
||||
{
|
||||
size_t vars = fun->countArgsAndVars();
|
||||
size_t slots = JSObject::CALL_RESERVED_SLOTS + vars;
|
||||
JSFinalizeGCThingKind kind = js_GetGCObjectKind(slots);
|
||||
|
||||
JSObject *callobj = js_NewGCObject(cx, kind);
|
||||
JSObject *callobj = js_NewGCObject(cx);
|
||||
if (!callobj)
|
||||
return NULL;
|
||||
|
||||
/* Init immediately to avoid GC seeing a half-init'ed object. */
|
||||
callobj->init(cx, &js_CallClass, NULL, &scopeChain, NULL, false);
|
||||
callobj->init(&js_CallClass, NULL, &scopeChain, NULL, cx);
|
||||
callobj->setMap(fun->u.i.names);
|
||||
|
||||
/* This must come after callobj->lastProp has been set. */
|
||||
if (!callobj->ensureInstanceReservedSlots(cx, vars))
|
||||
if (!callobj->ensureInstanceReservedSlots(cx, fun->countArgsAndVars()))
|
||||
return NULL;
|
||||
|
||||
#ifdef DEBUG
|
||||
|
@ -998,11 +992,11 @@ NewCallObject(JSContext *cx, JSFunction *fun, JSObject &scopeChain, JSObject &ca
|
|||
static inline JSObject *
|
||||
NewDeclEnvObject(JSContext *cx, JSStackFrame *fp)
|
||||
{
|
||||
JSObject *envobj = js_NewGCObject(cx, FINALIZE_OBJECT2);
|
||||
JSObject *envobj = js_NewGCObject(cx);
|
||||
if (!envobj)
|
||||
return NULL;
|
||||
|
||||
envobj->init(cx, &js_DeclEnvClass, NULL, &fp->scopeChain(), fp, false);
|
||||
envobj->init(&js_DeclEnvClass, NULL, &fp->scopeChain(), fp, cx);
|
||||
envobj->setMap(cx->runtime->emptyDeclEnvShape);
|
||||
return envobj;
|
||||
}
|
||||
|
@ -1077,9 +1071,34 @@ JS_DEFINE_CALLINFO_4(extern, OBJECT, js_CreateCallObjectOnTrace, CONTEXT, FUNCTI
|
|||
inline static void
|
||||
CopyValuesToCallObject(JSObject &callobj, uintN nargs, Value *argv, uintN nvars, Value *slots)
|
||||
{
|
||||
Value *base = callobj.getSlots() + JSObject::CALL_RESERVED_SLOTS;
|
||||
memcpy(base, argv, nargs * sizeof(Value));
|
||||
memcpy(base + nargs, slots, nvars * sizeof(Value));
|
||||
/* Copy however many args fit into fslots. */
|
||||
uintN first = JSSLOT_PRIVATE + JSObject::CALL_RESERVED_SLOTS + 1;
|
||||
JS_ASSERT(first <= JS_INITIAL_NSLOTS);
|
||||
|
||||
Value *vp = &callobj.fslots[first];
|
||||
uintN len = Min(nargs, uintN(JS_INITIAL_NSLOTS) - first);
|
||||
|
||||
memcpy(vp, argv, len * sizeof(Value));
|
||||
vp += len;
|
||||
|
||||
nargs -= len;
|
||||
if (nargs != 0) {
|
||||
/* Copy any remaining args into dslots. */
|
||||
vp = callobj.dslots;
|
||||
memcpy(vp, argv + len, nargs * sizeof(Value));
|
||||
vp += nargs;
|
||||
} else {
|
||||
/* Copy however many vars fit into any remaining fslots. */
|
||||
first += len;
|
||||
len = JS_MIN(nvars, JS_INITIAL_NSLOTS - first);
|
||||
memcpy(vp, slots, len * sizeof(Value));
|
||||
slots += len;
|
||||
nvars -= len;
|
||||
vp = callobj.dslots;
|
||||
}
|
||||
|
||||
/* Copy any remaining vars into dslots. */
|
||||
memcpy(vp, slots, nvars * sizeof(Value));
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -1098,23 +1117,28 @@ js_PutCallObject(JSContext *cx, JSStackFrame *fp)
|
|||
JS_ASSERT(fun == callobj.getCallObjCalleeFunction());
|
||||
uintN n = fun->countArgsAndVars();
|
||||
|
||||
/*
|
||||
* Since for a call object all fixed slots happen to be taken, we can copy
|
||||
* arguments and variables straight into JSObject.dslots.
|
||||
*/
|
||||
JS_STATIC_ASSERT(JS_INITIAL_NSLOTS - JSSLOT_PRIVATE ==
|
||||
1 + JSObject::CALL_RESERVED_SLOTS);
|
||||
if (n != 0) {
|
||||
JS_ASSERT(JSFunction::CLASS_RESERVED_SLOTS + n <= callobj.numSlots());
|
||||
JS_ASSERT(JSFunction::FIRST_FREE_SLOT + n <= callobj.numSlots());
|
||||
|
||||
uint32 nargs = fun->nargs;
|
||||
uint32 nvars = fun->u.i.nvars;
|
||||
|
||||
Value *base = callobj.getSlots() + JSObject::CALL_RESERVED_SLOTS;
|
||||
|
||||
#ifdef JS_METHODJIT
|
||||
JS_STATIC_ASSERT(JS_INITIAL_NSLOTS == JSSLOT_PRIVATE + JSObject::CALL_RESERVED_SLOTS + 1);
|
||||
JSScript *script = fun->u.i.script;
|
||||
memcpy(base, fp->formalArgs(), nargs * sizeof(Value));
|
||||
memcpy(callobj.dslots, fp->formalArgs(), nargs * sizeof(Value));
|
||||
if (!script->jit || script->usesEval) {
|
||||
memcpy(base + nargs, fp->slots(), nvars * sizeof(Value));
|
||||
memcpy(callobj.dslots + nargs, fp->slots(), nvars * sizeof(Value));
|
||||
} else if (script->jit) {
|
||||
for (uint32 i = 0; i < script->jit->nescaping; i++) {
|
||||
uint32 e = script->jit->escaping[i];
|
||||
base[nargs + e] = fp->slots()[e];
|
||||
callobj.dslots[nargs + e] = fp->slots()[e];
|
||||
}
|
||||
}
|
||||
#else
|
||||
|
@ -1209,13 +1233,16 @@ CallPropertyOp(JSContext *cx, JSObject *obj, jsid id, Value *vp,
|
|||
}
|
||||
|
||||
if (!fp) {
|
||||
i += JSObject::CALL_RESERVED_SLOTS;
|
||||
if (kind == JSCPK_VAR)
|
||||
i += fun->nargs;
|
||||
else
|
||||
JS_ASSERT(kind == JSCPK_ARG);
|
||||
|
||||
array = obj->getSlots();
|
||||
const uintN first = JSSLOT_PRIVATE + JSObject::CALL_RESERVED_SLOTS + 1;
|
||||
JS_ASSERT(first == JSSLOT_FREE(&js_CallClass));
|
||||
JS_ASSERT(first <= JS_INITIAL_NSLOTS);
|
||||
|
||||
array = (i < JS_INITIAL_NSLOTS - first) ? obj->fslots : obj->dslots;
|
||||
} else if (kind == JSCPK_ARG) {
|
||||
array = fp->formalArgs();
|
||||
} else {
|
||||
|
@ -1357,11 +1384,14 @@ call_trace(JSTracer *trc, JSObject *obj)
|
|||
* cycles involving Call objects whose frames are active without this
|
||||
* hiding hack.
|
||||
*/
|
||||
uintN first = JSObject::CALL_RESERVED_SLOTS;
|
||||
uintN count = fp->fun()->countArgsAndVars();
|
||||
uintN first = JSSLOT_PRIVATE + JSObject::CALL_RESERVED_SLOTS + 1;
|
||||
JS_ASSERT(first <= JS_INITIAL_NSLOTS);
|
||||
|
||||
JS_ASSERT(obj->numSlots() >= first + count);
|
||||
SetValueRangeToUndefined(obj->getSlots() + first, count);
|
||||
uintN count = fp->fun()->countArgsAndVars();
|
||||
uintN fixed = JS_MIN(count, JS_INITIAL_NSLOTS - first);
|
||||
|
||||
SetValueRangeToUndefined(&obj->fslots[first], fixed);
|
||||
SetValueRangeToUndefined(obj->dslots, count - fixed);
|
||||
}
|
||||
|
||||
MaybeMarkGenerator(trc, obj);
|
||||
|
@ -2375,8 +2405,8 @@ JSObject::initBoundFunction(JSContext *cx, const Value &thisArg,
|
|||
JS_ASSERT(isFunction());
|
||||
|
||||
flags |= JSObject::BOUND_FUNCTION;
|
||||
getSlotRef(JSSLOT_BOUND_FUNCTION_THIS) = thisArg;
|
||||
getSlotRef(JSSLOT_BOUND_FUNCTION_ARGS_COUNT).setPrivateUint32(argslen);
|
||||
fslots[JSSLOT_BOUND_FUNCTION_THIS] = thisArg;
|
||||
fslots[JSSLOT_BOUND_FUNCTION_ARGS_COUNT].setPrivateUint32(argslen);
|
||||
if (argslen != 0) {
|
||||
/* FIXME? Burn memory on an empty scope whose shape covers the args slots. */
|
||||
EmptyShape *empty = EmptyShape::create(cx, clasp);
|
||||
|
@ -2389,8 +2419,9 @@ JSObject::initBoundFunction(JSContext *cx, const Value &thisArg,
|
|||
if (!ensureInstanceReservedSlots(cx, argslen))
|
||||
return false;
|
||||
|
||||
JS_ASSERT(numSlots() >= argslen + FUN_CLASS_RESERVED_SLOTS);
|
||||
memcpy(getSlots() + FUN_CLASS_RESERVED_SLOTS, args, argslen * sizeof(Value));
|
||||
JS_ASSERT(dslots);
|
||||
JS_ASSERT(dslots[-1].toPrivateUint32() >= argslen);
|
||||
memcpy(&dslots[0], args, argslen * sizeof(Value));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -2411,7 +2442,7 @@ JSObject::getBoundFunctionThis() const
|
|||
JS_ASSERT(isFunction());
|
||||
JS_ASSERT(isBoundFunction());
|
||||
|
||||
return getSlot(JSSLOT_BOUND_FUNCTION_THIS);
|
||||
return fslots[JSSLOT_BOUND_FUNCTION_THIS];
|
||||
}
|
||||
|
||||
inline const js::Value *
|
||||
|
@ -2420,10 +2451,10 @@ JSObject::getBoundFunctionArguments(uintN &argslen) const
|
|||
JS_ASSERT(isFunction());
|
||||
JS_ASSERT(isBoundFunction());
|
||||
|
||||
argslen = getSlot(JSSLOT_BOUND_FUNCTION_ARGS_COUNT).toPrivateUint32();
|
||||
JS_ASSERT_IF(argslen > 0, numSlots() >= argslen);
|
||||
|
||||
return getSlots() + FUN_CLASS_RESERVED_SLOTS;
|
||||
argslen = fslots[JSSLOT_BOUND_FUNCTION_ARGS_COUNT].toPrivateUint32();
|
||||
JS_ASSERT_IF(argslen > 0, dslots);
|
||||
JS_ASSERT_IF(argslen > 0, dslots[-1].toPrivateUint32() >= argslen);
|
||||
return &dslots[0];
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
@ -3110,7 +3141,7 @@ JSFunction::addLocal(JSContext *cx, JSAtom *atom, JSLocalKind kind)
|
|||
uintN attrs = JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED;
|
||||
uint16 *indexp;
|
||||
PropertyOp getter, setter;
|
||||
uint32 slot = JSObject::CALL_RESERVED_SLOTS;
|
||||
uint32 slot = JSSLOT_START(&js_CallClass) + JSObject::CALL_RESERVED_SLOTS;
|
||||
|
||||
if (kind == JSLOCAL_ARG) {
|
||||
JS_ASSERT(u.i.nupvars == 0);
|
||||
|
|
|
@ -134,8 +134,6 @@ enum JSLocalKind {
|
|||
|
||||
struct JSFunction : public JSObject
|
||||
{
|
||||
/* Functions always have two fixed slots (FUN_CLASS_RESERVED_SLOTS). */
|
||||
|
||||
uint16 nargs; /* maximum number of specified arguments,
|
||||
reflected as f.length/f.arity */
|
||||
uint16 flags; /* flags, see JSFUN_* below and in jsapi.h */
|
||||
|
@ -271,7 +269,7 @@ struct JSFunction : public JSObject
|
|||
public:
|
||||
void setJoinable() {
|
||||
JS_ASSERT(FUN_INTERPRETED(this));
|
||||
getSlotRef(METHOD_ATOM_SLOT).setNull();
|
||||
fslots[METHOD_ATOM_SLOT].setNull();
|
||||
flags |= JSFUN_JOINABLE;
|
||||
}
|
||||
|
||||
|
@ -281,14 +279,14 @@ struct JSFunction : public JSObject
|
|||
* flattened upvars.
|
||||
*/
|
||||
JSAtom *methodAtom() const {
|
||||
return (joinable() && getSlot(METHOD_ATOM_SLOT).isString())
|
||||
? STRING_TO_ATOM(getSlot(METHOD_ATOM_SLOT).toString())
|
||||
return (joinable() && fslots[METHOD_ATOM_SLOT].isString())
|
||||
? STRING_TO_ATOM(fslots[METHOD_ATOM_SLOT].toString())
|
||||
: NULL;
|
||||
}
|
||||
|
||||
void setMethodAtom(JSAtom *atom) {
|
||||
JS_ASSERT(joinable());
|
||||
getSlotRef(METHOD_ATOM_SLOT).setString(ATOM_TO_STRING(atom));
|
||||
fslots[METHOD_ATOM_SLOT].setString(ATOM_TO_STRING(atom));
|
||||
}
|
||||
|
||||
js::Native maybeNative() const {
|
||||
|
@ -300,8 +298,9 @@ struct JSFunction : public JSObject
|
|||
return u.i.script;
|
||||
}
|
||||
|
||||
/* Number of extra fixed function object slots. */
|
||||
/* Number of extra fixed function object slots besides JSSLOT_PRIVATE. */
|
||||
static const uint32 CLASS_RESERVED_SLOTS = JSObject::FUN_CLASS_RESERVED_SLOTS;
|
||||
static const uint32 FIRST_FREE_SLOT = JSSLOT_PRIVATE + CLASS_RESERVED_SLOTS + 1;
|
||||
};
|
||||
|
||||
JS_STATIC_ASSERT(sizeof(JSFunction) % JS_GCTHING_ALIGN == 0);
|
||||
|
|
|
@ -235,7 +235,7 @@ const size_t GC_MARK_BITMAP_WORDS = GC_CELLS_PER_ARENA / JS_BITS_PER_WORD;
|
|||
JS_STATIC_ASSERT(sizeof(jsbitmap) == sizeof(jsuword));
|
||||
|
||||
JS_STATIC_ASSERT(sizeof(JSString) % GC_CELL_SIZE == 0);
|
||||
JS_STATIC_ASSERT(JSOBJECT_SIZE % GC_CELL_SIZE == 0);
|
||||
JS_STATIC_ASSERT(sizeof(JSObject) % GC_CELL_SIZE == 0);
|
||||
JS_STATIC_ASSERT(sizeof(JSFunction) % GC_CELL_SIZE == 0);
|
||||
#ifdef JSXML
|
||||
JS_STATIC_ASSERT(sizeof(JSXML) % GC_CELL_SIZE == 0);
|
||||
|
@ -771,15 +771,9 @@ static inline size_t
|
|||
GetFinalizableThingSize(unsigned thingKind)
|
||||
{
|
||||
JS_STATIC_ASSERT(JS_EXTERNAL_STRING_LIMIT == 8);
|
||||
JS_STATIC_ASSERT(FINALIZE_OBJECT_LAST - FINALIZE_OBJECT0 == 5);
|
||||
|
||||
static const uint8 map[FINALIZE_LIMIT] = {
|
||||
JSOBJECT_SIZE, /* FINALIZE_OBJECT0 */
|
||||
JSOBJECT_SIZE + 2 * sizeof(Value), /* FINALIZE_OBJECT2 */
|
||||
JSOBJECT_SIZE + 4 * sizeof(Value), /* FINALIZE_OBJECT4 */
|
||||
JSOBJECT_SIZE + 8 * sizeof(Value), /* FINALIZE_OBJECT8 */
|
||||
JSOBJECT_SIZE + 12 * sizeof(Value), /* FINALIZE_OBJECT12 */
|
||||
JSOBJECT_SIZE + 16 * sizeof(Value), /* FINALIZE_OBJECT16 */
|
||||
sizeof(JSObject), /* FINALIZE_OBJECT */
|
||||
sizeof(JSFunction), /* FINALIZE_FUNCTION */
|
||||
#if JS_HAS_XML_SUPPORT
|
||||
sizeof(JSXML), /* FINALIZE_XML */
|
||||
|
@ -806,12 +800,7 @@ GetFinalizableTraceKind(size_t thingKind)
|
|||
JS_STATIC_ASSERT(JS_EXTERNAL_STRING_LIMIT == 8);
|
||||
|
||||
static const uint8 map[FINALIZE_LIMIT] = {
|
||||
JSTRACE_OBJECT, /* FINALIZE_OBJECT0 */
|
||||
JSTRACE_OBJECT, /* FINALIZE_OBJECT2 */
|
||||
JSTRACE_OBJECT, /* FINALIZE_OBJECT4 */
|
||||
JSTRACE_OBJECT, /* FINALIZE_OBJECT8 */
|
||||
JSTRACE_OBJECT, /* FINALIZE_OBJECT12 */
|
||||
JSTRACE_OBJECT, /* FINALIZE_OBJECT16 */
|
||||
JSTRACE_OBJECT, /* FINALIZE_OBJECT */
|
||||
JSTRACE_OBJECT, /* FINALIZE_FUNCTION */
|
||||
#if JS_HAS_XML_SUPPORT /* FINALIZE_XML */
|
||||
JSTRACE_XML,
|
||||
|
@ -1560,22 +1549,8 @@ CheckGCFreeListLink(JSGCThing *thing)
|
|||
JS_ASSERT_IF(thing->link, thing < thing->link);
|
||||
}
|
||||
|
||||
JSFinalizeGCThingKind js_GCObjectSlotsToThingKind[] = {
|
||||
/* 0 */ FINALIZE_OBJECT0, FINALIZE_OBJECT2, FINALIZE_OBJECT2, FINALIZE_OBJECT4,
|
||||
/* 4 */ FINALIZE_OBJECT4, FINALIZE_OBJECT8, FINALIZE_OBJECT8, FINALIZE_OBJECT8,
|
||||
/* 8 */ FINALIZE_OBJECT8, FINALIZE_OBJECT12, FINALIZE_OBJECT12, FINALIZE_OBJECT12,
|
||||
/* 12 */ FINALIZE_OBJECT12, FINALIZE_OBJECT16, FINALIZE_OBJECT16, FINALIZE_OBJECT16,
|
||||
/* 16 */ FINALIZE_OBJECT16, FINALIZE_OBJECT0, FINALIZE_OBJECT0, FINALIZE_OBJECT0,
|
||||
/* 20 */ FINALIZE_OBJECT0, FINALIZE_OBJECT0, FINALIZE_OBJECT0, FINALIZE_OBJECT0,
|
||||
/* 24 */ FINALIZE_OBJECT0, FINALIZE_OBJECT0, FINALIZE_OBJECT0, FINALIZE_OBJECT0,
|
||||
/* 28 */ FINALIZE_OBJECT0, FINALIZE_OBJECT0, FINALIZE_OBJECT0, FINALIZE_OBJECT0,
|
||||
/* 32 */ FINALIZE_OBJECT0
|
||||
};
|
||||
|
||||
JS_STATIC_ASSERT(JS_ARRAY_LENGTH(js_GCObjectSlotsToThingKind) == SLOTS_TO_THING_KIND_LIMIT);
|
||||
|
||||
void *
|
||||
js_NewFinalizableGCThing(JSContext *cx, JSFinalizeGCThingKind thingKind)
|
||||
js_NewFinalizableGCThing(JSContext *cx, unsigned thingKind)
|
||||
{
|
||||
JS_ASSERT(thingKind < FINALIZE_LIMIT);
|
||||
#ifdef JS_THREADSAFE
|
||||
|
@ -1613,13 +1588,6 @@ js_NewFinalizableGCThing(JSContext *cx, JSFinalizeGCThingKind thingKind)
|
|||
return thing;
|
||||
}
|
||||
|
||||
JSFinalizeGCThingKind
|
||||
js_KindFromGCThing(const void *thing)
|
||||
{
|
||||
JSGCArenaInfo *info = JSGCArenaInfo::fromGCThing((void*)thing);
|
||||
return (JSFinalizeGCThingKind) info->list->thingKind;
|
||||
}
|
||||
|
||||
JSBool
|
||||
js_LockGCThingRT(JSRuntime *rt, void *thing)
|
||||
{
|
||||
|
@ -1676,14 +1644,8 @@ JS_TraceChildren(JSTracer *trc, void *thing, uint32 kind)
|
|||
JS_CALL_OBJECT_TRACER(trc, proto, "proto");
|
||||
if (JSObject *parent = obj->getParent())
|
||||
JS_CALL_OBJECT_TRACER(trc, parent, "parent");
|
||||
|
||||
if (obj->emptyShapes) {
|
||||
int count = FINALIZE_OBJECT_LAST - FINALIZE_OBJECT0 + 1;
|
||||
for (int i = 0; i < count; i++) {
|
||||
if (obj->emptyShapes[i])
|
||||
obj->emptyShapes[i]->trace(trc);
|
||||
}
|
||||
}
|
||||
if (obj->emptyShape)
|
||||
obj->emptyShape->trace(trc);
|
||||
|
||||
/* Delegate to ops or the native marking op. */
|
||||
JSTraceOp op = obj->getOps()->trace;
|
||||
|
@ -2387,7 +2349,7 @@ js_DestroyScriptsToGC(JSContext *cx, JSThreadData *data)
|
|||
inline void
|
||||
FinalizeObject(JSContext *cx, JSObject *obj, unsigned thingKind)
|
||||
{
|
||||
JS_ASSERT((thingKind >= FINALIZE_OBJECT0 && thingKind <= FINALIZE_OBJECT_LAST) ||
|
||||
JS_ASSERT(thingKind == FINALIZE_OBJECT ||
|
||||
thingKind == FINALIZE_FUNCTION);
|
||||
|
||||
/* Cope with stillborn objects that have no map. */
|
||||
|
@ -2526,14 +2488,14 @@ js_FinalizeStringRT(JSRuntime *rt, JSString *str)
|
|||
}
|
||||
}
|
||||
|
||||
template<typename T, unsigned SIZE,
|
||||
template<typename T,
|
||||
void finalizer(JSContext *cx, T *thing, unsigned thingKind)>
|
||||
static void
|
||||
FinalizeArenaList(JSContext *cx, unsigned thingKind)
|
||||
{
|
||||
JS_STATIC_ASSERT(!(SIZE & GC_CELL_MASK));
|
||||
JS_STATIC_ASSERT(!(sizeof(T) & GC_CELL_MASK));
|
||||
JSGCArenaList *arenaList = &cx->runtime->gcArenaList[thingKind];
|
||||
JS_ASSERT(SIZE == arenaList->thingSize);
|
||||
JS_ASSERT(sizeof(T) == arenaList->thingSize);
|
||||
|
||||
JSGCArena **ap = &arenaList->head;
|
||||
JSGCArena *a = *ap;
|
||||
|
@ -2554,8 +2516,7 @@ FinalizeArenaList(JSContext *cx, unsigned thingKind)
|
|||
bool allClear = true;
|
||||
|
||||
jsuword thing = a->toPageStart();
|
||||
jsuword thingsEnd = thing + GC_ARENA_SIZE - (GC_ARENA_SIZE % SIZE);
|
||||
JS_ASSERT((thingsEnd - thing) % SIZE == 0);
|
||||
jsuword thingsEnd = thing + GC_ARENA_SIZE / sizeof(T) * sizeof(T);
|
||||
|
||||
jsuword nextFree = reinterpret_cast<jsuword>(ainfo->freeList);
|
||||
if (!nextFree) {
|
||||
|
@ -2567,7 +2528,7 @@ FinalizeArenaList(JSContext *cx, unsigned thingKind)
|
|||
|
||||
jsuword gcCellIndex = 0;
|
||||
jsbitmap *bitmap = a->getMarkBitmap();
|
||||
for (;; thing += SIZE, gcCellIndex += SIZE >> GC_CELL_SHIFT) {
|
||||
for (;; thing += sizeof(T), gcCellIndex += sizeof(T) >> GC_CELL_SHIFT) {
|
||||
if (thing == nextFree) {
|
||||
if (thing == thingsEnd)
|
||||
break;
|
||||
|
@ -2587,7 +2548,7 @@ FinalizeArenaList(JSContext *cx, unsigned thingKind)
|
|||
T *t = reinterpret_cast<T *>(thing);
|
||||
finalizer(cx, t, thingKind);
|
||||
#ifdef DEBUG
|
||||
memset(t, JS_FREE_PATTERN, SIZE);
|
||||
memset(t, JS_FREE_PATTERN, sizeof(T));
|
||||
#endif
|
||||
}
|
||||
JSGCThing *t = reinterpret_cast<JSGCThing *>(thing);
|
||||
|
@ -2615,12 +2576,12 @@ FinalizeArenaList(JSContext *cx, unsigned thingKind)
|
|||
* Forget just assembled free list head for the arena and
|
||||
* add the arena itself to the destroy list.
|
||||
*/
|
||||
JS_ASSERT(nfree == ThingsPerArena(SIZE));
|
||||
JS_ASSERT(nfree == ThingsPerArena(sizeof(T)));
|
||||
*ap = ainfo->prev;
|
||||
ReleaseGCArena(cx->runtime, a);
|
||||
METER(nkilledarenas++);
|
||||
} else {
|
||||
JS_ASSERT(nfree < ThingsPerArena(SIZE));
|
||||
JS_ASSERT(nfree < ThingsPerArena(sizeof(T)));
|
||||
*tailp = NULL;
|
||||
ainfo->freeList = freeList;
|
||||
ap = &ainfo->prev;
|
||||
|
@ -2923,21 +2884,10 @@ MarkAndSweep(JSContext *cx GCTIMER_PARAM)
|
|||
* object's finalizer can access them even if they will be freed.
|
||||
*/
|
||||
JS_ASSERT(!rt->gcEmptyArenaList);
|
||||
FinalizeArenaList<JSObject, JSOBJECT_SIZE,
|
||||
FinalizeObject>(cx, FINALIZE_OBJECT0);
|
||||
FinalizeArenaList<JSObject, JSOBJECT_SIZE + sizeof(Value) * 2,
|
||||
FinalizeObject>(cx, FINALIZE_OBJECT2);
|
||||
FinalizeArenaList<JSObject, JSOBJECT_SIZE + sizeof(Value) * 4,
|
||||
FinalizeObject>(cx, FINALIZE_OBJECT4);
|
||||
FinalizeArenaList<JSObject, JSOBJECT_SIZE + sizeof(Value) * 8,
|
||||
FinalizeObject>(cx, FINALIZE_OBJECT8);
|
||||
FinalizeArenaList<JSObject, JSOBJECT_SIZE + sizeof(Value) * 12,
|
||||
FinalizeObject>(cx, FINALIZE_OBJECT12);
|
||||
FinalizeArenaList<JSObject, JSOBJECT_SIZE + sizeof(Value) * 16,
|
||||
FinalizeObject>(cx, FINALIZE_OBJECT16);
|
||||
FinalizeArenaList<JSFunction, sizeof(JSFunction), FinalizeFunction>(cx, FINALIZE_FUNCTION);
|
||||
FinalizeArenaList<JSObject, FinalizeObject>(cx, FINALIZE_OBJECT);
|
||||
FinalizeArenaList<JSFunction, FinalizeFunction>(cx, FINALIZE_FUNCTION);
|
||||
#if JS_HAS_XML_SUPPORT
|
||||
FinalizeArenaList<JSXML, sizeof(JSXML), FinalizeXML>(cx, FINALIZE_XML);
|
||||
FinalizeArenaList<JSXML, FinalizeXML>(cx, FINALIZE_XML);
|
||||
#endif
|
||||
TIMESTAMP(sweepObjectEnd);
|
||||
|
||||
|
@ -2947,13 +2897,12 @@ MarkAndSweep(JSContext *cx GCTIMER_PARAM)
|
|||
*/
|
||||
rt->deflatedStringCache->sweep(cx);
|
||||
|
||||
FinalizeArenaList<JSShortString, sizeof(JSShortString),
|
||||
FinalizeShortString>(cx, FINALIZE_SHORT_STRING);
|
||||
FinalizeArenaList<JSString, sizeof(JSString), FinalizeString>(cx, FINALIZE_STRING);
|
||||
FinalizeArenaList<JSShortString, FinalizeShortString>(cx, FINALIZE_SHORT_STRING);
|
||||
FinalizeArenaList<JSString, FinalizeString>(cx, FINALIZE_STRING);
|
||||
for (unsigned i = FINALIZE_EXTERNAL_STRING0;
|
||||
i <= FINALIZE_EXTERNAL_STRING_LAST;
|
||||
++i) {
|
||||
FinalizeArenaList<JSString, sizeof(JSString), FinalizeExternalString>(cx, i);
|
||||
FinalizeArenaList<JSString, FinalizeExternalString>(cx, i);
|
||||
}
|
||||
|
||||
rt->gcNewArenaTriggerBytes = rt->gcBytes < GC_ARENA_ALLOCATION_TRIGGER ?
|
||||
|
|
|
@ -236,13 +236,7 @@ js_WaitForGC(JSRuntime *rt);
|
|||
* ordinary string to simplify js_GetExternalStringGCType.
|
||||
*/
|
||||
enum JSFinalizeGCThingKind {
|
||||
FINALIZE_OBJECT0,
|
||||
FINALIZE_OBJECT2,
|
||||
FINALIZE_OBJECT4,
|
||||
FINALIZE_OBJECT8,
|
||||
FINALIZE_OBJECT12,
|
||||
FINALIZE_OBJECT16,
|
||||
FINALIZE_OBJECT_LAST = FINALIZE_OBJECT16,
|
||||
FINALIZE_OBJECT,
|
||||
FINALIZE_FUNCTION,
|
||||
#if JS_HAS_XML_SUPPORT
|
||||
FINALIZE_XML,
|
||||
|
@ -275,61 +269,12 @@ IsFinalizableStringKind(unsigned thingKind)
|
|||
* in the partially initialized thing.
|
||||
*/
|
||||
extern void *
|
||||
js_NewFinalizableGCThing(JSContext *cx, JSFinalizeGCThingKind thingKind);
|
||||
|
||||
/* Get the kind which was used when making a GC thing. */
|
||||
extern JSFinalizeGCThingKind
|
||||
js_KindFromGCThing(const void *thing);
|
||||
|
||||
/* Maximum number of fixed slots for an object. */
|
||||
const size_t JSOBJECT_FIXED_SLOTS_LIMIT = 16;
|
||||
|
||||
/* Capacity for js_GCObjectSlotsToThingKind */
|
||||
const size_t SLOTS_TO_THING_KIND_LIMIT = 33;
|
||||
|
||||
/* Get the best kind to use when making an object with the given slot count. */
|
||||
static inline JSFinalizeGCThingKind
|
||||
js_GetGCObjectKind(size_t numSlots)
|
||||
{
|
||||
extern JSFinalizeGCThingKind js_GCObjectSlotsToThingKind[];
|
||||
|
||||
if (numSlots >= SLOTS_TO_THING_KIND_LIMIT)
|
||||
return FINALIZE_OBJECT0;
|
||||
return js_GCObjectSlotsToThingKind[numSlots];
|
||||
}
|
||||
|
||||
/* Get the number of fixed slots and initial capacity associated with a kind. */
|
||||
static inline size_t
|
||||
js_GetGCKindSlots(JSFinalizeGCThingKind thingKind)
|
||||
{
|
||||
/* Using a switch in hopes that thingKind will usually be a compile-time constant. */
|
||||
switch (thingKind) {
|
||||
case FINALIZE_OBJECT0:
|
||||
return 0;
|
||||
case FINALIZE_OBJECT2:
|
||||
return 2;
|
||||
case FINALIZE_OBJECT4:
|
||||
return 4;
|
||||
case FINALIZE_OBJECT8:
|
||||
return 8;
|
||||
case FINALIZE_OBJECT12:
|
||||
return 12;
|
||||
case FINALIZE_OBJECT16:
|
||||
return 16;
|
||||
default:
|
||||
JS_NOT_REACHED("Bad object finalize kind");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
js_NewFinalizableGCThing(JSContext *cx, unsigned thingKind);
|
||||
|
||||
static inline JSObject *
|
||||
js_NewGCObject(JSContext *cx, JSFinalizeGCThingKind thingKind)
|
||||
js_NewGCObject(JSContext *cx)
|
||||
{
|
||||
JS_ASSERT(thingKind >= FINALIZE_OBJECT0 && thingKind <= FINALIZE_OBJECT_LAST);
|
||||
JSObject *obj = (JSObject *) js_NewFinalizableGCThing(cx, thingKind);
|
||||
if (obj)
|
||||
obj->capacity = js_GetGCKindSlots(thingKind);
|
||||
return obj;
|
||||
return (JSObject *) js_NewFinalizableGCThing(cx, FINALIZE_OBJECT);
|
||||
}
|
||||
|
||||
static inline JSString *
|
||||
|
@ -351,7 +296,7 @@ js_NewGCExternalString(JSContext *cx, uintN type)
|
|||
{
|
||||
JS_ASSERT(type < JS_EXTERNAL_STRING_LIMIT);
|
||||
type += FINALIZE_EXTERNAL_STRING0;
|
||||
return (JSString *) js_NewFinalizableGCThing(cx, JSFinalizeGCThingKind(type));
|
||||
return (JSString *) js_NewFinalizableGCThing(cx, type);
|
||||
}
|
||||
|
||||
static inline JSFunction *
|
||||
|
@ -359,13 +304,12 @@ js_NewGCFunction(JSContext *cx)
|
|||
{
|
||||
JSFunction* obj = (JSFunction *)js_NewFinalizableGCThing(cx, FINALIZE_FUNCTION);
|
||||
|
||||
if (obj) {
|
||||
obj->capacity = JSObject::FUN_CLASS_RESERVED_SLOTS;
|
||||
#ifdef DEBUG
|
||||
if (obj) {
|
||||
memset((uint8 *) obj + sizeof(JSObject), JS_FREE_PATTERN,
|
||||
sizeof(JSFunction) - sizeof(JSObject));
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
@ -472,13 +416,10 @@ class GCHelperThread {
|
|||
|
||||
void freeLater(void *ptr) {
|
||||
JS_ASSERT(!sweeping);
|
||||
js_free(ptr);
|
||||
/*
|
||||
if (freeCursor != freeCursorEnd)
|
||||
*freeCursor++ = ptr;
|
||||
else
|
||||
replenishAndFreeLater(ptr);
|
||||
*/
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -330,8 +330,8 @@ ComputeThisFromArgv(JSContext *cx, Value *argv)
|
|||
|
||||
#if JS_HAS_NO_SUCH_METHOD
|
||||
|
||||
const uint32 JSSLOT_FOUND_FUNCTION = 0;
|
||||
const uint32 JSSLOT_SAVED_ID = 1;
|
||||
const uint32 JSSLOT_FOUND_FUNCTION = JSSLOT_PRIVATE;
|
||||
const uint32 JSSLOT_SAVED_ID = JSSLOT_PRIVATE + 1;
|
||||
|
||||
Class js_NoSuchMethodClass = {
|
||||
"NoSuchMethod",
|
||||
|
@ -382,7 +382,7 @@ js_OnUnknownMethod(JSContext *cx, Value *vp)
|
|||
vp[0] = IdToValue(id);
|
||||
}
|
||||
#endif
|
||||
obj = js_NewGCObject(cx, FINALIZE_OBJECT2);
|
||||
obj = js_NewGCObject(cx);
|
||||
if (!obj)
|
||||
return false;
|
||||
|
||||
|
@ -393,9 +393,8 @@ js_OnUnknownMethod(JSContext *cx, Value *vp)
|
|||
* NoSuchMethod helper objects own no manually allocated resources.
|
||||
*/
|
||||
obj->map = NULL;
|
||||
obj->init(cx, &js_NoSuchMethodClass, NULL, NULL, NULL, false);
|
||||
obj->setSlot(JSSLOT_FOUND_FUNCTION, tvr.value());
|
||||
obj->setSlot(JSSLOT_SAVED_ID, vp[0]);
|
||||
obj->init(&js_NoSuchMethodClass, NULL, NULL, tvr.value(), cx);
|
||||
obj->fslots[JSSLOT_SAVED_ID] = vp[0];
|
||||
vp[0].setObject(*obj);
|
||||
}
|
||||
return true;
|
||||
|
@ -413,9 +412,9 @@ NoSuchMethod(JSContext *cx, uintN argc, Value *vp, uint32 flags)
|
|||
JSObject *obj = &vp[0].toObject();
|
||||
JS_ASSERT(obj->getClass() == &js_NoSuchMethodClass);
|
||||
|
||||
args.callee() = obj->getSlot(JSSLOT_FOUND_FUNCTION);
|
||||
args.callee() = obj->fslots[JSSLOT_FOUND_FUNCTION];
|
||||
args.thisv() = vp[1];
|
||||
args[0] = obj->getSlot(JSSLOT_SAVED_ID);
|
||||
args[0] = obj->fslots[JSSLOT_SAVED_ID];
|
||||
JSObject *argsobj = js_NewArrayObject(cx, argc, vp + 2);
|
||||
if (!argsobj)
|
||||
return JS_FALSE;
|
||||
|
@ -5652,20 +5651,15 @@ END_CASE(JSOP_NEWARRAY)
|
|||
|
||||
BEGIN_CASE(JSOP_NEWINIT)
|
||||
{
|
||||
jsint i = GET_UINT16(regs.pc);
|
||||
jsint count = GET_UINT16(regs.pc + UINT16_LEN);
|
||||
|
||||
jsint i = GET_INT8(regs.pc);
|
||||
JS_ASSERT(i == JSProto_Array || i == JSProto_Object);
|
||||
JSObject *obj;
|
||||
|
||||
JSFinalizeGCThingKind kind = GuessObjectGCKind(count);
|
||||
|
||||
if (i == JSProto_Array) {
|
||||
obj = NewArrayWithKind(cx, kind);
|
||||
obj = js_NewArrayObject(cx, 0, NULL);
|
||||
if (!obj)
|
||||
goto error;
|
||||
} else {
|
||||
obj = NewBuiltinClassInstance(cx, &js_ObjectClass, kind);
|
||||
obj = NewBuiltinClassInstance(cx, &js_ObjectClass);
|
||||
if (!obj)
|
||||
goto error;
|
||||
}
|
||||
|
|
|
@ -288,7 +288,7 @@ EnumerateDenseArrayProperties(JSContext *cx, JSObject *obj, JSObject *pobj, uint
|
|||
|
||||
if (pobj->getArrayLength() > 0) {
|
||||
size_t capacity = pobj->getDenseArrayCapacity();
|
||||
Value *vp = pobj->getDenseArrayElements();
|
||||
Value *vp = pobj->dslots;
|
||||
for (size_t i = 0; i < capacity; ++i, ++vp) {
|
||||
if (!vp->isMagic(JS_ARRAY_HOLE)) {
|
||||
/* Dense arrays never get so large that i would not fit into an integer id. */
|
||||
|
@ -455,10 +455,10 @@ NewIteratorObject(JSContext *cx, uintN flags)
|
|||
* helper objects) expect it to have a non-null map pointer, so we
|
||||
* share an empty Enumerator scope in the runtime.
|
||||
*/
|
||||
JSObject *obj = js_NewGCObject(cx, FINALIZE_OBJECT0);
|
||||
JSObject *obj = js_NewGCObject(cx);
|
||||
if (!obj)
|
||||
return false;
|
||||
obj->init(cx, &js_IteratorClass, NULL, NULL, NULL, false);
|
||||
obj->init(&js_IteratorClass, NULL, NULL, NullValue(), cx);
|
||||
obj->setMap(cx->runtime->emptyEnumeratorShape);
|
||||
return obj;
|
||||
}
|
||||
|
|
|
@ -507,7 +507,8 @@ FinishSharingTitle(JSContext *cx, JSTitle *title)
|
|||
JSObject *obj = TITLE_TO_OBJECT(title);
|
||||
if (obj) {
|
||||
uint32 nslots = obj->slotSpan();
|
||||
for (uint32 i = 0; i != nslots; ++i) {
|
||||
JS_ASSERT(nslots >= JSSLOT_START(obj->getClass()));
|
||||
for (uint32 i = JSSLOT_START(obj->getClass()); i != nslots; ++i) {
|
||||
Value v = obj->getSlot(i);
|
||||
if (v.isString() &&
|
||||
!js_MakeStringImmutable(cx, v.toString())) {
|
||||
|
|
250
js/src/jsobj.cpp
250
js/src/jsobj.cpp
|
@ -2610,17 +2610,15 @@ js_NewInstance(JSContext *cx, JSObject *callee)
|
|||
|
||||
static JS_ALWAYS_INLINE JSObject*
|
||||
NewObjectWithClassProto(JSContext *cx, Class *clasp, JSObject *proto,
|
||||
/*JSFinalizeGCThingKind*/ unsigned _kind)
|
||||
const Value &privateSlotValue)
|
||||
{
|
||||
JS_ASSERT(clasp->isNative());
|
||||
JSFinalizeGCThingKind kind = JSFinalizeGCThingKind(_kind);
|
||||
|
||||
JSObject* obj = js_NewGCObject(cx, kind);
|
||||
JSObject* obj = js_NewGCObject(cx);
|
||||
if (!obj)
|
||||
return NULL;
|
||||
|
||||
if (!obj->initSharingEmptyShape(cx, clasp, proto, proto->getParent(), NULL, kind))
|
||||
return NULL;
|
||||
obj->initSharingEmptyShape(clasp, proto, proto->getParent(), privateSlotValue, cx);
|
||||
return obj;
|
||||
}
|
||||
|
||||
|
@ -2628,7 +2626,8 @@ JSObject* FASTCALL
|
|||
js_Object_tn(JSContext* cx, JSObject* proto)
|
||||
{
|
||||
JS_ASSERT(!(js_ObjectClass.flags & JSCLASS_HAS_PRIVATE));
|
||||
return NewObjectWithClassProto(cx, &js_ObjectClass, proto, FINALIZE_OBJECT8);
|
||||
|
||||
return NewObjectWithClassProto(cx, &js_ObjectClass, proto, UndefinedValue());
|
||||
}
|
||||
|
||||
JS_DEFINE_TRCINFO_1(js_Object,
|
||||
|
@ -2640,7 +2639,7 @@ js_NonEmptyObject(JSContext* cx, JSObject* proto)
|
|||
{
|
||||
JS_ASSERT(!(js_ObjectClass.flags & JSCLASS_HAS_PRIVATE));
|
||||
|
||||
JSObject *obj = NewObjectWithClassProto(cx, &js_ObjectClass, proto, FINALIZE_OBJECT8);
|
||||
JSObject *obj = NewObjectWithClassProto(cx, &js_ObjectClass, proto, UndefinedValue());
|
||||
return (obj && obj->ensureClassReservedSlotsForEmptyObject(cx)) ? obj : NULL;
|
||||
}
|
||||
|
||||
|
@ -2651,11 +2650,7 @@ JSObject* FASTCALL
|
|||
js_String_tn(JSContext* cx, JSObject* proto, JSString* str)
|
||||
{
|
||||
JS_ASSERT(JS_ON_TRACE(cx));
|
||||
JSObject *obj = NewObjectWithClassProto(cx, &js_StringClass, proto, FINALIZE_OBJECT2);
|
||||
if (!obj)
|
||||
return NULL;
|
||||
obj->setPrimitiveThis(StringValue(str));
|
||||
return obj;
|
||||
return NewObjectWithClassProto(cx, &js_StringClass, proto, StringValue(str));
|
||||
}
|
||||
JS_DEFINE_CALLINFO_3(extern, OBJECT, js_String_tn, CONTEXT, CALLEE_PROTOTYPE, STRING, 0,
|
||||
nanojit::ACCSET_STORE_ANY)
|
||||
|
@ -2930,13 +2925,11 @@ js_NewWithObject(JSContext *cx, JSObject *proto, JSObject *parent, jsint depth)
|
|||
{
|
||||
JSObject *obj;
|
||||
|
||||
obj = js_NewGCObject(cx, FINALIZE_OBJECT2);
|
||||
obj = js_NewGCObject(cx);
|
||||
if (!obj)
|
||||
return NULL;
|
||||
|
||||
JSStackFrame *priv = js_FloatingFrameIfGenerator(cx, cx->fp());
|
||||
|
||||
obj->init(cx, &js_WithClass, proto, parent, priv, false);
|
||||
obj->init(&js_WithClass, proto, parent, js_FloatingFrameIfGenerator(cx, cx->fp()), cx);
|
||||
obj->setMap(cx->runtime->emptyWithShape);
|
||||
OBJ_SET_BLOCK_DEPTH(cx, obj, depth);
|
||||
|
||||
|
@ -2956,11 +2949,11 @@ js_NewBlockObject(JSContext *cx)
|
|||
* Null obj's proto slot so that Object.prototype.* does not pollute block
|
||||
* scopes and to give the block object its own scope.
|
||||
*/
|
||||
JSObject *blockObj = js_NewGCObject(cx, FINALIZE_OBJECT2);
|
||||
JSObject *blockObj = js_NewGCObject(cx);
|
||||
if (!blockObj)
|
||||
return NULL;
|
||||
|
||||
blockObj->init(cx, &js_BlockClass, NULL, NULL, NULL, false);
|
||||
blockObj->init(&js_BlockClass, NULL, NULL, NullValue(), cx);
|
||||
blockObj->setMap(cx->runtime->emptyBlockShape);
|
||||
return blockObj;
|
||||
}
|
||||
|
@ -2970,24 +2963,20 @@ js_CloneBlockObject(JSContext *cx, JSObject *proto, JSStackFrame *fp)
|
|||
{
|
||||
JS_ASSERT(proto->isStaticBlock());
|
||||
|
||||
size_t count = OBJ_BLOCK_COUNT(cx, proto);
|
||||
JSFinalizeGCThingKind kind = js_GetGCObjectKind(count + 1);
|
||||
|
||||
JSObject *clone = js_NewGCObject(cx, kind);
|
||||
JSObject *clone = js_NewGCObject(cx);
|
||||
if (!clone)
|
||||
return NULL;
|
||||
|
||||
JSStackFrame *priv = js_FloatingFrameIfGenerator(cx, fp);
|
||||
|
||||
/* The caller sets parent on its own. */
|
||||
clone->init(cx, &js_BlockClass, proto, NULL, priv, false);
|
||||
clone->init(&js_BlockClass, proto, NULL, priv, cx);
|
||||
clone->fslots[JSSLOT_BLOCK_DEPTH] = proto->fslots[JSSLOT_BLOCK_DEPTH];
|
||||
|
||||
clone->setMap(proto->map);
|
||||
if (!clone->ensureInstanceReservedSlots(cx, count + 1))
|
||||
if (!clone->ensureInstanceReservedSlots(cx, OBJ_BLOCK_COUNT(cx, proto)))
|
||||
return NULL;
|
||||
|
||||
clone->setSlot(JSSLOT_BLOCK_DEPTH, proto->getSlot(JSSLOT_BLOCK_DEPTH));
|
||||
|
||||
JS_ASSERT(clone->isClonedBlock());
|
||||
return clone;
|
||||
}
|
||||
|
@ -2995,6 +2984,9 @@ js_CloneBlockObject(JSContext *cx, JSObject *proto, JSStackFrame *fp)
|
|||
JS_REQUIRES_STACK JSBool
|
||||
js_PutBlockObject(JSContext *cx, JSBool normalUnwind)
|
||||
{
|
||||
/* Blocks have one fixed slot available for the first local.*/
|
||||
JS_STATIC_ASSERT(JS_INITIAL_NSLOTS == JSSLOT_BLOCK_DEPTH + 2);
|
||||
|
||||
JSStackFrame *const fp = cx->fp();
|
||||
JSObject *obj = &fp->scopeChain();
|
||||
JS_ASSERT(obj->isClonedBlock());
|
||||
|
@ -3002,7 +2994,7 @@ js_PutBlockObject(JSContext *cx, JSBool normalUnwind)
|
|||
|
||||
/* Block objects should have all reserved slots allocated early. */
|
||||
uintN count = OBJ_BLOCK_COUNT(cx, obj);
|
||||
JS_ASSERT(obj->numSlots() >= JSSLOT_BLOCK_DEPTH + 1 + count);
|
||||
JS_ASSERT(obj->numSlots() == JSSLOT_BLOCK_DEPTH + 1 + count);
|
||||
|
||||
/* The block and its locals must be on the current stack for GC safety. */
|
||||
uintN depth = OBJ_BLOCK_DEPTH(cx, obj);
|
||||
|
@ -3014,8 +3006,15 @@ js_PutBlockObject(JSContext *cx, JSBool normalUnwind)
|
|||
|
||||
if (normalUnwind) {
|
||||
uintN slot = JSSLOT_BLOCK_DEPTH + 1;
|
||||
uintN flen = JS_MIN(count, JS_INITIAL_NSLOTS - slot);
|
||||
uintN stop = slot + flen;
|
||||
|
||||
depth += fp->numFixed();
|
||||
memcpy(obj->getSlots() + slot, fp->slots() + depth, count * sizeof(Value));
|
||||
while (slot < stop)
|
||||
obj->fslots[slot++] = fp->slots()[depth++];
|
||||
count -= flen;
|
||||
if (count != 0)
|
||||
memcpy(obj->dslots, fp->slots() + depth, count * sizeof(Value));
|
||||
}
|
||||
|
||||
/* We must clear the private slot even with errors. */
|
||||
|
@ -3096,7 +3095,7 @@ GetObjectSize(JSObject *obj)
|
|||
{
|
||||
return (obj->isFunction() && !obj->getPrivate())
|
||||
? sizeof(JSFunction)
|
||||
: JSOBJECT_SIZE + obj->numFixedSlots() * sizeof(Value);
|
||||
: sizeof(JSObject);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -3105,31 +3104,17 @@ GetObjectSize(JSObject *obj)
|
|||
* transitions are inherently not thread-safe. Don't perform a swap operation on objects
|
||||
* shared across threads or, or bad things will happen. You have been warned.
|
||||
*/
|
||||
bool
|
||||
JSObject::swap(JSContext *cx, JSObject *other)
|
||||
void
|
||||
JSObject::swap(JSObject *other)
|
||||
{
|
||||
size_t size = GetObjectSize(this);
|
||||
JS_ASSERT(size == GetObjectSize(other));
|
||||
|
||||
bool thisInline = !hasSlotsArray();
|
||||
bool otherInline = !other->hasSlotsArray();
|
||||
|
||||
char tmp[tl::Max<sizeof(JSFunction),
|
||||
JSOBJECT_SIZE + JSOBJECT_FIXED_SLOTS_LIMIT * sizeof(Value)>::result];
|
||||
JS_ASSERT(size <= sizeof(tmp));
|
||||
|
||||
/* Trade the guts of the objects. */
|
||||
char tmp[tl::Max<sizeof(JSFunction), sizeof(JSObject)>::result];
|
||||
memcpy(tmp, this, size);
|
||||
memcpy(this, other, size);
|
||||
memcpy(other, tmp, size);
|
||||
|
||||
/* Fixup pointers for inline slots on the objects. */
|
||||
if (thisInline)
|
||||
other->slots = other->fixedSlots;
|
||||
if (otherInline)
|
||||
this->slots = this->fixedSlots;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#if JS_HAS_XDR
|
||||
|
@ -3315,12 +3300,13 @@ DefineStandardSlot(JSContext *cx, JSObject *obj, JSProtoKey key, JSAtom *atom,
|
|||
|
||||
const Shape *shape = obj->nativeLookup(id);
|
||||
if (!shape) {
|
||||
uint32 slot = 2 * JSProto_LIMIT + key;
|
||||
if (!js_SetReservedSlot(cx, obj, slot, v)) {
|
||||
uint32 index = 2 * JSProto_LIMIT + key;
|
||||
if (!js_SetReservedSlot(cx, obj, index, v)) {
|
||||
JS_UNLOCK_OBJ(cx, obj);
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32 slot = JSSLOT_START(obj->getClass()) + index;
|
||||
shape = obj->addProperty(cx, id, PropertyStub, PropertyStub, slot, attrs, 0, 0);
|
||||
|
||||
JS_UNLOCK_OBJ(cx, obj);
|
||||
|
@ -3486,7 +3472,7 @@ js_InitClass(JSContext *cx, JSObject *obj, JSObject *parent_proto,
|
|||
*/
|
||||
JS_ASSERT_IF(proto->clasp != clasp,
|
||||
clasp == &js_ArrayClass && proto->clasp == &js_SlowArrayClass);
|
||||
if (!proto->getEmptyShape(cx, proto->clasp, FINALIZE_OBJECT0))
|
||||
if (!proto->getEmptyShape(cx, proto->clasp))
|
||||
goto bad;
|
||||
|
||||
/* If this is a standard class, cache its prototype. */
|
||||
|
@ -3504,103 +3490,111 @@ bad:
|
|||
}
|
||||
|
||||
bool
|
||||
JSObject::allocSlots(JSContext *cx, size_t newcap)
|
||||
JSObject::allocSlots(JSContext *cx, size_t nslots)
|
||||
{
|
||||
uint32 oldcap = numSlots();
|
||||
JS_ASSERT(!dslots);
|
||||
JS_ASSERT(nslots > JS_INITIAL_NSLOTS);
|
||||
|
||||
JS_ASSERT(newcap >= oldcap && !hasSlotsArray());
|
||||
|
||||
if (newcap > NSLOTS_LIMIT) {
|
||||
if (!JS_ON_TRACE(cx))
|
||||
js_ReportAllocationOverflow(cx);
|
||||
size_t nwords = slotsToDynamicWords(nslots);
|
||||
dslots = (Value*) cx->malloc(nwords * sizeof(Value));
|
||||
if (!dslots)
|
||||
return false;
|
||||
}
|
||||
|
||||
Value *tmpslots = (Value*) cx->malloc(newcap * sizeof(Value));
|
||||
if (!tmpslots)
|
||||
return false; /* Leave slots at inline buffer. */
|
||||
slots = tmpslots;
|
||||
capacity = newcap;
|
||||
|
||||
/* Copy over anything from the inline buffer. */
|
||||
memcpy(slots, fixedSlots, oldcap * sizeof(Value));
|
||||
ClearValueRange(slots + oldcap, newcap - oldcap, isDenseArray());
|
||||
dslots++;
|
||||
dslots[-1].setPrivateUint32(nslots);
|
||||
SetValueRangeToUndefined(dslots, nslots - JS_INITIAL_NSLOTS);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
JSObject::growSlots(JSContext *cx, size_t newcap)
|
||||
JSObject::growSlots(JSContext *cx, size_t nslots)
|
||||
{
|
||||
/*
|
||||
* When an object with CAPACITY_DOUBLING_MAX or fewer slots needs to
|
||||
* grow, double its capacity, to add N elements in amortized O(N) time.
|
||||
*
|
||||
* Above this limit, grow by 12.5% each time. Speed is still amortized
|
||||
* O(N), with a higher constant factor, and we waste less space.
|
||||
* Minimal number of dynamic slots to allocate.
|
||||
*/
|
||||
static const size_t CAPACITY_DOUBLING_MAX = 1024 * 1024;
|
||||
static const size_t CAPACITY_CHUNK = CAPACITY_DOUBLING_MAX / sizeof(Value);
|
||||
const size_t MIN_DYNAMIC_WORDS = 4;
|
||||
|
||||
uint32 oldcap = numSlots();
|
||||
JS_ASSERT(oldcap < newcap);
|
||||
/*
|
||||
* The limit to switch to linear allocation strategy from the power of 2
|
||||
* growth no to waste too much memory.
|
||||
*/
|
||||
const size_t LINEAR_GROWTH_STEP = JS_BIT(16);
|
||||
|
||||
uint32 nextsize = (oldcap <= CAPACITY_DOUBLING_MAX)
|
||||
? oldcap * 2
|
||||
: oldcap + (oldcap >> 3);
|
||||
|
||||
uint32 actualCapacity = JS_MAX(newcap, nextsize);
|
||||
if (actualCapacity >= CAPACITY_CHUNK)
|
||||
actualCapacity = JS_ROUNDUP(actualCapacity, CAPACITY_CHUNK);
|
||||
else if (actualCapacity < SLOT_CAPACITY_MIN)
|
||||
actualCapacity = SLOT_CAPACITY_MIN;
|
||||
/* If we are allocating fslots, there is nothing to do. */
|
||||
if (nslots <= JS_INITIAL_NSLOTS)
|
||||
return true;
|
||||
|
||||
/* Don't let nslots get close to wrapping around uint32. */
|
||||
if (actualCapacity >= NSLOTS_LIMIT) {
|
||||
if (nslots >= NSLOTS_LIMIT) {
|
||||
JS_ReportOutOfMemory(cx);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* If nothing was allocated yet, treat it as initial allocation. */
|
||||
if (!hasSlotsArray())
|
||||
return allocSlots(cx, actualCapacity);
|
||||
size_t nwords = slotsToDynamicWords(nslots);
|
||||
|
||||
Value *tmpslots = (Value*) cx->realloc(slots, actualCapacity * sizeof(Value));
|
||||
if (!tmpslots)
|
||||
return false; /* Leave dslots as its old size. */
|
||||
slots = tmpslots;
|
||||
capacity = actualCapacity;
|
||||
/*
|
||||
* Round up nslots so the number of bytes in dslots array is power
|
||||
* of 2 to ensure exponential grouth.
|
||||
*/
|
||||
uintN log;
|
||||
if (nwords <= MIN_DYNAMIC_WORDS) {
|
||||
nwords = MIN_DYNAMIC_WORDS;
|
||||
} else if (nwords < LINEAR_GROWTH_STEP) {
|
||||
JS_CEILING_LOG2(log, nwords);
|
||||
nwords = JS_BIT(log);
|
||||
} else {
|
||||
nwords = JS_ROUNDUP(nwords, LINEAR_GROWTH_STEP);
|
||||
}
|
||||
nslots = dynamicWordsToSlots(nwords);
|
||||
|
||||
/*
|
||||
* If nothing was allocated yet, treat it as initial allocation (but with
|
||||
* the exponential growth algorithm applied).
|
||||
*/
|
||||
if (!dslots)
|
||||
return allocSlots(cx, nslots);
|
||||
|
||||
size_t oldnslots = dslots[-1].toPrivateUint32();
|
||||
|
||||
Value *tmpdslots = (Value*) cx->realloc(dslots - 1, nwords * sizeof(Value));
|
||||
if (!tmpdslots)
|
||||
return false; /* leave dslots at its old size */
|
||||
|
||||
dslots = tmpdslots;
|
||||
dslots++;
|
||||
dslots[-1].setPrivateUint32(nslots);
|
||||
|
||||
/* Initialize the additional slots we added. */
|
||||
ClearValueRange(slots + oldcap, actualCapacity - oldcap, isDenseArray());
|
||||
JS_ASSERT(nslots > oldnslots);
|
||||
Value *beg = dslots + (oldnslots - JS_INITIAL_NSLOTS);
|
||||
Value *end = dslots + (nslots - JS_INITIAL_NSLOTS);
|
||||
SetValueRangeToUndefined(beg, end);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
JSObject::shrinkSlots(JSContext *cx, size_t newcap)
|
||||
JSObject::shrinkSlots(JSContext *cx, size_t nslots)
|
||||
{
|
||||
uint32 oldcap = numSlots();
|
||||
JS_ASSERT(newcap <= oldcap);
|
||||
JS_ASSERT(newcap >= slotSpan());
|
||||
|
||||
if (oldcap <= SLOT_CAPACITY_MIN || !hasSlotsArray()) {
|
||||
/* We won't shrink the slots any more. Clear excess holes. */
|
||||
ClearValueRange(slots + newcap, oldcap - newcap, isDenseArray());
|
||||
/* Nothing to shrink? */
|
||||
if (!dslots)
|
||||
return;
|
||||
}
|
||||
|
||||
uint32 fill = newcap;
|
||||
if (newcap < SLOT_CAPACITY_MIN)
|
||||
newcap = SLOT_CAPACITY_MIN;
|
||||
JS_ASSERT(dslots[-1].toPrivateUint32() > JS_INITIAL_NSLOTS);
|
||||
JS_ASSERT(nslots <= dslots[-1].toPrivateUint32());
|
||||
|
||||
Value *tmpslots = (Value*) cx->realloc(slots, newcap * sizeof(Value));
|
||||
if (!tmpslots)
|
||||
return; /* Leave slots at its old size. */
|
||||
slots = tmpslots;
|
||||
capacity = newcap;
|
||||
if (nslots <= JS_INITIAL_NSLOTS) {
|
||||
freeSlotsArray(cx);
|
||||
dslots = NULL;
|
||||
} else {
|
||||
size_t nwords = slotsToDynamicWords(nslots);
|
||||
Value *tmpdslots = (Value*) cx->realloc(dslots - 1, nwords * sizeof(Value));
|
||||
if (!tmpdslots)
|
||||
return; /* leave dslots at its old size */
|
||||
|
||||
if (fill < newcap) {
|
||||
/* Clear any excess holes if we tried to shrink below SLOT_CAPACITY_MIN. */
|
||||
ClearValueRange(slots + fill, newcap - fill, isDenseArray());
|
||||
dslots = tmpdslots;
|
||||
dslots++;
|
||||
dslots[-1].setPrivateUint32(nslots);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4676,12 +4670,10 @@ js_NativeGet(JSContext *cx, JSObject *obj, JSObject *pobj, const Shape *shape, u
|
|||
JS_ASSERT(JS_IS_OBJ_LOCKED(cx, pobj));
|
||||
|
||||
slot = shape->slot;
|
||||
if (slot != SHAPE_INVALID_SLOT) {
|
||||
if (slot != SHAPE_INVALID_SLOT)
|
||||
*vp = pobj->lockedGetSlot(slot);
|
||||
JS_ASSERT(!vp->isMagic());
|
||||
} else {
|
||||
else
|
||||
vp->setUndefined();
|
||||
}
|
||||
if (shape->hasDefaultGetter())
|
||||
return true;
|
||||
|
||||
|
@ -5919,6 +5911,7 @@ js_PrintObjectSlotName(JSTracer *trc, char *buf, size_t bufsize)
|
|||
|
||||
JSObject *obj = (JSObject *)trc->debugPrintArg;
|
||||
uint32 slot = (uint32)trc->debugPrintIndex;
|
||||
JS_ASSERT(slot >= JSSLOT_START(obj->getClass()));
|
||||
|
||||
const Shape *shape;
|
||||
if (obj->isNative()) {
|
||||
|
@ -5933,8 +5926,9 @@ js_PrintObjectSlotName(JSTracer *trc, char *buf, size_t bufsize)
|
|||
const char *slotname = NULL;
|
||||
Class *clasp = obj->getClass();
|
||||
if (clasp->flags & JSCLASS_IS_GLOBAL) {
|
||||
uint32 key = slot - JSSLOT_START(clasp);
|
||||
#define JS_PROTO(name,code,init) \
|
||||
if ((code) == slot) { slotname = js_##name##_str; goto found; }
|
||||
if ((code) == key) { slotname = js_##name##_str; goto found; }
|
||||
#include "jsproto.tbl"
|
||||
#undef JS_PROTO
|
||||
}
|
||||
|
@ -5962,7 +5956,7 @@ js_TraceObject(JSTracer *trc, JSObject *obj)
|
|||
JS_ASSERT(obj->isNative());
|
||||
|
||||
JSContext *cx = trc->context;
|
||||
if (obj->hasSlotsArray() && !obj->nativeEmpty() && IS_GC_MARKING_TRACER(trc)) {
|
||||
if (!obj->nativeEmpty() && IS_GC_MARKING_TRACER(trc)) {
|
||||
/*
|
||||
* Trim overlong dslots allocations from the GC, to avoid thrashing in
|
||||
* case of delete-happy code that settles down at a given population.
|
||||
|
@ -6009,8 +6003,9 @@ js_TraceObject(JSTracer *trc, JSObject *obj)
|
|||
uint32 nslots = obj->numSlots();
|
||||
if (!obj->nativeEmpty() && obj->slotSpan() < nslots)
|
||||
nslots = obj->slotSpan();
|
||||
JS_ASSERT(nslots >= JSSLOT_START(clasp));
|
||||
|
||||
for (uint32 i = 0; i != nslots; ++i) {
|
||||
for (uint32 i = JSSLOT_START(clasp); i != nslots; ++i) {
|
||||
const Value &v = obj->getSlot(i);
|
||||
JS_SET_TRACING_DETAILS(trc, js_PrintObjectSlotName, obj, i);
|
||||
MarkValueRaw(trc, v);
|
||||
|
@ -6039,13 +6034,14 @@ js_ClearNative(JSContext *cx, JSObject *obj)
|
|||
}
|
||||
|
||||
bool
|
||||
js_GetReservedSlot(JSContext *cx, JSObject *obj, uint32 slot, Value *vp)
|
||||
js_GetReservedSlot(JSContext *cx, JSObject *obj, uint32 index, Value *vp)
|
||||
{
|
||||
if (!obj->isNative()) {
|
||||
vp->setUndefined();
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32 slot = JSSLOT_START(obj->getClass()) + index;
|
||||
JS_LOCK_OBJ(cx, obj);
|
||||
if (slot < obj->numSlots())
|
||||
*vp = obj->getSlot(slot);
|
||||
|
@ -6056,12 +6052,13 @@ js_GetReservedSlot(JSContext *cx, JSObject *obj, uint32 slot, Value *vp)
|
|||
}
|
||||
|
||||
bool
|
||||
js_SetReservedSlot(JSContext *cx, JSObject *obj, uint32 slot, const Value &v)
|
||||
js_SetReservedSlot(JSContext *cx, JSObject *obj, uint32 index, const Value &v)
|
||||
{
|
||||
if (!obj->isNative())
|
||||
return true;
|
||||
|
||||
Class *clasp = obj->getClass();
|
||||
uint32 slot = JSSLOT_START(clasp) + index;
|
||||
|
||||
JS_LOCK_OBJ(cx, obj);
|
||||
if (slot >= obj->numSlots()) {
|
||||
|
@ -6371,8 +6368,11 @@ js_DumpObject(JSObject *obj)
|
|||
dumpValue(ObjectOrNullValue(obj->getParent()));
|
||||
fputc('\n', stderr);
|
||||
|
||||
if (clasp->flags & JSCLASS_HAS_PRIVATE)
|
||||
i = JSSLOT_PRIVATE;
|
||||
if (clasp->flags & JSCLASS_HAS_PRIVATE) {
|
||||
i = JSSLOT_PRIVATE + 1;
|
||||
fprintf(stderr, "private %p\n", obj->getPrivate());
|
||||
}
|
||||
|
||||
fprintf(stderr, "slots:\n");
|
||||
reservedEnd = i + JSCLASS_RESERVED_SLOTS(clasp);
|
||||
|
|
255
js/src/jsobj.h
255
js/src/jsobj.h
|
@ -235,6 +235,17 @@ js_TypeOf(JSContext *cx, JSObject *obj);
|
|||
|
||||
struct NativeIterator;
|
||||
|
||||
const uint32 JS_INITIAL_NSLOTS = 3;
|
||||
|
||||
/*
|
||||
* The first available slot to store generic value. For JSCLASS_HAS_PRIVATE
|
||||
* classes the slot stores a pointer to private data stuffed in a Value.
|
||||
* Such pointer is stored as is without an overhead of PRIVATE_TO_JSVAL
|
||||
* tagging and should be accessed using the (get|set)Private methods of
|
||||
* JSObject.
|
||||
*/
|
||||
const uint32 JSSLOT_PRIVATE = 0;
|
||||
|
||||
struct JSFunction;
|
||||
|
||||
/*
|
||||
|
@ -263,9 +274,9 @@ struct JSFunction;
|
|||
* Both these flag bits are initially zero; they may be set or queried using
|
||||
* the (is|set)(Delegate|System) inline methods.
|
||||
*
|
||||
* The dslots member is a pointer to the slot vector for the object,
|
||||
* either an inline array starting at data or a dynamically allocated array.
|
||||
* In both cases, capacity gives the number of available slots.
|
||||
* The dslots member is null or a pointer into a dynamically allocated vector
|
||||
* of Values for reserved and dynamic slots. If dslots is not null, dslots[-1]
|
||||
* records the number of available slots.
|
||||
*/
|
||||
struct JSObject {
|
||||
/*
|
||||
|
@ -333,22 +344,18 @@ struct JSObject {
|
|||
uint32 flags; /* flags */
|
||||
uint32 objShape; /* copy of lastProp->shape, or override if different */
|
||||
|
||||
JSObject *proto; /* object's prototype */
|
||||
JSObject *parent; /* object's parent */
|
||||
js::Value *dslots; /* dynamically allocated slots */
|
||||
|
||||
/* Empty shape of kids if prototype, located here to align fslots on 32 bit targets. */
|
||||
js::EmptyShape *emptyShape;
|
||||
|
||||
js::Value fslots[JS_INITIAL_NSLOTS]; /* small number of fixed slots */
|
||||
#ifdef JS_THREADSAFE
|
||||
JSTitle title;
|
||||
#endif
|
||||
|
||||
/* If prototype, lazily filled array of empty shapes for each object size. */
|
||||
js::EmptyShape **emptyShapes;
|
||||
|
||||
JSObject *proto; /* object's prototype */
|
||||
JSObject *parent; /* object's parent */
|
||||
void *privateData; /* private data */
|
||||
jsuword capacity; /* capacity of slots */
|
||||
js::Value *slots; /* dynamically allocated slots,
|
||||
or pointer to fixedSlots */
|
||||
js::Value fixedSlots[2]; /* inline slots for object. count is not fixed,
|
||||
may be less or greater than two */
|
||||
|
||||
/*
|
||||
* Return an immutable, shareable, empty shape with the same clasp as this
|
||||
* and the same slotSpan as this had when empty.
|
||||
|
@ -357,8 +364,7 @@ struct JSObject {
|
|||
* used as the scope of a new object whose prototype is |proto|.
|
||||
*/
|
||||
inline bool canProvideEmptyShape(js::Class *clasp);
|
||||
inline js::EmptyShape *getEmptyShape(JSContext *cx, js::Class *aclasp,
|
||||
/* JSFinalizeGCThingKind */ unsigned kind);
|
||||
inline js::EmptyShape *getEmptyShape(JSContext *cx, js::Class *aclasp);
|
||||
|
||||
bool isNative() const { return map->isNative(); }
|
||||
|
||||
|
@ -524,27 +530,29 @@ struct JSObject {
|
|||
|
||||
inline bool hasPropertyTable() const;
|
||||
|
||||
uint32 numSlots() const { return capacity; }
|
||||
uint32 numSlots(void) const {
|
||||
return dslots ? dslots[-1].toPrivateUint32() : uint32(JS_INITIAL_NSLOTS);
|
||||
}
|
||||
|
||||
size_t slotsAndStructSize(uint32 nslots) const;
|
||||
size_t slotsAndStructSize() const { return slotsAndStructSize(numSlots()); }
|
||||
|
||||
inline size_t numFixedSlots() const;
|
||||
private:
|
||||
static size_t slotsToDynamicWords(size_t nslots) {
|
||||
JS_ASSERT(nslots > JS_INITIAL_NSLOTS);
|
||||
return nslots + 1 - JS_INITIAL_NSLOTS;
|
||||
}
|
||||
|
||||
static size_t dynamicWordsToSlots(size_t nwords) {
|
||||
JS_ASSERT(nwords > 1);
|
||||
return nwords - 1 + JS_INITIAL_NSLOTS;
|
||||
}
|
||||
|
||||
public:
|
||||
/* Minimum size for dynamically allocated slots. */
|
||||
static const uint32 SLOT_CAPACITY_MIN = 8;
|
||||
|
||||
bool allocSlots(JSContext *cx, size_t nslots);
|
||||
bool growSlots(JSContext *cx, size_t nslots);
|
||||
void shrinkSlots(JSContext *cx, size_t nslots);
|
||||
|
||||
bool ensureSlots(JSContext *cx, size_t nslots) {
|
||||
if (numSlots() < nslots)
|
||||
return growSlots(cx, nslots);
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Ensure that the object has at least JSCLASS_RESERVED_SLOTS(clasp) +
|
||||
* nreserved slots.
|
||||
|
@ -563,14 +571,6 @@ struct JSObject {
|
|||
*/
|
||||
bool ensureInstanceReservedSlots(JSContext *cx, size_t nreserved);
|
||||
|
||||
/*
|
||||
* Get a direct pointer to the object's slots.
|
||||
* This can be reallocated if the object is modified, watch out!
|
||||
*/
|
||||
js::Value *getSlots() const {
|
||||
return slots;
|
||||
}
|
||||
|
||||
/*
|
||||
* NB: ensureClassReservedSlotsForEmptyObject asserts that nativeEmpty()
|
||||
* Use ensureClassReservedSlots for any object, either empty or already
|
||||
|
@ -585,18 +585,26 @@ struct JSObject {
|
|||
bool containsSlot(uint32 slot) const { return slot < slotSpan(); }
|
||||
|
||||
js::Value& getSlotRef(uintN slot) {
|
||||
JS_ASSERT(slot < capacity);
|
||||
return slots[slot];
|
||||
return (slot < JS_INITIAL_NSLOTS)
|
||||
? fslots[slot]
|
||||
: (JS_ASSERT(slot < dslots[-1].toPrivateUint32()),
|
||||
dslots[slot - JS_INITIAL_NSLOTS]);
|
||||
}
|
||||
|
||||
const js::Value &getSlot(uintN slot) const {
|
||||
JS_ASSERT(slot < capacity);
|
||||
return slots[slot];
|
||||
return (slot < JS_INITIAL_NSLOTS)
|
||||
? fslots[slot]
|
||||
: (JS_ASSERT(slot < dslots[-1].toPrivateUint32()),
|
||||
dslots[slot - JS_INITIAL_NSLOTS]);
|
||||
}
|
||||
|
||||
void setSlot(uintN slot, const js::Value &value) {
|
||||
JS_ASSERT(slot < capacity);
|
||||
slots[slot] = value;
|
||||
if (slot < JS_INITIAL_NSLOTS) {
|
||||
fslots[slot] = value;
|
||||
} else {
|
||||
JS_ASSERT(slot < dslots[-1].toPrivateUint32());
|
||||
dslots[slot - JS_INITIAL_NSLOTS] = value;
|
||||
}
|
||||
}
|
||||
|
||||
inline const js::Value &lockedGetSlot(uintN slot) const;
|
||||
|
@ -605,7 +613,8 @@ struct JSObject {
|
|||
/*
|
||||
* These ones are for multi-threaded ("MT") objects. Use getSlot(),
|
||||
* getSlotRef(), setSlot() to directly manipulate slots in obj when only
|
||||
* one thread can access obj.
|
||||
* one thread can access obj, or when accessing read-only slots within
|
||||
* JS_INITIAL_NSLOTS.
|
||||
*/
|
||||
inline js::Value getSlotMT(JSContext *cx, uintN slot);
|
||||
inline void setSlotMT(JSContext *cx, uintN slot, const js::Value &value);
|
||||
|
@ -656,12 +665,12 @@ struct JSObject {
|
|||
|
||||
void *getPrivate() const {
|
||||
JS_ASSERT(getClass()->flags & JSCLASS_HAS_PRIVATE);
|
||||
return privateData;
|
||||
return *(void **)&fslots[JSSLOT_PRIVATE];
|
||||
}
|
||||
|
||||
void setPrivate(void *data) {
|
||||
JS_ASSERT(getClass()->flags & JSCLASS_HAS_PRIVATE);
|
||||
privateData = data;
|
||||
*(void **)&fslots[JSSLOT_PRIVATE] = data;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -669,7 +678,7 @@ struct JSObject {
|
|||
*/
|
||||
|
||||
private:
|
||||
static const uint32 JSSLOT_PRIMITIVE_THIS = 0;
|
||||
static const uint32 JSSLOT_PRIMITIVE_THIS = JSSLOT_PRIVATE;
|
||||
|
||||
public:
|
||||
inline const js::Value &getPrimitiveThis() const;
|
||||
|
@ -679,16 +688,36 @@ struct JSObject {
|
|||
* Array-specific getters and setters (for both dense and slow arrays).
|
||||
*/
|
||||
|
||||
// Used by dense and slow arrays.
|
||||
static const uint32 JSSLOT_ARRAY_LENGTH = JSSLOT_PRIVATE;
|
||||
|
||||
static const uint32 JSSLOT_DENSE_ARRAY_CAPACITY = JSSLOT_PRIVATE + 1;
|
||||
|
||||
// This assertion must remain true; see comment in js_MakeArraySlow().
|
||||
// (Nb: This method is never called, it just contains a static assertion.
|
||||
// The static assertion isn't inline because that doesn't work on Mac.)
|
||||
inline void staticAssertArrayLengthIsInPrivateSlot();
|
||||
|
||||
public:
|
||||
static const uint32 DENSE_ARRAY_CLASS_RESERVED_SLOTS = 3;
|
||||
|
||||
inline uint32 getArrayLength() const;
|
||||
inline void setArrayLength(uint32 length);
|
||||
|
||||
inline uint32 getDenseArrayCapacity();
|
||||
inline js::Value* getDenseArrayElements();
|
||||
inline const js::Value &getDenseArrayElement(uintN idx);
|
||||
inline js::Value* addressOfDenseArrayElement(uintN idx);
|
||||
inline void setDenseArrayElement(uintN idx, const js::Value &val);
|
||||
inline bool ensureDenseArrayElements(JSContext *cx, uintN cap);
|
||||
inline void shrinkDenseArrayElements(JSContext *cx, uintN cap);
|
||||
inline uint32 getDenseArrayCapacity() const;
|
||||
inline void setDenseArrayCapacity(uint32 capacity);
|
||||
|
||||
inline const js::Value &getDenseArrayElement(uint32 i) const;
|
||||
inline js::Value *addressOfDenseArrayElement(uint32 i);
|
||||
inline void setDenseArrayElement(uint32 i, const js::Value &v);
|
||||
|
||||
inline js::Value *getDenseArrayElements() const; // returns pointer to the Array's elements array
|
||||
bool growDenseArrayElements(JSContext *cx, uint32 oldcap, uint32 newcap);
|
||||
bool ensureDenseArrayElements(JSContext *cx, uint32 newcap);
|
||||
bool shrinkDenseArrayElements(JSContext *cx, uint32 newcap);
|
||||
inline void freeDenseArrayElements(JSContext *cx);
|
||||
|
||||
inline void voidDenseOnlyArraySlots(); // used when converting a dense array to a slow array
|
||||
|
||||
JSBool makeDenseArraySlow(JSContext *cx);
|
||||
|
||||
|
@ -700,7 +729,7 @@ struct JSObject {
|
|||
/*
|
||||
* Reserved slot structure for Arguments objects:
|
||||
*
|
||||
* private - the function's stack frame until the function
|
||||
* JSSLOT_PRIVATE - the function's stack frame until the function
|
||||
* returns; also, JS_ARGUMENTS_OBJECT_ON_TRACE if
|
||||
* arguments was created on trace
|
||||
* JSSLOT_ARGS_LENGTH - the number of actual arguments and a flag
|
||||
|
@ -718,13 +747,13 @@ struct JSObject {
|
|||
* Argument index i is stored in ArgumentsData.slots[i], accessible via
|
||||
* {get,set}ArgsElement().
|
||||
*/
|
||||
static const uint32 JSSLOT_ARGS_DATA = 1;
|
||||
static const uint32 JSSLOT_ARGS_DATA = JSSLOT_PRIVATE + 2;
|
||||
|
||||
public:
|
||||
/* Number of extra fixed arguments object slots besides JSSLOT_PRIVATE. */
|
||||
static const uint32 JSSLOT_ARGS_LENGTH = 0;
|
||||
static const uint32 JSSLOT_ARGS_LENGTH = JSSLOT_PRIVATE + 1;
|
||||
static const uint32 ARGS_CLASS_RESERVED_SLOTS = 2;
|
||||
static const uint32 ARGS_FIRST_FREE_SLOT = ARGS_CLASS_RESERVED_SLOTS + 1;
|
||||
static const uint32 ARGS_FIRST_FREE_SLOT = JSSLOT_PRIVATE + ARGS_CLASS_RESERVED_SLOTS + 1;
|
||||
|
||||
/* Lower-order bit stolen from the length slot. */
|
||||
static const uint32 ARGS_LENGTH_OVERRIDDEN_BIT = 0x1;
|
||||
|
@ -751,18 +780,19 @@ struct JSObject {
|
|||
inline void setArgsCallee(const js::Value &callee);
|
||||
|
||||
inline const js::Value &getArgsElement(uint32 i) const;
|
||||
inline js::Value *addressOfArgsElement(uint32 i);
|
||||
inline js::Value *addressOfArgsElement(uint32 i) const;
|
||||
inline void setArgsElement(uint32 i, const js::Value &v);
|
||||
|
||||
private:
|
||||
/*
|
||||
* Reserved slot structure for Arguments objects:
|
||||
*
|
||||
*/
|
||||
static const uint32 JSSLOT_CALL_CALLEE = 0;
|
||||
static const uint32 JSSLOT_CALL_ARGUMENTS = 1;
|
||||
static const uint32 JSSLOT_CALL_CALLEE = JSSLOT_PRIVATE + 1;
|
||||
static const uint32 JSSLOT_CALL_ARGUMENTS = JSSLOT_PRIVATE + 2;
|
||||
|
||||
public:
|
||||
/* Number of reserved slots. */
|
||||
/* Number of extra fixed slots besides JSSLOT_PRIVATE. */
|
||||
static const uint32 CALL_RESERVED_SLOTS = 2;
|
||||
|
||||
inline JSObject &getCallObjCallee() const;
|
||||
|
@ -776,23 +806,23 @@ struct JSObject {
|
|||
* Date-specific getters and setters.
|
||||
*/
|
||||
|
||||
static const uint32 JSSLOT_DATE_UTC_TIME = 0;
|
||||
static const uint32 JSSLOT_DATE_UTC_TIME = JSSLOT_PRIVATE;
|
||||
|
||||
/*
|
||||
* Cached slots holding local properties of the date.
|
||||
* These are undefined until the first actual lookup occurs
|
||||
* and are reset to undefined whenever the date's time is modified.
|
||||
*/
|
||||
static const uint32 JSSLOT_DATE_COMPONENTS_START = 1;
|
||||
static const uint32 JSSLOT_DATE_COMPONENTS_START = JSSLOT_PRIVATE + 1;
|
||||
|
||||
static const uint32 JSSLOT_DATE_LOCAL_TIME = 1;
|
||||
static const uint32 JSSLOT_DATE_LOCAL_YEAR = 2;
|
||||
static const uint32 JSSLOT_DATE_LOCAL_MONTH = 3;
|
||||
static const uint32 JSSLOT_DATE_LOCAL_DATE = 4;
|
||||
static const uint32 JSSLOT_DATE_LOCAL_DAY = 5;
|
||||
static const uint32 JSSLOT_DATE_LOCAL_HOURS = 6;
|
||||
static const uint32 JSSLOT_DATE_LOCAL_MINUTES = 7;
|
||||
static const uint32 JSSLOT_DATE_LOCAL_SECONDS = 8;
|
||||
static const uint32 JSSLOT_DATE_LOCAL_TIME = JSSLOT_PRIVATE + 1;
|
||||
static const uint32 JSSLOT_DATE_LOCAL_YEAR = JSSLOT_PRIVATE + 2;
|
||||
static const uint32 JSSLOT_DATE_LOCAL_MONTH = JSSLOT_PRIVATE + 3;
|
||||
static const uint32 JSSLOT_DATE_LOCAL_DATE = JSSLOT_PRIVATE + 4;
|
||||
static const uint32 JSSLOT_DATE_LOCAL_DAY = JSSLOT_PRIVATE + 5;
|
||||
static const uint32 JSSLOT_DATE_LOCAL_HOURS = JSSLOT_PRIVATE + 6;
|
||||
static const uint32 JSSLOT_DATE_LOCAL_MINUTES = JSSLOT_PRIVATE + 7;
|
||||
static const uint32 JSSLOT_DATE_LOCAL_SECONDS = JSSLOT_PRIVATE + 8;
|
||||
|
||||
static const uint32 DATE_CLASS_RESERVED_SLOTS = 9;
|
||||
|
||||
|
@ -811,18 +841,17 @@ struct JSObject {
|
|||
* Flat closures with one or more upvars snapshot the upvars' values into a
|
||||
* vector of js::Values referenced from this slot.
|
||||
*/
|
||||
static const uint32 JSSLOT_FLAT_CLOSURE_UPVARS = 0;
|
||||
static const uint32 JSSLOT_FLAT_CLOSURE_UPVARS = JSSLOT_PRIVATE + 1;
|
||||
|
||||
/*
|
||||
* Null closures set or initialized as methods have these slots. See the
|
||||
* "method barrier" comments and methods.
|
||||
*/
|
||||
static const uint32 JSSLOT_FUN_METHOD_ATOM = JSSLOT_PRIVATE + 1;
|
||||
static const uint32 JSSLOT_FUN_METHOD_OBJ = JSSLOT_PRIVATE + 2;
|
||||
|
||||
static const uint32 JSSLOT_FUN_METHOD_ATOM = 0;
|
||||
static const uint32 JSSLOT_FUN_METHOD_OBJ = 1;
|
||||
|
||||
static const uint32 JSSLOT_BOUND_FUNCTION_THIS = 0;
|
||||
static const uint32 JSSLOT_BOUND_FUNCTION_ARGS_COUNT = 1;
|
||||
static const uint32 JSSLOT_BOUND_FUNCTION_THIS = JSSLOT_PRIVATE + 1;
|
||||
static const uint32 JSSLOT_BOUND_FUNCTION_ARGS_COUNT = JSSLOT_PRIVATE + 2;
|
||||
|
||||
public:
|
||||
static const uint32 FUN_CLASS_RESERVED_SLOTS = 2;
|
||||
|
@ -848,7 +877,7 @@ struct JSObject {
|
|||
*/
|
||||
|
||||
private:
|
||||
static const uint32 JSSLOT_REGEXP_LAST_INDEX = 0;
|
||||
static const uint32 JSSLOT_REGEXP_LAST_INDEX = JSSLOT_PRIVATE + 1;
|
||||
|
||||
public:
|
||||
static const uint32 REGEXP_CLASS_RESERVED_SLOTS = 1;
|
||||
|
@ -877,12 +906,12 @@ struct JSObject {
|
|||
* - Others (js_XMLClass, js_XMLFilterClass) don't reserve any slots.
|
||||
*/
|
||||
private:
|
||||
static const uint32 JSSLOT_NAME_PREFIX = 0; // shared
|
||||
static const uint32 JSSLOT_NAME_URI = 1; // shared
|
||||
static const uint32 JSSLOT_NAME_PREFIX = JSSLOT_PRIVATE; // shared
|
||||
static const uint32 JSSLOT_NAME_URI = JSSLOT_PRIVATE + 1; // shared
|
||||
|
||||
static const uint32 JSSLOT_NAMESPACE_DECLARED = 2;
|
||||
static const uint32 JSSLOT_NAMESPACE_DECLARED = JSSLOT_PRIVATE + 2;
|
||||
|
||||
static const uint32 JSSLOT_QNAME_LOCAL_NAME = 2;
|
||||
static const uint32 JSSLOT_QNAME_LOCAL_NAME = JSSLOT_PRIVATE + 2;
|
||||
|
||||
public:
|
||||
static const uint32 NAMESPACE_CLASS_RESERVED_SLOTS = 3;
|
||||
|
@ -920,8 +949,14 @@ struct JSObject {
|
|||
inline bool isCallable();
|
||||
|
||||
/* The map field is not initialized here and should be set separately. */
|
||||
void init(JSContext *cx, js::Class *aclasp, JSObject *proto, JSObject *parent,
|
||||
void *priv, bool useHoles);
|
||||
inline void initCommon(js::Class *aclasp, JSObject *proto, JSObject *parent,
|
||||
JSContext *cx);
|
||||
inline void init(js::Class *aclasp, JSObject *proto, JSObject *parent,
|
||||
JSContext *cx);
|
||||
inline void init(js::Class *aclasp, JSObject *proto, JSObject *parent,
|
||||
void *priv, JSContext *cx);
|
||||
inline void init(js::Class *aclasp, JSObject *proto, JSObject *parent,
|
||||
const js::Value &privateSlotValue, JSContext *cx);
|
||||
|
||||
inline void finish(JSContext *cx);
|
||||
|
||||
|
@ -929,24 +964,22 @@ struct JSObject {
|
|||
* Like init, but also initializes map. The catch: proto must be the result
|
||||
* of a call to js_InitClass(...clasp, ...).
|
||||
*/
|
||||
inline bool initSharingEmptyShape(JSContext *cx,
|
||||
js::Class *clasp,
|
||||
inline void initSharingEmptyShape(js::Class *clasp,
|
||||
JSObject *proto,
|
||||
JSObject *parent,
|
||||
const js::Value &privateSlotValue,
|
||||
JSContext *cx);
|
||||
inline void initSharingEmptyShape(js::Class *clasp,
|
||||
JSObject *proto,
|
||||
JSObject *parent,
|
||||
void *priv,
|
||||
/* JSFinalizeGCThingKind */ unsigned kind);
|
||||
JSContext *cx);
|
||||
|
||||
inline bool hasSlotsArray() const { return (slots != &fixedSlots[0]); }
|
||||
inline bool hasSlotsArray() const { return !!dslots; }
|
||||
|
||||
/* This method can only be called when hasSlotsArray() returns true. */
|
||||
inline void freeSlotsArray(JSContext *cx);
|
||||
|
||||
/*
|
||||
* Frees slots array and cleans up object so it may continue to be used,
|
||||
* although slotSpan may exceed numSlots.
|
||||
*/
|
||||
inline void removeSlotsArray(JSContext *cx);
|
||||
|
||||
inline bool hasProperty(JSContext *cx, jsid id, bool *foundp, uintN flags = 0);
|
||||
|
||||
bool allocSlot(JSContext *cx, uint32 *slotp);
|
||||
|
@ -1058,10 +1091,10 @@ struct JSObject {
|
|||
|
||||
inline JSObject *getThrowTypeError() const;
|
||||
|
||||
bool swap(JSContext *cx, JSObject *obj);
|
||||
|
||||
const js::Shape *defineBlockVariable(JSContext *cx, jsid id, intN index);
|
||||
|
||||
void swap(JSObject *obj);
|
||||
|
||||
inline bool canHaveMethodBarrier() const;
|
||||
|
||||
inline bool isArguments() const;
|
||||
|
@ -1098,17 +1131,23 @@ struct JSObject {
|
|||
inline void initArrayClass();
|
||||
};
|
||||
|
||||
JS_STATIC_ASSERT(offsetof(JSObject, fslots) % sizeof(js::Value) == 0);
|
||||
JS_STATIC_ASSERT(sizeof(JSObject) % JS_GCTHING_ALIGN == 0);
|
||||
|
||||
#define JSSLOT_START(clasp) (((clasp)->flags & JSCLASS_HAS_PRIVATE) \
|
||||
? JSSLOT_PRIVATE + 1 \
|
||||
: JSSLOT_PRIVATE)
|
||||
|
||||
#define JSSLOT_FREE(clasp) (JSSLOT_START(clasp) \
|
||||
+ JSCLASS_RESERVED_SLOTS(clasp))
|
||||
|
||||
/*
|
||||
* Base size of an object, excluding any fixed slots. Use instead of sizeof.
|
||||
* fixedSlots has a declared capacity of two to match FUN_CLASS_RESERVED_SLOTS,
|
||||
* and because some compilers don't like empty arrays in superclasses.
|
||||
* Maximum capacity of the obj->dslots vector, net of the hidden slot at
|
||||
* obj->dslots[-1] that is used to store the length of the vector biased by
|
||||
* JS_INITIAL_NSLOTS (and again net of the slot at index -1).
|
||||
*/
|
||||
static const size_t JSOBJECT_SIZE = offsetof(JSObject, fixedSlots);
|
||||
|
||||
JS_STATIC_ASSERT(JSOBJECT_SIZE % sizeof(js::Value) == 0);
|
||||
JS_STATIC_ASSERT(JSOBJECT_SIZE % JS_GCTHING_ALIGN == 0);
|
||||
|
||||
#define JSSLOT_FREE(clasp) JSCLASS_RESERVED_SLOTS(clasp)
|
||||
#define MAX_DSLOTS_LENGTH (~size_t(0) / sizeof(js::Value) - 1)
|
||||
#define MAX_DSLOTS_LENGTH32 (~uint32(0) / sizeof(js::Value) - 1)
|
||||
|
||||
#define OBJ_CHECK_SLOT(obj,slot) JS_ASSERT((obj)->containsSlot(slot))
|
||||
|
||||
|
@ -1168,7 +1207,7 @@ inline bool JSObject::isBlock() const { return getClass() == &js_BlockClass; }
|
|||
/*
|
||||
* Block scope object macros. The slots reserved by js_BlockClass are:
|
||||
*
|
||||
* private JSStackFrame * active frame pointer or null
|
||||
* JSSLOT_PRIVATE JSStackFrame * active frame pointer or null
|
||||
* JSSLOT_BLOCK_DEPTH int depth of block slots in frame
|
||||
*
|
||||
* After JSSLOT_BLOCK_DEPTH come one or more slots for the block locals.
|
||||
|
@ -1180,7 +1219,7 @@ inline bool JSObject::isBlock() const { return getClass() == &js_BlockClass; }
|
|||
* whose activation they were created (or null if the with or block object
|
||||
* outlives the frame).
|
||||
*/
|
||||
static const uint32 JSSLOT_BLOCK_DEPTH = 0;
|
||||
static const uint32 JSSLOT_BLOCK_DEPTH = JSSLOT_PRIVATE + 1;
|
||||
|
||||
inline bool
|
||||
JSObject::isStaticBlock() const
|
||||
|
@ -1194,7 +1233,7 @@ JSObject::isClonedBlock() const
|
|||
return isBlock() && !!getProto();
|
||||
}
|
||||
|
||||
static const uint32 JSSLOT_WITH_THIS = 1;
|
||||
static const uint32 JSSLOT_WITH_THIS = JSSLOT_PRIVATE + 2;
|
||||
|
||||
#define OBJ_BLOCK_COUNT(cx,obj) \
|
||||
(obj)->propertyCount()
|
||||
|
|
|
@ -224,7 +224,8 @@ JSObject::setSlotMT(JSContext *cx, uintN slot, const js::Value &value)
|
|||
inline js::Value
|
||||
JSObject::getReservedSlot(uintN index) const
|
||||
{
|
||||
return (index < numSlots()) ? getSlot(index) : js::UndefinedValue();
|
||||
uint32 slot = JSSLOT_START(getClass()) + index;
|
||||
return (slot < numSlots()) ? getSlot(slot) : js::UndefinedValue();
|
||||
}
|
||||
|
||||
inline bool
|
||||
|
@ -243,100 +244,115 @@ inline const js::Value &
|
|||
JSObject::getPrimitiveThis() const
|
||||
{
|
||||
JS_ASSERT(isPrimitive());
|
||||
return getSlot(JSSLOT_PRIMITIVE_THIS);
|
||||
return fslots[JSSLOT_PRIMITIVE_THIS];
|
||||
}
|
||||
|
||||
inline void
|
||||
JSObject::setPrimitiveThis(const js::Value &pthis)
|
||||
{
|
||||
JS_ASSERT(isPrimitive());
|
||||
setSlot(JSSLOT_PRIMITIVE_THIS, pthis);
|
||||
fslots[JSSLOT_PRIMITIVE_THIS] = pthis;
|
||||
}
|
||||
|
||||
inline size_t
|
||||
JSObject::numFixedSlots() const
|
||||
inline void
|
||||
JSObject::staticAssertArrayLengthIsInPrivateSlot()
|
||||
{
|
||||
if (isFunction())
|
||||
return JSObject::FUN_CLASS_RESERVED_SLOTS;
|
||||
if (!hasSlotsArray())
|
||||
return capacity;
|
||||
JSFinalizeGCThingKind kind = js_KindFromGCThing(this);
|
||||
return js_GetGCKindSlots(kind);
|
||||
}
|
||||
|
||||
inline size_t
|
||||
JSObject::slotsAndStructSize(uint32 nslots) const
|
||||
{
|
||||
bool isFun = isFunction() && this == (JSObject*) getPrivate();
|
||||
|
||||
int ndslots = hasSlotsArray() ? nslots : 0;
|
||||
int nfslots = isFun ? 0 : numFixedSlots();
|
||||
|
||||
return sizeof(js::Value) * (ndslots + nfslots)
|
||||
+ isFun ? sizeof(JSFunction) : sizeof(JSObject);
|
||||
JS_STATIC_ASSERT(JSSLOT_ARRAY_LENGTH == JSSLOT_PRIVATE);
|
||||
}
|
||||
|
||||
inline uint32
|
||||
JSObject::getArrayLength() const
|
||||
{
|
||||
JS_ASSERT(isArray());
|
||||
return (uint32)(size_t) getPrivate();
|
||||
return fslots[JSSLOT_ARRAY_LENGTH].toPrivateUint32();
|
||||
}
|
||||
|
||||
inline void
|
||||
JSObject::setArrayLength(uint32 length)
|
||||
{
|
||||
JS_ASSERT(isArray());
|
||||
setPrivate((void*) length);
|
||||
fslots[JSSLOT_ARRAY_LENGTH].setPrivateUint32(length);
|
||||
}
|
||||
|
||||
inline uint32
|
||||
JSObject::getDenseArrayCapacity()
|
||||
JSObject::getDenseArrayCapacity() const
|
||||
{
|
||||
JS_ASSERT(isDenseArray());
|
||||
return numSlots();
|
||||
return fslots[JSSLOT_DENSE_ARRAY_CAPACITY].toPrivateUint32();
|
||||
}
|
||||
|
||||
inline js::Value*
|
||||
JSObject::getDenseArrayElements()
|
||||
inline void
|
||||
JSObject::setDenseArrayCapacity(uint32 capacity)
|
||||
{
|
||||
JS_ASSERT(isDenseArray());
|
||||
return getSlots();
|
||||
JS_ASSERT(!capacity == !dslots);
|
||||
fslots[JSSLOT_DENSE_ARRAY_CAPACITY].setPrivateUint32(capacity);
|
||||
}
|
||||
|
||||
inline size_t
|
||||
JSObject::slotsAndStructSize(uint32 nslots) const
|
||||
{
|
||||
int ndslots;
|
||||
if (isDenseArray())
|
||||
ndslots = getDenseArrayCapacity() + 1;
|
||||
else {
|
||||
ndslots = nslots - JS_INITIAL_NSLOTS;
|
||||
if (ndslots <= 0)
|
||||
ndslots = 0;
|
||||
else
|
||||
ndslots++; /* number of total slots is stored at index -1 */
|
||||
}
|
||||
|
||||
return sizeof(js::Value) * ndslots
|
||||
+ (isFunction() && !getPrivate()) ? sizeof(JSFunction) : sizeof(JSObject);
|
||||
}
|
||||
|
||||
inline const js::Value &
|
||||
JSObject::getDenseArrayElement(uintN idx)
|
||||
JSObject::getDenseArrayElement(uint32 i) const
|
||||
{
|
||||
JS_ASSERT(isDenseArray());
|
||||
return getSlot(idx);
|
||||
JS_ASSERT(i < getDenseArrayCapacity());
|
||||
return dslots[i];
|
||||
}
|
||||
|
||||
inline js::Value *
|
||||
JSObject::addressOfDenseArrayElement(uintN idx)
|
||||
JSObject::addressOfDenseArrayElement(uint32 i)
|
||||
{
|
||||
JS_ASSERT(isDenseArray());
|
||||
return &getSlotRef(idx);
|
||||
JS_ASSERT(i < getDenseArrayCapacity());
|
||||
return &dslots[i];
|
||||
}
|
||||
|
||||
inline void
|
||||
JSObject::setDenseArrayElement(uintN idx, const js::Value &val)
|
||||
JSObject::setDenseArrayElement(uint32 i, const js::Value &v)
|
||||
{
|
||||
JS_ASSERT(isDenseArray());
|
||||
setSlot(idx, val);
|
||||
JS_ASSERT(i < getDenseArrayCapacity());
|
||||
dslots[i] = v;
|
||||
}
|
||||
|
||||
inline bool
|
||||
JSObject::ensureDenseArrayElements(JSContext *cx, uintN cap)
|
||||
inline js::Value *
|
||||
JSObject::getDenseArrayElements() const
|
||||
{
|
||||
JS_ASSERT(isDenseArray());
|
||||
return ensureSlots(cx, cap);
|
||||
return dslots;
|
||||
}
|
||||
|
||||
inline void
|
||||
JSObject::shrinkDenseArrayElements(JSContext *cx, uintN cap)
|
||||
JSObject::freeDenseArrayElements(JSContext *cx)
|
||||
{
|
||||
JS_ASSERT(isDenseArray());
|
||||
shrinkSlots(cx, cap);
|
||||
if (dslots) {
|
||||
cx->free(dslots - 1);
|
||||
dslots = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
inline void
|
||||
JSObject::voidDenseOnlyArraySlots()
|
||||
{
|
||||
JS_ASSERT(isDenseArray());
|
||||
fslots[JSSLOT_DENSE_ARRAY_CAPACITY].setUndefined();
|
||||
}
|
||||
|
||||
inline void
|
||||
|
@ -345,7 +361,7 @@ JSObject::setArgsLength(uint32 argc)
|
|||
JS_ASSERT(isArguments());
|
||||
JS_ASSERT(argc <= JS_ARGS_LENGTH_MAX);
|
||||
JS_ASSERT(UINT32_MAX > (uint64(argc) << ARGS_PACKED_BITS_COUNT));
|
||||
getSlotRef(JSSLOT_ARGS_LENGTH).setInt32(argc << ARGS_PACKED_BITS_COUNT);
|
||||
fslots[JSSLOT_ARGS_LENGTH].setInt32(argc << ARGS_PACKED_BITS_COUNT);
|
||||
JS_ASSERT(!isArgsLengthOverridden());
|
||||
}
|
||||
|
||||
|
@ -353,7 +369,7 @@ inline uint32
|
|||
JSObject::getArgsInitialLength() const
|
||||
{
|
||||
JS_ASSERT(isArguments());
|
||||
uint32 argc = uint32(getSlot(JSSLOT_ARGS_LENGTH).toInt32()) >> ARGS_PACKED_BITS_COUNT;
|
||||
uint32 argc = uint32(fslots[JSSLOT_ARGS_LENGTH].toInt32()) >> ARGS_PACKED_BITS_COUNT;
|
||||
JS_ASSERT(argc <= JS_ARGS_LENGTH_MAX);
|
||||
return argc;
|
||||
}
|
||||
|
@ -362,14 +378,14 @@ inline void
|
|||
JSObject::setArgsLengthOverridden()
|
||||
{
|
||||
JS_ASSERT(isArguments());
|
||||
getSlotRef(JSSLOT_ARGS_LENGTH).getInt32Ref() |= ARGS_LENGTH_OVERRIDDEN_BIT;
|
||||
fslots[JSSLOT_ARGS_LENGTH].getInt32Ref() |= ARGS_LENGTH_OVERRIDDEN_BIT;
|
||||
}
|
||||
|
||||
inline bool
|
||||
JSObject::isArgsLengthOverridden() const
|
||||
{
|
||||
JS_ASSERT(isArguments());
|
||||
const js::Value &v = getSlot(JSSLOT_ARGS_LENGTH);
|
||||
const js::Value &v = fslots[JSSLOT_ARGS_LENGTH];
|
||||
return v.toInt32() & ARGS_LENGTH_OVERRIDDEN_BIT;
|
||||
}
|
||||
|
||||
|
@ -377,14 +393,14 @@ inline js::ArgumentsData *
|
|||
JSObject::getArgsData() const
|
||||
{
|
||||
JS_ASSERT(isArguments());
|
||||
return (js::ArgumentsData *) getSlot(JSSLOT_ARGS_DATA).toPrivate();
|
||||
return (js::ArgumentsData *) fslots[JSSLOT_ARGS_DATA].toPrivate();
|
||||
}
|
||||
|
||||
inline void
|
||||
JSObject::setArgsData(js::ArgumentsData *data)
|
||||
{
|
||||
JS_ASSERT(isArguments());
|
||||
getSlotRef(JSSLOT_ARGS_DATA).setPrivate(data);
|
||||
fslots[JSSLOT_ARGS_DATA].setPrivate(data);
|
||||
}
|
||||
|
||||
inline const js::Value &
|
||||
|
@ -408,7 +424,7 @@ JSObject::getArgsElement(uint32 i) const
|
|||
}
|
||||
|
||||
inline js::Value *
|
||||
JSObject::addressOfArgsElement(uint32 i)
|
||||
JSObject::addressOfArgsElement(uint32 i) const
|
||||
{
|
||||
JS_ASSERT(isArguments());
|
||||
JS_ASSERT(i < getArgsInitialLength());
|
||||
|
@ -428,49 +444,49 @@ JSObject::setCallObjCallee(JSObject &callee)
|
|||
{
|
||||
JS_ASSERT(isCall());
|
||||
JS_ASSERT(callee.isFunction());
|
||||
return getSlotRef(JSSLOT_CALL_CALLEE).setObject(callee);
|
||||
return fslots[JSSLOT_CALL_CALLEE].setObject(callee);
|
||||
}
|
||||
|
||||
inline JSObject &
|
||||
JSObject::getCallObjCallee() const
|
||||
{
|
||||
JS_ASSERT(isCall());
|
||||
return getSlot(JSSLOT_CALL_CALLEE).toObject();
|
||||
return fslots[JSSLOT_CALL_CALLEE].toObject();
|
||||
}
|
||||
|
||||
inline JSFunction *
|
||||
JSObject::getCallObjCalleeFunction() const
|
||||
{
|
||||
JS_ASSERT(isCall());
|
||||
return getSlot(JSSLOT_CALL_CALLEE).toObject().getFunctionPrivate();
|
||||
return fslots[JSSLOT_CALL_CALLEE].toObject().getFunctionPrivate();
|
||||
}
|
||||
|
||||
inline const js::Value &
|
||||
JSObject::getCallObjArguments() const
|
||||
{
|
||||
JS_ASSERT(isCall());
|
||||
return getSlot(JSSLOT_CALL_ARGUMENTS);
|
||||
return fslots[JSSLOT_CALL_ARGUMENTS];
|
||||
}
|
||||
|
||||
inline void
|
||||
JSObject::setCallObjArguments(const js::Value &v)
|
||||
{
|
||||
JS_ASSERT(isCall());
|
||||
setSlot(JSSLOT_CALL_ARGUMENTS, v);
|
||||
fslots[JSSLOT_CALL_ARGUMENTS] = v;
|
||||
}
|
||||
|
||||
inline const js::Value &
|
||||
JSObject::getDateUTCTime() const
|
||||
{
|
||||
JS_ASSERT(isDate());
|
||||
return getSlot(JSSLOT_DATE_UTC_TIME);
|
||||
return fslots[JSSLOT_DATE_UTC_TIME];
|
||||
}
|
||||
|
||||
inline void
|
||||
JSObject::setDateUTCTime(const js::Value &time)
|
||||
{
|
||||
JS_ASSERT(isDate());
|
||||
setSlot(JSSLOT_DATE_UTC_TIME, time);
|
||||
fslots[JSSLOT_DATE_UTC_TIME] = time;
|
||||
}
|
||||
|
||||
inline js::Value *
|
||||
|
@ -478,7 +494,7 @@ JSObject::getFlatClosureUpvars() const
|
|||
{
|
||||
JS_ASSERT(isFunction());
|
||||
JS_ASSERT(FUN_FLAT_CLOSURE(getFunctionPrivate()));
|
||||
return (js::Value *) getSlot(JSSLOT_FLAT_CLOSURE_UPVARS).toPrivate();
|
||||
return (js::Value *) fslots[JSSLOT_FLAT_CLOSURE_UPVARS].toPrivate();
|
||||
}
|
||||
|
||||
inline js::Value
|
||||
|
@ -492,21 +508,20 @@ JSObject::setFlatClosureUpvars(js::Value *upvars)
|
|||
{
|
||||
JS_ASSERT(isFunction());
|
||||
JS_ASSERT(FUN_FLAT_CLOSURE(getFunctionPrivate()));
|
||||
getSlotRef(JSSLOT_FLAT_CLOSURE_UPVARS).setPrivate(upvars);
|
||||
fslots[JSSLOT_FLAT_CLOSURE_UPVARS].setPrivate(upvars);
|
||||
}
|
||||
|
||||
inline bool
|
||||
JSObject::hasMethodObj(const JSObject& obj) const
|
||||
{
|
||||
return JSSLOT_FUN_METHOD_OBJ < numSlots() &&
|
||||
getSlot(JSSLOT_FUN_METHOD_OBJ).isObject() &&
|
||||
&getSlot(JSSLOT_FUN_METHOD_OBJ).toObject() == &obj;
|
||||
return fslots[JSSLOT_FUN_METHOD_OBJ].isObject() &&
|
||||
&fslots[JSSLOT_FUN_METHOD_OBJ].toObject() == &obj;
|
||||
}
|
||||
|
||||
inline void
|
||||
JSObject::setMethodObj(JSObject& obj)
|
||||
{
|
||||
getSlotRef(JSSLOT_FUN_METHOD_OBJ).setObject(obj);
|
||||
fslots[JSSLOT_FUN_METHOD_OBJ].setObject(obj);
|
||||
}
|
||||
|
||||
inline NativeIterator *
|
||||
|
@ -525,74 +540,76 @@ inline jsval
|
|||
JSObject::getNamePrefix() const
|
||||
{
|
||||
JS_ASSERT(isNamespace() || isQName());
|
||||
return js::Jsvalify(getSlot(JSSLOT_NAME_PREFIX));
|
||||
return js::Jsvalify(fslots[JSSLOT_NAME_PREFIX]);
|
||||
}
|
||||
|
||||
inline void
|
||||
JSObject::setNamePrefix(jsval prefix)
|
||||
{
|
||||
JS_ASSERT(isNamespace() || isQName());
|
||||
setSlot(JSSLOT_NAME_PREFIX, js::Valueify(prefix));
|
||||
fslots[JSSLOT_NAME_PREFIX] = js::Valueify(prefix);
|
||||
}
|
||||
|
||||
inline jsval
|
||||
JSObject::getNameURI() const
|
||||
{
|
||||
JS_ASSERT(isNamespace() || isQName());
|
||||
return js::Jsvalify(getSlot(JSSLOT_NAME_URI));
|
||||
return js::Jsvalify(fslots[JSSLOT_NAME_URI]);
|
||||
}
|
||||
|
||||
inline void
|
||||
JSObject::setNameURI(jsval uri)
|
||||
{
|
||||
JS_ASSERT(isNamespace() || isQName());
|
||||
setSlot(JSSLOT_NAME_URI, js::Valueify(uri));
|
||||
fslots[JSSLOT_NAME_URI] = js::Valueify(uri);
|
||||
}
|
||||
|
||||
inline jsval
|
||||
JSObject::getNamespaceDeclared() const
|
||||
{
|
||||
JS_ASSERT(isNamespace());
|
||||
return js::Jsvalify(getSlot(JSSLOT_NAMESPACE_DECLARED));
|
||||
return js::Jsvalify(fslots[JSSLOT_NAMESPACE_DECLARED]);
|
||||
}
|
||||
|
||||
inline void
|
||||
JSObject::setNamespaceDeclared(jsval decl)
|
||||
{
|
||||
JS_ASSERT(isNamespace());
|
||||
setSlot(JSSLOT_NAMESPACE_DECLARED, js::Valueify(decl));
|
||||
fslots[JSSLOT_NAMESPACE_DECLARED] = js::Valueify(decl);
|
||||
}
|
||||
|
||||
inline jsval
|
||||
JSObject::getQNameLocalName() const
|
||||
{
|
||||
JS_ASSERT(isQName());
|
||||
return js::Jsvalify(getSlot(JSSLOT_QNAME_LOCAL_NAME));
|
||||
return js::Jsvalify(fslots[JSSLOT_QNAME_LOCAL_NAME]);
|
||||
}
|
||||
|
||||
inline void
|
||||
JSObject::setQNameLocalName(jsval name)
|
||||
{
|
||||
JS_ASSERT(isQName());
|
||||
setSlot(JSSLOT_QNAME_LOCAL_NAME, js::Valueify(name));
|
||||
fslots[JSSLOT_QNAME_LOCAL_NAME] = js::Valueify(name);
|
||||
}
|
||||
|
||||
inline JSObject *
|
||||
JSObject::getWithThis() const
|
||||
{
|
||||
return &getSlot(JSSLOT_WITH_THIS).toObject();
|
||||
return &fslots[JSSLOT_WITH_THIS].toObject();
|
||||
}
|
||||
|
||||
inline void
|
||||
JSObject::setWithThis(JSObject *thisp)
|
||||
{
|
||||
getSlotRef(JSSLOT_WITH_THIS).setObject(*thisp);
|
||||
fslots[JSSLOT_WITH_THIS].setObject(*thisp);
|
||||
}
|
||||
|
||||
inline void
|
||||
JSObject::init(JSContext *cx, js::Class *aclasp, JSObject *proto, JSObject *parent,
|
||||
void *priv, bool useHoles)
|
||||
JSObject::initCommon(js::Class *aclasp, JSObject *proto, JSObject *parent,
|
||||
JSContext *cx)
|
||||
{
|
||||
JS_STATIC_ASSERT(JSSLOT_PRIVATE + 3 == JS_INITIAL_NSLOTS);
|
||||
|
||||
clasp = aclasp;
|
||||
flags = 0;
|
||||
|
||||
|
@ -609,22 +626,43 @@ JSObject::init(JSContext *cx, js::Class *aclasp, JSObject *proto, JSObject *pare
|
|||
|
||||
setProto(proto);
|
||||
setParent(parent);
|
||||
fslots[JSSLOT_PRIVATE + 1].setUndefined();
|
||||
fslots[JSSLOT_PRIVATE + 2].setUndefined();
|
||||
|
||||
privateData = priv;
|
||||
slots = &fixedSlots[0];
|
||||
|
||||
/*
|
||||
* Fill the fixed slots with undefined or array holes. This object must
|
||||
* already have its capacity filled in, as by js_NewGCObject.
|
||||
*/
|
||||
JS_ASSERT(capacity == numFixedSlots());
|
||||
ClearValueRange(fixedSlots, capacity, useHoles);
|
||||
dslots = NULL;
|
||||
|
||||
#ifdef JS_THREADSAFE
|
||||
js_InitTitle(cx, &title);
|
||||
#endif
|
||||
|
||||
emptyShapes = NULL;
|
||||
emptyShape = NULL;
|
||||
}
|
||||
|
||||
inline void
|
||||
JSObject::init(js::Class *aclasp, JSObject *proto, JSObject *parent,
|
||||
const js::Value &privateSlotValue, JSContext *cx)
|
||||
{
|
||||
initCommon(aclasp, proto, parent, cx);
|
||||
fslots[JSSLOT_PRIVATE] = privateSlotValue;
|
||||
}
|
||||
|
||||
inline void
|
||||
JSObject::init(js::Class *aclasp, JSObject *proto, JSObject *parent,
|
||||
void *priv, JSContext *cx)
|
||||
{
|
||||
initCommon(aclasp, proto, parent, cx);
|
||||
*(void **)&fslots[JSSLOT_PRIVATE] = priv;
|
||||
}
|
||||
|
||||
inline void
|
||||
JSObject::init(js::Class *aclasp, JSObject *proto, JSObject *parent,
|
||||
JSContext *cx)
|
||||
{
|
||||
initCommon(aclasp, proto, parent, cx);
|
||||
if (clasp->flags & JSCLASS_HAS_PRIVATE)
|
||||
*(void **)&fslots[JSSLOT_PRIVATE] = NULL;
|
||||
else
|
||||
fslots[JSSLOT_PRIVATE].setUndefined();
|
||||
}
|
||||
|
||||
inline void
|
||||
|
@ -641,45 +679,40 @@ JSObject::finish(JSContext *cx)
|
|||
#endif
|
||||
}
|
||||
|
||||
inline bool
|
||||
JSObject::initSharingEmptyShape(JSContext *cx,
|
||||
js::Class *aclasp,
|
||||
inline void
|
||||
JSObject::initSharingEmptyShape(js::Class *aclasp,
|
||||
JSObject *proto,
|
||||
JSObject *parent,
|
||||
void *privateValue,
|
||||
/* JSFinalizeGCThingKind */ unsigned kind)
|
||||
const js::Value &privateSlotValue,
|
||||
JSContext *cx)
|
||||
{
|
||||
init(cx, aclasp, proto, parent, privateValue, false);
|
||||
|
||||
JS_ASSERT(!isDenseArray());
|
||||
|
||||
js::EmptyShape *empty = proto->getEmptyShape(cx, aclasp, JSFinalizeGCThingKind(kind));
|
||||
if (!empty)
|
||||
return false;
|
||||
init(aclasp, proto, parent, privateSlotValue, cx);
|
||||
|
||||
js::EmptyShape *empty = proto->emptyShape;
|
||||
JS_ASSERT(empty->getClass() == aclasp);
|
||||
setMap(empty);
|
||||
}
|
||||
|
||||
inline void
|
||||
JSObject::initSharingEmptyShape(js::Class *aclasp,
|
||||
JSObject *proto,
|
||||
JSObject *parent,
|
||||
void *priv,
|
||||
JSContext *cx)
|
||||
{
|
||||
init(aclasp, proto, parent, priv, cx);
|
||||
|
||||
js::EmptyShape *empty = proto->emptyShape;
|
||||
JS_ASSERT(empty->getClass() == aclasp);
|
||||
setMap(empty);
|
||||
return true;
|
||||
}
|
||||
|
||||
inline void
|
||||
JSObject::freeSlotsArray(JSContext *cx)
|
||||
{
|
||||
JS_ASSERT(hasSlotsArray());
|
||||
cx->free(slots);
|
||||
}
|
||||
|
||||
inline void
|
||||
JSObject::removeSlotsArray(JSContext *cx)
|
||||
{
|
||||
JS_ASSERT(hasSlotsArray());
|
||||
|
||||
size_t fixed = numFixedSlots();
|
||||
JS_ASSERT(fixed <= capacity);
|
||||
memcpy(fixedSlots, slots, fixed * sizeof(js::Value));
|
||||
|
||||
freeSlotsArray(cx);
|
||||
slots = &fixedSlots[0];
|
||||
capacity = fixed;
|
||||
JS_ASSERT(dslots[-1].toPrivateUint32() > JS_INITIAL_NSLOTS);
|
||||
cx->free(dslots - 1);
|
||||
}
|
||||
|
||||
inline bool
|
||||
|
@ -758,8 +791,7 @@ class AutoPropertyDescriptorRooter : private AutoGCRooter, public PropertyDescri
|
|||
};
|
||||
|
||||
static inline bool
|
||||
InitScopeForObject(JSContext* cx, JSObject* obj, js::Class *clasp, JSObject* proto,
|
||||
JSFinalizeGCThingKind kind)
|
||||
InitScopeForObject(JSContext* cx, JSObject* obj, js::Class *clasp, JSObject* proto)
|
||||
{
|
||||
JS_ASSERT(clasp->isNative());
|
||||
JS_ASSERT(proto == obj->getProto());
|
||||
|
@ -770,7 +802,7 @@ InitScopeForObject(JSContext* cx, JSObject* obj, js::Class *clasp, JSObject* pro
|
|||
if (proto) {
|
||||
JS_LOCK_OBJ(cx, proto);
|
||||
if (proto->canProvideEmptyShape(clasp)) {
|
||||
empty = proto->getEmptyShape(cx, clasp, kind);
|
||||
empty = proto->getEmptyShape(cx, clasp);
|
||||
JS_UNLOCK_OBJ(cx, proto);
|
||||
if (!empty)
|
||||
goto bad;
|
||||
|
@ -780,11 +812,13 @@ InitScopeForObject(JSContext* cx, JSObject* obj, js::Class *clasp, JSObject* pro
|
|||
}
|
||||
|
||||
if (!empty) {
|
||||
uint32 freeslot = JSSLOT_FREE(clasp);
|
||||
JS_ASSERT(freeslot >= JSSLOT_PRIVATE);
|
||||
|
||||
empty = js::EmptyShape::create(cx, clasp);
|
||||
if (!empty)
|
||||
goto bad;
|
||||
uint32 freeslot = JSSLOT_FREE(clasp);
|
||||
if (freeslot > obj->numSlots() && !obj->allocSlots(cx, freeslot))
|
||||
if (freeslot > JS_INITIAL_NSLOTS && !obj->allocSlots(cx, freeslot))
|
||||
goto bad;
|
||||
}
|
||||
|
||||
|
@ -804,8 +838,7 @@ InitScopeForObject(JSContext* cx, JSObject* obj, js::Class *clasp, JSObject* pro
|
|||
* and its parent global as parent.
|
||||
*/
|
||||
static inline JSObject *
|
||||
NewNativeClassInstance(JSContext *cx, Class *clasp, JSObject *proto,
|
||||
JSObject *parent, JSFinalizeGCThingKind kind)
|
||||
NewNativeClassInstance(JSContext *cx, Class *clasp, JSObject *proto, JSObject *parent)
|
||||
{
|
||||
JS_ASSERT(proto);
|
||||
JS_ASSERT(proto->isNative());
|
||||
|
@ -815,19 +848,18 @@ NewNativeClassInstance(JSContext *cx, Class *clasp, JSObject *proto,
|
|||
* Allocate an object from the GC heap and initialize all its fields before
|
||||
* doing any operation that can potentially trigger GC.
|
||||
*/
|
||||
JSObject* obj = js_NewGCObject(cx, kind);
|
||||
JSObject* obj = js_NewGCObject(cx);
|
||||
|
||||
if (obj) {
|
||||
/*
|
||||
* Default parent to the parent of the prototype, which was set from
|
||||
* the parent of the prototype's constructor.
|
||||
*/
|
||||
bool useHoles = (clasp == &js_ArrayClass);
|
||||
obj->init(cx, clasp, proto, parent, NULL, useHoles);
|
||||
obj->init(clasp, proto, parent, cx);
|
||||
|
||||
JS_LOCK_OBJ(cx, proto);
|
||||
JS_ASSERT(proto->canProvideEmptyShape(clasp));
|
||||
js::EmptyShape *empty = proto->getEmptyShape(cx, clasp, kind);
|
||||
js::EmptyShape *empty = proto->getEmptyShape(cx, clasp);
|
||||
JS_UNLOCK_OBJ(cx, proto);
|
||||
|
||||
if (empty)
|
||||
|
@ -839,13 +871,6 @@ NewNativeClassInstance(JSContext *cx, Class *clasp, JSObject *proto,
|
|||
return obj;
|
||||
}
|
||||
|
||||
static inline JSObject *
|
||||
NewNativeClassInstance(JSContext *cx, Class *clasp, JSObject *proto, JSObject *parent)
|
||||
{
|
||||
JSFinalizeGCThingKind kind = js_GetGCObjectKind(JSCLASS_RESERVED_SLOTS(clasp));
|
||||
return NewNativeClassInstance(cx, clasp, proto, parent, kind);
|
||||
}
|
||||
|
||||
bool
|
||||
FindClassPrototype(JSContext *cx, JSObject *scope, JSProtoKey protoKey, JSObject **protop,
|
||||
Class *clasp);
|
||||
|
@ -857,7 +882,7 @@ FindClassPrototype(JSContext *cx, JSObject *scope, JSProtoKey protoKey, JSObject
|
|||
* right default proto and parent for clasp in cx.
|
||||
*/
|
||||
static inline JSObject *
|
||||
NewBuiltinClassInstance(JSContext *cx, Class *clasp, JSFinalizeGCThingKind kind)
|
||||
NewBuiltinClassInstance(JSContext *cx, Class *clasp)
|
||||
{
|
||||
VOUCH_DOES_NOT_REQUIRE_STACK();
|
||||
|
||||
|
@ -886,14 +911,7 @@ NewBuiltinClassInstance(JSContext *cx, Class *clasp, JSFinalizeGCThingKind kind)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
return NewNativeClassInstance(cx, clasp, proto, global, kind);
|
||||
}
|
||||
|
||||
static inline JSObject *
|
||||
NewBuiltinClassInstance(JSContext *cx, Class *clasp)
|
||||
{
|
||||
JSFinalizeGCThingKind kind = js_GetGCObjectKind(JSCLASS_RESERVED_SLOTS(clasp));
|
||||
return NewBuiltinClassInstance(cx, clasp, kind);
|
||||
return NewNativeClassInstance(cx, clasp, proto, global);
|
||||
}
|
||||
|
||||
static inline JSProtoKey
|
||||
|
@ -944,8 +962,7 @@ namespace detail
|
|||
{
|
||||
template <bool withProto, bool isFunction>
|
||||
static JS_ALWAYS_INLINE JSObject *
|
||||
NewObject(JSContext *cx, js::Class *clasp, JSObject *proto, JSObject *parent,
|
||||
JSFinalizeGCThingKind kind)
|
||||
NewObject(JSContext *cx, js::Class *clasp, JSObject *proto, JSObject *parent)
|
||||
{
|
||||
/* Bootstrap the ur-object, and make it the default prototype object. */
|
||||
if (withProto == WithProto::Class && !proto) {
|
||||
|
@ -954,7 +971,8 @@ NewObject(JSContext *cx, js::Class *clasp, JSObject *proto, JSObject *parent,
|
|||
return NULL;
|
||||
if (!proto && !js_GetClassPrototype(cx, parent, JSProto_Object, &proto))
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Allocate an object from the GC heap and initialize all its fields before
|
||||
|
@ -963,23 +981,18 @@ NewObject(JSContext *cx, js::Class *clasp, JSObject *proto, JSObject *parent,
|
|||
*
|
||||
* The should be specialized by the template.
|
||||
*/
|
||||
JSObject* obj = isFunction ? js_NewGCFunction(cx) : js_NewGCObject(cx, kind);
|
||||
JSObject* obj = isFunction ? js_NewGCFunction(cx) : js_NewGCObject(cx);
|
||||
if (!obj)
|
||||
goto out;
|
||||
|
||||
/* This needs to match up with the size of JSFunction::data_padding. */
|
||||
JS_ASSERT_IF(isFunction, kind == FINALIZE_OBJECT2);
|
||||
|
||||
/*
|
||||
* Default parent to the parent of the prototype, which was set from
|
||||
* the parent of the prototype's constructor.
|
||||
*/
|
||||
obj->init(cx, clasp, proto,
|
||||
(!parent && proto) ? proto->getParent() : parent,
|
||||
NULL, clasp == &js_ArrayClass);
|
||||
obj->init(clasp, proto, (!parent && proto) ? proto->getParent() : parent, cx);
|
||||
|
||||
if (clasp->isNative()) {
|
||||
if (!InitScopeForObject(cx, obj, clasp, proto, kind)) {
|
||||
if (!InitScopeForObject(cx, obj, clasp, proto)) {
|
||||
obj = NULL;
|
||||
goto out;
|
||||
}
|
||||
|
@ -991,73 +1004,28 @@ out:
|
|||
Probes::createObject(cx, obj);
|
||||
return obj;
|
||||
}
|
||||
} /* namespace detail */
|
||||
}
|
||||
|
||||
static JS_ALWAYS_INLINE JSObject *
|
||||
NewFunction(JSContext *cx, JSObject *parent)
|
||||
{
|
||||
return detail::NewObject<WithProto::Class, true>(cx, &js_FunctionClass, NULL, parent,
|
||||
FINALIZE_OBJECT2);
|
||||
}
|
||||
|
||||
template <WithProto::e withProto>
|
||||
static JS_ALWAYS_INLINE JSObject *
|
||||
NewNonFunction(JSContext *cx, js::Class *clasp, JSObject *proto, JSObject *parent,
|
||||
JSFinalizeGCThingKind kind)
|
||||
{
|
||||
return detail::NewObject<withProto, false>(cx, clasp, proto, parent, kind);
|
||||
return detail::NewObject<WithProto::Class, true>(cx, &js_FunctionClass, NULL, parent);
|
||||
}
|
||||
|
||||
template <WithProto::e withProto>
|
||||
static JS_ALWAYS_INLINE JSObject *
|
||||
NewNonFunction(JSContext *cx, js::Class *clasp, JSObject *proto, JSObject *parent)
|
||||
{
|
||||
JSFinalizeGCThingKind kind = js_GetGCObjectKind(JSCLASS_RESERVED_SLOTS(clasp));
|
||||
return detail::NewObject<withProto, false>(cx, clasp, proto, parent, kind);
|
||||
return detail::NewObject<withProto, false>(cx, clasp, proto, parent);
|
||||
}
|
||||
|
||||
template <WithProto::e withProto>
|
||||
static JS_ALWAYS_INLINE JSObject *
|
||||
NewObject(JSContext *cx, js::Class *clasp, JSObject *proto, JSObject *parent)
|
||||
{
|
||||
if (clasp == &js_FunctionClass) {
|
||||
return detail::NewObject<withProto, true>(cx, clasp, proto, parent,
|
||||
FINALIZE_OBJECT2);
|
||||
} else {
|
||||
JSFinalizeGCThingKind kind = js_GetGCObjectKind(JSCLASS_RESERVED_SLOTS(clasp));
|
||||
return detail::NewObject<withProto, false>(cx, clasp, proto, parent, kind);
|
||||
}
|
||||
}
|
||||
|
||||
/* Creates a new array with a zero length and the given finalize kind. */
|
||||
static inline JSObject *
|
||||
NewArrayWithKind(JSContext* cx, JSFinalizeGCThingKind kind)
|
||||
{
|
||||
return NewNonFunction<WithProto::Class>(cx, &js_ArrayClass, NULL, NULL, kind);
|
||||
}
|
||||
|
||||
/*
|
||||
* As for js_GetGCObjectKind, where numSlots is a guess at the final size of
|
||||
* the object, zero if the final size is unknown.
|
||||
*/
|
||||
static inline JSFinalizeGCThingKind
|
||||
GuessObjectGCKind(size_t numSlots)
|
||||
{
|
||||
return numSlots ? js_GetGCObjectKind(numSlots) : FINALIZE_OBJECT8;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the GC kind to use for scripted 'new' on the given class.
|
||||
* FIXME bug 547327: estimate the size from the allocation site.
|
||||
*/
|
||||
static inline JSFinalizeGCThingKind
|
||||
NewObjectGCKind(JSContext *cx, js::Class *clasp)
|
||||
{
|
||||
if (clasp == &js_ArrayClass || clasp == &js_SlowArrayClass)
|
||||
return FINALIZE_OBJECT8;
|
||||
if (clasp == &js_FunctionClass)
|
||||
return FINALIZE_OBJECT2;
|
||||
return FINALIZE_OBJECT4;
|
||||
return (clasp == &js_FunctionClass)
|
||||
? detail::NewObject<withProto, true>(cx, clasp, proto, parent)
|
||||
: detail::NewObject<withProto, false>(cx, clasp, proto, parent);
|
||||
}
|
||||
|
||||
} /* namespace js */
|
||||
|
|
|
@ -4483,7 +4483,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
|
|||
|
||||
case JSOP_NEWINIT:
|
||||
{
|
||||
i = GET_UINT16(pc);
|
||||
i = GET_INT8(pc);
|
||||
LOCAL_ASSERT(i == JSProto_Array || i == JSProto_Object);
|
||||
|
||||
todo = ss->sprinter.offset;
|
||||
|
|
|
@ -244,7 +244,7 @@ OPDEF(JSOP_SETLOCAL, 87,"setlocal", NULL, 3, 1, 1, 3, JOF_LOCAL|
|
|||
OPDEF(JSOP_UINT16, 88, "uint16", NULL, 3, 0, 1, 16, JOF_UINT16)
|
||||
|
||||
/* Object and array literal support. */
|
||||
OPDEF(JSOP_NEWINIT, 89, "newinit", NULL, 5, 0, 1, 19, JOF_UINT16PAIR)
|
||||
OPDEF(JSOP_NEWINIT, 89, "newinit", NULL, 2, 0, 1, 19, JOF_INT8)
|
||||
OPDEF(JSOP_ENDINIT, 90, "endinit", NULL, 1, 0, 0, 19, JOF_BYTE)
|
||||
OPDEF(JSOP_INITPROP, 91, "initprop", NULL, 3, 2, 1, 3, JOF_ATOM|JOF_PROP|JOF_SET|JOF_DETECTING)
|
||||
OPDEF(JSOP_INITELEM, 92, "initelem", NULL, 1, 3, 1, 3, JOF_BYTE |JOF_ELEM|JOF_SET|JOF_DETECTING)
|
||||
|
|
|
@ -1207,8 +1207,8 @@ static JSFunctionSpec static_methods[] = {
|
|||
|
||||
extern Class CallableObjectClass;
|
||||
|
||||
static const uint32 JSSLOT_CALLABLE_CALL = 0;
|
||||
static const uint32 JSSLOT_CALLABLE_CONSTRUCT = 1;
|
||||
static const uint32 JSSLOT_CALLABLE_CALL = JSSLOT_PRIVATE;
|
||||
static const uint32 JSSLOT_CALLABLE_CONSTRUCT = JSSLOT_PRIVATE + 1;
|
||||
|
||||
static JSBool
|
||||
callable_Call(JSContext *cx, uintN argc, Value *vp)
|
||||
|
@ -1219,7 +1219,7 @@ callable_Call(JSContext *cx, uintN argc, Value *vp)
|
|||
|
||||
JSObject *callable = &JS_CALLEE(cx, vp).toObject();
|
||||
JS_ASSERT(callable->getClass() == &CallableObjectClass);
|
||||
const Value &fval = callable->getSlot(JSSLOT_CALLABLE_CALL);
|
||||
const Value &fval = callable->fslots[JSSLOT_CALLABLE_CALL];
|
||||
Value rval;
|
||||
bool ok = ExternalInvoke(cx, thisobj, fval, argc, JS_ARGV(cx, vp), &rval);
|
||||
*vp = rval;
|
||||
|
@ -1235,10 +1235,10 @@ callable_Construct(JSContext *cx, uintN argc, Value *vp)
|
|||
|
||||
JSObject *callable = &vp[0].toObject();
|
||||
JS_ASSERT(callable->getClass() == &CallableObjectClass);
|
||||
Value fval = callable->getSlot(JSSLOT_CALLABLE_CONSTRUCT);
|
||||
Value fval = callable->fslots[JSSLOT_CALLABLE_CONSTRUCT];
|
||||
if (fval.isUndefined()) {
|
||||
/* We don't have an explicit constructor so allocate a new object and use the call. */
|
||||
fval = callable->getSlot(JSSLOT_CALLABLE_CALL);
|
||||
fval = callable->fslots[JSSLOT_CALLABLE_CALL];
|
||||
JS_ASSERT(fval.isObject());
|
||||
|
||||
/* callable is the constructor, so get callable.prototype is the proto of the new object. */
|
||||
|
@ -1260,7 +1260,7 @@ callable_Construct(JSContext *cx, uintN argc, Value *vp)
|
|||
|
||||
/* If the call returns an object, return that, otherwise the original newobj. */
|
||||
Value rval;
|
||||
if (!ExternalInvoke(cx, newobj, callable->getSlot(JSSLOT_CALLABLE_CALL),
|
||||
if (!ExternalInvoke(cx, newobj, callable->fslots[JSSLOT_CALLABLE_CALL],
|
||||
argc, vp + 2, &rval)) {
|
||||
return false;
|
||||
}
|
||||
|
@ -1318,19 +1318,15 @@ FixProxy(JSContext *cx, JSObject *proxy, JSBool *bp)
|
|||
JSObject *parent = proxy->getParent();
|
||||
Class *clasp = proxy->isFunctionProxy() ? &CallableObjectClass : &js_ObjectClass;
|
||||
|
||||
/*
|
||||
* Make a blank object from the recipe fix provided to us. This must have
|
||||
* number of fixed slots as the proxy so that we can swap their contents.
|
||||
*/
|
||||
JSFinalizeGCThingKind kind = js_KindFromGCThing(proxy);
|
||||
JSObject *newborn = NewNonFunction<WithProto::Given>(cx, clasp, proto, parent, kind);
|
||||
/* Make a blank object from the recipe fix provided to us. */
|
||||
JSObject *newborn = NewNonFunction<WithProto::Given>(cx, clasp, proto, parent);
|
||||
if (!newborn)
|
||||
return NULL;
|
||||
AutoObjectRooter tvr2(cx, newborn);
|
||||
|
||||
if (clasp == &CallableObjectClass) {
|
||||
newborn->setSlot(JSSLOT_CALLABLE_CALL, GetCall(proxy));
|
||||
newborn->setSlot(JSSLOT_CALLABLE_CONSTRUCT, GetConstruct(proxy));
|
||||
newborn->fslots[JSSLOT_CALLABLE_CALL] = GetCall(proxy);
|
||||
newborn->fslots[JSSLOT_CALLABLE_CONSTRUCT] = GetConstruct(proxy);
|
||||
}
|
||||
|
||||
{
|
||||
|
@ -1340,8 +1336,7 @@ FixProxy(JSContext *cx, JSObject *proxy, JSBool *bp)
|
|||
}
|
||||
|
||||
/* Trade spaces between the newborn object and the proxy. */
|
||||
if (!proxy->swap(cx, newborn))
|
||||
return false;
|
||||
proxy->swap(newborn);
|
||||
|
||||
/* The GC will dispose of the proxy object. */
|
||||
|
||||
|
|
|
@ -126,11 +126,11 @@ class JSProxy {
|
|||
};
|
||||
|
||||
/* Shared between object and function proxies. */
|
||||
const uint32 JSSLOT_PROXY_HANDLER = 0;
|
||||
const uint32 JSSLOT_PROXY_PRIVATE = 1;
|
||||
const uint32 JSSLOT_PROXY_HANDLER = JSSLOT_PRIVATE + 0;
|
||||
const uint32 JSSLOT_PROXY_PRIVATE = JSSLOT_PRIVATE + 1;
|
||||
/* Function proxies only. */
|
||||
const uint32 JSSLOT_PROXY_CALL = 2;
|
||||
const uint32 JSSLOT_PROXY_CONSTRUCT = 3;
|
||||
const uint32 JSSLOT_PROXY_CALL = JSSLOT_PRIVATE + 2;
|
||||
const uint32 JSSLOT_PROXY_CONSTRUCT = JSSLOT_PRIVATE + 3;
|
||||
|
||||
extern JS_FRIEND_API(js::Class) ObjectProxyClass;
|
||||
extern JS_FRIEND_API(js::Class) FunctionProxyClass;
|
||||
|
|
|
@ -174,28 +174,28 @@ inline const js::Value &
|
|||
JSObject::getRegExpLastIndex() const
|
||||
{
|
||||
JS_ASSERT(isRegExp());
|
||||
return getSlot(JSSLOT_REGEXP_LAST_INDEX);
|
||||
return fslots[JSSLOT_REGEXP_LAST_INDEX];
|
||||
}
|
||||
|
||||
inline void
|
||||
JSObject::setRegExpLastIndex(const js::Value &v)
|
||||
{
|
||||
JS_ASSERT(isRegExp());
|
||||
setSlot(JSSLOT_REGEXP_LAST_INDEX, v);
|
||||
fslots[JSSLOT_REGEXP_LAST_INDEX] = v;
|
||||
}
|
||||
|
||||
inline void
|
||||
JSObject::setRegExpLastIndex(jsdouble d)
|
||||
{
|
||||
JS_ASSERT(isRegExp());
|
||||
setSlot(JSSLOT_REGEXP_LAST_INDEX, js::NumberValue(d));
|
||||
fslots[JSSLOT_REGEXP_LAST_INDEX] = js::NumberValue(d);
|
||||
}
|
||||
|
||||
inline void
|
||||
JSObject::zeroRegExpLastIndex()
|
||||
{
|
||||
JS_ASSERT(isRegExp());
|
||||
getSlotRef(JSSLOT_REGEXP_LAST_INDEX).setInt32(0);
|
||||
fslots[JSSLOT_REGEXP_LAST_INDEX].setInt32(0);
|
||||
}
|
||||
|
||||
namespace js { class AutoStringRooter; }
|
||||
|
|
|
@ -1128,22 +1128,6 @@ JSObject::removeProperty(JSContext *cx, jsid id)
|
|||
*/
|
||||
JS_ASSERT(shape == lastProp);
|
||||
removeLastProperty();
|
||||
|
||||
/*
|
||||
* Revert to fixed slots if this was the first dynamically allocated slot,
|
||||
* preserving invariant that objects with the same shape use the fixed
|
||||
* slots in the same way.
|
||||
*/
|
||||
size_t fixed = numFixedSlots();
|
||||
if (shape->slot == fixed) {
|
||||
JS_ASSERT(hasSlotsArray());
|
||||
JS_ASSERT_IF(!lastProp->isEmptyShape() && lastProp->hasSlot(),
|
||||
lastProp->slot == fixed - 1);
|
||||
memcpy(fixedSlots, slots, fixed * sizeof(Value));
|
||||
freeSlotsArray(cx);
|
||||
slots = fixedSlots;
|
||||
capacity = fixed;
|
||||
}
|
||||
}
|
||||
updateShape(cx);
|
||||
|
||||
|
|
|
@ -60,45 +60,19 @@ js::Shape::freeTable(JSContext *cx)
|
|||
}
|
||||
|
||||
inline js::EmptyShape *
|
||||
JSObject::getEmptyShape(JSContext *cx, js::Class *aclasp,
|
||||
/* JSFinalizeGCThingKind */ unsigned kind)
|
||||
JSObject::getEmptyShape(JSContext *cx, js::Class *aclasp)
|
||||
{
|
||||
JS_ASSERT(kind >= FINALIZE_OBJECT0 && kind <= FINALIZE_OBJECT_LAST);
|
||||
int i = kind - FINALIZE_OBJECT0;
|
||||
|
||||
if (!emptyShapes) {
|
||||
int count = FINALIZE_OBJECT_LAST - FINALIZE_OBJECT0 + 1;
|
||||
emptyShapes = (js::EmptyShape**) cx->calloc(sizeof(js::EmptyShape*) * count);
|
||||
if (!emptyShapes)
|
||||
return NULL;
|
||||
|
||||
/*
|
||||
* Always fill in emptyShapes[0], so canProvideEmptyShape works.
|
||||
* Other empty shapes are filled in lazily.
|
||||
*/
|
||||
emptyShapes[0] = js::EmptyShape::create(cx, aclasp);
|
||||
if (!emptyShapes[0]) {
|
||||
cx->free(emptyShapes);
|
||||
emptyShapes = NULL;
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
JS_ASSERT(aclasp == emptyShapes[0]->getClass());
|
||||
|
||||
if (!emptyShapes[i]) {
|
||||
emptyShapes[i] = js::EmptyShape::create(cx, aclasp);
|
||||
if (!emptyShapes[i])
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return emptyShapes[i];
|
||||
if (emptyShape)
|
||||
JS_ASSERT(aclasp == emptyShape->getClass());
|
||||
else
|
||||
emptyShape = js::EmptyShape::create(cx, aclasp);
|
||||
return emptyShape;
|
||||
}
|
||||
|
||||
inline bool
|
||||
JSObject::canProvideEmptyShape(js::Class *aclasp)
|
||||
{
|
||||
return !emptyShapes || emptyShapes[0]->getClass() == aclasp;
|
||||
return !emptyShape || emptyShape->getClass() == aclasp;
|
||||
}
|
||||
|
||||
inline void
|
||||
|
|
|
@ -2673,7 +2673,9 @@ ptrdiff_t
|
|||
TraceRecorder::nativeGlobalSlot(const Value* p) const
|
||||
{
|
||||
JS_ASSERT(isGlobal(p));
|
||||
return ptrdiff_t(p - globalObj->slots);
|
||||
if (size_t(p - globalObj->fslots) < JS_INITIAL_NSLOTS)
|
||||
return ptrdiff_t(p - globalObj->fslots);
|
||||
return ptrdiff_t((p - globalObj->dslots) + JS_INITIAL_NSLOTS);
|
||||
}
|
||||
|
||||
/* Determine the offset in the native global frame for a jsval we track. */
|
||||
|
@ -2687,7 +2689,8 @@ TraceRecorder::nativeGlobalOffset(const Value* p) const
|
|||
bool
|
||||
TraceRecorder::isGlobal(const Value* p) const
|
||||
{
|
||||
return (size_t(p - globalObj->slots) < globalObj->numSlots());
|
||||
return ((size_t(p - globalObj->fslots) < JS_INITIAL_NSLOTS) ||
|
||||
(size_t(p - globalObj->dslots) < (globalObj->numSlots() - JS_INITIAL_NSLOTS)));
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -3444,7 +3447,7 @@ struct ArgClosureTraits
|
|||
|
||||
// Get the offset of our object slots from the object's dslots pointer.
|
||||
static inline uint32 slot_offset(JSObject* obj) {
|
||||
return JSObject::CALL_RESERVED_SLOTS;
|
||||
return JSSLOT_START(&js_CallClass) + JSObject::CALL_RESERVED_SLOTS;
|
||||
}
|
||||
|
||||
// Get the maximum slot index of this type that should be allowed
|
||||
|
@ -3475,7 +3478,7 @@ struct VarClosureTraits
|
|||
}
|
||||
|
||||
static inline uint32 slot_offset(JSObject* obj) {
|
||||
return JSObject::CALL_RESERVED_SLOTS +
|
||||
return JSSLOT_START(&js_CallClass) + JSObject::CALL_RESERVED_SLOTS +
|
||||
obj->getCallObjCalleeFunction()->nargs;
|
||||
}
|
||||
|
||||
|
@ -3940,7 +3943,7 @@ TraceRecorder::known(JSObject** p)
|
|||
}
|
||||
|
||||
/*
|
||||
* The slots of the global object are sometimes reallocated by the interpreter.
|
||||
* The dslots of the global object are sometimes reallocated by the interpreter.
|
||||
* This function check for that condition and re-maps the entries of the tracker
|
||||
* accordingly.
|
||||
*/
|
||||
|
@ -3949,8 +3952,8 @@ TraceRecorder::checkForGlobalObjectReallocationHelper()
|
|||
{
|
||||
debug_only_print0(LC_TMTracer, "globalObj->dslots relocated, updating tracker\n");
|
||||
Value* src = global_dslots;
|
||||
Value* dst = globalObj->getSlots();
|
||||
jsuint length = globalObj->capacity;
|
||||
Value* dst = globalObj->dslots;
|
||||
jsuint length = globalObj->dslots[-1].toPrivateUint32() - JS_INITIAL_NSLOTS;
|
||||
LIns** map = (LIns**)alloca(sizeof(LIns*) * length);
|
||||
for (jsuint n = 0; n < length; ++n) {
|
||||
map[n] = tracker.get(src);
|
||||
|
@ -3958,7 +3961,7 @@ TraceRecorder::checkForGlobalObjectReallocationHelper()
|
|||
}
|
||||
for (jsuint n = 0; n < length; ++n)
|
||||
tracker.set(dst++, map[n]);
|
||||
global_dslots = globalObj->getSlots();
|
||||
global_dslots = globalObj->dslots;
|
||||
}
|
||||
|
||||
/* Determine whether the current branch is a loop edge (taken or not taken). */
|
||||
|
@ -8720,7 +8723,7 @@ TraceRecorder::incProp(jsint incr, bool pre)
|
|||
CHECK_STATUS_A(inc(v, v_ins, incr, pre));
|
||||
|
||||
LIns* dslots_ins = NULL;
|
||||
stobj_set_slot(obj, obj_ins, slot, dslots_ins, v, v_ins);
|
||||
stobj_set_slot(obj_ins, slot, dslots_ins, v, v_ins);
|
||||
return ARECORD_CONTINUE;
|
||||
}
|
||||
|
||||
|
@ -9458,7 +9461,7 @@ TraceRecorder::guardPropertyCacheHit(LIns* obj_ins,
|
|||
void
|
||||
TraceRecorder::stobj_set_fslot(LIns *obj_ins, unsigned slot, const Value &v, LIns* v_ins)
|
||||
{
|
||||
box_value_into(v, v_ins, obj_ins, offsetof(JSObject, fixedSlots) + slot * sizeof(Value), ACCSET_OTHER);
|
||||
box_value_into(v, v_ins, obj_ins, offsetof(JSObject, fslots) + slot * sizeof(Value), ACCSET_OTHER);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -9466,32 +9469,49 @@ TraceRecorder::stobj_set_dslot(LIns *obj_ins, unsigned slot, LIns*& dslots_ins,
|
|||
const Value &v, LIns* v_ins)
|
||||
{
|
||||
if (!dslots_ins)
|
||||
dslots_ins = lir->insLoad(LIR_ldp, obj_ins, offsetof(JSObject, slots), ACCSET_OTHER);
|
||||
dslots_ins = lir->insLoad(LIR_ldp, obj_ins, offsetof(JSObject, dslots), ACCSET_OTHER);
|
||||
box_value_into(v, v_ins, dslots_ins, slot * sizeof(Value), ACCSET_OTHER);
|
||||
}
|
||||
|
||||
void
|
||||
TraceRecorder::stobj_set_slot(JSObject *obj, LIns* obj_ins, unsigned slot, LIns*& dslots_ins,
|
||||
TraceRecorder::stobj_set_slot(LIns* obj_ins, unsigned slot, LIns*& dslots_ins,
|
||||
const Value &v, LIns* v_ins)
|
||||
{
|
||||
/*
|
||||
* A shape guard must have already been generated for obj, which will
|
||||
* ensure that future objects have the same number of fixed slots.
|
||||
*/
|
||||
if (!obj->hasSlotsArray()) {
|
||||
JS_ASSERT(slot < obj->numSlots());
|
||||
if (slot < JS_INITIAL_NSLOTS)
|
||||
stobj_set_fslot(obj_ins, slot, v, v_ins);
|
||||
} else {
|
||||
stobj_set_dslot(obj_ins, slot, dslots_ins, v, v_ins);
|
||||
}
|
||||
else
|
||||
stobj_set_dslot(obj_ins, slot - JS_INITIAL_NSLOTS, dslots_ins, v, v_ins);
|
||||
}
|
||||
|
||||
#if JS_BITS_PER_WORD == 32 || JS_BITS_PER_WORD == 64
|
||||
LIns*
|
||||
TraceRecorder::stobj_get_slot_uint32(LIns* obj_ins, unsigned slot)
|
||||
void
|
||||
TraceRecorder::set_array_fslot(LIns *obj_ins, unsigned slot, uint32 val)
|
||||
{
|
||||
LIns *vaddr_ins = lir->insLoad(LIR_ldp, obj_ins, offsetof(JSObject, slots), ACCSET_OTHER);
|
||||
return lir->insLoad(LIR_ldi, vaddr_ins, slot * sizeof(Value) + sPayloadOffset, ACCSET_OTHER);
|
||||
/*
|
||||
* We can assume the destination fslot has been appropriately tagged so we
|
||||
* can just overwrite the 32-bit payload.
|
||||
*/
|
||||
lir->insStore(INS_CONSTU(val), obj_ins,
|
||||
offsetof(JSObject, fslots) + slot * sizeof(Value) + sPayloadOffset,
|
||||
ACCSET_OTHER);
|
||||
}
|
||||
|
||||
LIns*
|
||||
TraceRecorder::stobj_get_fslot_uint32(LIns* obj_ins, unsigned slot)
|
||||
{
|
||||
JS_ASSERT(slot < JS_INITIAL_NSLOTS);
|
||||
return lir->insLoad(LIR_ldi, obj_ins,
|
||||
offsetof(JSObject, fslots) + slot * sizeof(Value) + sPayloadOffset,
|
||||
ACCSET_OTHER);
|
||||
}
|
||||
|
||||
LIns*
|
||||
TraceRecorder::stobj_set_fslot_uint32(LIns* value_ins, LIns* obj_ins, unsigned slot)
|
||||
{
|
||||
JS_ASSERT(slot < JS_INITIAL_NSLOTS);
|
||||
return lir->insStore(LIR_sti, value_ins, obj_ins,
|
||||
offsetof(JSObject, fslots) + slot * sizeof(Value) + sPayloadOffset,
|
||||
ACCSET_OTHER);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -9500,14 +9520,12 @@ TraceRecorder::unbox_slot(JSObject *obj, LIns *obj_ins, uint32 slot, VMSideExit
|
|||
{
|
||||
LIns *vaddr_ins;
|
||||
ptrdiff_t offset;
|
||||
|
||||
/* Same guarantee about fixed slots as stobj_set_slot. */
|
||||
if (!obj->hasSlotsArray()) {
|
||||
if (slot < JS_INITIAL_NSLOTS) {
|
||||
vaddr_ins = obj_ins;
|
||||
offset = offsetof(JSObject, fixedSlots) + slot * sizeof(Value);
|
||||
offset = offsetof(JSObject, fslots) + slot * sizeof(Value);
|
||||
} else {
|
||||
vaddr_ins = lir->insLoad(LIR_ldp, obj_ins, offsetof(JSObject, slots), ACCSET_OTHER);
|
||||
offset = slot * sizeof(Value);
|
||||
vaddr_ins = lir->insLoad(LIR_ldp, obj_ins, offsetof(JSObject, dslots), ACCSET_OTHER);
|
||||
offset = (slot - JS_INITIAL_NSLOTS) * sizeof(Value);
|
||||
}
|
||||
|
||||
const Value &v = obj->getSlot(slot);
|
||||
|
@ -9517,11 +9535,12 @@ TraceRecorder::unbox_slot(JSObject *obj, LIns *obj_ins, uint32 slot, VMSideExit
|
|||
#if JS_BITS_PER_WORD == 32
|
||||
|
||||
LIns*
|
||||
TraceRecorder::stobj_get_const_private_ptr(LIns *obj_ins, unsigned slot)
|
||||
TraceRecorder::stobj_get_fslot_private_ptr(LIns *obj_ins, unsigned slot)
|
||||
{
|
||||
LIns *vaddr_ins = lir->insLoad(LIR_ldp, obj_ins, offsetof(JSObject, slots), ACCSET_OTHER);
|
||||
return lir->insLoad(LIR_ldi, vaddr_ins,
|
||||
slot * sizeof(Value) + sPayloadOffset, ACCSET_OTHER, LOAD_CONST);
|
||||
JS_ASSERT(slot < JS_INITIAL_NSLOTS && slot != JSSLOT_PRIVATE);
|
||||
return lir->insLoad(LIR_ldi, obj_ins,
|
||||
offsetof(JSObject, fslots) + slot * sizeof(Value) + sPayloadOffset,
|
||||
ACCSET_OTHER, LOAD_CONST);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -9678,12 +9697,13 @@ TraceRecorder::box_value_for_native_call(const Value &v, LIns *v_ins)
|
|||
#elif JS_BITS_PER_WORD == 64
|
||||
|
||||
LIns*
|
||||
TraceRecorder::stobj_get_const_private_ptr(LIns *obj_ins, unsigned slot)
|
||||
TraceRecorder::stobj_get_fslot_private_ptr(LIns *obj_ins, unsigned slot)
|
||||
{
|
||||
/* N.B. On 64-bit, privates are encoded differently from other pointers. */
|
||||
LIns *vaddr_ins = lir->insLoad(LIR_ldp, obj_ins, offsetof(JSObject, slots), ACCSET_OTHER);
|
||||
LIns *v_ins = lir->insLoad(LIR_ldq, vaddr_ins,
|
||||
slot * sizeof(Value) + sPayloadOffset, ACCSET_OTHER, LOAD_CONST);
|
||||
JS_ASSERT(slot < JS_INITIAL_NSLOTS && slot != JSSLOT_PRIVATE);
|
||||
LIns *v_ins = lir->insLoad(LIR_ldq, obj_ins,
|
||||
offsetof(JSObject, fslots) + slot * sizeof(Value),
|
||||
ACCSET_OTHER, LOAD_CONST);
|
||||
return lir->ins2ImmI(LIR_lshq, v_ins, 1);
|
||||
}
|
||||
|
||||
|
@ -9854,17 +9874,8 @@ TraceRecorder::stobj_get_parent(nanojit::LIns* obj_ins)
|
|||
LIns*
|
||||
TraceRecorder::stobj_get_private(nanojit::LIns* obj_ins)
|
||||
{
|
||||
return lir->insLoad(LIR_ldp, obj_ins,
|
||||
offsetof(JSObject, privateData),
|
||||
ACCSET_OTHER);
|
||||
}
|
||||
|
||||
LIns*
|
||||
TraceRecorder::stobj_get_private_uint32(nanojit::LIns* obj_ins)
|
||||
{
|
||||
return lir->insLoad(LIR_ldi, obj_ins,
|
||||
offsetof(JSObject, privateData),
|
||||
ACCSET_OTHER);
|
||||
JS_STATIC_ASSERT(JSSLOT_PRIVATE == 0);
|
||||
return lir->insLoad(LIR_ldp, obj_ins, offsetof(JSObject, fslots), ACCSET_OTHER);
|
||||
}
|
||||
|
||||
LIns*
|
||||
|
@ -10410,7 +10421,7 @@ TraceRecorder::newArguments(LIns* callee_ins, bool strict)
|
|||
guard(false, lir->insEqP_0(argsobj_ins), OOM_EXIT);
|
||||
|
||||
if (strict) {
|
||||
LIns* argsData_ins = stobj_get_const_private_ptr(argsobj_ins, JSObject::JSSLOT_ARGS_DATA);
|
||||
LIns* argsData_ins = stobj_get_fslot_private_ptr(argsobj_ins, JSObject::JSSLOT_ARGS_DATA);
|
||||
ptrdiff_t slotsOffset = offsetof(ArgumentsData, slots);
|
||||
cx->fp()->forEachCanonicalActualArg(BoxArg(this, slotsOffset, argsData_ins));
|
||||
}
|
||||
|
@ -10805,7 +10816,7 @@ TraceRecorder::getClassPrototype(JSObject* ctor, LIns*& proto_ins)
|
|||
// that pval is usable.
|
||||
JS_ASSERT(!pval.isPrimitive());
|
||||
JSObject *proto = &pval.toObject();
|
||||
JS_ASSERT_IF(clasp != &js_ArrayClass, proto->emptyShapes[0]->getClass() == clasp);
|
||||
JS_ASSERT_IF(clasp != &js_ArrayClass, proto->emptyShape->getClass() == clasp);
|
||||
|
||||
proto_ins = INS_CONSTOBJ(proto);
|
||||
return RECORD_CONTINUE;
|
||||
|
@ -10829,8 +10840,7 @@ TraceRecorder::getClassPrototype(JSProtoKey key, LIns*& proto_ins)
|
|||
/* Double-check that a native proto has a matching emptyShape. */
|
||||
if (key != JSProto_Array) {
|
||||
JS_ASSERT(proto->isNative());
|
||||
JS_ASSERT(proto->emptyShapes);
|
||||
EmptyShape *empty = proto->emptyShapes[0];
|
||||
EmptyShape *empty = proto->emptyShape;
|
||||
JS_ASSERT(empty);
|
||||
JS_ASSERT(JSCLASS_CACHED_PROTO_KEY(empty->getClass()) == key);
|
||||
}
|
||||
|
@ -11744,7 +11754,7 @@ TraceRecorder::nativeSet(JSObject* obj, LIns* obj_ins, const Shape* shape,
|
|||
set(&obj->getSlotRef(slot), v_ins);
|
||||
} else {
|
||||
LIns* dslots_ins = NULL;
|
||||
stobj_set_slot(obj, obj_ins, slot, dslots_ins, v, v_ins);
|
||||
stobj_set_slot(obj_ins, slot, dslots_ins, v, v_ins);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -11913,7 +11923,7 @@ TraceRecorder::setCallProp(JSObject *callobj, LIns *callobj_ins, const Shape *sh
|
|||
JS_ASSERT(shape->hasShortID());
|
||||
|
||||
LIns* dslots_ins = NULL;
|
||||
stobj_set_dslot(callobj_ins, slot, dslots_ins, v, v_ins);
|
||||
stobj_set_slot(callobj_ins, slot, dslots_ins, v, v_ins);
|
||||
return RECORD_CONTINUE;
|
||||
}
|
||||
|
||||
|
@ -12866,14 +12876,22 @@ TraceRecorder::setElem(int lval_spindex, int idx_spindex, int v_spindex)
|
|||
// be an integer.
|
||||
idx_ins = makeNumberInt32(idx_ins);
|
||||
|
||||
if (MAX_DSLOTS_LENGTH > MAX_DSLOTS_LENGTH32) {
|
||||
/*
|
||||
* Check for negative values bleeding through on 64-bit machines only,
|
||||
* since we can't allocate large enough arrays for this on 32-bit
|
||||
* machines.
|
||||
*/
|
||||
guard(true, lir->ins2ImmI(LIR_gei, idx_ins, 0), mismatchExit);
|
||||
}
|
||||
|
||||
if (!js_EnsureDenseArrayCapacity(cx, obj, idx.toInt32()))
|
||||
RETURN_STOP_A("couldn't ensure dense array capacity for setelem");
|
||||
|
||||
// Grow the array if the index exceeds the capacity. This happens
|
||||
// rarely, eg. less than 1% of the time in SunSpider.
|
||||
LIns* capacity_ins =
|
||||
addName(lir->insLoad(LIR_ldi, obj_ins,
|
||||
offsetof(JSObject, capacity), ACCSET_OTHER),
|
||||
addName(stobj_get_fslot_uint32(obj_ins, JSObject::JSSLOT_DENSE_ARRAY_CAPACITY),
|
||||
"capacity");
|
||||
LIns* br = lir->insBranch(LIR_jt, lir->ins2(LIR_ltui, idx_ins, capacity_ins), NULL);
|
||||
LIns* args[] = { idx_ins, obj_ins, cx_ins };
|
||||
|
@ -12883,7 +12901,7 @@ TraceRecorder::setElem(int lval_spindex, int idx_spindex, int v_spindex)
|
|||
|
||||
// Get the address of the element.
|
||||
LIns *dslots_ins =
|
||||
addName(lir->insLoad(LIR_ldp, obj_ins, offsetof(JSObject, slots), ACCSET_OTHER), "dslots");
|
||||
addName(lir->insLoad(LIR_ldp, obj_ins, offsetof(JSObject, dslots), ACCSET_OTHER), "dslots");
|
||||
JS_ASSERT(sizeof(Value) == 8); // The |3| in the following statement requires this.
|
||||
LIns *addr_ins = lir->ins2(LIR_addp, dslots_ins,
|
||||
lir->ins2ImmI(LIR_lshp, lir->insUI2P(idx_ins), 3));
|
||||
|
@ -13089,7 +13107,7 @@ TraceRecorder::record_JSOP_GETFCSLOT()
|
|||
JSObject& callee = cx->fp()->callee();
|
||||
LIns* callee_ins = get(&cx->fp()->calleeValue());
|
||||
|
||||
LIns* upvars_ins = stobj_get_const_private_ptr(callee_ins,
|
||||
LIns* upvars_ins = stobj_get_fslot_private_ptr(callee_ins,
|
||||
JSObject::JSSLOT_FLAT_CLOSURE_UPVARS);
|
||||
|
||||
unsigned index = GET_UINT16(cx->regs->pc);
|
||||
|
@ -13349,7 +13367,7 @@ TraceRecorder::record_JSOP_APPLY()
|
|||
length = aobj->getArrayLength();
|
||||
guard(true,
|
||||
lir->ins2ImmI(LIR_eqi,
|
||||
stobj_get_private_uint32(aobj_ins),
|
||||
stobj_get_fslot_uint32(aobj_ins, JSObject::JSSLOT_ARRAY_LENGTH),
|
||||
length),
|
||||
BRANCH_EXIT);
|
||||
} else if (aobj->isArguments()) {
|
||||
|
@ -13726,10 +13744,8 @@ TraceRecorder::denseArrayElement(Value& oval, Value& ival, Value*& vp, LIns*& v_
|
|||
* the correct value.
|
||||
*/
|
||||
LIns* capacity_ins =
|
||||
addName(lir->insLoad(LIR_ldi, obj_ins,
|
||||
offsetof(JSObject, capacity), ACCSET_OTHER),
|
||||
addName(stobj_get_fslot_uint32(obj_ins, JSObject::JSSLOT_DENSE_ARRAY_CAPACITY),
|
||||
"capacity");
|
||||
|
||||
jsuint capacity = obj->getDenseArrayCapacity();
|
||||
bool within = (jsuint(idx) < capacity);
|
||||
if (!within) {
|
||||
|
@ -13749,8 +13765,8 @@ TraceRecorder::denseArrayElement(Value& oval, Value& ival, Value*& vp, LIns*& v_
|
|||
|
||||
/* Load the value and guard on its type to unbox it. */
|
||||
LIns* dslots_ins =
|
||||
addName(lir->insLoad(LIR_ldp, obj_ins, offsetof(JSObject, slots), ACCSET_OTHER), "dslots");
|
||||
vp = &obj->slots[jsuint(idx)];
|
||||
addName(lir->insLoad(LIR_ldp, obj_ins, offsetof(JSObject, dslots), ACCSET_OTHER), "dslots");
|
||||
vp = &obj->dslots[jsuint(idx)];
|
||||
JS_ASSERT(sizeof(Value) == 8); // The |3| in the following statement requires this.
|
||||
addr_ins = lir->ins2(LIR_addp, dslots_ins,
|
||||
lir->ins2ImmI(LIR_lshp, lir->insUI2P(idx_ins), 3));
|
||||
|
@ -14061,7 +14077,7 @@ TraceRecorder::record_JSOP_UINT16()
|
|||
JS_REQUIRES_STACK AbortableRecordingStatus
|
||||
TraceRecorder::record_JSOP_NEWINIT()
|
||||
{
|
||||
JSProtoKey key = JSProtoKey(GET_UINT16(cx->regs->pc));
|
||||
JSProtoKey key = JSProtoKey(GET_INT8(cx->regs->pc));
|
||||
LIns* proto_ins;
|
||||
CHECK_STATUS_A(getClassPrototype(key, proto_ins));
|
||||
|
||||
|
@ -15022,7 +15038,7 @@ TraceRecorder::record_JSOP_LAMBDA_FC()
|
|||
|
||||
if (fun->u.i.nupvars) {
|
||||
JSUpvarArray *uva = fun->u.i.script->upvars();
|
||||
LIns* upvars_ins = stobj_get_const_private_ptr(closure_ins,
|
||||
LIns* upvars_ins = stobj_get_fslot_private_ptr(closure_ins,
|
||||
JSObject::JSSLOT_FLAT_CLOSURE_UPVARS);
|
||||
|
||||
for (uint32 i = 0, n = uva->length; i < n; i++) {
|
||||
|
@ -15106,7 +15122,7 @@ TraceRecorder::guardArgsLengthNotAssigned(LIns* argsobj_ins)
|
|||
{
|
||||
// The following implements JSObject::isArgsLengthOverridden on trace.
|
||||
// ARGS_LENGTH_OVERRIDDEN_BIT is set if length was overridden.
|
||||
LIns *len_ins = stobj_get_slot_uint32(argsobj_ins, JSObject::JSSLOT_ARGS_LENGTH);
|
||||
LIns *len_ins = stobj_get_fslot_uint32(argsobj_ins, JSObject::JSSLOT_ARGS_LENGTH);
|
||||
LIns *ovr_ins = lir->ins2(LIR_andi, len_ins, INS_CONST(JSObject::ARGS_LENGTH_OVERRIDDEN_BIT));
|
||||
guard(true, lir->insEqI_0(ovr_ins), snapshot(BRANCH_EXIT));
|
||||
return len_ins;
|
||||
|
@ -15813,7 +15829,7 @@ TraceRecorder::record_JSOP_LENGTH()
|
|||
JS_ASSERT(obj->isSlowArray());
|
||||
guardClass(obj_ins, &js_SlowArrayClass, snapshot(BRANCH_EXIT), LOAD_NORMAL);
|
||||
}
|
||||
v_ins = lir->ins1(LIR_i2d, stobj_get_private_uint32(obj_ins));
|
||||
v_ins = lir->ins1(LIR_i2d, stobj_get_fslot_uint32(obj_ins, JSObject::JSSLOT_ARRAY_LENGTH));
|
||||
} else if (OkToTraceTypedArrays && js_IsTypedArray(obj)) {
|
||||
// Ensure array is a typed array and is the same type as what was written
|
||||
guardClass(obj_ins, obj->getClass(), snapshot(BRANCH_EXIT), LOAD_NORMAL);
|
||||
|
|
|
@ -1067,7 +1067,7 @@ class TraceRecorder
|
|||
* entries of the tracker accordingly.
|
||||
*/
|
||||
JS_REQUIRES_STACK void checkForGlobalObjectReallocation() {
|
||||
if (global_dslots != globalObj->getSlots())
|
||||
if (global_dslots != globalObj->dslots)
|
||||
checkForGlobalObjectReallocationHelper();
|
||||
}
|
||||
JS_REQUIRES_STACK void checkForGlobalObjectReallocationHelper();
|
||||
|
@ -1173,20 +1173,21 @@ class TraceRecorder
|
|||
nanojit::LIns* v_ins);
|
||||
void stobj_set_dslot(nanojit::LIns *obj_ins, unsigned slot,
|
||||
nanojit::LIns*& dslots_ins, const Value &v, nanojit::LIns* v_ins);
|
||||
void stobj_set_slot(JSObject *obj, nanojit::LIns* obj_ins, unsigned slot,
|
||||
void stobj_set_slot(nanojit::LIns* obj_ins, unsigned slot,
|
||||
nanojit::LIns*& dslots_ins, const Value &v, nanojit::LIns* v_ins);
|
||||
void set_array_fslot(nanojit::LIns *obj_ins, unsigned slot, uint32 val);
|
||||
|
||||
nanojit::LIns* stobj_get_slot_uint32(nanojit::LIns* obj_ins, unsigned slot);
|
||||
nanojit::LIns* stobj_get_fslot_private_ptr(nanojit::LIns* obj_ins,
|
||||
unsigned slot);
|
||||
nanojit::LIns* stobj_get_fslot_uint32(nanojit::LIns* obj_ins, unsigned slot);
|
||||
nanojit::LIns* stobj_set_fslot_uint32(nanojit::LIns* value_ins, nanojit::LIns* obj_ins,
|
||||
unsigned slot);
|
||||
nanojit::LIns* unbox_slot(JSObject *obj, nanojit::LIns *obj_ins, uint32 slot,
|
||||
VMSideExit *exit);
|
||||
nanojit::LIns* stobj_get_parent(nanojit::LIns* obj_ins);
|
||||
nanojit::LIns* stobj_get_private(nanojit::LIns* obj_ins);
|
||||
nanojit::LIns* stobj_get_private_uint32(nanojit::LIns* obj_ins);
|
||||
nanojit::LIns* stobj_get_proto(nanojit::LIns* obj_ins);
|
||||
|
||||
/* For slots holding private pointers. */
|
||||
nanojit::LIns* stobj_get_const_private_ptr(nanojit::LIns *obj_ins, unsigned slot);
|
||||
|
||||
JS_REQUIRES_STACK AbortableRecordingStatus name(Value*& vp, nanojit::LIns*& ins, NameResult& nr);
|
||||
JS_REQUIRES_STACK AbortableRecordingStatus prop(JSObject* obj, nanojit::LIns* obj_ins,
|
||||
uint32 *slotp, nanojit::LIns** v_insp,
|
||||
|
|
|
@ -818,18 +818,6 @@ PrivateValue(void *ptr)
|
|||
return v;
|
||||
}
|
||||
|
||||
static JS_ALWAYS_INLINE void
|
||||
ClearValueRange(Value *vec, uintN len, bool useHoles)
|
||||
{
|
||||
if (useHoles) {
|
||||
for (uintN i = 0; i < len; i++)
|
||||
vec[i].setMagic(JS_ARRAY_HOLE);
|
||||
} else {
|
||||
for (uintN i = 0; i < len; i++)
|
||||
vec[i].setUndefined();
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
/*
|
||||
|
|
|
@ -166,9 +166,14 @@ static const JSC::MacroAssembler::RegisterID JSParamReg_Argc = JSC::ARMRegiste
|
|||
* Finds and returns the address of a known object and slot.
|
||||
*/
|
||||
Address objSlotRef(JSObject *obj, RegisterID reg, uint32 slot) {
|
||||
move(ImmPtr(&obj->slots), reg);
|
||||
if (slot < JS_INITIAL_NSLOTS) {
|
||||
void *vp = &obj->getSlotRef(slot);
|
||||
move(ImmPtr(vp), reg);
|
||||
return Address(reg, 0);
|
||||
}
|
||||
move(ImmPtr(&obj->dslots), reg);
|
||||
loadPtr(reg, reg);
|
||||
return Address(reg, slot * sizeof(Value));
|
||||
return Address(reg, (slot - JS_INITIAL_NSLOTS) * sizeof(Value));
|
||||
}
|
||||
|
||||
#ifdef JS_CPU_X86
|
||||
|
|
|
@ -50,7 +50,6 @@
|
|||
#include "assembler/jit/ExecutableAllocator.h"
|
||||
#include "assembler/assembler/LinkBuffer.h"
|
||||
#include "FrameState-inl.h"
|
||||
#include "jsobjinlines.h"
|
||||
#include "jsscriptinlines.h"
|
||||
#include "InlineFrameAssembler.h"
|
||||
|
||||
|
@ -1226,13 +1225,10 @@ mjit::Compiler::generateMethod()
|
|||
|
||||
BEGIN_CASE(JSOP_NEWINIT)
|
||||
{
|
||||
jsint i = GET_UINT16(PC);
|
||||
uint32 count = GET_UINT16(PC + UINT16_LEN);
|
||||
|
||||
jsint i = GET_INT8(PC);
|
||||
JS_ASSERT(i == JSProto_Array || i == JSProto_Object);
|
||||
|
||||
prepareStubCall(Uses(0));
|
||||
masm.move(Imm32(count), Registers::ArgReg1);
|
||||
if (i == JSProto_Array)
|
||||
stubCall(stubs::NewInitArray);
|
||||
else
|
||||
|
@ -1442,8 +1438,8 @@ mjit::Compiler::generateMethod()
|
|||
RegisterID reg = frame.allocReg();
|
||||
masm.loadPayload(Address(JSFrameReg, JSStackFrame::offsetOfCallee(fun)), reg);
|
||||
// obj->getFlatClosureUpvars()
|
||||
masm.loadPtr(Address(reg, offsetof(JSObject, slots)), reg);
|
||||
Address upvarAddress(reg, JSObject::JSSLOT_FLAT_CLOSURE_UPVARS * sizeof(Value));
|
||||
Address upvarAddress(reg, offsetof(JSObject, fslots) +
|
||||
JSObject::JSSLOT_FLAT_CLOSURE_UPVARS * sizeof(Value));
|
||||
masm.loadPrivate(upvarAddress, reg);
|
||||
// push ((Value *) reg)[index]
|
||||
frame.freeReg(reg);
|
||||
|
@ -2406,7 +2402,7 @@ mjit::Compiler::jsop_getprop(JSAtom *atom, bool doTypeCheck)
|
|||
#elif defined JS_PUNBOX64
|
||||
Label dslotsLoadLabel = masm.label();
|
||||
#endif
|
||||
masm.loadPtr(Address(objReg, offsetof(JSObject, slots)), objReg);
|
||||
masm.loadPtr(Address(objReg, offsetof(JSObject, dslots)), objReg);
|
||||
|
||||
/* Copy the slot value to the expression stack. */
|
||||
Address slot(objReg, 1 << 24);
|
||||
|
@ -2507,7 +2503,7 @@ mjit::Compiler::jsop_getelem_pic(FrameEntry *obj, FrameEntry *id, RegisterID obj
|
|||
#elif defined JS_PUNBOX64
|
||||
Label dslotsLoadLabel = masm.label();
|
||||
#endif
|
||||
masm.loadPtr(Address(objReg, offsetof(JSObject, slots)), objReg);
|
||||
masm.loadPtr(Address(objReg, offsetof(JSObject, dslots)), objReg);
|
||||
|
||||
/* Copy the slot value to the expression stack. */
|
||||
Address slot(objReg, 1 << 24);
|
||||
|
@ -2639,7 +2635,7 @@ mjit::Compiler::jsop_callprop_generic(JSAtom *atom)
|
|||
#elif defined JS_PUNBOX64
|
||||
Label dslotsLoadLabel = masm.label();
|
||||
#endif
|
||||
masm.loadPtr(Address(objReg, offsetof(JSObject, slots)), objReg);
|
||||
masm.loadPtr(Address(objReg, offsetof(JSObject, dslots)), objReg);
|
||||
|
||||
/* Copy the slot value to the expression stack. */
|
||||
Address slot(objReg, 1 << 24);
|
||||
|
@ -2797,7 +2793,7 @@ mjit::Compiler::jsop_callprop_obj(JSAtom *atom)
|
|||
#elif defined JS_PUNBOX64
|
||||
Label dslotsLoadLabel = masm.label();
|
||||
#endif
|
||||
masm.loadPtr(Address(objReg, offsetof(JSObject, slots)), objReg);
|
||||
masm.loadPtr(Address(objReg, offsetof(JSObject, dslots)), objReg);
|
||||
|
||||
/* Copy the slot value to the expression stack. */
|
||||
Address slot(objReg, 1 << 24);
|
||||
|
@ -2966,7 +2962,7 @@ mjit::Compiler::jsop_setprop(JSAtom *atom)
|
|||
#elif defined JS_PUNBOX64
|
||||
Label dslotsLoadLabel = masm.label();
|
||||
#endif
|
||||
masm.loadPtr(Address(objReg, offsetof(JSObject, slots)), objReg);
|
||||
masm.loadPtr(Address(objReg, offsetof(JSObject, dslots)), objReg);
|
||||
|
||||
/* Store RHS into object slot. */
|
||||
Address slot(objReg, 1 << 24);
|
||||
|
@ -3510,7 +3506,8 @@ mjit::Compiler::iter(uintN flags)
|
|||
stubcc.linkExit(nullIterator, Uses(1));
|
||||
|
||||
/* Get NativeIterator from iter obj. :FIXME: X64, also most of this function */
|
||||
masm.loadPtr(Address(ioreg, offsetof(JSObject, privateData)), nireg);
|
||||
Address privSlot(ioreg, offsetof(JSObject, fslots) + sizeof(Value) * JSSLOT_PRIVATE);
|
||||
masm.loadPtr(privSlot, nireg);
|
||||
|
||||
/* Test for active iterator. */
|
||||
Address flagsAddr(nireg, offsetof(NativeIterator, flags));
|
||||
|
@ -3694,7 +3691,8 @@ mjit::Compiler::iterEnd()
|
|||
stubcc.linkExit(notIterator, Uses(1));
|
||||
|
||||
/* Get private from iter obj. :FIXME: X64 */
|
||||
masm.loadPtr(Address(reg, offsetof(JSObject, privateData)), T1);
|
||||
Address privSlot(reg, offsetof(JSObject, fslots) + sizeof(Value) * JSSLOT_PRIVATE);
|
||||
masm.loadPtr(privSlot, T1);
|
||||
|
||||
RegisterID T2 = frame.allocReg();
|
||||
|
||||
|
@ -3808,7 +3806,7 @@ mjit::Compiler::jsop_getgname(uint32 index)
|
|||
/* Garbage value. */
|
||||
uint32 slot = 1 << 24;
|
||||
|
||||
masm.loadPtr(Address(objReg, offsetof(JSObject, slots)), objReg);
|
||||
masm.loadPtr(Address(objReg, offsetof(JSObject, dslots)), objReg);
|
||||
Address address(objReg, slot);
|
||||
|
||||
/*
|
||||
|
@ -3929,7 +3927,7 @@ mjit::Compiler::jsop_setgname(uint32 index)
|
|||
v = fe->getValue();
|
||||
}
|
||||
|
||||
masm.loadPtr(Address(objReg, offsetof(JSObject, slots)), objReg);
|
||||
masm.loadPtr(Address(objReg, offsetof(JSObject, dslots)), objReg);
|
||||
Address address(objReg, slot);
|
||||
|
||||
mic.load = masm.label();
|
||||
|
|
|
@ -1200,21 +1200,26 @@ mjit::Compiler::jsop_setelem()
|
|||
stubcc.linkExit(guardDense, Uses(3));
|
||||
|
||||
/* guard within capacity */
|
||||
Address capacity(objReg, offsetof(JSObject, capacity));
|
||||
Address capacity(objReg, offsetof(JSObject, fslots) +
|
||||
JSObject::JSSLOT_DENSE_ARRAY_CAPACITY * sizeof(Value));
|
||||
|
||||
Jump inRange;
|
||||
MaybeRegisterID maybeIdReg;
|
||||
if (id->isConstant()) {
|
||||
inRange = masm.branch32(Assembler::LessThanOrEqual, capacity,
|
||||
inRange = masm.branch32(Assembler::LessThanOrEqual,
|
||||
masm.payloadOf(capacity),
|
||||
Imm32(id->getValue().toInt32()));
|
||||
} else {
|
||||
maybeIdReg = frame.copyDataIntoReg(id);
|
||||
inRange = masm.branch32(Assembler::AboveOrEqual, maybeIdReg.reg(), capacity);
|
||||
inRange = masm.branch32(Assembler::AboveOrEqual, maybeIdReg.reg(),
|
||||
masm.payloadOf(capacity));
|
||||
}
|
||||
stubcc.linkExit(inRange, Uses(3));
|
||||
|
||||
/* load dslots */
|
||||
masm.loadPtr(Address(objReg, offsetof(JSObject, slots)), objReg);
|
||||
/* dslots non-NULL */
|
||||
masm.loadPtr(Address(objReg, offsetof(JSObject, dslots)), objReg);
|
||||
Jump guardSlots = masm.branchTestPtr(Assembler::Zero, objReg, objReg);
|
||||
stubcc.linkExit(guardSlots, Uses(3));
|
||||
|
||||
/* guard within capacity */
|
||||
if (id->isConstant()) {
|
||||
|
@ -1293,17 +1298,17 @@ mjit::Compiler::jsop_setelem()
|
|||
extendedObject.linkTo(syncTarget, &stubcc.masm);
|
||||
|
||||
/* Update the array length if needed. Don't worry about overflow. */
|
||||
Address arrayLength(baseReg, offsetof(JSObject, privateData));
|
||||
stubcc.masm.load32(arrayLength, T1);
|
||||
Address arrayLength(baseReg, offsetof(JSObject, fslots[JSObject::JSSLOT_ARRAY_LENGTH]));
|
||||
stubcc.masm.loadPayload(arrayLength, T1);
|
||||
Jump underLength = stubcc.masm.branch32(Assembler::LessThan, idReg, T1);
|
||||
stubcc.masm.move(idReg, T1);
|
||||
stubcc.masm.add32(Imm32(1), T1);
|
||||
stubcc.masm.store32(T1, arrayLength);
|
||||
stubcc.masm.storePayload(T1, arrayLength);
|
||||
underLength.linkTo(stubcc.masm.label(), &stubcc.masm);
|
||||
|
||||
/* Restore the dslots register if we clobbered it with the object. */
|
||||
if (baseReg == objReg)
|
||||
stubcc.masm.loadPtr(Address(objReg, offsetof(JSObject, slots)), objReg);
|
||||
stubcc.masm.loadPtr(Address(objReg, offsetof(JSObject, dslots)), objReg);
|
||||
|
||||
/* Rejoin OOL path with inline path to do the store itself. */
|
||||
Jump jmpHoleExit = stubcc.masm.jump();
|
||||
|
@ -1349,17 +1354,22 @@ mjit::Compiler::jsop_getelem_dense(FrameEntry *obj, FrameEntry *id, RegisterID o
|
|||
|
||||
/* Guard within capacity. */
|
||||
Jump inRange;
|
||||
Address capacity(objReg, offsetof(JSObject, capacity));
|
||||
Address capacity(objReg, offsetof(JSObject, fslots) +
|
||||
JSObject::JSSLOT_DENSE_ARRAY_CAPACITY * sizeof(Value));
|
||||
if (id->isConstant()) {
|
||||
inRange = masm.branch32(Assembler::LessThanOrEqual, capacity,
|
||||
inRange = masm.branch32(Assembler::LessThanOrEqual,
|
||||
masm.payloadOf(capacity),
|
||||
Imm32(id->getValue().toInt32()));
|
||||
} else {
|
||||
inRange = masm.branch32(Assembler::AboveOrEqual, idReg.reg(), capacity);
|
||||
inRange = masm.branch32(Assembler::AboveOrEqual, idReg.reg(),
|
||||
masm.payloadOf(capacity));
|
||||
}
|
||||
stubcc.linkExit(inRange, Uses(2));
|
||||
|
||||
/* load dslots */
|
||||
masm.loadPtr(Address(objReg, offsetof(JSObject, slots)), objReg);
|
||||
/* dslots non-NULL */
|
||||
masm.loadPtr(Address(objReg, offsetof(JSObject, dslots)), objReg);
|
||||
Jump guardSlots = masm.branchTestPtr(Assembler::Zero, objReg, objReg);
|
||||
stubcc.linkExit(guardSlots, Uses(2));
|
||||
|
||||
/* guard within capacity */
|
||||
if (id->isConstant()) {
|
||||
|
|
|
@ -237,8 +237,7 @@ stubs::NewObject(VMFrame &f, uint32 argc)
|
|||
THROWV(JS_FALSE);
|
||||
|
||||
JSObject *proto = vp[1].isObject() ? &vp[1].toObject() : NULL;
|
||||
JSObject *obj = NewNonFunction<WithProto::Class>(cx, &js_ObjectClass, proto, funobj->getParent(),
|
||||
FINALIZE_OBJECT4);
|
||||
JSObject *obj = NewNonFunction<WithProto::Class>(cx, &js_ObjectClass, proto, funobj->getParent());
|
||||
if (!obj)
|
||||
THROWV(JS_FALSE);
|
||||
|
||||
|
|
|
@ -109,6 +109,8 @@ ic::GetGlobalName(VMFrame &f, uint32 index)
|
|||
repatch.repatch(mic.shape, obj->shape());
|
||||
|
||||
/* Patch loads. */
|
||||
JS_ASSERT(slot >= JS_INITIAL_NSLOTS);
|
||||
slot -= JS_INITIAL_NSLOTS;
|
||||
slot *= sizeof(Value);
|
||||
JSC::RepatchBuffer loads(mic.load.executableAddress(), 32, false);
|
||||
#if defined JS_CPU_X86
|
||||
|
@ -189,6 +191,8 @@ ic::SetGlobalName(VMFrame &f, uint32 index)
|
|||
repatch.repatch(mic.shape, obj->shape());
|
||||
|
||||
/* Patch loads. */
|
||||
JS_ASSERT(slot >= JS_INITIAL_NSLOTS);
|
||||
slot -= JS_INITIAL_NSLOTS;
|
||||
slot *= sizeof(Value);
|
||||
|
||||
JSC::RepatchBuffer stores(mic.load.executableAddress(), 32, false);
|
||||
|
|
|
@ -89,14 +89,13 @@ class Assembler : public BaseAssembler
|
|||
return BaseIndex(address.base, address.index, address.scale, address.offset + TAG_OFFSET);
|
||||
}
|
||||
|
||||
void loadSlot(RegisterID obj, RegisterID clobber, uint32 slot, bool inlineAccess,
|
||||
RegisterID type, RegisterID data) {
|
||||
void loadSlot(RegisterID obj, RegisterID clobber, uint32 slot, RegisterID type, RegisterID data) {
|
||||
JS_ASSERT(type != data);
|
||||
Address address(obj, offsetof(JSObject, fixedSlots) + slot * sizeof(Value));
|
||||
Address address(obj, offsetof(JSObject, fslots) + slot * sizeof(Value));
|
||||
RegisterID activeAddressReg = obj;
|
||||
if (!inlineAccess) {
|
||||
loadPtr(Address(obj, offsetof(JSObject, slots)), clobber);
|
||||
address = Address(clobber, slot * sizeof(Value));
|
||||
if (slot >= JS_INITIAL_NSLOTS) {
|
||||
loadPtr(Address(obj, offsetof(JSObject, dslots)), clobber);
|
||||
address = Address(clobber, (slot - JS_INITIAL_NSLOTS) * sizeof(Value));
|
||||
activeAddressReg = clobber;
|
||||
}
|
||||
if (activeAddressReg == type) {
|
||||
|
@ -205,8 +204,9 @@ class Assembler : public BaseAssembler
|
|||
}
|
||||
|
||||
void loadFunctionPrivate(RegisterID base, RegisterID to) {
|
||||
Address priv(base, offsetof(JSObject, privateData));
|
||||
loadPtr(priv, to);
|
||||
Address privSlot(base, offsetof(JSObject, fslots) +
|
||||
JSSLOT_PRIVATE * sizeof(Value));
|
||||
loadPtr(privSlot, to);
|
||||
}
|
||||
|
||||
Jump testNull(Assembler::Condition cond, RegisterID reg) {
|
||||
|
|
|
@ -253,7 +253,7 @@ class SetPropCompiler : public PICStubCompiler
|
|||
repatcher.relinkCallerToTrampoline(retPtr, target);
|
||||
}
|
||||
|
||||
bool patchInline(const Shape *shape, bool inlineSlot)
|
||||
bool patchInline(const Shape *shape)
|
||||
{
|
||||
JS_ASSERT(!pic.inlinePathPatched);
|
||||
JaegerSpew(JSpew_PICs, "patch setprop inline at %p\n", pic.fastPathStart.executableAddress());
|
||||
|
@ -261,7 +261,7 @@ class SetPropCompiler : public PICStubCompiler
|
|||
PICRepatchBuffer repatcher(pic, pic.fastPathStart);
|
||||
|
||||
int32 offset;
|
||||
if (inlineSlot) {
|
||||
if (shape->slot < JS_INITIAL_NSLOTS) {
|
||||
JSC::CodeLocationInstruction istr;
|
||||
istr = pic.storeBack.instructionAtOffset(dslotsLoadOffset());
|
||||
repatcher.repatchLoadPtrToLEA(istr);
|
||||
|
@ -273,12 +273,12 @@ class SetPropCompiler : public PICStubCompiler
|
|||
// Because the offset is wrong, it's necessary to correct it
|
||||
// below.
|
||||
//
|
||||
int32 diff = int32(offsetof(JSObject, fixedSlots)) -
|
||||
int32(offsetof(JSObject, slots));
|
||||
int32 diff = int32(offsetof(JSObject, fslots)) -
|
||||
int32(offsetof(JSObject, dslots));
|
||||
JS_ASSERT(diff != 0);
|
||||
offset = (int32(shape->slot) * sizeof(Value)) + diff;
|
||||
} else {
|
||||
offset = shape->slot * sizeof(Value);
|
||||
offset = (shape->slot - JS_INITIAL_NSLOTS) * sizeof(Value);
|
||||
}
|
||||
|
||||
uint32 shapeOffs = pic.shapeGuard + inlineShapeOffset();
|
||||
|
@ -326,7 +326,7 @@ class SetPropCompiler : public PICStubCompiler
|
|||
}
|
||||
}
|
||||
|
||||
bool generateStub(uint32 initialShape, const Shape *shape, bool adding, bool inlineSlot)
|
||||
bool generateStub(uint32 initialShape, const Shape *shape, bool adding)
|
||||
{
|
||||
/* Exits to the slow path. */
|
||||
Vector<Jump, 8> slowExits(f.cx);
|
||||
|
@ -406,21 +406,28 @@ class SetPropCompiler : public PICStubCompiler
|
|||
}
|
||||
}
|
||||
|
||||
if (inlineSlot) {
|
||||
if (shape->slot < JS_INITIAL_NSLOTS) {
|
||||
Address address(pic.objReg,
|
||||
offsetof(JSObject, fixedSlots) + shape->slot * sizeof(Value));
|
||||
offsetof(JSObject, fslots) + shape->slot * sizeof(Value));
|
||||
emitStore(masm, address);
|
||||
} else {
|
||||
/* Check dslots non-zero. */
|
||||
masm.loadPtr(Address(pic.objReg, offsetof(JSObject, dslots)), pic.shapeReg);
|
||||
Jump emptyDslots = masm.branchPtr(Assembler::Equal, pic.shapeReg, ImmPtr(0));
|
||||
if (!slowExits.append(emptyDslots))
|
||||
return false;
|
||||
|
||||
/* Check capacity. */
|
||||
Address capacity(pic.objReg, offsetof(JSObject, capacity));
|
||||
Address capacity(pic.shapeReg, -ptrdiff_t(sizeof(Value)));
|
||||
masm.load32(masm.payloadOf(capacity), pic.shapeReg);
|
||||
Jump overCapacity = masm.branch32(Assembler::LessThanOrEqual, pic.shapeReg,
|
||||
Imm32(shape->slot));
|
||||
if (!slowExits.append(overCapacity))
|
||||
return false;
|
||||
|
||||
masm.loadPtr(Address(pic.objReg, offsetof(JSObject, slots)), pic.shapeReg);
|
||||
Address address(pic.shapeReg, shape->slot * sizeof(Value));
|
||||
masm.loadPtr(Address(pic.objReg, offsetof(JSObject, dslots)), pic.shapeReg);
|
||||
Address address(pic.shapeReg,
|
||||
(shape->slot - JS_INITIAL_NSLOTS) * sizeof(Value));
|
||||
emitStore(masm, address);
|
||||
}
|
||||
|
||||
|
@ -441,10 +448,10 @@ class SetPropCompiler : public PICStubCompiler
|
|||
masm.store32(pic.shapeReg, flags);
|
||||
}
|
||||
} else if (shape->hasDefaultSetter()) {
|
||||
Address address(pic.objReg, offsetof(JSObject, fixedSlots) + shape->slot * sizeof(Value));
|
||||
if (!inlineSlot) {
|
||||
masm.loadPtr(Address(pic.objReg, offsetof(JSObject, slots)), pic.objReg);
|
||||
address = Address(pic.objReg, shape->slot * sizeof(Value));
|
||||
Address address(pic.objReg, offsetof(JSObject, fslots) + shape->slot * sizeof(Value));
|
||||
if (shape->slot >= JS_INITIAL_NSLOTS) {
|
||||
masm.loadPtr(Address(pic.objReg, offsetof(JSObject, dslots)), pic.objReg);
|
||||
address = Address(pic.objReg, (shape->slot - JS_INITIAL_NSLOTS) * sizeof(Value));
|
||||
}
|
||||
|
||||
// If the scope is branded, or has a method barrier. It's now necessary
|
||||
|
@ -486,9 +493,9 @@ class SetPropCompiler : public PICStubCompiler
|
|||
{
|
||||
if (shape->setterOp() == SetCallVar)
|
||||
slot += fun->nargs;
|
||||
masm.loadPtr(Address(pic.objReg, offsetof(JSObject, slots)), pic.objReg);
|
||||
masm.loadPtr(Address(pic.objReg, offsetof(JSObject, dslots)), pic.objReg);
|
||||
|
||||
Address dslot(pic.objReg, (slot + JSObject::CALL_RESERVED_SLOTS) * sizeof(Value));
|
||||
Address dslot(pic.objReg, slot * sizeof(Value));
|
||||
emitStore(masm, dslot);
|
||||
}
|
||||
|
||||
|
@ -668,7 +675,7 @@ class SetPropCompiler : public PICStubCompiler
|
|||
if (obj->numSlots() != slots)
|
||||
return disable("insufficient slot capacity");
|
||||
|
||||
return generateStub(initialShape, shape, true, !obj->hasSlotsArray());
|
||||
return generateStub(initialShape, shape, true);
|
||||
}
|
||||
|
||||
AutoPropertyDropper dropper(f.cx, holder, prop);
|
||||
|
@ -696,10 +703,10 @@ class SetPropCompiler : public PICStubCompiler
|
|||
!obj->brandedOrHasMethodBarrier() &&
|
||||
shape->hasDefaultSetter() &&
|
||||
!obj->isDenseArray()) {
|
||||
return patchInline(shape, !obj->hasSlotsArray());
|
||||
return patchInline(shape);
|
||||
}
|
||||
|
||||
return generateStub(obj->shape(), shape, false, !obj->hasSlotsArray());
|
||||
return generateStub(obj->shape(), shape, false);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -803,8 +810,9 @@ class GetPropCompiler : public PICStubCompiler
|
|||
Address clasp(pic.objReg, offsetof(JSObject, clasp));
|
||||
Jump notArgs = masm.branchPtr(Assembler::NotEqual, clasp, ImmPtr(obj->getClass()));
|
||||
|
||||
masm.loadPtr(Address(pic.objReg, offsetof(JSObject, slots)), pic.objReg);
|
||||
masm.load32(Address(pic.objReg, JSObject::JSSLOT_ARGS_LENGTH * sizeof(Value)),
|
||||
masm.load32(Address(pic.objReg,
|
||||
offsetof(JSObject, fslots)
|
||||
+ JSObject::JSSLOT_ARGS_LENGTH * sizeof(Value)),
|
||||
pic.objReg);
|
||||
masm.move(pic.objReg, pic.shapeReg);
|
||||
Jump overridden = masm.branchTest32(Assembler::NonZero, pic.shapeReg, Imm32(1));
|
||||
|
@ -848,7 +856,10 @@ class GetPropCompiler : public PICStubCompiler
|
|||
ImmPtr(&js_SlowArrayClass));
|
||||
|
||||
isDense.linkTo(masm.label(), &masm);
|
||||
masm.load32(Address(pic.objReg, offsetof(JSObject, privateData)), pic.objReg);
|
||||
masm.load32(Address(pic.objReg,
|
||||
offsetof(JSObject, fslots)
|
||||
+ JSObject::JSSLOT_ARRAY_LENGTH * sizeof(Value)),
|
||||
pic.objReg);
|
||||
Jump oob = masm.branch32(Assembler::Above, pic.objReg, Imm32(JSVAL_INT_MAX));
|
||||
masm.move(ImmType(JSVAL_TYPE_INT32), pic.shapeReg);
|
||||
Jump done = masm.jump();
|
||||
|
@ -933,8 +944,7 @@ class GetPropCompiler : public PICStubCompiler
|
|||
masm.loadShape(pic.objReg, pic.shapeReg);
|
||||
Jump shapeMismatch = masm.branch32(Assembler::NotEqual, pic.shapeReg,
|
||||
Imm32(obj->shape()));
|
||||
masm.loadSlot(pic.objReg, pic.objReg, shape->slot, !obj->hasSlotsArray(),
|
||||
pic.shapeReg, pic.objReg);
|
||||
masm.loadSlot(pic.objReg, pic.objReg, shape->slot, pic.shapeReg, pic.objReg);
|
||||
|
||||
Jump done = masm.jump();
|
||||
|
||||
|
@ -1013,7 +1023,7 @@ class GetPropCompiler : public PICStubCompiler
|
|||
PICRepatchBuffer repatcher(pic, pic.fastPathStart);
|
||||
|
||||
int32 offset;
|
||||
if (!holder->hasSlotsArray()) {
|
||||
if (shape->slot < JS_INITIAL_NSLOTS) {
|
||||
JSC::CodeLocationInstruction istr;
|
||||
istr = pic.storeBack.instructionAtOffset(dslotsLoad());
|
||||
repatcher.repatchLoadPtrToLEA(istr);
|
||||
|
@ -1025,12 +1035,12 @@ class GetPropCompiler : public PICStubCompiler
|
|||
// Because the offset is wrong, it's necessary to correct it
|
||||
// below.
|
||||
//
|
||||
int32 diff = int32(offsetof(JSObject, fixedSlots)) -
|
||||
int32(offsetof(JSObject, slots));
|
||||
int32 diff = int32(offsetof(JSObject, fslots)) -
|
||||
int32(offsetof(JSObject, dslots));
|
||||
JS_ASSERT(diff != 0);
|
||||
offset = (int32(shape->slot) * sizeof(Value)) + diff;
|
||||
} else {
|
||||
offset = shape->slot * sizeof(Value);
|
||||
offset = (shape->slot - JS_INITIAL_NSLOTS) * sizeof(Value);
|
||||
}
|
||||
|
||||
uint32 shapeOffs = pic.shapeGuard + inlineShapeOffset();
|
||||
|
@ -1136,8 +1146,7 @@ class GetPropCompiler : public PICStubCompiler
|
|||
}
|
||||
|
||||
/* Load the value out of the object. */
|
||||
masm.loadSlot(pic.objReg, pic.objReg, shape->slot, !holder->hasSlotsArray(),
|
||||
pic.shapeReg, pic.objReg);
|
||||
masm.loadSlot(pic.objReg, pic.objReg, shape->slot, pic.shapeReg, pic.objReg);
|
||||
Jump done = masm.jump();
|
||||
|
||||
JSC::ExecutablePool *ep = getExecPool(masm.size());
|
||||
|
@ -1349,7 +1358,7 @@ class GetElemCompiler : public PICStubCompiler
|
|||
PICRepatchBuffer repatcher(pic, pic.fastPathStart);
|
||||
|
||||
int32 offset;
|
||||
if (!holder->hasSlotsArray()) {
|
||||
if (shape->slot < JS_INITIAL_NSLOTS) {
|
||||
JSC::CodeLocationInstruction istr = pic.storeBack.instructionAtOffset(dslotsLoad());
|
||||
repatcher.repatchLoadPtrToLEA(istr);
|
||||
|
||||
|
@ -1360,11 +1369,11 @@ class GetElemCompiler : public PICStubCompiler
|
|||
// Because the offset is wrong, it's necessary to correct it
|
||||
// below.
|
||||
//
|
||||
int32 diff = int32(offsetof(JSObject, fixedSlots)) - int32(offsetof(JSObject, slots));
|
||||
int32 diff = int32(offsetof(JSObject, fslots)) - int32(offsetof(JSObject, dslots));
|
||||
JS_ASSERT(diff != 0);
|
||||
offset = (int32(shape->slot) * sizeof(Value)) + diff;
|
||||
} else {
|
||||
offset = shape->slot * sizeof(Value);
|
||||
offset = (shape->slot - JS_INITIAL_NSLOTS) * sizeof(Value);
|
||||
}
|
||||
|
||||
uint32 shapeOffset = pic.shapeGuard + inlineShapeOffset();
|
||||
|
@ -1493,8 +1502,7 @@ class GetElemCompiler : public PICStubCompiler
|
|||
}
|
||||
|
||||
/* Load the value out of the object. */
|
||||
masm.loadSlot(pic.objReg, pic.objReg, shape->slot, !holder->hasSlotsArray(),
|
||||
pic.shapeReg, pic.objReg);
|
||||
masm.loadSlot(pic.objReg, pic.objReg, shape->slot, pic.shapeReg, pic.objReg);
|
||||
Jump done = masm.jump();
|
||||
|
||||
JSC::ExecutablePool *ep = getExecPool(masm.size());
|
||||
|
@ -1683,7 +1691,7 @@ class ScopeNameCompiler : public PICStubCompiler
|
|||
masm.loadShape(pic.objReg, pic.shapeReg);
|
||||
Jump finalShape = masm.branch32(Assembler::NotEqual, pic.shapeReg, Imm32(holder->shape()));
|
||||
|
||||
masm.loadSlot(pic.objReg, pic.objReg, shape->slot, false, pic.shapeReg, pic.objReg);
|
||||
masm.loadSlot(pic.objReg, pic.objReg, shape->slot, pic.shapeReg, pic.objReg);
|
||||
|
||||
Jump done = masm.jump();
|
||||
|
||||
|
@ -1786,11 +1794,11 @@ class ScopeNameCompiler : public PICStubCompiler
|
|||
escapedFrame.linkTo(masm.label(), &masm);
|
||||
|
||||
{
|
||||
masm.loadPtr(Address(pic.objReg, offsetof(JSObject, slots)), pic.objReg);
|
||||
masm.loadPtr(Address(pic.objReg, offsetof(JSObject, dslots)), pic.objReg);
|
||||
|
||||
if (kind == VAR)
|
||||
slot += fun->nargs;
|
||||
Address dslot(pic.objReg, (slot + JSObject::CALL_RESERVED_SLOTS) * sizeof(Value));
|
||||
Address dslot(pic.objReg, slot * sizeof(Value));
|
||||
|
||||
/* Safe because type is loaded first. */
|
||||
masm.loadValueAsComponents(dslot, pic.shapeReg, pic.objReg);
|
||||
|
|
|
@ -93,13 +93,12 @@ class Assembler : public BaseAssembler
|
|||
return address;
|
||||
}
|
||||
|
||||
void loadSlot(RegisterID obj, RegisterID clobber, uint32 slot, bool inlineAccess,
|
||||
RegisterID type, RegisterID data) {
|
||||
void loadSlot(RegisterID obj, RegisterID clobber, uint32 slot, RegisterID type, RegisterID data) {
|
||||
JS_ASSERT(type != data);
|
||||
Address address(obj, offsetof(JSObject, fixedSlots) + slot * sizeof(Value));
|
||||
if (!inlineAccess) {
|
||||
loadPtr(Address(obj, offsetof(JSObject, slots)), clobber);
|
||||
address = Address(clobber, slot * sizeof(Value));
|
||||
Address address(obj, offsetof(JSObject, fslots) + slot * sizeof(Value));
|
||||
if (slot >= JS_INITIAL_NSLOTS) {
|
||||
loadPtr(Address(obj, offsetof(JSObject, dslots)), clobber);
|
||||
address = Address(clobber, (slot - JS_INITIAL_NSLOTS) * sizeof(Value));
|
||||
}
|
||||
|
||||
loadValueAsComponents(address, type, data);
|
||||
|
@ -247,8 +246,9 @@ class Assembler : public BaseAssembler
|
|||
}
|
||||
|
||||
void loadFunctionPrivate(RegisterID base, RegisterID to) {
|
||||
Address priv(base, offsetof(JSObject, privateData));
|
||||
loadPtr(priv, to);
|
||||
Address privSlot(base, offsetof(JSObject, fslots) +
|
||||
JSSLOT_PRIVATE * sizeof(Value));
|
||||
loadPtr(privSlot, to);
|
||||
}
|
||||
|
||||
Jump testNull(Assembler::Condition cond, RegisterID reg) {
|
||||
|
|
|
@ -1432,25 +1432,21 @@ stubs::Neg(VMFrame &f)
|
|||
}
|
||||
|
||||
JSObject * JS_FASTCALL
|
||||
stubs::NewInitArray(VMFrame &f, uint32 count)
|
||||
stubs::NewInitArray(VMFrame &f)
|
||||
{
|
||||
JSContext *cx = f.cx;
|
||||
JSFinalizeGCThingKind kind = GuessObjectGCKind(count);
|
||||
|
||||
JSObject *obj = NewArrayWithKind(cx, kind);
|
||||
if (!obj || !obj->ensureSlots(cx, count))
|
||||
JSObject *obj = js_NewArrayObject(f.cx, 0, NULL);
|
||||
if (!obj)
|
||||
THROWV(NULL);
|
||||
return obj;
|
||||
}
|
||||
|
||||
JSObject * JS_FASTCALL
|
||||
stubs::NewInitObject(VMFrame &f, uint32 count)
|
||||
stubs::NewInitObject(VMFrame &f)
|
||||
{
|
||||
JSContext *cx = f.cx;
|
||||
JSFinalizeGCThingKind kind = GuessObjectGCKind(count);
|
||||
|
||||
JSObject *obj = NewBuiltinClassInstance(cx, &js_ObjectClass, kind);
|
||||
if (!obj || !obj->ensureSlots(cx, count))
|
||||
JSObject *obj = NewBuiltinClassInstance(cx, &js_ObjectClass);
|
||||
if (!obj)
|
||||
THROWV(NULL);
|
||||
|
||||
return obj;
|
||||
|
|
|
@ -49,8 +49,8 @@ namespace stubs {
|
|||
|
||||
void JS_FASTCALL This(VMFrame &f);
|
||||
void JS_FASTCALL ComputeThis(VMFrame &f);
|
||||
JSObject * JS_FASTCALL NewInitArray(VMFrame &f, uint32 count);
|
||||
JSObject * JS_FASTCALL NewInitObject(VMFrame &f, uint32 count);
|
||||
JSObject * JS_FASTCALL NewInitArray(VMFrame &f);
|
||||
JSObject * JS_FASTCALL NewInitObject(VMFrame &f);
|
||||
JSObject * JS_FASTCALL NewArray(VMFrame &f, uint32 len);
|
||||
void JS_FASTCALL Trap(VMFrame &f, jsbytecode *pc);
|
||||
void JS_FASTCALL Debugger(VMFrame &f, jsbytecode *pc);
|
||||
|
|
|
@ -8,8 +8,7 @@ function f(i) {
|
|||
return 1;
|
||||
}
|
||||
|
||||
/* trailing 'true' ensures array has capacity >= 10 */
|
||||
var arr = [ false, false, false, false, false, , , , , , true ];
|
||||
var arr = [ false, false, false, false, false, , , , ];
|
||||
|
||||
for (var i = 0; i < 10; ++i) {
|
||||
(s = arr[i]) + f(i);
|
||||
|
|
|
@ -6,5 +6,5 @@ function caller(obj) {
|
|||
var x = ({ dana : "zuul" });
|
||||
return x;
|
||||
}
|
||||
trap(caller, 23, "x = 'success'; nop()");
|
||||
trap(caller, 20, "x = 'success'; nop()");
|
||||
assertEq(caller(this), "success");
|
||||
|
|
|
@ -1373,10 +1373,10 @@ DebugCheckWrapperClass(JSObject* obj)
|
|||
// Only use these macros if IS_WRAPPER_CLASS(obj->getClass()) is true.
|
||||
#define IS_WN_WRAPPER_OBJECT(obj) \
|
||||
(DebugCheckWrapperClass(obj) && \
|
||||
obj->getSlot(0).isUndefined())
|
||||
obj->getSlot(JSSLOT_START(obj->getClass())).isUndefined())
|
||||
#define IS_SLIM_WRAPPER_OBJECT(obj) \
|
||||
(DebugCheckWrapperClass(obj) && \
|
||||
!obj->getSlot(0).isUndefined())
|
||||
!obj->getSlot(JSSLOT_START(obj->getClass())).isUndefined())
|
||||
|
||||
// Use these macros if IS_WRAPPER_CLASS(obj->getClass()) might be false.
|
||||
// Avoid calling them if IS_WRAPPER_CLASS(obj->getClass()) can only be
|
||||
|
@ -2284,7 +2284,7 @@ extern JSBool MorphSlimWrapper(JSContext *cx, JSObject *obj);
|
|||
static inline XPCWrappedNativeProto*
|
||||
GetSlimWrapperProto(JSObject *obj)
|
||||
{
|
||||
const js::Value &v = obj->getSlot(0);
|
||||
const js::Value &v = obj->getSlot(JSSLOT_START(obj->getClass()));
|
||||
return static_cast<XPCWrappedNativeProto*>(v.toPrivate());
|
||||
}
|
||||
|
||||
|
|
|
@ -52,7 +52,7 @@ namespace xpc {
|
|||
|
||||
using namespace js;
|
||||
|
||||
static const uint32 JSSLOT_WN_OBJ = 0;
|
||||
static const uint32 JSSLOT_WN_OBJ = JSSLOT_PRIVATE;
|
||||
|
||||
static JSBool
|
||||
holder_get(JSContext *cx, JSObject *holder, jsid id, jsval *vp);
|
||||
|
|
Загрузка…
Ссылка в новой задаче