Flexible length JSObject, bug 584917. r=brendan,igor

This commit is contained in:
Brian Hackett 2010-10-13 11:49:22 -07:00
Родитель 31725d8b36
Коммит b6bbf1729a
48 изменённых файлов: 1286 добавлений и 1367 удалений

Просмотреть файл

@ -52,7 +52,7 @@ bool checkObjectFields(JSObject *savedCopy, JSObject *obj)
* doing memcmp.
*/
savedCopy->objShape = obj->objShape;
savedCopy->dslots = obj->dslots;
savedCopy->slots = obj->slots;
CHECK(!memcmp(savedCopy, obj, sizeof(*obj)));
return true;
}

Просмотреть файл

@ -1246,7 +1246,8 @@ JS_TransplantWrapper(JSContext *cx, JSObject *wrapper, JSObject *target)
// If the wrapper is in the same compartment as the destination, then
// we know that we won't find wrapper in the destination's cross
// compartment map and that the same object will continue to work.
wrapper->swap(target);
if (!wrapper->swap(cx, target))
return NULL;
return wrapper;
}
@ -1261,7 +1262,8 @@ JS_TransplantWrapper(JSContext *cx, JSObject *wrapper, JSObject *target)
// possibly security wrapper, innards).
obj = &p->value.toObject();
map.remove(p);
obj->swap(target);
if (!obj->swap(cx, target))
return NULL;
} else {
// Otherwise, this is going to be our outer window proxy in the new
// compartment.
@ -1297,7 +1299,8 @@ JS_TransplantWrapper(JSContext *cx, JSObject *wrapper, JSObject *target)
// entry in the compartment's wrapper map to point to the old
// wrapper.
JS_ASSERT(tobj != wobj);
wobj->swap(tobj);
if (!wobj->swap(cx, tobj))
return NULL;
pmap.put(targetv, ObjectValue(*wobj));
}
}
@ -1308,7 +1311,8 @@ JS_TransplantWrapper(JSContext *cx, JSObject *wrapper, JSObject *target)
JSObject *tobj = obj;
if (!ac.enter(cx, wrapper) || !JS_WrapObject(cx, &tobj))
return NULL;
wrapper->swap(tobj);
if (!wrapper->swap(cx, tobj))
return NULL;
wrapper->getCompartment()->crossCompartmentWrappers.put(targetv, wrapperv);
}
@ -3107,8 +3111,6 @@ JS_DeepFreezeObject(JSContext *cx, JSObject *obj)
/* 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_DeepFreezeObject(cx, &v.toObject()))
@ -3908,8 +3910,7 @@ 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 = JSSLOT_PRIVATE + 1;
JS_STATIC_ASSERT(JSSLOT_ITER_INDEX < JS_INITIAL_NSLOTS);
const uint32 JSSLOT_ITER_INDEX = 0;
static void
prop_iter_finalize(JSContext *cx, JSObject *obj)
@ -3918,7 +3919,7 @@ prop_iter_finalize(JSContext *cx, JSObject *obj)
if (!pdata)
return;
if (obj->fslots[JSSLOT_ITER_INDEX].toInt32() >= 0) {
if (obj->getSlot(JSSLOT_ITER_INDEX).toInt32() >= 0) {
/* Non-native case: destroy the ida enumerated when obj was created. */
JSIdArray *ida = (JSIdArray *) pdata;
JS_DestroyIdArray(cx, ida);
@ -3932,7 +3933,7 @@ prop_iter_trace(JSTracer *trc, JSObject *obj)
if (!pdata)
return;
if (obj->fslots[JSSLOT_ITER_INDEX].toInt32() < 0) {
if (obj->getSlot(JSSLOT_ITER_INDEX).toInt32() < 0) {
/* Native case: just mark the next property to visit. */
((Shape *) pdata)->trace(trc);
} else {
@ -3998,7 +3999,7 @@ JS_NewPropertyIterator(JSContext *cx, JSObject *obj)
/* iterobj cannot escape to other threads here. */
iterobj->setPrivate(const_cast<void *>(pdata));
iterobj->fslots[JSSLOT_ITER_INDEX].setInt32(index);
iterobj->getSlotRef(JSSLOT_ITER_INDEX).setInt32(index);
return iterobj;
}
@ -4012,7 +4013,7 @@ JS_NextProperty(JSContext *cx, JSObject *iterobj, jsid *idp)
CHECK_REQUEST(cx);
assertSameCompartment(cx, iterobj);
i = iterobj->fslots[JSSLOT_ITER_INDEX].toInt32();
i = iterobj->getSlot(JSSLOT_ITER_INDEX).toInt32();
if (i < 0) {
/* Native case: private data is a property tree node pointer. */
obj = iterobj->getParent();

Просмотреть файл

@ -312,109 +312,6 @@ 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)
{
@ -542,8 +439,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);
return obj->ensureDenseArrayElements(cx, u + 1);
}
JS_DEFINE_CALLINFO_3(extern, BOOL, js_EnsureDenseArrayCapacity, CONTEXT, OBJECT, INT32, 0,
nanojit::ACCSET_STORE_ANY)
@ -672,13 +569,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, resizeDenseArrayElements will fill all slots to the
* shrink slots here, ensureDenseArrayElements 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))
return false;
if (oldcap > newlen)
obj->shrinkDenseArrayElements(cx, newlen);
obj->setArrayLength(newlen);
} else if (oldlen - newlen < (1 << 24)) {
do {
@ -986,20 +883,11 @@ 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++) {
@ -1040,7 +928,7 @@ array_fix(JSContext *cx, JSObject *obj, bool *success, AutoIdVector *props)
Class js_ArrayClass = {
"Array",
Class::NON_NATIVE |
JSCLASS_HAS_RESERVED_SLOTS(JSObject::DENSE_ARRAY_CLASS_RESERVED_SLOTS) |
JSCLASS_HAS_PRIVATE |
JSCLASS_HAS_CACHED_PROTO(JSProto_Array),
PropertyStub, /* addProperty */
PropertyStub, /* delProperty */
@ -1049,7 +937,7 @@ Class js_ArrayClass = {
EnumerateStub,
ResolveStub,
js_TryValueOf,
array_finalize,
NULL,
NULL, /* reserved0 */
NULL, /* checkAccess */
NULL, /* call */
@ -1134,26 +1022,18 @@ JSObject::makeDenseArraySlow(JSContext *cx)
* the same initial shape.
*/
JSObject *arrayProto = getProto();
if (!InitScopeForObject(cx, this, &js_SlowArrayClass, arrayProto))
if (!InitScopeForObject(cx, this, &js_SlowArrayClass, arrayProto, FINALIZE_OBJECT0))
return false;
uint32 capacity;
uint32 capacity = getDenseArrayCapacity();
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. */
/*
* 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 (!addProperty(cx, ATOM_TO_JSID(cx->runtime->atomState.lengthAtom),
array_length_getter, NULL,
JSSLOT_ARRAY_LENGTH, JSPROP_PERMANENT | JSPROP_SHARED, 0, 0)) {
SHAPE_INVALID_SLOT, JSPROP_PERMANENT | JSPROP_SHARED, 0, 0)) {
setMap(oldMap);
return false;
}
@ -1171,24 +1051,12 @@ JSObject::makeDenseArraySlow(JSContext *cx)
continue;
}
/* 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)) {
if (!addDataProperty(cx, id, 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
@ -1530,7 +1398,6 @@ 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))
@ -2488,10 +2355,8 @@ 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
* 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.
* the normal case where length is <= capacity, nobj and aobj will have
* the same capacity.
*/
length = aobj->getArrayLength();
jsuint capacity = aobj->getDenseArrayCapacity();
@ -3000,10 +2865,12 @@ static JSFunctionSpec array_static_methods[] = {
JS_FS_END
};
/* The count here is a guess for the final capacity. */
static inline JSObject *
NewDenseArrayObject(JSContext *cx)
NewDenseArrayObject(JSContext *cx, jsuint count)
{
return NewNonFunction<WithProto::Class>(cx, &js_ArrayClass, NULL, NULL);
gc::FinalizeKind kind = GuessObjectGCKind(count, true);
return NewNonFunction<WithProto::Class>(cx, &js_ArrayClass, NULL, NULL, kind);
}
JSBool
@ -3012,12 +2879,6 @@ 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;
@ -3034,6 +2895,12 @@ 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);
}
@ -3045,15 +2912,15 @@ js_NewEmptyArray(JSContext* cx, JSObject* proto, int32 len)
JS_ASSERT(proto->isArray());
JSObject* obj = js_NewGCObject(cx);
gc::FinalizeKind kind = GuessObjectGCKind(len, true);
JSObject* obj = js_NewGCObject(cx, kind);
if (!obj)
return NULL;
/* Initialize all fields, calling init before setting obj->map. */
obj->init(&js_ArrayClass, proto, proto->getParent(), NullValue(), cx);
/* Initialize all fields of JSObject. */
obj->init(cx, &js_ArrayClass, proto, proto->getParent(),
(void*) len, true);
obj->setSharedNonNativeMap();
obj->setArrayLength(len);
obj->setDenseArrayCapacity(0);
return obj;
}
#ifdef JS_TRACER
@ -3067,7 +2934,7 @@ js_NewPreallocatedArray(JSContext* cx, JSObject* proto, int32 len)
JSObject *obj = js_NewEmptyArray(cx, proto, len);
if (!obj)
return NULL;
if (!obj->growDenseArrayElements(cx, 0, JS_MAX(len, ARRAY_CAPACITY_MIN)))
if (!obj->ensureDenseArrayElements(cx, len))
return NULL;
return obj;
}
@ -3076,6 +2943,17 @@ JS_DEFINE_CALLINFO_3(extern, OBJECT, js_NewPreallocatedArray, CONTEXT, OBJECT, I
0, nanojit::ACCSET_STORE_ANY)
#endif
JSObject* JS_FASTCALL
js_InitializerArray(JSContext* cx, int32 count)
{
gc::FinalizeKind kind = GuessObjectGCKind(count, true);
return NewArrayWithKind(cx, kind);
}
#ifdef JS_TRACER
JS_DEFINE_CALLINFO_2(extern, OBJECT, js_InitializerArray, CONTEXT, INT32, 0,
nanojit::ACCSET_STORE_ANY)
#endif
JSObject *
js_InitArrayClass(JSContext *cx, JSObject *obj)
{
@ -3088,7 +2966,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->emptyShape->getClass() == proto->getClass());
JS_ASSERT(proto->emptyShapes && proto->emptyShapes[0]->getClass() == proto->getClass());
proto->setArrayLength(0);
return proto;
@ -3097,7 +2975,7 @@ js_InitArrayClass(JSContext *cx, JSObject *obj)
JSObject *
js_NewArrayObject(JSContext *cx, jsuint length, const Value *vector)
{
JSObject *obj = NewDenseArrayObject(cx);
JSObject *obj = NewDenseArrayObject(cx, length);
if (!obj)
return NULL;
@ -3220,7 +3098,7 @@ js_IsDensePrimitiveArray(JSObject *obj)
jsuint capacity = obj->getDenseArrayCapacity();
for (jsuint i = 0; i < capacity; i++) {
if (obj->dslots[i].isObject())
if (obj->getDenseArrayElement(i).isObject())
return JS_FALSE;
}
@ -3244,10 +3122,9 @@ 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 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.
* |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.
*/
jsuint jsvalCount = JS_MIN(obj->getDenseArrayCapacity(), length);
@ -3256,7 +3133,7 @@ js_CloneDensePrimitiveArray(JSContext *cx, JSObject *obj, JSObject **clone)
return JS_FALSE;
for (jsuint i = 0; i < jsvalCount; i++) {
const Value &val = obj->dslots[i];
const Value &val = obj->getDenseArrayElement(i);
if (val.isString()) {
// Strings must be made immutable before being copied to a clone.

Просмотреть файл

@ -46,8 +46,6 @@
#include "jspubtd.h"
#include "jsobj.h"
#define ARRAY_CAPACITY_MIN 7
extern JSBool
js_StringIsIndex(JSString *str, jsuint *indexp);
@ -139,13 +137,6 @@ 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,11 +302,14 @@ 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);
JSObject* closure = js_NewGCObject(cx, gc::FINALIZE_OBJECT2);
if (!closure)
return NULL;
closure->initSharingEmptyShape(&js_FunctionClass, proto, parent, fun, cx);
if (!closure->initSharingEmptyShape(cx, &js_FunctionClass, proto, parent,
fun, gc::FINALIZE_OBJECT2)) {
return NULL;
}
return closure;
}
JS_DEFINE_CALLINFO_4(extern, OBJECT, js_NewNullClosure, CONTEXT, OBJECT, OBJECT, OBJECT,

Просмотреть файл

@ -578,6 +578,7 @@ js_dmod(jsdouble a, jsdouble b);
JS_DECLARE_CALLINFO(js_Array_dense_setelem_hole)
JS_DECLARE_CALLINFO(js_NewEmptyArray)
JS_DECLARE_CALLINFO(js_NewPreallocatedArray)
JS_DECLARE_CALLINFO(js_InitializerArray)
JS_DECLARE_CALLINFO(js_ArrayCompPush_tn)
JS_DECLARE_CALLINFO(js_EnsureDenseArrayCapacity)
@ -614,7 +615,7 @@ JS_DECLARE_CALLINFO(js_NumberToString)
/* Defined in jsobj.cpp. */
JS_DECLARE_CALLINFO(js_Object_tn)
JS_DECLARE_CALLINFO(js_CreateThisFromTrace)
JS_DECLARE_CALLINFO(js_NonEmptyObject)
JS_DECLARE_CALLINFO(js_InitializerObject)
/* Defined in jsregexp.cpp. */
JS_DECLARE_CALLINFO(js_CloneRegExpObject)

Просмотреть файл

@ -66,15 +66,8 @@ bool
JSCompartment::init()
{
chunk = NULL;
shortStringArena.init();
stringArena.init();
funArena.init();
#if JS_HAS_XML_SUPPORT
xmlArena.init();
#endif
objArena.init();
for (unsigned i = 0; i < JS_EXTERNAL_STRING_LIMIT; i++)
externalStringArenas[i].init();
for (unsigned i = 0; i < FINALIZE_LIMIT; i++)
arenas[i].init();
for (unsigned i = 0; i < FINALIZE_LIMIT; i++)
freeLists.finalizables[i] = NULL;
#ifdef JS_GCMETER
@ -86,21 +79,10 @@ JSCompartment::init()
bool
JSCompartment::arenaListsAreEmpty()
{
bool empty = objArena.isEmpty() &&
funArena.isEmpty() &&
#if JS_HAS_XML_SUPPORT
xmlArena.isEmpty() &&
#endif
shortStringArena.isEmpty() &&
stringArena.isEmpty();
if (!empty)
return false;
for (unsigned i = 0; i < JS_EXTERNAL_STRING_LIMIT; i++) {
if (!externalStringArenas[i].isEmpty())
for (unsigned i = 0; i < FINALIZE_LIMIT; i++) {
if (!arenas[i].isEmpty())
return false;
}
return true;
}

Просмотреть файл

@ -54,17 +54,9 @@ struct JS_FRIEND_API(JSCompartment) {
JSPrincipals *principals;
js::gc::Chunk *chunk;
js::gc::ArenaList<JSObject> objArena;
js::gc::ArenaList<JSFunction> funArena;
js::gc::ArenaList<JSShortString> shortStringArena;
js::gc::ArenaList<JSString> stringArena;
js::gc::ArenaList<JSString> externalStringArenas[js::gc::JS_EXTERNAL_STRING_LIMIT];
#if JS_HAS_XML_SUPPORT
js::gc::ArenaList<JSXML> xmlArena;
#endif
js::gc::ArenaList arenas[js::gc::FINALIZE_LIMIT];
js::gc::FreeLists freeLists;
js::gc::FreeLists freeLists;
#ifdef JS_GCMETER
js::gc::JSGCArenaStats compartmentStats[js::gc::FINALIZE_LIMIT];
#endif

Просмотреть файл

@ -2563,7 +2563,9 @@ JS_FRIEND_API(JSObject *)
js_NewDateObjectMsec(JSContext *cx, jsdouble msec_time)
{
JSObject *obj = NewBuiltinClassInstance(cx, &js_DateClass);
if (!obj || !SetUTCTime(cx, obj, msec_time))
if (!obj || !obj->ensureSlots(cx, JSObject::DATE_CLASS_RESERVED_SLOTS))
return NULL;
if (!SetUTCTime(cx, obj, msec_time))
return NULL;
return obj;
}

Просмотреть файл

@ -1667,15 +1667,7 @@ JS_SetDebugErrorHook(JSRuntime *rt, JSDebugErrorHook hook, void *closure)
JS_PUBLIC_API(size_t)
JS_GetObjectTotalSize(JSContext *cx, JSObject *obj)
{
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;
return obj->slotsAndStructSize();
}
static size_t

Просмотреть файл

@ -244,7 +244,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->fslots[JSSLOT_BLOCK_DEPTH].isUndefined());
JS_ASSERT(blockObj->getSlot(JSSLOT_BLOCK_DEPTH).isUndefined());
OBJ_SET_BLOCK_DEPTH(cx, blockObj, cg->stackDepth);
ndefs = OBJ_BLOCK_COUNT(cx, blockObj);
@ -1650,9 +1650,8 @@ js_LexicalLookup(JSTreeContext *tc, JSAtom *atom, jsint *slotp, JSStmtInfo *stmt
JS_ASSERT(shape->hasShortID());
if (slotp) {
JS_ASSERT(obj->fslots[JSSLOT_BLOCK_DEPTH].isInt32());
*slotp = obj->fslots[JSSLOT_BLOCK_DEPTH].toInt32() +
shape->shortid;
JS_ASSERT(obj->getSlot(JSSLOT_BLOCK_DEPTH).isInt32());
*slotp = obj->getSlot(JSSLOT_BLOCK_DEPTH).toInt32() + shape->shortid;
}
return stmt;
}
@ -4460,8 +4459,15 @@ EmitFunctionDefNop(JSContext *cx, JSCodeGenerator *cg, uintN index)
static bool
EmitNewInit(JSContext *cx, JSCodeGenerator *cg, JSProtoKey key, JSParseNode *pn, int sharpnum)
{
if (js_Emit2(cx, cg, JSOP_NEWINIT, (jsbytecode) key) < 0)
return false;
/*
* 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 >= JS_BIT(16)) ? JS_BIT(16) - 1 : pn->pn_count;
EMIT_UINT16PAIR_IMM_OP(JSOP_NEWINIT, (uint16) key, count);
#if JS_HAS_SHARP_VARS
if (cg->hasSharps()) {
if (pn->pn_count != 0)

Просмотреть файл

@ -183,7 +183,8 @@ NewArguments(JSContext *cx, JSObject *parent, uint32 argc, JSObject &callee)
if (!js_GetClassPrototype(cx, parent, JSProto_Object, &proto))
return NULL;
JSObject *argsobj = js_NewGCObject(cx);
JS_STATIC_ASSERT(JSObject::ARGS_CLASS_RESERVED_SLOTS == 2);
JSObject *argsobj = js_NewGCObject(cx, FINALIZE_OBJECT2);
if (!argsobj)
return NULL;
@ -194,10 +195,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(callee.getFunctionPrivate()->inStrictMode()
argsobj->init(cx, callee.getFunctionPrivate()->inStrictMode()
? &StrictArgumentsClass
: &js_ArgumentsClass,
proto, parent, NULL, cx);
proto, parent, NULL, false);
argsobj->setMap(cx->runtime->emptyArgumentsShape);
@ -972,15 +973,20 @@ CalleeGetter(JSContext *cx, JSObject *obj, jsid id, Value *vp)
static JSObject *
NewCallObject(JSContext *cx, JSFunction *fun, JSObject &scopeChain, JSObject &callee)
{
JSObject *callobj = js_NewGCObject(cx);
size_t vars = fun->countArgsAndVars();
size_t slots = JSObject::CALL_RESERVED_SLOTS + vars;
gc::FinalizeKind kind = gc::GetGCObjectKind(slots);
JSObject *callobj = js_NewGCObject(cx, kind);
if (!callobj)
return NULL;
callobj->init(&js_CallClass, NULL, &scopeChain, NULL, cx);
/* Init immediately to avoid GC seeing a half-init'ed object. */
callobj->init(cx, &js_CallClass, NULL, &scopeChain, NULL, false);
callobj->setMap(fun->u.i.names);
/* This must come after callobj->lastProp has been set. */
if (!callobj->ensureInstanceReservedSlots(cx, fun->countArgsAndVars()))
if (!callobj->ensureInstanceReservedSlots(cx, vars))
return NULL;
#ifdef DEBUG
@ -1000,11 +1006,11 @@ NewCallObject(JSContext *cx, JSFunction *fun, JSObject &scopeChain, JSObject &ca
static inline JSObject *
NewDeclEnvObject(JSContext *cx, JSStackFrame *fp)
{
JSObject *envobj = js_NewGCObject(cx);
JSObject *envobj = js_NewGCObject(cx, FINALIZE_OBJECT2);
if (!envobj)
return NULL;
envobj->init(&js_DeclEnvClass, NULL, &fp->scopeChain(), fp, cx);
envobj->init(cx, &js_DeclEnvClass, NULL, &fp->scopeChain(), fp, false);
envobj->setMap(cx->runtime->emptyDeclEnvShape);
return envobj;
}
@ -1079,34 +1085,10 @@ JS_DEFINE_CALLINFO_4(extern, OBJECT, js_CreateCallObjectOnTrace, CONTEXT, FUNCTI
inline static void
CopyValuesToCallObject(JSObject &callobj, uintN nargs, Value *argv, uintN nvars, Value *slots)
{
/* 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));
JS_ASSERT(callobj.numSlots() >= JSObject::CALL_RESERVED_SLOTS + nargs + nvars);
Value *base = callobj.getSlots() + JSObject::CALL_RESERVED_SLOTS;
memcpy(base, argv, nargs * sizeof(Value));
memcpy(base + nargs, slots, nvars * sizeof(Value));
}
void
@ -1125,22 +1107,13 @@ 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::FIRST_FREE_SLOT + n <= callobj.numSlots());
JS_ASSERT(JSFunction::CLASS_RESERVED_SLOTS + n <= callobj.numSlots());
uint32 nargs = fun->nargs;
uint32 nvars = fun->u.i.nvars;
JS_STATIC_ASSERT(JS_INITIAL_NSLOTS == JSSLOT_PRIVATE + JSObject::CALL_RESERVED_SLOTS + 1);
JSScript *script = fun->u.i.script;
memcpy(callobj.dslots, fp->formalArgs(), nargs * sizeof(Value));
if (script->usesEval
#ifdef JS_METHODJIT
|| script->debugMode
@ -1156,13 +1129,13 @@ js_PutCallObject(JSContext *cx, JSStackFrame *fp)
uint32 nclosed = script->nClosedArgs;
for (uint32 i = 0; i < nclosed; i++) {
uint32 e = script->getClosedArg(i);
callobj.dslots[e] = fp->formalArg(e);
callobj.setSlot(JSObject::CALL_RESERVED_SLOTS + e, fp->formalArg(e));
}
nclosed = script->nClosedVars;
for (uint32 i = 0; i < nclosed; i++) {
uint32 e = script->getClosedVar(i);
callobj.dslots[nargs + e] = fp->slots()[e];
callobj.setSlot(JSObject::CALL_RESERVED_SLOTS + nargs + e, fp->slots()[e]);
}
}
}
@ -1255,16 +1228,13 @@ 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);
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;
array = obj->getSlots();
} else if (kind == JSCPK_ARG) {
array = fp->formalArgs();
} else {
@ -1410,14 +1380,11 @@ call_trace(JSTracer *trc, JSObject *obj)
* cycles involving Call objects whose frames are active without this
* hiding hack.
*/
uintN first = JSSLOT_PRIVATE + JSObject::CALL_RESERVED_SLOTS + 1;
JS_ASSERT(first <= JS_INITIAL_NSLOTS);
uintN first = JSObject::CALL_RESERVED_SLOTS;
uintN count = fp->fun()->countArgsAndVars();
uintN fixed = JS_MIN(count, JS_INITIAL_NSLOTS - first);
SetValueRangeToUndefined(&obj->fslots[first], fixed);
SetValueRangeToUndefined(obj->dslots, count - fixed);
JS_ASSERT(obj->numSlots() >= first + count);
SetValueRangeToUndefined(obj->getSlots() + first, count);
}
MaybeMarkGenerator(trc, obj);
@ -2418,8 +2385,8 @@ JSObject::initBoundFunction(JSContext *cx, const Value &thisArg,
JS_ASSERT(isFunction());
flags |= JSObject::BOUND_FUNCTION;
fslots[JSSLOT_BOUND_FUNCTION_THIS] = thisArg;
fslots[JSSLOT_BOUND_FUNCTION_ARGS_COUNT].setPrivateUint32(argslen);
getSlotRef(JSSLOT_BOUND_FUNCTION_THIS) = thisArg;
getSlotRef(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);
@ -2432,9 +2399,8 @@ JSObject::initBoundFunction(JSContext *cx, const Value &thisArg,
if (!ensureInstanceReservedSlots(cx, argslen))
return false;
JS_ASSERT(dslots);
JS_ASSERT(dslots[-1].toPrivateUint32() >= argslen);
memcpy(&dslots[0], args, argslen * sizeof(Value));
JS_ASSERT(numSlots() >= argslen + FUN_CLASS_RESERVED_SLOTS);
memcpy(getSlots() + FUN_CLASS_RESERVED_SLOTS, args, argslen * sizeof(Value));
}
return true;
}
@ -2455,7 +2421,7 @@ JSObject::getBoundFunctionThis() const
JS_ASSERT(isFunction());
JS_ASSERT(isBoundFunction());
return fslots[JSSLOT_BOUND_FUNCTION_THIS];
return getSlot(JSSLOT_BOUND_FUNCTION_THIS);
}
inline const js::Value *
@ -2464,10 +2430,10 @@ JSObject::getBoundFunctionArguments(uintN &argslen) const
JS_ASSERT(isFunction());
JS_ASSERT(isBoundFunction());
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];
argslen = getSlot(JSSLOT_BOUND_FUNCTION_ARGS_COUNT).toPrivateUint32();
JS_ASSERT_IF(argslen > 0, numSlots() >= argslen);
return getSlots() + FUN_CLASS_RESERVED_SLOTS;
}
namespace {
@ -3174,7 +3140,7 @@ JSFunction::addLocal(JSContext *cx, JSAtom *atom, JSLocalKind kind)
uintN attrs = JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED;
uint16 *indexp;
PropertyOp getter, setter;
uint32 slot = JSSLOT_START(&js_CallClass) + JSObject::CALL_RESERVED_SLOTS;
uint32 slot = JSObject::CALL_RESERVED_SLOTS;
if (kind == JSLOCAL_ARG) {
JS_ASSERT(u.i.nupvars == 0);

Просмотреть файл

@ -136,8 +136,10 @@ enum JSLocalKind {
JSLOCAL_UPVAR
};
struct JSFunction : public JSObject
struct JSFunction : public JSObject_Slots2
{
/* 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 */
@ -277,7 +279,7 @@ struct JSFunction : public JSObject
public:
void setJoinable() {
JS_ASSERT(FUN_INTERPRETED(this));
fslots[METHOD_ATOM_SLOT].setNull();
getSlotRef(METHOD_ATOM_SLOT).setNull();
flags |= JSFUN_JOINABLE;
}
@ -287,14 +289,14 @@ struct JSFunction : public JSObject
* flattened upvars.
*/
JSAtom *methodAtom() const {
return (joinable() && fslots[METHOD_ATOM_SLOT].isString())
? STRING_TO_ATOM(fslots[METHOD_ATOM_SLOT].toString())
return (joinable() && getSlot(METHOD_ATOM_SLOT).isString())
? STRING_TO_ATOM(getSlot(METHOD_ATOM_SLOT).toString())
: NULL;
}
void setMethodAtom(JSAtom *atom) {
JS_ASSERT(joinable());
fslots[METHOD_ATOM_SLOT].setString(ATOM_TO_STRING(atom));
getSlotRef(METHOD_ATOM_SLOT).setString(ATOM_TO_STRING(atom));
}
js::Native maybeNative() const {
@ -306,9 +308,8 @@ struct JSFunction : public JSObject
return u.i.script;
}
/* Number of extra fixed function object slots besides JSSLOT_PRIVATE. */
/* Number of extra fixed function object slots. */
static const uint32 CLASS_RESERVED_SLOTS = JSObject::FUN_CLASS_RESERVED_SLOTS;
static const uint32 FIRST_FREE_SLOT = JSSLOT_PRIVATE + CLASS_RESERVED_SLOTS + 1;
};
/*

Просмотреть файл

@ -157,6 +157,17 @@ JS_STATIC_ASSERT(sizeof(Arena<JSXML>) == 4096);
namespace js{
namespace gc{
/* This array should be const, but that doesn't link right under GCC. */
FinalizeKind slotsToThingKind[] = {
/* 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
};
JS_STATIC_ASSERT(JS_ARRAY_LENGTH(slotsToThingKind) == SLOTS_TO_THING_KIND_LIMIT);
/* Initialize the arena and setup the free list. */
template <typename T>
void
@ -202,52 +213,12 @@ Arena<T>::inFreeList(void *thing) const
return false;
}
template<typename T>
inline T *
Arena<T>::getAlignedThing(T *thing)
{
jsuword start = reinterpret_cast<jsuword>(&t.things[0]);
jsuword offset = reinterpret_cast<jsuword>(thing) - start;
offset -= offset % aheader.thingSize;
return reinterpret_cast<T *>(start + offset);
}
#ifdef DEBUG
template <typename T>
bool
Arena<T>::assureThingIsAligned(T *thing)
{
return (getAlignedThing(thing) == thing);
}
template
bool
Arena<JSObject>::assureThingIsAligned(JSObject *thing);
template
bool
Arena<JSFunction>::assureThingIsAligned(JSFunction *thing);
template
bool
Arena<JSString>::assureThingIsAligned(JSString *thing);
template
bool
Arena<JSShortString>::assureThingIsAligned(JSShortString *thing);
#if JS_HAS_XML_SUPPORT
template
bool
Arena<JSXML>::assureThingIsAligned(JSXML *thing);
#endif
#endif
template<typename T>
inline ConservativeGCTest
Arena<T>::mark(T *thing, JSTracer *trc)
{
JS_ASSERT(sizeof(T) == aheader.thingSize);
thing = getAlignedThing(thing);
if (thing > &t.things[ThingsPerArena-1].t || thing < &t.things[0].t)
@ -267,119 +238,35 @@ Arena<T>::mark(T *thing, JSTracer *trc)
#ifdef DEBUG
bool
checkArenaListsForThing(JSCompartment *comp, void *thing) {
if (comp->objArena.arenasContainThing(thing) ||
comp->funArena.arenasContainThing(thing) ||
if (comp->arenas[FINALIZE_OBJECT0].arenasContainThing<JSObject>(thing) ||
comp->arenas[FINALIZE_OBJECT2].arenasContainThing<JSObject_Slots2>(thing) ||
comp->arenas[FINALIZE_OBJECT4].arenasContainThing<JSObject_Slots4>(thing) ||
comp->arenas[FINALIZE_OBJECT8].arenasContainThing<JSObject_Slots8>(thing) ||
comp->arenas[FINALIZE_OBJECT12].arenasContainThing<JSObject_Slots12>(thing) ||
comp->arenas[FINALIZE_OBJECT16].arenasContainThing<JSObject_Slots16>(thing) ||
comp->arenas[FINALIZE_FUNCTION].arenasContainThing<JSFunction>(thing) ||
#if JS_HAS_XML_SUPPORT
comp->xmlArena.arenasContainThing(thing) ||
comp->arenas[FINALIZE_XML].arenasContainThing<JSXML>(thing) ||
#endif
comp->shortStringArena.arenasContainThing(thing) ||
comp->stringArena.arenasContainThing(thing)) {
comp->arenas[FINALIZE_SHORT_STRING].arenasContainThing<JSShortString>(thing)) {
return true;
}
for (unsigned i = 0; i < JS_EXTERNAL_STRING_LIMIT; i++) {
if (comp->externalStringArenas[i].arenasContainThing(thing))
for (unsigned i = FINALIZE_STRING; i <= FINALIZE_EXTERNAL_STRING_LAST; i++) {
if (comp->arenas[i].arenasContainThing<JSString>(thing))
return true;
}
return false;
}
#endif
template <typename T>
void
EmptyArenaLists::insert(Arena<T> *arena) {
Arena<FreeCell> *a = reinterpret_cast<Arena<FreeCell> *>(arena);
a->header()->next = cellFreeList;
cellFreeList = a;
}
template<>
void
EmptyArenaLists::insert(Arena<JSObject> *arena) {
arena->header()->next = objectFreeList;
objectFreeList = arena;
}
template<>
void
EmptyArenaLists::insert(Arena<JSFunction> *arena) {
arena->header()->next = functionFreeList;
functionFreeList = arena;
}
template<>
void
EmptyArenaLists::insert(Arena<JSString> *arena) {
arena->header()->next = stringFreeList;
stringFreeList = arena;
}
template<>
void
EmptyArenaLists::insert(Arena<JSShortString> *arena) {
arena->header()->next = shortStringFreeList;
shortStringFreeList = arena;
}
template<typename T>
Arena<T> *EmptyArenaLists::getTypedFreeList() {
return NULL;
}
template<>
Arena<JSObject> *EmptyArenaLists::getTypedFreeList<JSObject>() {
Arena<JSObject> *arena = objectFreeList;
if (arena) {
objectFreeList = arena->header()->next;
return arena;
}
return NULL;
}
template<>
Arena<JSString> *EmptyArenaLists::getTypedFreeList<JSString>() {
Arena<JSString> *arena = stringFreeList;
if (arena) {
stringFreeList = arena->header()->next;
return arena;
}
return NULL;
}
template<>
Arena<JSShortString> *EmptyArenaLists::getTypedFreeList<JSShortString>() {
Arena<JSShortString> *arena = shortStringFreeList;
if (arena) {
shortStringFreeList = arena->header()->next;
return arena;
}
return NULL;
}
template<>
Arena<JSFunction> *EmptyArenaLists::getTypedFreeList<JSFunction>() {
Arena<JSFunction> *arena = functionFreeList;
if (arena) {
functionFreeList = arena->header()->next;
return arena;
}
return NULL;
}
} /* namespace gc */
} /* namespace js */
void
JSCompartment::finishArenaLists()
{
objArena.releaseAll();
funArena.releaseAll();
shortStringArena.releaseAll();
stringArena.releaseAll();
#if JS_HAS_XML_SUPPORT
xmlArena.releaseAll();
#endif
for (unsigned i = 0; i < 8; i++)
externalStringArenas[i].releaseAll();
for (int i = 0; i < FINALIZE_LIMIT; i++)
arenas[i].releaseAll();
}
void
@ -454,7 +341,7 @@ Chunk::releaseArena(Arena<T> *arena)
JS_ASSERT(rt->gcBytes >= sizeof(Arena<T>));
rt->gcBytes -= sizeof(Arena<T>);
info.emptyArenaLists.insert(arena);
info.emptyArenaLists.insert((Arena<Cell> *)arena);
arena->header()->isUsed = false;
++info.numFree;
if (unused())
@ -683,6 +570,13 @@ js_InitGC(JSRuntime *rt, uint32 maxbytes)
namespace js {
template <typename T>
static inline ConservativeGCTest
MarkCell(Cell *cell, JSTracer *trc)
{
return GetArena<T>(cell)->mark((T *)cell, trc);
}
/*
* Returns CGCT_VALID and mark it if the w can be a live GC thing and sets traceKind
* accordingly. Otherwise returns the reason for rejection.
@ -732,7 +626,7 @@ MarkIfGCThingWord(JSTracer *trc, jsuword w, uint32 &traceKind)
if (!chunk->withinArenasRange(cell))
return CGCT_NOTARENA;
ArenaHeader<Cell> *aheader = cell->arena()->header();
ArenaHeader *aheader = cell->arena()->header();
if (!aheader->isUsed)
return CGCT_FREEARENA;
@ -741,8 +635,23 @@ MarkIfGCThingWord(JSTracer *trc, jsuword w, uint32 &traceKind)
traceKind = aheader->thingKind;
switch (traceKind) {
case FINALIZE_OBJECT:
test = GetArena<JSObject>(cell)->mark((JSObject *)cell, trc);
case FINALIZE_OBJECT0:
test = MarkCell<JSObject>(cell, trc);
break;
case FINALIZE_OBJECT2:
test = MarkCell<JSObject_Slots2>(cell, trc);
break;
case FINALIZE_OBJECT4:
test = MarkCell<JSObject_Slots4>(cell, trc);
break;
case FINALIZE_OBJECT8:
test = MarkCell<JSObject_Slots8>(cell, trc);
break;
case FINALIZE_OBJECT12:
test = MarkCell<JSObject_Slots12>(cell, trc);
break;
case FINALIZE_OBJECT16:
test = MarkCell<JSObject_Slots16>(cell, trc);
break;
case FINALIZE_STRING:
case FINALIZE_EXTERNAL_STRING0:
@ -753,17 +662,17 @@ MarkIfGCThingWord(JSTracer *trc, jsuword w, uint32 &traceKind)
case FINALIZE_EXTERNAL_STRING5:
case FINALIZE_EXTERNAL_STRING6:
case FINALIZE_EXTERNAL_STRING7:
test = GetArena<JSString>(cell)->mark((JSString *)cell, trc);
test = MarkCell<JSString>(cell, trc);
break;
case FINALIZE_SHORT_STRING:
test = GetArena<JSShortString>(cell)->mark((JSShortString *)cell, trc);
test = MarkCell<JSShortString>(cell, trc);
break;
case FINALIZE_FUNCTION:
test = GetArena<JSFunction>(cell)->mark((JSFunction *)cell, trc);
test = MarkCell<JSFunction>(cell, trc);
break;
#if JS_HAS_XML_SUPPORT
case FINALIZE_XML:
test = GetArena<JSXML>(cell)->mark((JSXML *)cell, trc);
test = MarkCell<JSXML>(cell, trc);
break;
#endif
default:
@ -1142,50 +1051,12 @@ IsGCThresholdReached(JSRuntime *rt)
struct JSShortString;
template <typename T>
ArenaList<T> *
GetFinalizableArenaList(JSCompartment *c, unsigned thingKind);
template <>
ArenaList<JSObject> *
GetFinalizableArenaList<JSObject>(JSCompartment *c, unsigned thingKind) {
JS_ASSERT(thingKind == FINALIZE_OBJECT);
return &c->objArena;
ArenaList *
GetFinalizableArenaList(JSCompartment *c, unsigned thingKind) {
JS_ASSERT(thingKind < FINALIZE_LIMIT);
return &c->arenas[thingKind];
}
template <>
ArenaList<JSString> *
GetFinalizableArenaList<JSString>(JSCompartment *c, unsigned thingKind) {
JS_ASSERT(thingKind >= FINALIZE_STRING && thingKind <= FINALIZE_EXTERNAL_STRING_LAST);
if (JS_LIKELY(thingKind == FINALIZE_STRING))
return &c->stringArena;
return &c->externalStringArenas[thingKind - FINALIZE_EXTERNAL_STRING0];
}
template <>
ArenaList<JSShortString> *
GetFinalizableArenaList<JSShortString>(JSCompartment *c, unsigned thingKind) {
JS_ASSERT(thingKind == FINALIZE_SHORT_STRING);
return &c->shortStringArena;
}
template <>
ArenaList<JSFunction> *
GetFinalizableArenaList<JSFunction>(JSCompartment *c, unsigned thingKind) {
JS_ASSERT(thingKind == FINALIZE_FUNCTION);
return &c->funArena;
}
#if JS_HAS_XML_SUPPORT
template <>
ArenaList<JSXML> *
GetFinalizableArenaList<JSXML>(JSCompartment *c, unsigned thingKind) {
JS_ASSERT(thingKind == FINALIZE_XML);
return &c->xmlArena;
}
#endif
#ifdef DEBUG
bool
CheckAllocation(JSContext *cx)
@ -1199,15 +1070,15 @@ CheckAllocation(JSContext *cx)
#endif
template <typename T>
bool
RefillFinalizableFreeList(JSContext *cx, unsigned thingKind)
inline bool
RefillTypedFreeList(JSContext *cx, unsigned thingKind)
{
JSCompartment *compartment = cx->compartment;
JS_ASSERT_IF(compartment->freeLists.finalizables[thingKind],
!*compartment->freeLists.finalizables[thingKind]);
JSRuntime *rt = cx->runtime;
ArenaList<T> *arenaList;
ArenaList *arenaList;
Arena<T> *a;
JS_ASSERT(!rt->gcRunning);
@ -1217,7 +1088,7 @@ RefillFinalizableFreeList(JSContext *cx, unsigned thingKind)
bool canGC = !JS_ON_TRACE(cx) && !JS_THREAD_DATA(cx)->waiveGCQuota;
bool doGC = canGC && IsGCThresholdReached(rt);
arenaList = GetFinalizableArenaList<T>(cx->compartment, thingKind);
arenaList = GetFinalizableArenaList(cx->compartment, thingKind);
do {
if (doGC) {
JS_ASSERT(!JS_ON_TRACE(cx));
@ -1238,15 +1109,16 @@ RefillFinalizableFreeList(JSContext *cx, unsigned thingKind)
if (compartment->freeLists.finalizables[thingKind])
return true;
}
if ((a = arenaList->getNextWithFreeList())) {
if ((a = (Arena<T> *) arenaList->getNextWithFreeList())) {
JS_ASSERT(a->header()->freeList);
JS_ASSERT(sizeof(T) == a->header()->thingSize);
compartment->freeLists.populate(a, thingKind);
return true;
}
a = AllocateArena<T>(cx, thingKind);
if (a) {
compartment->freeLists.populate(a, thingKind);
arenaList->insert(a);
arenaList->insert((Arena<FreeCell> *) a);
a->getMarkingDelay()->init();
return true;
}
@ -1259,27 +1131,45 @@ RefillFinalizableFreeList(JSContext *cx, unsigned thingKind)
} while (true);
}
template
bool
RefillFinalizableFreeList<JSObject>(JSContext *cx, unsigned thingKind);
template
bool
RefillFinalizableFreeList<JSFunction>(JSContext *cx, unsigned thingKind);
template
bool
RefillFinalizableFreeList<JSString>(JSContext *cx, unsigned thingKind);
template
bool
RefillFinalizableFreeList<JSShortString>(JSContext *cx, unsigned thingKind);
RefillFinalizableFreeList(JSContext *cx, unsigned thingKind)
{
switch (thingKind) {
case FINALIZE_OBJECT0:
return RefillTypedFreeList<JSObject>(cx, thingKind);
case FINALIZE_OBJECT2:
return RefillTypedFreeList<JSObject_Slots2>(cx, thingKind);
case FINALIZE_OBJECT4:
return RefillTypedFreeList<JSObject_Slots4>(cx, thingKind);
case FINALIZE_OBJECT8:
return RefillTypedFreeList<JSObject_Slots8>(cx, thingKind);
case FINALIZE_OBJECT12:
return RefillTypedFreeList<JSObject_Slots12>(cx, thingKind);
case FINALIZE_OBJECT16:
return RefillTypedFreeList<JSObject_Slots16>(cx, thingKind);
case FINALIZE_STRING:
case FINALIZE_EXTERNAL_STRING0:
case FINALIZE_EXTERNAL_STRING1:
case FINALIZE_EXTERNAL_STRING2:
case FINALIZE_EXTERNAL_STRING3:
case FINALIZE_EXTERNAL_STRING4:
case FINALIZE_EXTERNAL_STRING5:
case FINALIZE_EXTERNAL_STRING6:
case FINALIZE_EXTERNAL_STRING7:
return RefillTypedFreeList<JSString>(cx, thingKind);
case FINALIZE_SHORT_STRING:
return RefillTypedFreeList<JSShortString>(cx, thingKind);
case FINALIZE_FUNCTION:
return RefillTypedFreeList<JSFunction>(cx, thingKind);
#if JS_HAS_XML_SUPPORT
template
bool
RefillFinalizableFreeList<JSXML>(JSContext *cx, unsigned thingKind);
case FINALIZE_XML:
return RefillTypedFreeList<JSXML>(cx, thingKind);
#endif
default:
JS_NOT_REACHED("bad finalize kind");
return false;
}
}
intN
js_GetExternalStringGCType(JSString *str) {
@ -1455,9 +1345,24 @@ GCMarker::markDelayedChildren()
#endif
switch (a->header()->thingKind) {
case FINALIZE_OBJECT:
case FINALIZE_OBJECT0:
reinterpret_cast<Arena<JSObject> *>(a)->markDelayedChildren(this);
break;
case FINALIZE_OBJECT2:
reinterpret_cast<Arena<JSObject_Slots2> *>(a)->markDelayedChildren(this);
break;
case FINALIZE_OBJECT4:
reinterpret_cast<Arena<JSObject_Slots4> *>(a)->markDelayedChildren(this);
break;
case FINALIZE_OBJECT8:
reinterpret_cast<Arena<JSObject_Slots8> *>(a)->markDelayedChildren(this);
break;
case FINALIZE_OBJECT12:
reinterpret_cast<Arena<JSObject_Slots12> *>(a)->markDelayedChildren(this);
break;
case FINALIZE_OBJECT16:
reinterpret_cast<Arena<JSObject_Slots16> *>(a)->markDelayedChildren(this);
break;
case FINALIZE_STRING:
case FINALIZE_EXTERNAL_STRING0:
case FINALIZE_EXTERNAL_STRING1:
@ -1929,9 +1834,9 @@ static void
FinalizeArenaList(JSCompartment *comp, JSContext *cx, unsigned thingKind)
{
JS_STATIC_ASSERT(!(sizeof(T) & Cell::CellMask));
ArenaList<T> *arenaList = GetFinalizableArenaList<T>(comp, thingKind);
Arena<T> **ap = &arenaList->head;
Arena<T> *a = *ap;
ArenaList *arenaList = GetFinalizableArenaList(comp, thingKind);
Arena<FreeCell> **ap = &arenaList->head;
Arena<T> *a = (Arena<T> *) *ap;
if (!a)
return;
JS_ASSERT(sizeof(T) == arenaList->head->header()->thingSize);
@ -1940,7 +1845,7 @@ FinalizeArenaList(JSCompartment *comp, JSContext *cx, unsigned thingKind)
uint32 nlivearenas = 0, nkilledarenas = 0, nthings = 0;
#endif
for (;;) {
ArenaHeader<T> *header = a->header();
ArenaHeader *header = a->header();
JS_ASSERT_IF(header->hasFreeThings, header->freeList);
JS_ASSERT(header->thingKind == thingKind);
JS_ASSERT(!a->getMarkingDelay()->link);
@ -2018,7 +1923,7 @@ FinalizeArenaList(JSCompartment *comp, JSContext *cx, unsigned thingKind)
#endif
*ap = (header->next);
JS_ASSERT((T *)header->freeList == &a->t.things[0].t);
a->chunk()->releaseArena((Arena<T> *)a);
a->chunk()->releaseArena(a);
METER(nkilledarenas++);
} else {
JS_ASSERT(nfree < a->ThingsPerArena);
@ -2030,7 +1935,7 @@ FinalizeArenaList(JSCompartment *comp, JSContext *cx, unsigned thingKind)
ap = &header->next;
METER(nlivearenas++);
}
if (!(a = *ap))
if (!(a = (Arena<T> *) *ap))
break;
}
arenaList->cursor = arenaList->head;
@ -2336,7 +2241,12 @@ MarkAndSweep(JSContext *cx, JSGCInvocationKind gckind GCTIMER_PARAM)
*/
for (JSCompartment **comp = rt->compartments.begin(); comp != rt->compartments.end(); comp++) {
FinalizeArenaList<JSObject>(*comp, cx, FINALIZE_OBJECT);
FinalizeArenaList<JSObject>(*comp, cx, FINALIZE_OBJECT0);
FinalizeArenaList<JSObject_Slots2>(*comp, cx, FINALIZE_OBJECT2);
FinalizeArenaList<JSObject_Slots4>(*comp, cx, FINALIZE_OBJECT4);
FinalizeArenaList<JSObject_Slots8>(*comp, cx, FINALIZE_OBJECT8);
FinalizeArenaList<JSObject_Slots12>(*comp, cx, FINALIZE_OBJECT12);
FinalizeArenaList<JSObject_Slots16>(*comp, cx, FINALIZE_OBJECT16);
FinalizeArenaList<JSFunction>(*comp, cx, FINALIZE_FUNCTION);
#if JS_HAS_XML_SUPPORT
FinalizeArenaList<JSXML>(*comp, cx, FINALIZE_XML);

Просмотреть файл

@ -72,11 +72,43 @@ js_TraceXML(JSTracer *trc, JSXML* thing);
namespace js {
namespace gc {
/*
* The kind of GC thing with a finalizer. The external strings follow the
* ordinary string to simplify js_GetExternalStringGCType.
*/
enum FinalizeKind {
FINALIZE_OBJECT0,
FINALIZE_OBJECT2,
FINALIZE_OBJECT4,
FINALIZE_OBJECT8,
FINALIZE_OBJECT12,
FINALIZE_OBJECT16,
FINALIZE_OBJECT_LAST = FINALIZE_OBJECT16,
FINALIZE_FUNCTION,
#if JS_HAS_XML_SUPPORT
FINALIZE_XML,
#endif
FINALIZE_SHORT_STRING,
FINALIZE_STRING,
FINALIZE_EXTERNAL_STRING0,
FINALIZE_EXTERNAL_STRING1,
FINALIZE_EXTERNAL_STRING2,
FINALIZE_EXTERNAL_STRING3,
FINALIZE_EXTERNAL_STRING4,
FINALIZE_EXTERNAL_STRING5,
FINALIZE_EXTERNAL_STRING6,
FINALIZE_EXTERNAL_STRING7,
FINALIZE_EXTERNAL_STRING_LAST = FINALIZE_EXTERNAL_STRING7,
FINALIZE_LIMIT
};
const uintN JS_FINALIZE_OBJECT_LIMIT = 6;
const uintN JS_EXTERNAL_STRING_LIMIT = 8;
/* Every arena has a header. */
template <typename T>
struct ArenaHeader {
JSCompartment *compartment;
Arena<T> *next;
Arena<FreeCell> *next;
FreeCell *freeList;
unsigned thingKind;
bool isUsed;
@ -108,12 +140,12 @@ struct Arena {
static const size_t ArenaSize = 4096;
struct AlignedArenaHeader {
T align[(sizeof(ArenaHeader<T>) + sizeof(T) - 1) / sizeof(T)];
T align[(sizeof(ArenaHeader) + sizeof(T) - 1) / sizeof(T)];
};
/* We want things in the arena to be aligned, so align the header. */
union {
ArenaHeader<T> aheader;
ArenaHeader aheader;
AlignedArenaHeader align;
};
@ -124,7 +156,7 @@ struct Arena {
inline Chunk *chunk() const;
inline size_t arenaIndex() const;
inline ArenaHeader<T> *header() { return &aheader; };
inline ArenaHeader *header() { return &aheader; };
inline MarkingDelay *getMarkingDelay() const;
inline ArenaBitmap *bitmap() const;
@ -132,9 +164,9 @@ struct Arena {
inline ConservativeGCTest mark(T *thing, JSTracer *trc);
void markDelayedChildren(JSTracer *trc);
inline bool inFreeList(void *thing) const;
inline T *getAlignedThing(T *thing);
inline T *getAlignedThing(void *thing);
#ifdef DEBUG
bool assureThingIsAligned(T *thing);
inline bool assureThingIsAligned(void *thing);
#endif
void init(JSCompartment *compartment, unsigned thingKind);
@ -198,55 +230,60 @@ struct MarkingDelay {
};
struct EmptyArenaLists {
Arena<FreeCell> *cellFreeList;
Arena<JSObject> *objectFreeList;
Arena<JSString> *stringFreeList;
Arena<JSShortString> *shortStringFreeList;
Arena<JSFunction> *functionFreeList;
/* Arenas with no internal freelist prepared. */
Arena<FreeCell> *cellFreeList;
/* Arenas with internal freelists prepared for a given finalize kind. */
Arena<FreeCell> *freeLists[FINALIZE_LIMIT];
void init() {
cellFreeList = NULL;
objectFreeList = NULL;
stringFreeList = NULL;
shortStringFreeList = NULL;
functionFreeList = NULL;
PodZero(this);
}
Arena<FreeCell> *getOtherArena() {
Arena<FreeCell> *arena = NULL;
if ((arena = (Arena<FreeCell> *)cellFreeList)) {
cellFreeList = cellFreeList->header()->next;
return arena;
} else if ((arena = (Arena<FreeCell> *)objectFreeList)) {
objectFreeList = objectFreeList->header()->next;
return arena;
} else if ((arena = (Arena<FreeCell> *)stringFreeList)) {
stringFreeList = stringFreeList->header()->next;
return arena;
} else if ((arena = (Arena<FreeCell> *)shortStringFreeList)) {
shortStringFreeList = shortStringFreeList->header()->next;
return arena;
} else {
JS_ASSERT(functionFreeList);
arena = (Arena<FreeCell> *)functionFreeList;
functionFreeList = functionFreeList->header()->next;
Arena<FreeCell> *arena = cellFreeList;
if (arena) {
cellFreeList = arena->header()->next;
return arena;
}
for (int i = 0; i < FINALIZE_LIMIT; i++) {
if ((arena = (Arena<FreeCell> *) freeLists[i])) {
freeLists[i] = freeLists[i]->header()->next;
return arena;
}
}
JS_NOT_REACHED("No arena");
return NULL;
}
template <typename T>
Arena<T> *getTypedFreeList();
inline Arena<T> *getTypedFreeList(unsigned thingKind);
template <typename T>
Arena<T> *getNext(JSCompartment *comp, unsigned thingKind);
inline Arena<T> *getNext(JSCompartment *comp, unsigned thingKind);
template <typename T>
void insert(Arena<T> *arena);
inline void insert(Arena<T> *arena);
};
template <typename T>
inline Arena<T> *
EmptyArenaLists::getTypedFreeList(unsigned thingKind) {
JS_ASSERT(thingKind < FINALIZE_LIMIT);
if (thingKind >= FINALIZE_EXTERNAL_STRING0)
thingKind = FINALIZE_STRING;
Arena<T> *arena = (Arena<T>*) freeLists[thingKind];
if (arena) {
freeLists[thingKind] = freeLists[thingKind]->header()->next;
return arena;
}
return NULL;
}
template<typename T>
Arena<T> *EmptyArenaLists::getNext(JSCompartment *comp, unsigned thingKind) {
Arena<T> *arena = getTypedFreeList<T>();
inline Arena<T> *
EmptyArenaLists::getNext(JSCompartment *comp, unsigned thingKind) {
Arena<T> *arena = getTypedFreeList<T>(thingKind);
if (arena) {
JS_ASSERT(arena->header()->isUsed == false);
JS_ASSERT(arena->header()->thingSize == sizeof(T));
@ -261,6 +298,17 @@ Arena<T> *EmptyArenaLists::getNext(JSCompartment *comp, unsigned thingKind) {
return arena;
}
template <typename T>
inline void
EmptyArenaLists::insert(Arena<T> *arena) {
unsigned thingKind = arena->header()->thingKind;
JS_ASSERT(thingKind < FINALIZE_LIMIT);
if (thingKind >= FINALIZE_EXTERNAL_STRING0)
thingKind = FINALIZE_STRING;
arena->header()->next = freeLists[thingKind];
freeLists[thingKind] = (Arena<FreeCell> *) arena;
}
/* The chunk header (located at the end of the chunk to preserve arena alignment). */
struct ChunkInfo {
Chunk *link;
@ -366,6 +414,25 @@ Arena<T>::bitmap() const
return &chunk()->bitmaps[arenaIndex()];
}
template <typename T>
inline T *
Arena<T>::getAlignedThing(void *thing)
{
jsuword start = reinterpret_cast<jsuword>(&t.things[0]);
jsuword offset = reinterpret_cast<jsuword>(thing) - start;
offset -= offset % aheader.thingSize;
return reinterpret_cast<T *>(start + offset);
}
#ifdef DEBUG
template <typename T>
inline bool
Arena<T>::assureThingIsAligned(void *thing)
{
return (getAlignedThing(thing) == thing);
}
#endif
static void
AssertValidColor(const void *thing, uint32 color)
{
@ -400,30 +467,6 @@ GetArena(Cell *cell)
return reinterpret_cast<Arena<T> *>(cell->arena());
}
/*
* The kind of GC thing with a finalizer. The external strings follow the
* ordinary string to simplify js_GetExternalStringGCType.
*/
enum JSFinalizeGCThingKind {
FINALIZE_OBJECT,
FINALIZE_FUNCTION,
#if JS_HAS_XML_SUPPORT
FINALIZE_XML,
#endif
FINALIZE_SHORT_STRING,
FINALIZE_STRING,
FINALIZE_EXTERNAL_STRING0,
FINALIZE_EXTERNAL_STRING1,
FINALIZE_EXTERNAL_STRING2,
FINALIZE_EXTERNAL_STRING3,
FINALIZE_EXTERNAL_STRING4,
FINALIZE_EXTERNAL_STRING5,
FINALIZE_EXTERNAL_STRING6,
FINALIZE_EXTERNAL_STRING7,
FINALIZE_EXTERNAL_STRING_LAST = FINALIZE_EXTERNAL_STRING7,
FINALIZE_LIMIT
};
#define JSTRACE_XML 2
/*
@ -443,15 +486,18 @@ const size_t GC_ARENA_ALLOCATION_TRIGGER = 30 * js::GC_CHUNK_SIZE;
*/
const float GC_HEAP_GROWTH_FACTOR = 3;
const uintN JS_EXTERNAL_STRING_LIMIT = 8;
static inline size_t
GetFinalizableTraceKind(size_t thingKind)
{
JS_STATIC_ASSERT(JS_EXTERNAL_STRING_LIMIT == 8);
static const uint8 map[FINALIZE_LIMIT] = {
JSTRACE_OBJECT, /* FINALIZE_OBJECT */
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_FUNCTION */
#if JS_HAS_XML_SUPPORT /* FINALIZE_XML */
JSTRACE_XML,
@ -515,22 +561,22 @@ extern bool
checkArenaListsForThing(JSCompartment *comp, jsuword thing);
#endif
template <typename T>
/* The arenas in a list have uniform kind. */
struct ArenaList {
Arena<T> *head; /* list start */
Arena<T> *cursor; /* arena with free things */
Arena<FreeCell> *head; /* list start */
Arena<FreeCell> *cursor; /* arena with free things */
inline void init() {
head = NULL;
cursor = NULL;
}
inline Arena<T> *getNextWithFreeList() {
Arena<T> *a;
inline Arena<FreeCell> *getNextWithFreeList() {
Arena<FreeCell> *a;
while (cursor != NULL) {
ArenaHeader<T> *aheader = cursor->header();
ArenaHeader *aheader = cursor->header();
a = cursor;
cursor = (Arena<T> *)aheader->next;
cursor = aheader->next;
if (aheader->freeList)
return a;
}
@ -538,8 +584,9 @@ struct ArenaList {
}
#ifdef DEBUG
template <typename T>
bool arenasContainThing(void *thing) {
for (Arena<T> *a = head; a; a = (Arena<T> *)a->header()->next) {
for (Arena<T> *a = (Arena<T> *) head; a; a = (Arena<T> *) a->header()->next) {
JS_ASSERT(a->header()->isUsed);
if (thing >= &a->t.things[0] && thing < &a->t.things[a->ThingsPerArena])
return true;
@ -548,14 +595,14 @@ struct ArenaList {
}
#endif
inline void insert(Arena<T> *a) {
inline void insert(Arena<FreeCell> *a) {
a->header()->next = head;
head = a;
}
void releaseAll() {
while (head) {
Arena<T> *next = head->header()->next;
Arena<FreeCell> *next = head->header()->next;
head->chunk()->releaseArena(head);
head = next;
}
@ -668,7 +715,6 @@ CheckGCFreeListLink(js::gc::FreeCell *cell)
JS_ASSERT_IF(cell->link, cell < cell->link);
}
template <typename T>
extern bool
RefillFinalizableFreeList(JSContext *cx, unsigned thingKind);

Просмотреть файл

@ -55,6 +55,50 @@
# define METER_IF(condition, x) ((void) 0)
#endif
namespace js {
namespace gc {
/* Capacity for slotsToThingKind */
const size_t SLOTS_TO_THING_KIND_LIMIT = 17;
/* Get the best kind to use when making an object with the given slot count. */
static inline FinalizeKind
GetGCObjectKind(size_t numSlots)
{
extern FinalizeKind slotsToThingKind[];
if (numSlots >= SLOTS_TO_THING_KIND_LIMIT)
return FINALIZE_OBJECT0;
return slotsToThingKind[numSlots];
}
/* Get the number of fixed slots and initial capacity associated with a kind. */
static inline size_t
GetGCKindSlots(FinalizeKind 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;
}
}
} /* namespace gc */
} /* namespace js */
/*
* Allocates a new GC thing. After a successful allocation the caller must
* fully initialize the thing before calling any function that can potentially
@ -80,7 +124,7 @@ NewFinalizableGCThing(JSContext *cx, unsigned thingKind)
CheckGCFreeListLink(cell);
return (T *)cell;
}
if (!RefillFinalizableFreeList<T>(cx, thingKind))
if (!RefillFinalizableFreeList(cx, thingKind))
return NULL;
} while (true);
}
@ -89,9 +133,13 @@ NewFinalizableGCThing(JSContext *cx, unsigned thingKind)
#undef METER_IF
inline JSObject *
js_NewGCObject(JSContext *cx)
js_NewGCObject(JSContext *cx, js::gc::FinalizeKind kind)
{
return NewFinalizableGCThing<JSObject>(cx, js::gc::FINALIZE_OBJECT);
JS_ASSERT(kind >= js::gc::FINALIZE_OBJECT0 && kind <= js::gc::FINALIZE_OBJECT_LAST);
JSObject *obj = NewFinalizableGCThing<JSObject>(cx, kind);
if (obj)
obj->capacity = js::gc::GetGCKindSlots(kind);
return obj;
}
inline JSString *
@ -117,7 +165,10 @@ js_NewGCExternalString(JSContext *cx, uintN type)
inline JSFunction*
js_NewGCFunction(JSContext *cx)
{
return NewFinalizableGCThing<JSFunction>(cx, js::gc::FINALIZE_FUNCTION);
JSFunction *fun = NewFinalizableGCThing<JSFunction>(cx, js::gc::FINALIZE_FUNCTION);
if (fun)
fun->capacity = JSObject::FUN_CLASS_RESERVED_SLOTS;
return fun;
}
#if JS_HAS_XML_SUPPORT
@ -180,7 +231,12 @@ MarkObject(JSTracer *trc, JSObject &obj, const char *name)
JS_ASSERT(&obj);
JS_SET_TRACING_NAME(trc, name);
JS_ASSERT(GetArena<JSObject>((Cell *)&obj)->assureThingIsAligned(&obj) ||
GetArena<JSFunction>((Cell *)&obj)->assureThingIsAligned((JSFunction *)&obj));
GetArena<JSObject_Slots2>((Cell *)&obj)->assureThingIsAligned(&obj) ||
GetArena<JSObject_Slots4>((Cell *)&obj)->assureThingIsAligned(&obj) ||
GetArena<JSObject_Slots8>((Cell *)&obj)->assureThingIsAligned(&obj) ||
GetArena<JSObject_Slots12>((Cell *)&obj)->assureThingIsAligned(&obj) ||
GetArena<JSObject_Slots16>((Cell *)&obj)->assureThingIsAligned(&obj) ||
GetArena<JSFunction>((Cell *)&obj)->assureThingIsAligned(&obj));
Mark(trc, &obj);
}
@ -196,8 +252,14 @@ MarkChildren(JSTracer *trc, JSObject *obj)
MarkObject(trc, *proto, "proto");
if (JSObject *parent = obj->getParent())
MarkObject(trc, *parent, "parent");
if (obj->emptyShape)
obj->emptyShape->trace(trc);
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);
}
}
/* Delegate to ops or the native marking op. */
TraceOp op = obj->getOps()->trace;

Просмотреть файл

@ -111,7 +111,12 @@ UpdateCompartmentStats(JSCompartment *comp, unsigned thingKind, uint32 nlivearen
}
static const char *const GC_ARENA_NAMES[] = {
"object",
"object_0",
"object_2",
"object_4",
"object_8",
"object_12",
"object_16",
"function",
#if JS_HAS_XML_SUPPORT
"xml",
@ -129,12 +134,34 @@ static const char *const GC_ARENA_NAMES[] = {
};
JS_STATIC_ASSERT(JS_ARRAY_LENGTH(GC_ARENA_NAMES) == FINALIZE_LIMIT);
template <typename T>
static inline void
GetSizeAndThings(size_t &thingSize, size_t &thingsPerArena)
{
thingSize = sizeof(T);
thingsPerArena = Arena<T>::ThingsPerArena;
}
void GetSizeAndThingsPerArena(int thingKind, size_t &thingSize, size_t &thingsPerArena)
{
switch (thingKind) {
case FINALIZE_OBJECT:
thingSize = sizeof(JSObject);
thingsPerArena = Arena<JSObject>::ThingsPerArena;
case FINALIZE_OBJECT0:
GetSizeAndThings<JSObject>(thingSize, thingsPerArena);
break;
case FINALIZE_OBJECT2:
GetSizeAndThings<JSObject_Slots2>(thingSize, thingsPerArena);
break;
case FINALIZE_OBJECT4:
GetSizeAndThings<JSObject_Slots4>(thingSize, thingsPerArena);
break;
case FINALIZE_OBJECT8:
GetSizeAndThings<JSObject_Slots8>(thingSize, thingsPerArena);
break;
case FINALIZE_OBJECT12:
GetSizeAndThings<JSObject_Slots12>(thingSize, thingsPerArena);
break;
case FINALIZE_OBJECT16:
GetSizeAndThings<JSObject_Slots16>(thingSize, thingsPerArena);
break;
case FINALIZE_STRING:
case FINALIZE_EXTERNAL_STRING0:
@ -145,21 +172,17 @@ void GetSizeAndThingsPerArena(int thingKind, size_t &thingSize, size_t &thingsPe
case FINALIZE_EXTERNAL_STRING5:
case FINALIZE_EXTERNAL_STRING6:
case FINALIZE_EXTERNAL_STRING7:
thingSize = sizeof(JSString);
thingsPerArena = Arena<JSString>::ThingsPerArena;
GetSizeAndThings<JSString>(thingSize, thingsPerArena);
break;
case FINALIZE_SHORT_STRING:
thingSize = sizeof(JSShortString);
thingsPerArena = Arena<JSShortString>::ThingsPerArena;
GetSizeAndThings<JSShortString>(thingSize, thingsPerArena);
break;
case FINALIZE_FUNCTION:
thingSize = sizeof(JSFunction);
thingsPerArena = Arena<JSFunction>::ThingsPerArena;
GetSizeAndThings<JSFunction>(thingSize, thingsPerArena);
break;
#if JS_HAS_XML_SUPPORT
case FINALIZE_XML:
thingSize = sizeof(JSXML);
thingsPerArena = Arena<JSXML>::ThingsPerArena;
GetSizeAndThings<JSXML>(thingSize, thingsPerArena);
break;
#endif
default:

Просмотреть файл

@ -512,8 +512,8 @@ ComputeThisFromArgv(JSContext *cx, Value *argv)
#if JS_HAS_NO_SUCH_METHOD
const uint32 JSSLOT_FOUND_FUNCTION = JSSLOT_PRIVATE;
const uint32 JSSLOT_SAVED_ID = JSSLOT_PRIVATE + 1;
const uint32 JSSLOT_FOUND_FUNCTION = 0;
const uint32 JSSLOT_SAVED_ID = 1;
Class js_NoSuchMethodClass = {
"NoSuchMethod",
@ -564,7 +564,7 @@ js_OnUnknownMethod(JSContext *cx, Value *vp)
vp[0] = IdToValue(id);
}
#endif
obj = js_NewGCObject(cx);
obj = js_NewGCObject(cx, FINALIZE_OBJECT2);
if (!obj)
return false;
@ -575,8 +575,9 @@ js_OnUnknownMethod(JSContext *cx, Value *vp)
* NoSuchMethod helper objects own no manually allocated resources.
*/
obj->map = NULL;
obj->init(&js_NoSuchMethodClass, NULL, NULL, tvr.value(), cx);
obj->fslots[JSSLOT_SAVED_ID] = vp[0];
obj->init(cx, &js_NoSuchMethodClass, NULL, NULL, NULL, false);
obj->setSlot(JSSLOT_FOUND_FUNCTION, tvr.value());
obj->setSlot(JSSLOT_SAVED_ID, vp[0]);
vp[0].setObject(*obj);
}
return true;
@ -594,9 +595,9 @@ NoSuchMethod(JSContext *cx, uintN argc, Value *vp, uint32 flags)
JSObject *obj = &vp[0].toObject();
JS_ASSERT(obj->getClass() == &js_NoSuchMethodClass);
args.callee() = obj->fslots[JSSLOT_FOUND_FUNCTION];
args.callee() = obj->getSlot(JSSLOT_FOUND_FUNCTION);
args.thisv() = vp[1];
args[0] = obj->fslots[JSSLOT_SAVED_ID];
args[0] = obj->getSlot(JSSLOT_SAVED_ID);
JSObject *argsobj = js_NewArrayObject(cx, argc, vp + 2);
if (!argsobj)
return JS_FALSE;
@ -5890,15 +5891,20 @@ END_CASE(JSOP_NEWARRAY)
BEGIN_CASE(JSOP_NEWINIT)
{
jsint i = GET_INT8(regs.pc);
jsint i = GET_UINT16(regs.pc);
jsint count = GET_UINT16(regs.pc + UINT16_LEN);
JS_ASSERT(i == JSProto_Array || i == JSProto_Object);
JSObject *obj;
gc::FinalizeKind kind = GuessObjectGCKind(count, i == JSProto_Array);
if (i == JSProto_Array) {
obj = js_NewArrayObject(cx, 0, NULL);
obj = NewArrayWithKind(cx, kind);
if (!obj)
goto error;
} else {
obj = NewBuiltinClassInstance(cx, &js_ObjectClass);
obj = NewBuiltinClassInstance(cx, &js_ObjectClass, kind);
if (!obj)
goto error;
}

Просмотреть файл

@ -289,7 +289,7 @@ EnumerateDenseArrayProperties(JSContext *cx, JSObject *obj, JSObject *pobj, uint
if (pobj->getArrayLength() > 0) {
size_t capacity = pobj->getDenseArrayCapacity();
Value *vp = pobj->dslots;
Value *vp = pobj->getDenseArrayElements();
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. */
@ -460,10 +460,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);
JSObject *obj = js_NewGCObject(cx, FINALIZE_OBJECT0);
if (!obj)
return false;
obj->init(&js_IteratorClass, NULL, NULL, NullValue(), cx);
obj->init(cx, &js_IteratorClass, NULL, NULL, NULL, false);
obj->setMap(cx->runtime->emptyEnumeratorShape);
return obj;
}

Просмотреть файл

@ -507,8 +507,7 @@ FinishSharingTitle(JSContext *cx, JSTitle *title)
JSObject *obj = TITLE_TO_OBJECT(title);
if (obj) {
uint32 nslots = obj->slotSpan();
JS_ASSERT(nslots >= JSSLOT_START(obj->getClass()));
for (uint32 i = JSSLOT_START(obj->getClass()); i != nslots; ++i) {
for (uint32 i = 0; i != nslots; ++i) {
Value v = obj->getSlot(i);
if (v.isString() &&
!js_MakeStringImmutable(cx, v.toString())) {

Просмотреть файл

@ -2758,7 +2758,8 @@ js_Object(JSContext *cx, uintN argc, Value *vp)
if (!obj) {
/* Make an object whether this was called with 'new' or not. */
JS_ASSERT(!argc || vp[2].isNull() || vp[2].isUndefined());
obj = NewBuiltinClassInstance(cx, &js_ObjectClass);
gc::FinalizeKind kind = NewObjectGCKind(cx, &js_ObjectClass);
obj = NewBuiltinClassInstance(cx, &js_ObjectClass, kind);
if (!obj)
return JS_FALSE;
}
@ -2784,13 +2785,15 @@ js_CreateThis(JSContext *cx, JSObject *callee)
JSObject *proto = protov.isObjectOrNull() ? protov.toObjectOrNull() : NULL;
JSObject *parent = callee->getParent();
return NewObject<WithProto::Class>(cx, newclasp, proto, parent);
gc::FinalizeKind kind = NewObjectGCKind(cx, newclasp);
return NewObject<WithProto::Class>(cx, newclasp, proto, parent, kind);
}
JSObject *
js_CreateThisForFunctionWithProto(JSContext *cx, JSObject *callee, JSObject *proto)
{
return NewNonFunction<WithProto::Class>(cx, &js_ObjectClass, proto, callee->getParent());
gc::FinalizeKind kind = NewObjectGCKind(cx, &js_ObjectClass);
return NewNonFunction<WithProto::Class>(cx, &js_ObjectClass, proto, callee->getParent(), kind);
}
JSObject *
@ -2810,15 +2813,17 @@ js_CreateThisForFunction(JSContext *cx, JSObject *callee)
static JS_ALWAYS_INLINE JSObject*
NewObjectWithClassProto(JSContext *cx, Class *clasp, JSObject *proto,
const Value &privateSlotValue)
/*gc::FinalizeKind*/ unsigned _kind)
{
JS_ASSERT(clasp->isNative());
gc::FinalizeKind kind = gc::FinalizeKind(_kind);
JSObject* obj = js_NewGCObject(cx);
JSObject* obj = js_NewGCObject(cx, kind);
if (!obj)
return NULL;
obj->initSharingEmptyShape(clasp, proto, proto->getParent(), privateSlotValue, cx);
if (!obj->initSharingEmptyShape(cx, clasp, proto, proto->getParent(), NULL, kind))
return NULL;
return obj;
}
@ -2826,8 +2831,7 @@ JSObject* FASTCALL
js_Object_tn(JSContext* cx, JSObject* proto)
{
JS_ASSERT(!(js_ObjectClass.flags & JSCLASS_HAS_PRIVATE));
return NewObjectWithClassProto(cx, &js_ObjectClass, proto, UndefinedValue());
return NewObjectWithClassProto(cx, &js_ObjectClass, proto, FINALIZE_OBJECT8);
}
JS_DEFINE_TRCINFO_1(js_Object,
@ -2835,22 +2839,24 @@ JS_DEFINE_TRCINFO_1(js_Object,
nanojit::ACCSET_STORE_ANY)))
JSObject* FASTCALL
js_NonEmptyObject(JSContext* cx, JSObject* proto)
js_InitializerObject(JSContext* cx, int32 count)
{
JS_ASSERT(!(js_ObjectClass.flags & JSCLASS_HAS_PRIVATE));
JSObject *obj = NewObjectWithClassProto(cx, &js_ObjectClass, proto, UndefinedValue());
return (obj && obj->ensureClassReservedSlotsForEmptyObject(cx)) ? obj : NULL;
gc::FinalizeKind kind = GuessObjectGCKind(count, false);
return NewBuiltinClassInstance(cx, &js_ObjectClass, kind);
}
JS_DEFINE_CALLINFO_2(extern, CONSTRUCTOR_RETRY, js_NonEmptyObject, CONTEXT, CALLEE_PROTOTYPE, 0,
JS_DEFINE_CALLINFO_2(extern, OBJECT, js_InitializerObject, CONTEXT, INT32, 0,
nanojit::ACCSET_STORE_ANY)
JSObject* FASTCALL
js_String_tn(JSContext* cx, JSObject* proto, JSString* str)
{
JS_ASSERT(JS_ON_TRACE(cx));
return NewObjectWithClassProto(cx, &js_StringClass, proto, StringValue(str));
JSObject *obj = NewObjectWithClassProto(cx, &js_StringClass, proto, FINALIZE_OBJECT2);
if (!obj)
return NULL;
obj->setPrimitiveThis(StringValue(str));
return obj;
}
JS_DEFINE_CALLINFO_3(extern, OBJECT, js_String_tn, CONTEXT, CALLEE_PROTOTYPE, STRING, 0,
nanojit::ACCSET_STORE_ANY)
@ -2904,7 +2910,8 @@ js_CreateThisFromTrace(JSContext *cx, Class *clasp, JSObject *ctor)
* FIXME: 561785 at least. Quasi-natives including XML objects prevent us
* from easily or unconditionally calling NewNativeClassInstance here.
*/
return NewNonFunction<WithProto::Given>(cx, clasp, proto, parent);
gc::FinalizeKind kind = NewObjectGCKind(cx, clasp);
return NewNonFunction<WithProto::Given>(cx, clasp, proto, parent, kind);
}
JS_DEFINE_CALLINFO_3(extern, CONSTRUCTOR_RETRY, js_CreateThisFromTrace, CONTEXT, CLASS, OBJECT, 0,
@ -3126,11 +3133,13 @@ js_NewWithObject(JSContext *cx, JSObject *proto, JSObject *parent, jsint depth)
{
JSObject *obj;
obj = js_NewGCObject(cx);
obj = js_NewGCObject(cx, FINALIZE_OBJECT2);
if (!obj)
return NULL;
obj->init(&js_WithClass, proto, parent, js_FloatingFrameIfGenerator(cx, cx->fp()), cx);
JSStackFrame *priv = js_FloatingFrameIfGenerator(cx, cx->fp());
obj->init(cx, &js_WithClass, proto, parent, priv, false);
obj->setMap(cx->runtime->emptyWithShape);
OBJ_SET_BLOCK_DEPTH(cx, obj, depth);
@ -3152,11 +3161,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);
JSObject *blockObj = js_NewGCObject(cx, FINALIZE_OBJECT2);
if (!blockObj)
return NULL;
blockObj->init(&js_BlockClass, NULL, NULL, NullValue(), cx);
blockObj->init(cx, &js_BlockClass, NULL, NULL, NULL, false);
blockObj->setMap(cx->runtime->emptyBlockShape);
return blockObj;
}
@ -3166,20 +3175,24 @@ js_CloneBlockObject(JSContext *cx, JSObject *proto, JSStackFrame *fp)
{
JS_ASSERT(proto->isStaticBlock());
JSObject *clone = js_NewGCObject(cx);
size_t count = OBJ_BLOCK_COUNT(cx, proto);
gc::FinalizeKind kind = gc::GetGCObjectKind(count + 1);
JSObject *clone = js_NewGCObject(cx, kind);
if (!clone)
return NULL;
JSStackFrame *priv = js_FloatingFrameIfGenerator(cx, fp);
/* The caller sets parent on its own. */
clone->init(&js_BlockClass, proto, NULL, priv, cx);
clone->fslots[JSSLOT_BLOCK_DEPTH] = proto->fslots[JSSLOT_BLOCK_DEPTH];
clone->init(cx, &js_BlockClass, proto, NULL, priv, false);
clone->setMap(proto->map);
if (!clone->ensureInstanceReservedSlots(cx, OBJ_BLOCK_COUNT(cx, proto)))
if (!clone->ensureInstanceReservedSlots(cx, count + 1))
return NULL;
clone->setSlot(JSSLOT_BLOCK_DEPTH, proto->getSlot(JSSLOT_BLOCK_DEPTH));
JS_ASSERT(clone->isClonedBlock());
return clone;
}
@ -3187,9 +3200,6 @@ 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());
@ -3197,7 +3207,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);
@ -3209,15 +3219,8 @@ js_PutBlockObject(JSContext *cx, JSBool normalUnwind)
if (normalUnwind) {
uintN slot = JSSLOT_BLOCK_FIRST_FREE_SLOT;
uintN flen = JS_MIN(count, JS_INITIAL_NSLOTS - slot);
uintN stop = slot + flen;
depth += fp->numFixed();
while (slot < stop)
obj->fslots[slot++] = fp->slots()[depth++];
count -= flen;
if (count != 0)
memcpy(obj->dslots, fp->slots() + depth, count * sizeof(Value));
memcpy(obj->getSlots() + slot, fp->slots() + depth, count * sizeof(Value));
}
/* We must clear the private slot even with errors. */
@ -3298,7 +3301,7 @@ GetObjectSize(JSObject *obj)
{
return (obj->isFunction() && !obj->getPrivate())
? sizeof(JSFunction)
: sizeof(JSObject);
: sizeof(JSObject) + sizeof(js::Value) * obj->numFixedSlots();
}
/*
@ -3307,17 +3310,50 @@ 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.
*/
void
JSObject::swap(JSObject *other)
bool
JSObject::swap(JSContext *cx, JSObject *other)
{
size_t size = GetObjectSize(this);
JS_ASSERT(size == GetObjectSize(other));
if (size != GetObjectSize(other)) {
/*
* Objects with different numbers of fixed slots can be swapped only if they
* are both shapeless non-natives, to preserve the invariant that objects with the
* same shape have the same number of fixed slots. Use a dynamic array for both.
*/
JS_ASSERT(!isNative());
JS_ASSERT(!other->isNative());
size = sizeof(JSObject);
if (!hasSlotsArray()) {
if (!allocSlots(cx, numSlots()))
return false;
}
if (!other->hasSlotsArray()) {
if (!other->allocSlots(cx, other->numSlots()))
return false;
}
}
bool thisInline = !hasSlotsArray();
bool otherInline = !other->hasSlotsArray();
JS_STATIC_ASSERT(FINALIZE_OBJECT_LAST == FINALIZE_OBJECT16);
char tmp[tl::Max<sizeof(JSFunction), sizeof(JSObject_Slots16)>::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
@ -3503,13 +3539,12 @@ DefineStandardSlot(JSContext *cx, JSObject *obj, JSProtoKey key, JSAtom *atom,
const Shape *shape = obj->nativeLookup(id);
if (!shape) {
uint32 index = 2 * JSProto_LIMIT + key;
if (!js_SetReservedSlot(cx, obj, index, v)) {
uint32 slot = 2 * JSProto_LIMIT + key;
if (!js_SetReservedSlot(cx, obj, slot, 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);
@ -3675,7 +3710,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))
if (!proto->getEmptyShape(cx, proto->clasp, FINALIZE_OBJECT0))
goto bad;
/* If this is a standard class, cache its prototype. */
@ -3693,111 +3728,103 @@ bad:
}
bool
JSObject::allocSlots(JSContext *cx, size_t nslots)
JSObject::allocSlots(JSContext *cx, size_t newcap)
{
JS_ASSERT(!dslots);
JS_ASSERT(nslots > JS_INITIAL_NSLOTS);
uint32 oldcap = numSlots();
size_t nwords = slotsToDynamicWords(nslots);
dslots = (Value*) cx->malloc(nwords * sizeof(Value));
if (!dslots)
JS_ASSERT(newcap >= oldcap && !hasSlotsArray());
if (newcap > NSLOTS_LIMIT) {
if (!JS_ON_TRACE(cx))
js_ReportAllocationOverflow(cx);
return false;
}
dslots++;
dslots[-1].setPrivateUint32(nslots);
SetValueRangeToUndefined(dslots, nslots - JS_INITIAL_NSLOTS);
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());
return true;
}
bool
JSObject::growSlots(JSContext *cx, size_t nslots)
JSObject::growSlots(JSContext *cx, size_t newcap)
{
/*
* Minimal number of dynamic slots to allocate.
* 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.
*/
const size_t MIN_DYNAMIC_WORDS = 4;
static const size_t CAPACITY_DOUBLING_MAX = 1024 * 1024;
static const size_t CAPACITY_CHUNK = CAPACITY_DOUBLING_MAX / sizeof(Value);
/*
* 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 oldcap = numSlots();
JS_ASSERT(oldcap < newcap);
/* If we are allocating fslots, there is nothing to do. */
if (nslots <= JS_INITIAL_NSLOTS)
return true;
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;
/* Don't let nslots get close to wrapping around uint32. */
if (nslots >= NSLOTS_LIMIT) {
if (actualCapacity >= NSLOTS_LIMIT) {
JS_ReportOutOfMemory(cx);
return false;
}
size_t nwords = slotsToDynamicWords(nslots);
/* If nothing was allocated yet, treat it as initial allocation. */
if (!hasSlotsArray())
return allocSlots(cx, 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);
Value *tmpslots = (Value*) cx->realloc(slots, actualCapacity * sizeof(Value));
if (!tmpslots)
return false; /* Leave dslots as its old size. */
slots = tmpslots;
capacity = actualCapacity;
/* Initialize the additional slots we added. */
JS_ASSERT(nslots > oldnslots);
Value *beg = dslots + (oldnslots - JS_INITIAL_NSLOTS);
Value *end = dslots + (nslots - JS_INITIAL_NSLOTS);
SetValueRangeToUndefined(beg, end);
ClearValueRange(slots + oldcap, actualCapacity - oldcap, isDenseArray());
return true;
}
void
JSObject::shrinkSlots(JSContext *cx, size_t nslots)
JSObject::shrinkSlots(JSContext *cx, size_t newcap)
{
/* Nothing to shrink? */
if (!dslots)
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());
return;
}
JS_ASSERT(dslots[-1].toPrivateUint32() > JS_INITIAL_NSLOTS);
JS_ASSERT(nslots <= dslots[-1].toPrivateUint32());
uint32 fill = newcap;
if (newcap < SLOT_CAPACITY_MIN)
newcap = SLOT_CAPACITY_MIN;
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 */
Value *tmpslots = (Value*) cx->realloc(slots, newcap * sizeof(Value));
if (!tmpslots)
return; /* Leave slots at its old size. */
slots = tmpslots;
capacity = newcap;
dslots = tmpdslots;
dslots++;
dslots[-1].setPrivateUint32(nslots);
if (fill < newcap) {
/* Clear any excess holes if we tried to shrink below SLOT_CAPACITY_MIN. */
ClearValueRange(slots + fill, newcap - fill, isDenseArray());
}
}
@ -4888,10 +4915,12 @@ js_NativeGetInline(JSContext *cx, JSObject *obj, JSObject *pobj, const Shape *sh
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);
else
JS_ASSERT(!vp->isMagic());
} else {
vp->setUndefined();
}
if (shape->hasDefaultGetter())
return true;
@ -6173,7 +6202,6 @@ 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()) {
@ -6190,9 +6218,8 @@ 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) == key) { slotname = js_##name##_str; goto found; }
if ((code) == slot) { slotname = js_##name##_str; goto found; }
#include "jsproto.tbl"
#undef JS_PROTO
}
@ -6220,7 +6247,7 @@ js_TraceObject(JSTracer *trc, JSObject *obj)
JS_ASSERT(obj->isNative());
JSContext *cx = trc->context;
if (!obj->nativeEmpty() && IS_GC_MARKING_TRACER(trc)) {
if (obj->hasSlotsArray() && !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.
@ -6267,9 +6294,8 @@ 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 = JSSLOT_START(clasp); i != nslots; ++i) {
for (uint32 i = 0; i != nslots; ++i) {
const Value &v = obj->getSlot(i);
JS_SET_TRACING_DETAILS(trc, js_PrintObjectSlotName, obj, i);
MarkValueRaw(trc, v);
@ -6298,14 +6324,13 @@ js_ClearNative(JSContext *cx, JSObject *obj)
}
bool
js_GetReservedSlot(JSContext *cx, JSObject *obj, uint32 index, Value *vp)
js_GetReservedSlot(JSContext *cx, JSObject *obj, uint32 slot, 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);
@ -6316,13 +6341,12 @@ js_GetReservedSlot(JSContext *cx, JSObject *obj, uint32 index, Value *vp)
}
bool
js_SetReservedSlot(JSContext *cx, JSObject *obj, uint32 index, const Value &v)
js_SetReservedSlot(JSContext *cx, JSObject *obj, uint32 slot, 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()) {
@ -6595,11 +6619,8 @@ js_DumpObject(JSObject *obj)
dumpValue(ObjectOrNullValue(obj->getParent()));
fputc('\n', stderr);
i = JSSLOT_PRIVATE;
if (clasp->flags & JSCLASS_HAS_PRIVATE) {
i = JSSLOT_PRIVATE + 1;
if (clasp->flags & JSCLASS_HAS_PRIVATE)
fprintf(stderr, "private %p\n", obj->getPrivate());
}
fprintf(stderr, "slots:\n");
reservedEnd = i + JSCLASS_RESERVED_SLOTS(clasp);

Просмотреть файл

@ -237,17 +237,6 @@ 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;
/*
@ -276,9 +265,12 @@ 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 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.
* The slots member is a pointer to the slot vector for the object.
* This can be either a fixed array allocated immediately after the object,
* or a dynamically allocated array. A dynamic array can be tested for with
* hasSlotsArray(). In all cases, capacity gives the number of usable slots.
* Two objects with the same shape have the same number of fixed slots,
* and either both have or neither have dynamically allocated slot arrays.
*/
struct JSObject : js::gc::Cell {
/*
@ -346,18 +338,20 @@ struct JSObject : js::gc::Cell {
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() */
/*
* Return an immutable, shareable, empty shape with the same clasp as this
* and the same slotSpan as this had when empty.
@ -366,7 +360,8 @@ struct JSObject : js::gc::Cell {
* 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);
inline js::EmptyShape *getEmptyShape(JSContext *cx, js::Class *aclasp,
/* gc::FinalizeKind */ unsigned kind);
bool isNative() const { return map->isNative(); }
@ -529,29 +524,30 @@ struct JSObject : js::gc::Cell {
inline bool hasPropertyTable() const;
uint32 numSlots(void) const {
return dslots ? dslots[-1].toPrivateUint32() : uint32(JS_INITIAL_NSLOTS);
}
uint32 numSlots() const { return capacity; }
size_t slotsAndStructSize(uint32 nslots) const;
size_t slotsAndStructSize() const { return slotsAndStructSize(numSlots()); }
private:
static size_t slotsToDynamicWords(size_t nslots) {
JS_ASSERT(nslots > JS_INITIAL_NSLOTS);
return nslots + 1 - JS_INITIAL_NSLOTS;
}
inline js::Value* fixedSlots() const;
inline size_t numFixedSlots() const;
static size_t dynamicWordsToSlots(size_t nwords) {
JS_ASSERT(nwords > 1);
return nwords - 1 + JS_INITIAL_NSLOTS;
}
static inline size_t getFixedSlotOffset(size_t slot);
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.
@ -570,6 +566,14 @@ struct JSObject : js::gc::Cell {
*/
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
@ -584,26 +588,18 @@ struct JSObject : js::gc::Cell {
bool containsSlot(uint32 slot) const { return slot < slotSpan(); }
js::Value& getSlotRef(uintN slot) {
return (slot < JS_INITIAL_NSLOTS)
? fslots[slot]
: (JS_ASSERT(slot < dslots[-1].toPrivateUint32()),
dslots[slot - JS_INITIAL_NSLOTS]);
JS_ASSERT(slot < capacity);
return slots[slot];
}
const js::Value &getSlot(uintN slot) const {
return (slot < JS_INITIAL_NSLOTS)
? fslots[slot]
: (JS_ASSERT(slot < dslots[-1].toPrivateUint32()),
dslots[slot - JS_INITIAL_NSLOTS]);
JS_ASSERT(slot < capacity);
return slots[slot];
}
void setSlot(uintN slot, const js::Value &value) {
if (slot < JS_INITIAL_NSLOTS) {
fslots[slot] = value;
} else {
JS_ASSERT(slot < dslots[-1].toPrivateUint32());
dslots[slot - JS_INITIAL_NSLOTS] = value;
}
JS_ASSERT(slot < capacity);
slots[slot] = value;
}
inline const js::Value &lockedGetSlot(uintN slot) const;
@ -612,8 +608,7 @@ struct JSObject : js::gc::Cell {
/*
* 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, or when accessing read-only slots within
* JS_INITIAL_NSLOTS.
* one thread can access obj.
*/
inline js::Value getSlotMT(JSContext *cx, uintN slot);
inline void setSlotMT(JSContext *cx, uintN slot, const js::Value &value);
@ -664,12 +659,12 @@ struct JSObject : js::gc::Cell {
void *getPrivate() const {
JS_ASSERT(getClass()->flags & JSCLASS_HAS_PRIVATE);
return *(void **)&fslots[JSSLOT_PRIVATE];
return privateData;
}
void setPrivate(void *data) {
JS_ASSERT(getClass()->flags & JSCLASS_HAS_PRIVATE);
*(void **)&fslots[JSSLOT_PRIVATE] = data;
privateData = data;
}
@ -700,7 +695,7 @@ struct JSObject : js::gc::Cell {
*/
private:
static const uint32 JSSLOT_PRIMITIVE_THIS = JSSLOT_PRIVATE;
static const uint32 JSSLOT_PRIMITIVE_THIS = 0;
public:
inline const js::Value &getPrimitiveThis() const;
@ -710,36 +705,16 @@ struct JSObject : js::gc::Cell {
* 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() 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
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);
JSBool makeDenseArraySlow(JSContext *cx);
@ -751,7 +726,7 @@ struct JSObject : js::gc::Cell {
/*
* Reserved slot structure for Arguments objects:
*
* JSSLOT_PRIVATE - the function's stack frame until the function
* 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
@ -769,13 +744,13 @@ struct JSObject : js::gc::Cell {
* Argument index i is stored in ArgumentsData.slots[i], accessible via
* {get,set}ArgsElement().
*/
static const uint32 JSSLOT_ARGS_DATA = JSSLOT_PRIVATE + 2;
static const uint32 JSSLOT_ARGS_DATA = 1;
public:
/* Number of extra fixed arguments object slots besides JSSLOT_PRIVATE. */
static const uint32 JSSLOT_ARGS_LENGTH = JSSLOT_PRIVATE + 1;
static const uint32 JSSLOT_ARGS_LENGTH = 0;
static const uint32 ARGS_CLASS_RESERVED_SLOTS = 2;
static const uint32 ARGS_FIRST_FREE_SLOT = JSSLOT_PRIVATE + ARGS_CLASS_RESERVED_SLOTS + 1;
static const uint32 ARGS_FIRST_FREE_SLOT = ARGS_CLASS_RESERVED_SLOTS + 1;
/* Lower-order bit stolen from the length slot. */
static const uint32 ARGS_LENGTH_OVERRIDDEN_BIT = 0x1;
@ -802,19 +777,18 @@ struct JSObject : js::gc::Cell {
inline void setArgsCallee(const js::Value &callee);
inline const js::Value &getArgsElement(uint32 i) const;
inline js::Value *addressOfArgsElement(uint32 i) const;
inline js::Value *addressOfArgsElement(uint32 i);
inline void setArgsElement(uint32 i, const js::Value &v);
private:
/*
* Reserved slot structure for Arguments objects:
*
*/
static const uint32 JSSLOT_CALL_CALLEE = JSSLOT_PRIVATE + 1;
static const uint32 JSSLOT_CALL_ARGUMENTS = JSSLOT_PRIVATE + 2;
static const uint32 JSSLOT_CALL_CALLEE = 0;
static const uint32 JSSLOT_CALL_ARGUMENTS = 1;
public:
/* Number of extra fixed slots besides JSSLOT_PRIVATE. */
/* Number of reserved slots. */
static const uint32 CALL_RESERVED_SLOTS = 2;
inline JSObject &getCallObjCallee() const;
@ -828,23 +802,23 @@ struct JSObject : js::gc::Cell {
* Date-specific getters and setters.
*/
static const uint32 JSSLOT_DATE_UTC_TIME = JSSLOT_PRIVATE;
static const uint32 JSSLOT_DATE_UTC_TIME = 0;
/*
* 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 = JSSLOT_PRIVATE + 1;
static const uint32 JSSLOT_DATE_COMPONENTS_START = 1;
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 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 DATE_CLASS_RESERVED_SLOTS = 9;
@ -863,17 +837,18 @@ struct JSObject : js::gc::Cell {
* 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 = JSSLOT_PRIVATE + 1;
static const uint32 JSSLOT_FLAT_CLOSURE_UPVARS = 0;
/*
* 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_BOUND_FUNCTION_THIS = JSSLOT_PRIVATE + 1;
static const uint32 JSSLOT_BOUND_FUNCTION_ARGS_COUNT = 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;
public:
static const uint32 FUN_CLASS_RESERVED_SLOTS = 2;
@ -899,7 +874,7 @@ struct JSObject : js::gc::Cell {
*/
private:
static const uint32 JSSLOT_REGEXP_LAST_INDEX = JSSLOT_PRIVATE + 1;
static const uint32 JSSLOT_REGEXP_LAST_INDEX = 0;
public:
static const uint32 REGEXP_CLASS_RESERVED_SLOTS = 1;
@ -928,12 +903,12 @@ struct JSObject : js::gc::Cell {
* - Others (js_XMLClass, js_XMLFilterClass) don't reserve any slots.
*/
private:
static const uint32 JSSLOT_NAME_PREFIX = JSSLOT_PRIVATE; // shared
static const uint32 JSSLOT_NAME_URI = JSSLOT_PRIVATE + 1; // shared
static const uint32 JSSLOT_NAME_PREFIX = 0; // shared
static const uint32 JSSLOT_NAME_URI = 1; // shared
static const uint32 JSSLOT_NAMESPACE_DECLARED = JSSLOT_PRIVATE + 2;
static const uint32 JSSLOT_NAMESPACE_DECLARED = 2;
static const uint32 JSSLOT_QNAME_LOCAL_NAME = JSSLOT_PRIVATE + 2;
static const uint32 JSSLOT_QNAME_LOCAL_NAME = 2;
public:
static const uint32 NAMESPACE_CLASS_RESERVED_SLOTS = 3;
@ -973,14 +948,8 @@ struct JSObject : js::gc::Cell {
inline bool isCallable();
/* The map field is not initialized here and should be set separately. */
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);
void init(JSContext *cx, js::Class *aclasp, JSObject *proto, JSObject *parent,
void *priv, bool useHoles);
inline void finish(JSContext *cx);
JS_ALWAYS_INLINE void finalize(JSContext *cx, unsigned thindKind);
@ -989,22 +958,21 @@ struct JSObject : js::gc::Cell {
* Like init, but also initializes map. The catch: proto must be the result
* of a call to js_InitClass(...clasp, ...).
*/
inline void initSharingEmptyShape(js::Class *clasp,
JSObject *proto,
JSObject *parent,
const js::Value &privateSlotValue,
JSContext *cx);
inline void initSharingEmptyShape(js::Class *clasp,
inline bool initSharingEmptyShape(JSContext *cx,
js::Class *clasp,
JSObject *proto,
JSObject *parent,
void *priv,
JSContext *cx);
/* gc::FinalizeKind */ unsigned kind);
inline bool hasSlotsArray() const { return !!dslots; }
inline bool hasSlotsArray() const;
/* This method can only be called when hasSlotsArray() returns true. */
inline void freeSlotsArray(JSContext *cx);
/* Free the slots array and copy slots that fit into the fixed array. */
inline void revertToFixedSlots(JSContext *cx);
inline bool hasProperty(JSContext *cx, jsid id, bool *foundp, uintN flags = 0);
bool allocSlot(JSContext *cx, uint32 *slotp);
@ -1125,9 +1093,9 @@ struct JSObject : js::gc::Cell {
inline JSObject *getThrowTypeError() const;
const js::Shape *defineBlockVariable(JSContext *cx, jsid id, intN index);
bool swap(JSContext *cx, JSObject *obj);
void swap(JSObject *obj);
const js::Shape *defineBlockVariable(JSContext *cx, jsid id, intN index);
inline bool canHaveMethodBarrier() const;
@ -1165,22 +1133,29 @@ struct JSObject : js::gc::Cell {
inline void initArrayClass();
};
JS_STATIC_ASSERT(offsetof(JSObject, fslots) % sizeof(js::Value) == 0);
/* Check alignment for any fixed slots allocated after the object. */
JS_STATIC_ASSERT(sizeof(JSObject) % sizeof(js::Value) == 0);
#define JSSLOT_START(clasp) (((clasp)->flags & JSCLASS_HAS_PRIVATE) \
? JSSLOT_PRIVATE + 1 \
: JSSLOT_PRIVATE)
inline js::Value*
JSObject::fixedSlots() const {
return (js::Value*) (jsuword(this) + sizeof(JSObject));
}
#define JSSLOT_FREE(clasp) (JSSLOT_START(clasp) \
+ JSCLASS_RESERVED_SLOTS(clasp))
inline bool
JSObject::hasSlotsArray() const { return this->slots != fixedSlots(); }
/*
* 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).
*/
#define MAX_DSLOTS_LENGTH (~size_t(0) / sizeof(js::Value) - 1)
#define MAX_DSLOTS_LENGTH32 (~uint32(0) / sizeof(js::Value) - 1)
/* static */ inline size_t
JSObject::getFixedSlotOffset(size_t slot) {
return sizeof(JSObject) + (slot * sizeof(js::Value));
}
struct JSObject_Slots2 : JSObject { js::Value fslots[2]; };
struct JSObject_Slots4 : JSObject { js::Value fslots[4]; };
struct JSObject_Slots8 : JSObject { js::Value fslots[8]; };
struct JSObject_Slots12 : JSObject { js::Value fslots[12]; };
struct JSObject_Slots16 : JSObject { js::Value fslots[16]; };
#define JSSLOT_FREE(clasp) JSCLASS_RESERVED_SLOTS(clasp)
#define OBJ_CHECK_SLOT(obj,slot) JS_ASSERT((obj)->containsSlot(slot))
@ -1240,7 +1215,7 @@ inline bool JSObject::isBlock() const { return getClass() == &js_BlockClass; }
/*
* Block scope object macros. The slots reserved by js_BlockClass are:
*
* JSSLOT_PRIVATE JSStackFrame * active frame pointer or null
* 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.
@ -1252,7 +1227,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 = JSSLOT_PRIVATE + 1;
static const uint32 JSSLOT_BLOCK_DEPTH = 0;
static const uint32 JSSLOT_BLOCK_FIRST_FREE_SLOT = JSSLOT_BLOCK_DEPTH + 1;
inline bool
@ -1267,7 +1242,7 @@ JSObject::isClonedBlock() const
return isBlock() && !!getProto();
}
static const uint32 JSSLOT_WITH_THIS = JSSLOT_PRIVATE + 2;
static const uint32 JSSLOT_WITH_THIS = 1;
#define OBJ_BLOCK_COUNT(cx,obj) \
(obj)->propertyCount()

Просмотреть файл

@ -121,8 +121,8 @@ JSObject::unbrand(JSContext *cx)
inline void
JSObject::finalize(JSContext *cx, unsigned thingKind)
{
JS_ASSERT(thingKind == js::gc::FINALIZE_OBJECT ||
thingKind == js::gc::FINALIZE_FUNCTION);
JS_ASSERT(thingKind >= js::gc::FINALIZE_OBJECT0 &&
thingKind <= js::gc::FINALIZE_FUNCTION);
/* Cope with stillborn objects that have no map. */
if (!map)
@ -263,8 +263,7 @@ JSObject::setSlotMT(JSContext *cx, uintN slot, const js::Value &value)
inline js::Value
JSObject::getReservedSlot(uintN index) const
{
uint32 slot = JSSLOT_START(getClass()) + index;
return (slot < numSlots()) ? getSlot(slot) : js::UndefinedValue();
return (index < numSlots()) ? getSlot(index) : js::UndefinedValue();
}
inline bool
@ -283,115 +282,100 @@ inline const js::Value &
JSObject::getPrimitiveThis() const
{
JS_ASSERT(isPrimitive());
return fslots[JSSLOT_PRIMITIVE_THIS];
return getSlot(JSSLOT_PRIMITIVE_THIS);
}
inline void
JSObject::setPrimitiveThis(const js::Value &pthis)
{
JS_ASSERT(isPrimitive());
fslots[JSSLOT_PRIMITIVE_THIS] = pthis;
setSlot(JSSLOT_PRIMITIVE_THIS, pthis);
}
inline void
JSObject::staticAssertArrayLengthIsInPrivateSlot()
inline size_t
JSObject::numFixedSlots() const
{
JS_STATIC_ASSERT(JSSLOT_ARRAY_LENGTH == JSSLOT_PRIVATE);
if (isFunction())
return JSObject::FUN_CLASS_RESERVED_SLOTS;
if (!hasSlotsArray())
return capacity;
js::gc::FinalizeKind kind = js::gc::FinalizeKind(arena()->header()->thingKind);
return js::gc::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);
}
inline uint32
JSObject::getArrayLength() const
{
JS_ASSERT(isArray());
return fslots[JSSLOT_ARRAY_LENGTH].toPrivateUint32();
return (uint32)(size_t) getPrivate();
}
inline void
JSObject::setArrayLength(uint32 length)
{
JS_ASSERT(isArray());
fslots[JSSLOT_ARRAY_LENGTH].setPrivateUint32(length);
setPrivate((void*) length);
}
inline uint32
JSObject::getDenseArrayCapacity() const
JSObject::getDenseArrayCapacity()
{
JS_ASSERT(isDenseArray());
return fslots[JSSLOT_DENSE_ARRAY_CAPACITY].toPrivateUint32();
return numSlots();
}
inline void
JSObject::setDenseArrayCapacity(uint32 capacity)
inline js::Value*
JSObject::getDenseArrayElements()
{
JS_ASSERT(isDenseArray());
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);
return getSlots();
}
inline const js::Value &
JSObject::getDenseArrayElement(uint32 i) const
JSObject::getDenseArrayElement(uintN idx)
{
JS_ASSERT(isDenseArray());
JS_ASSERT(i < getDenseArrayCapacity());
return dslots[i];
return getSlot(idx);
}
inline js::Value *
JSObject::addressOfDenseArrayElement(uint32 i)
JSObject::addressOfDenseArrayElement(uintN idx)
{
JS_ASSERT(isDenseArray());
JS_ASSERT(i < getDenseArrayCapacity());
return &dslots[i];
return &getSlotRef(idx);
}
inline void
JSObject::setDenseArrayElement(uint32 i, const js::Value &v)
JSObject::setDenseArrayElement(uintN idx, const js::Value &val)
{
JS_ASSERT(isDenseArray());
JS_ASSERT(i < getDenseArrayCapacity());
dslots[i] = v;
setSlot(idx, val);
}
inline js::Value *
JSObject::getDenseArrayElements() const
inline bool
JSObject::ensureDenseArrayElements(JSContext *cx, uintN cap)
{
JS_ASSERT(isDenseArray());
return dslots;
return ensureSlots(cx, cap);
}
inline void
JSObject::freeDenseArrayElements(JSContext *cx)
JSObject::shrinkDenseArrayElements(JSContext *cx, uintN cap)
{
JS_ASSERT(isDenseArray());
if (dslots) {
cx->free(dslots - 1);
dslots = NULL;
}
}
inline void
JSObject::voidDenseOnlyArraySlots()
{
JS_ASSERT(isDenseArray());
fslots[JSSLOT_DENSE_ARRAY_CAPACITY].setUndefined();
shrinkSlots(cx, cap);
}
inline void
@ -400,7 +384,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));
fslots[JSSLOT_ARGS_LENGTH].setInt32(argc << ARGS_PACKED_BITS_COUNT);
getSlotRef(JSSLOT_ARGS_LENGTH).setInt32(argc << ARGS_PACKED_BITS_COUNT);
JS_ASSERT(!isArgsLengthOverridden());
}
@ -408,7 +392,7 @@ inline uint32
JSObject::getArgsInitialLength() const
{
JS_ASSERT(isArguments());
uint32 argc = uint32(fslots[JSSLOT_ARGS_LENGTH].toInt32()) >> ARGS_PACKED_BITS_COUNT;
uint32 argc = uint32(getSlot(JSSLOT_ARGS_LENGTH).toInt32()) >> ARGS_PACKED_BITS_COUNT;
JS_ASSERT(argc <= JS_ARGS_LENGTH_MAX);
return argc;
}
@ -417,14 +401,14 @@ inline void
JSObject::setArgsLengthOverridden()
{
JS_ASSERT(isArguments());
fslots[JSSLOT_ARGS_LENGTH].getInt32Ref() |= ARGS_LENGTH_OVERRIDDEN_BIT;
getSlotRef(JSSLOT_ARGS_LENGTH).getInt32Ref() |= ARGS_LENGTH_OVERRIDDEN_BIT;
}
inline bool
JSObject::isArgsLengthOverridden() const
{
JS_ASSERT(isArguments());
const js::Value &v = fslots[JSSLOT_ARGS_LENGTH];
const js::Value &v = getSlot(JSSLOT_ARGS_LENGTH);
return v.toInt32() & ARGS_LENGTH_OVERRIDDEN_BIT;
}
@ -432,14 +416,14 @@ inline js::ArgumentsData *
JSObject::getArgsData() const
{
JS_ASSERT(isArguments());
return (js::ArgumentsData *) fslots[JSSLOT_ARGS_DATA].toPrivate();
return (js::ArgumentsData *) getSlot(JSSLOT_ARGS_DATA).toPrivate();
}
inline void
JSObject::setArgsData(js::ArgumentsData *data)
{
JS_ASSERT(isArguments());
fslots[JSSLOT_ARGS_DATA].setPrivate(data);
getSlotRef(JSSLOT_ARGS_DATA).setPrivate(data);
}
inline const js::Value &
@ -463,7 +447,7 @@ JSObject::getArgsElement(uint32 i) const
}
inline js::Value *
JSObject::addressOfArgsElement(uint32 i) const
JSObject::addressOfArgsElement(uint32 i)
{
JS_ASSERT(isArguments());
JS_ASSERT(i < getArgsInitialLength());
@ -483,49 +467,49 @@ JSObject::setCallObjCallee(JSObject &callee)
{
JS_ASSERT(isCall());
JS_ASSERT(callee.isFunction());
return fslots[JSSLOT_CALL_CALLEE].setObject(callee);
return getSlotRef(JSSLOT_CALL_CALLEE).setObject(callee);
}
inline JSObject &
JSObject::getCallObjCallee() const
{
JS_ASSERT(isCall());
return fslots[JSSLOT_CALL_CALLEE].toObject();
return getSlot(JSSLOT_CALL_CALLEE).toObject();
}
inline JSFunction *
JSObject::getCallObjCalleeFunction() const
{
JS_ASSERT(isCall());
return fslots[JSSLOT_CALL_CALLEE].toObject().getFunctionPrivate();
return getSlot(JSSLOT_CALL_CALLEE).toObject().getFunctionPrivate();
}
inline const js::Value &
JSObject::getCallObjArguments() const
{
JS_ASSERT(isCall());
return fslots[JSSLOT_CALL_ARGUMENTS];
return getSlot(JSSLOT_CALL_ARGUMENTS);
}
inline void
JSObject::setCallObjArguments(const js::Value &v)
{
JS_ASSERT(isCall());
fslots[JSSLOT_CALL_ARGUMENTS] = v;
setSlot(JSSLOT_CALL_ARGUMENTS, v);
}
inline const js::Value &
JSObject::getDateUTCTime() const
{
JS_ASSERT(isDate());
return fslots[JSSLOT_DATE_UTC_TIME];
return getSlot(JSSLOT_DATE_UTC_TIME);
}
inline void
JSObject::setDateUTCTime(const js::Value &time)
{
JS_ASSERT(isDate());
fslots[JSSLOT_DATE_UTC_TIME] = time;
setSlot(JSSLOT_DATE_UTC_TIME, time);
}
inline js::Value *
@ -533,7 +517,7 @@ JSObject::getFlatClosureUpvars() const
{
JS_ASSERT(isFunction());
JS_ASSERT(FUN_FLAT_CLOSURE(getFunctionPrivate()));
return (js::Value *) fslots[JSSLOT_FLAT_CLOSURE_UPVARS].toPrivate();
return (js::Value *) getSlot(JSSLOT_FLAT_CLOSURE_UPVARS).toPrivate();
}
inline js::Value
@ -547,20 +531,21 @@ JSObject::setFlatClosureUpvars(js::Value *upvars)
{
JS_ASSERT(isFunction());
JS_ASSERT(FUN_FLAT_CLOSURE(getFunctionPrivate()));
fslots[JSSLOT_FLAT_CLOSURE_UPVARS].setPrivate(upvars);
getSlotRef(JSSLOT_FLAT_CLOSURE_UPVARS).setPrivate(upvars);
}
inline bool
JSObject::hasMethodObj(const JSObject& obj) const
{
return fslots[JSSLOT_FUN_METHOD_OBJ].isObject() &&
&fslots[JSSLOT_FUN_METHOD_OBJ].toObject() == &obj;
return JSSLOT_FUN_METHOD_OBJ < numSlots() &&
getSlot(JSSLOT_FUN_METHOD_OBJ).isObject() &&
&getSlot(JSSLOT_FUN_METHOD_OBJ).toObject() == &obj;
}
inline void
JSObject::setMethodObj(JSObject& obj)
{
fslots[JSSLOT_FUN_METHOD_OBJ].setObject(obj);
getSlotRef(JSSLOT_FUN_METHOD_OBJ).setObject(obj);
}
inline js::NativeIterator *
@ -579,76 +564,74 @@ inline jsval
JSObject::getNamePrefix() const
{
JS_ASSERT(isNamespace() || isQName());
return js::Jsvalify(fslots[JSSLOT_NAME_PREFIX]);
return js::Jsvalify(getSlot(JSSLOT_NAME_PREFIX));
}
inline void
JSObject::setNamePrefix(jsval prefix)
{
JS_ASSERT(isNamespace() || isQName());
fslots[JSSLOT_NAME_PREFIX] = js::Valueify(prefix);
setSlot(JSSLOT_NAME_PREFIX, js::Valueify(prefix));
}
inline jsval
JSObject::getNameURI() const
{
JS_ASSERT(isNamespace() || isQName());
return js::Jsvalify(fslots[JSSLOT_NAME_URI]);
return js::Jsvalify(getSlot(JSSLOT_NAME_URI));
}
inline void
JSObject::setNameURI(jsval uri)
{
JS_ASSERT(isNamespace() || isQName());
fslots[JSSLOT_NAME_URI] = js::Valueify(uri);
setSlot(JSSLOT_NAME_URI, js::Valueify(uri));
}
inline jsval
JSObject::getNamespaceDeclared() const
{
JS_ASSERT(isNamespace());
return js::Jsvalify(fslots[JSSLOT_NAMESPACE_DECLARED]);
return js::Jsvalify(getSlot(JSSLOT_NAMESPACE_DECLARED));
}
inline void
JSObject::setNamespaceDeclared(jsval decl)
{
JS_ASSERT(isNamespace());
fslots[JSSLOT_NAMESPACE_DECLARED] = js::Valueify(decl);
setSlot(JSSLOT_NAMESPACE_DECLARED, js::Valueify(decl));
}
inline jsval
JSObject::getQNameLocalName() const
{
JS_ASSERT(isQName());
return js::Jsvalify(fslots[JSSLOT_QNAME_LOCAL_NAME]);
return js::Jsvalify(getSlot(JSSLOT_QNAME_LOCAL_NAME));
}
inline void
JSObject::setQNameLocalName(jsval name)
{
JS_ASSERT(isQName());
fslots[JSSLOT_QNAME_LOCAL_NAME] = js::Valueify(name);
setSlot(JSSLOT_QNAME_LOCAL_NAME, js::Valueify(name));
}
inline JSObject *
JSObject::getWithThis() const
{
return &fslots[JSSLOT_WITH_THIS].toObject();
return &getSlot(JSSLOT_WITH_THIS).toObject();
}
inline void
JSObject::setWithThis(JSObject *thisp)
{
fslots[JSSLOT_WITH_THIS].setObject(*thisp);
getSlotRef(JSSLOT_WITH_THIS).setObject(*thisp);
}
inline void
JSObject::initCommon(js::Class *aclasp, JSObject *proto, JSObject *parent,
JSContext *cx)
JSObject::init(JSContext *cx, js::Class *aclasp, JSObject *proto, JSObject *parent,
void *priv, bool useHoles)
{
JS_STATIC_ASSERT(JSSLOT_PRIVATE + 3 == JS_INITIAL_NSLOTS);
clasp = aclasp;
flags = 0;
@ -665,43 +648,22 @@ JSObject::initCommon(js::Class *aclasp, JSObject *proto, JSObject *parent,
setProto(proto);
setParent(parent);
fslots[JSSLOT_PRIVATE + 1].setUndefined();
fslots[JSSLOT_PRIVATE + 2].setUndefined();
dslots = NULL;
privateData = priv;
slots = fixedSlots();
/*
* 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(slots, capacity, useHoles);
#ifdef JS_THREADSAFE
js_InitTitle(cx, &title);
#endif
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();
emptyShapes = NULL;
}
inline void
@ -718,40 +680,43 @@ JSObject::finish(JSContext *cx)
#endif
}
inline void
JSObject::initSharingEmptyShape(js::Class *aclasp,
inline bool
JSObject::initSharingEmptyShape(JSContext *cx,
js::Class *aclasp,
JSObject *proto,
JSObject *parent,
const js::Value &privateSlotValue,
JSContext *cx)
void *privateValue,
/* js::gc::FinalizeKind */ unsigned kind)
{
init(aclasp, proto, parent, privateSlotValue, cx);
init(cx, aclasp, proto, parent, privateValue, false);
JS_ASSERT(!isDenseArray());
js::EmptyShape *empty = proto->getEmptyShape(cx, aclasp, kind);
if (!empty)
return false;
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());
JS_ASSERT(dslots[-1].toPrivateUint32() > JS_INITIAL_NSLOTS);
cx->free(dslots - 1);
cx->free(slots);
}
inline void
JSObject::revertToFixedSlots(JSContext *cx)
{
JS_ASSERT(hasSlotsArray());
size_t fixed = numFixedSlots();
JS_ASSERT(capacity >= fixed);
memcpy(fixedSlots(), slots, fixed * sizeof(js::Value));
freeSlotsArray(cx);
slots = fixedSlots();
capacity = fixed;
}
inline bool
@ -830,7 +795,8 @@ class AutoPropertyDescriptorRooter : private AutoGCRooter, public PropertyDescri
};
static inline bool
InitScopeForObject(JSContext* cx, JSObject* obj, js::Class *clasp, JSObject* proto)
InitScopeForObject(JSContext* cx, JSObject* obj, js::Class *clasp, JSObject* proto,
gc::FinalizeKind kind)
{
JS_ASSERT(clasp->isNative());
JS_ASSERT(proto == obj->getProto());
@ -841,7 +807,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);
empty = proto->getEmptyShape(cx, clasp, kind);
JS_UNLOCK_OBJ(cx, proto);
if (!empty)
goto bad;
@ -851,13 +817,11 @@ 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;
if (freeslot > JS_INITIAL_NSLOTS && !obj->allocSlots(cx, freeslot))
uint32 freeslot = JSSLOT_FREE(clasp);
if (freeslot > obj->numSlots() && !obj->allocSlots(cx, freeslot))
goto bad;
}
@ -877,7 +841,8 @@ 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)
NewNativeClassInstance(JSContext *cx, Class *clasp, JSObject *proto,
JSObject *parent, gc::FinalizeKind kind)
{
JS_ASSERT(proto);
JS_ASSERT(proto->isNative());
@ -887,18 +852,19 @@ NewNativeClassInstance(JSContext *cx, Class *clasp, JSObject *proto, JSObject *p
* 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);
JSObject* obj = js_NewGCObject(cx, kind);
if (obj) {
/*
* Default parent to the parent of the prototype, which was set from
* the parent of the prototype's constructor.
*/
obj->init(clasp, proto, parent, cx);
bool useHoles = (clasp == &js_ArrayClass);
obj->init(cx, clasp, proto, parent, NULL, useHoles);
JS_LOCK_OBJ(cx, proto);
JS_ASSERT(proto->canProvideEmptyShape(clasp));
js::EmptyShape *empty = proto->getEmptyShape(cx, clasp);
js::EmptyShape *empty = proto->getEmptyShape(cx, clasp, kind);
JS_UNLOCK_OBJ(cx, proto);
if (empty)
@ -910,6 +876,13 @@ NewNativeClassInstance(JSContext *cx, Class *clasp, JSObject *proto, JSObject *p
return obj;
}
static inline JSObject *
NewNativeClassInstance(JSContext *cx, Class *clasp, JSObject *proto, JSObject *parent)
{
gc::FinalizeKind kind = gc::GetGCObjectKind(JSCLASS_RESERVED_SLOTS(clasp));
return NewNativeClassInstance(cx, clasp, proto, parent, kind);
}
bool
FindClassPrototype(JSContext *cx, JSObject *scope, JSProtoKey protoKey, JSObject **protop,
Class *clasp);
@ -921,7 +894,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)
NewBuiltinClassInstance(JSContext *cx, Class *clasp, gc::FinalizeKind kind)
{
VOUCH_DOES_NOT_REQUIRE_STACK();
@ -950,7 +923,14 @@ NewBuiltinClassInstance(JSContext *cx, Class *clasp)
return NULL;
}
return NewNativeClassInstance(cx, clasp, proto, global);
return NewNativeClassInstance(cx, clasp, proto, global, kind);
}
static inline JSObject *
NewBuiltinClassInstance(JSContext *cx, Class *clasp)
{
gc::FinalizeKind kind = gc::GetGCObjectKind(JSCLASS_RESERVED_SLOTS(clasp));
return NewBuiltinClassInstance(cx, clasp, kind);
}
static inline JSProtoKey
@ -1001,7 +981,8 @@ namespace detail
{
template <bool withProto, bool isFunction>
static JS_ALWAYS_INLINE JSObject *
NewObject(JSContext *cx, js::Class *clasp, JSObject *proto, JSObject *parent)
NewObject(JSContext *cx, js::Class *clasp, JSObject *proto, JSObject *parent,
gc::FinalizeKind kind)
{
/* Bootstrap the ur-object, and make it the default prototype object. */
if (withProto == WithProto::Class && !proto) {
@ -1010,8 +991,7 @@ 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
@ -1020,18 +1000,23 @@ 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);
JSObject* obj = isFunction ? js_NewGCFunction(cx) : js_NewGCObject(cx, kind);
if (!obj)
goto out;
/* This needs to match up with the size of JSFunction::data_padding. */
JS_ASSERT_IF(isFunction, kind == gc::FINALIZE_OBJECT2);
/*
* Default parent to the parent of the prototype, which was set from
* the parent of the prototype's constructor.
*/
obj->init(clasp, proto, (!parent && proto) ? proto->getParent() : parent, cx);
obj->init(cx, clasp, proto,
(!parent && proto) ? proto->getParent() : parent,
NULL, clasp == &js_ArrayClass);
if (clasp->isNative()) {
if (!InitScopeForObject(cx, obj, clasp, proto)) {
if (!InitScopeForObject(cx, obj, clasp, proto, kind)) {
obj = NULL;
goto out;
}
@ -1043,28 +1028,80 @@ 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);
return detail::NewObject<WithProto::Class, true>(cx, &js_FunctionClass, NULL, parent,
gc::FINALIZE_OBJECT2);
}
template <WithProto::e withProto>
static JS_ALWAYS_INLINE JSObject *
NewNonFunction(JSContext *cx, js::Class *clasp, JSObject *proto, JSObject *parent,
gc::FinalizeKind kind)
{
return detail::NewObject<withProto, false>(cx, clasp, proto, parent, kind);
}
template <WithProto::e withProto>
static JS_ALWAYS_INLINE JSObject *
NewNonFunction(JSContext *cx, js::Class *clasp, JSObject *proto, JSObject *parent)
{
return detail::NewObject<withProto, false>(cx, clasp, proto, parent);
gc::FinalizeKind kind = gc::GetGCObjectKind(JSCLASS_RESERVED_SLOTS(clasp));
return detail::NewObject<withProto, false>(cx, clasp, proto, parent, kind);
}
template <WithProto::e withProto>
static JS_ALWAYS_INLINE JSObject *
NewObject(JSContext *cx, js::Class *clasp, JSObject *proto, JSObject *parent,
gc::FinalizeKind kind)
{
if (clasp == &js_FunctionClass)
return detail::NewObject<withProto, true>(cx, clasp, proto, parent, kind);
return detail::NewObject<withProto, false>(cx, clasp, proto, parent, kind);
}
template <WithProto::e withProto>
static JS_ALWAYS_INLINE JSObject *
NewObject(JSContext *cx, js::Class *clasp, JSObject *proto, JSObject *parent)
{
return (clasp == &js_FunctionClass)
? detail::NewObject<withProto, true>(cx, clasp, proto, parent)
: detail::NewObject<withProto, false>(cx, clasp, proto, parent);
gc::FinalizeKind kind = gc::GetGCObjectKind(JSCLASS_RESERVED_SLOTS(clasp));
return NewObject<withProto>(cx, clasp, proto, parent, kind);
}
/* Creates a new array with a zero length and the given finalize kind. */
static inline JSObject *
NewArrayWithKind(JSContext* cx, gc::FinalizeKind 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 gc::FinalizeKind
GuessObjectGCKind(size_t numSlots, bool isArray)
{
if (numSlots)
return gc::GetGCObjectKind(numSlots);
return isArray ? gc::FINALIZE_OBJECT8 : gc::FINALIZE_OBJECT4;
}
/*
* 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 gc::FinalizeKind
NewObjectGCKind(JSContext *cx, js::Class *clasp)
{
if (clasp == &js_ArrayClass || clasp == &js_SlowArrayClass)
return gc::FINALIZE_OBJECT8;
if (clasp == &js_FunctionClass)
return gc::FINALIZE_OBJECT2;
return gc::FINALIZE_OBJECT4;
}
class AutoPropertyDropper {

Просмотреть файл

@ -4492,7 +4492,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
case JSOP_NEWINIT:
{
i = GET_INT8(pc);
i = GET_UINT16(pc);
LOCAL_ASSERT(i == JSProto_Array || i == JSProto_Object);
todo = ss->sprinter.offset;

Просмотреть файл

@ -246,7 +246,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, 2, 0, 1, 19, JOF_INT8)
OPDEF(JSOP_NEWINIT, 89, "newinit", NULL, 5, 0, 1, 19, JOF_UINT16PAIR)
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)

Просмотреть файл

@ -1090,8 +1090,9 @@ NewProxyObject(JSContext *cx, JSProxyHandler *handler, const Value &priv, JSObje
clasp = &FunctionProxyClass;
else
clasp = handler->isOuterWindow() ? &OuterWindowProxyClass : &ObjectProxyClass;
JSObject *obj = NewNonFunction<WithProto::Given>(cx, clasp, proto, parent);
if (!obj || (construct && !obj->ensureInstanceReservedSlots(cx, 0)))
if (!obj || !obj->ensureInstanceReservedSlots(cx, 0))
return NULL;
obj->setSlot(JSSLOT_PROXY_HANDLER, PrivateValue(handler));
obj->setSlot(JSSLOT_PROXY_PRIVATE, priv);
@ -1235,8 +1236,8 @@ static JSFunctionSpec static_methods[] = {
extern Class CallableObjectClass;
static const uint32 JSSLOT_CALLABLE_CALL = JSSLOT_PRIVATE;
static const uint32 JSSLOT_CALLABLE_CONSTRUCT = JSSLOT_PRIVATE + 1;
static const uint32 JSSLOT_CALLABLE_CALL = 0;
static const uint32 JSSLOT_CALLABLE_CONSTRUCT = 1;
static JSBool
callable_Call(JSContext *cx, uintN argc, Value *vp)
@ -1247,7 +1248,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->fslots[JSSLOT_CALLABLE_CALL];
const Value &fval = callable->getSlot(JSSLOT_CALLABLE_CALL);
Value rval;
bool ok = ExternalInvoke(cx, thisobj, fval, argc, JS_ARGV(cx, vp), &rval);
*vp = rval;
@ -1263,10 +1264,10 @@ callable_Construct(JSContext *cx, uintN argc, Value *vp)
JSObject *callable = &vp[0].toObject();
JS_ASSERT(callable->getClass() == &CallableObjectClass);
Value fval = callable->fslots[JSSLOT_CALLABLE_CONSTRUCT];
Value fval = callable->getSlot(JSSLOT_CALLABLE_CONSTRUCT);
if (fval.isUndefined()) {
/* We don't have an explicit constructor so allocate a new object and use the call. */
fval = callable->fslots[JSSLOT_CALLABLE_CALL];
fval = callable->getSlot(JSSLOT_CALLABLE_CALL);
JS_ASSERT(fval.isObject());
/* callable is the constructor, so get callable.prototype is the proto of the new object. */
@ -1288,7 +1289,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->fslots[JSSLOT_CALLABLE_CALL],
if (!ExternalInvoke(cx, newobj, callable->getSlot(JSSLOT_CALLABLE_CALL),
argc, vp + 2, &rval)) {
return false;
}
@ -1346,15 +1347,19 @@ 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. */
JSObject *newborn = NewNonFunction<WithProto::Given>(cx, clasp, proto, parent);
/*
* 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.
*/
gc::FinalizeKind kind = gc::FinalizeKind(proxy->arena()->header()->thingKind);
JSObject *newborn = NewNonFunction<WithProto::Given>(cx, clasp, proto, parent, kind);
if (!newborn)
return NULL;
AutoObjectRooter tvr2(cx, newborn);
if (clasp == &CallableObjectClass) {
newborn->fslots[JSSLOT_CALLABLE_CALL] = GetCall(proxy);
newborn->fslots[JSSLOT_CALLABLE_CONSTRUCT] = GetConstruct(proxy);
newborn->setSlot(JSSLOT_CALLABLE_CALL, GetCall(proxy));
newborn->setSlot(JSSLOT_CALLABLE_CONSTRUCT, GetConstruct(proxy));
}
{
@ -1364,7 +1369,8 @@ FixProxy(JSContext *cx, JSObject *proxy, JSBool *bp)
}
/* Trade contents between the newborn object and the proxy. */
proxy->swap(newborn);
if (!proxy->swap(cx, newborn))
return false;
/* The GC will dispose of the proxy object. */

Просмотреть файл

@ -128,12 +128,12 @@ class JSProxy {
};
/* Shared between object and function proxies. */
const uint32 JSSLOT_PROXY_HANDLER = JSSLOT_PRIVATE + 0;
const uint32 JSSLOT_PROXY_PRIVATE = JSSLOT_PRIVATE + 1;
const uint32 JSSLOT_PROXY_EXTRA = JSSLOT_PRIVATE + 2;
const uint32 JSSLOT_PROXY_HANDLER = 0;
const uint32 JSSLOT_PROXY_PRIVATE = 1;
const uint32 JSSLOT_PROXY_EXTRA = 2;
/* Function proxies only. */
const uint32 JSSLOT_PROXY_CALL = JSSLOT_PRIVATE + 2;
const uint32 JSSLOT_PROXY_CONSTRUCT = JSSLOT_PRIVATE + 3;
const uint32 JSSLOT_PROXY_CALL = 2;
const uint32 JSSLOT_PROXY_CONSTRUCT = 3;
extern JS_FRIEND_API(js::Class) ObjectProxyClass;
extern JS_FRIEND_API(js::Class) FunctionProxyClass;

Просмотреть файл

@ -216,28 +216,28 @@ inline const js::Value &
JSObject::getRegExpLastIndex() const
{
JS_ASSERT(isRegExp());
return fslots[JSSLOT_REGEXP_LAST_INDEX];
return getSlot(JSSLOT_REGEXP_LAST_INDEX);
}
inline void
JSObject::setRegExpLastIndex(const js::Value &v)
{
JS_ASSERT(isRegExp());
fslots[JSSLOT_REGEXP_LAST_INDEX] = v;
setSlot(JSSLOT_REGEXP_LAST_INDEX, v);
}
inline void
JSObject::setRegExpLastIndex(jsdouble d)
{
JS_ASSERT(isRegExp());
fslots[JSSLOT_REGEXP_LAST_INDEX] = js::NumberValue(d);
setSlot(JSSLOT_REGEXP_LAST_INDEX, js::NumberValue(d));
}
inline void
JSObject::zeroRegExpLastIndex()
{
JS_ASSERT(isRegExp());
fslots[JSSLOT_REGEXP_LAST_INDEX].setInt32(0);
getSlotRef(JSSLOT_REGEXP_LAST_INDEX).setInt32(0);
}
namespace js { class AutoStringRooter; }

Просмотреть файл

@ -1170,6 +1170,18 @@ 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_IF(!lastProp->isEmptyShape() && lastProp->hasSlot(),
lastProp->slot == fixed - 1);
revertToFixedSlots(cx);
}
}
updateShape(cx);
@ -1205,6 +1217,14 @@ JSObject::clear(JSContext *cx)
if (inDictionaryMode())
shape->listp = &lastProp;
/*
* Revert to fixed slots if we have cleared below the first dynamically
* allocated slot, preserving invariant that objects with the same shape
* use the fixed slots in the same way.
*/
if (hasSlotsArray() && JSSLOT_FREE(getClass()) <= numFixedSlots())
revertToFixedSlots(cx);
/*
* We have rewound to a uniquely-shaped empty scope, so we don't need an
* override for this object's shape.

Просмотреть файл

@ -60,19 +60,45 @@ js::Shape::freeTable(JSContext *cx)
}
inline js::EmptyShape *
JSObject::getEmptyShape(JSContext *cx, js::Class *aclasp)
JSObject::getEmptyShape(JSContext *cx, js::Class *aclasp,
/* gc::FinalizeKind */ unsigned kind)
{
if (emptyShape)
JS_ASSERT(aclasp == emptyShape->getClass());
else
emptyShape = js::EmptyShape::create(cx, aclasp);
return emptyShape;
JS_ASSERT(kind >= js::gc::FINALIZE_OBJECT0 && kind <= js::gc::FINALIZE_OBJECT_LAST);
int i = kind - js::gc::FINALIZE_OBJECT0;
if (!emptyShapes) {
emptyShapes = (js::EmptyShape**)
cx->calloc(sizeof(js::EmptyShape*) * js::gc::JS_FINALIZE_OBJECT_LIMIT);
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];
}
inline bool
JSObject::canProvideEmptyShape(js::Class *aclasp)
{
return !emptyShape || emptyShape->getClass() == aclasp;
return !emptyShapes || emptyShapes[0]->getClass() == aclasp;
}
inline void

Просмотреть файл

@ -2700,9 +2700,7 @@ ptrdiff_t
TraceRecorder::nativeGlobalSlot(const Value* p) const
{
JS_ASSERT(isGlobal(p));
if (size_t(p - globalObj->fslots) < JS_INITIAL_NSLOTS)
return ptrdiff_t(p - globalObj->fslots);
return ptrdiff_t((p - globalObj->dslots) + JS_INITIAL_NSLOTS);
return ptrdiff_t(p - globalObj->slots);
}
/* Determine the offset in the native global frame for a jsval we track. */
@ -2716,8 +2714,7 @@ TraceRecorder::nativeGlobalOffset(const Value* p) const
bool
TraceRecorder::isGlobal(const Value* p) const
{
return ((size_t(p - globalObj->fslots) < JS_INITIAL_NSLOTS) ||
(size_t(p - globalObj->dslots) < (globalObj->numSlots() - JS_INITIAL_NSLOTS)));
return (size_t(p - globalObj->slots) < globalObj->numSlots());
}
bool
@ -3495,7 +3492,7 @@ struct ArgClosureTraits
// Get the offset of our object slots from the object's dslots pointer.
static inline uint32 slot_offset(JSObject* obj) {
return JSSLOT_START(&js_CallClass) + JSObject::CALL_RESERVED_SLOTS;
return JSObject::CALL_RESERVED_SLOTS;
}
// Get the maximum slot index of this type that should be allowed
@ -3526,7 +3523,7 @@ struct VarClosureTraits
}
static inline uint32 slot_offset(JSObject* obj) {
return JSSLOT_START(&js_CallClass) + JSObject::CALL_RESERVED_SLOTS +
return JSObject::CALL_RESERVED_SLOTS +
obj->getCallObjCalleeFunction()->nargs;
}
@ -3991,7 +3988,7 @@ TraceRecorder::known(JSObject** p)
}
/*
* The dslots of the global object are sometimes reallocated by the interpreter.
* The slots 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.
*/
@ -4000,8 +3997,8 @@ TraceRecorder::checkForGlobalObjectReallocationHelper()
{
debug_only_print0(LC_TMTracer, "globalObj->dslots relocated, updating tracker\n");
Value* src = global_dslots;
Value* dst = globalObj->dslots;
jsuint length = globalObj->dslots[-1].toPrivateUint32() - JS_INITIAL_NSLOTS;
Value* dst = globalObj->getSlots();
jsuint length = globalObj->capacity;
LIns** map = (LIns**)alloca(sizeof(LIns*) * length);
for (jsuint n = 0; n < length; ++n) {
map[n] = tracker.get(src);
@ -4009,7 +4006,7 @@ TraceRecorder::checkForGlobalObjectReallocationHelper()
}
for (jsuint n = 0; n < length; ++n)
tracker.set(dst++, map[n]);
global_dslots = globalObj->dslots;
global_dslots = globalObj->getSlots();
}
/* Determine whether the current branch is a loop edge (taken or not taken). */
@ -8837,7 +8834,7 @@ TraceRecorder::incProp(jsint incr, bool pre)
CHECK_STATUS_A(inc(v, v_ins, incr, pre));
LIns* dslots_ins = NULL;
stobj_set_slot(obj_ins, slot, dslots_ins, v, v_ins);
stobj_set_slot(obj, obj_ins, slot, dslots_ins, v, v_ins);
return ARECORD_CONTINUE;
}
@ -9575,7 +9572,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, fslots) + slot * sizeof(Value), ACCSET_OTHER);
box_value_into(v, v_ins, obj_ins, JSObject::getFixedSlotOffset(slot), ACCSET_OTHER);
}
void
@ -9583,49 +9580,32 @@ 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, dslots), ACCSET_OTHER);
dslots_ins = lir->insLoad(LIR_ldp, obj_ins, offsetof(JSObject, slots), ACCSET_OTHER);
box_value_into(v, v_ins, dslots_ins, slot * sizeof(Value), ACCSET_OTHER);
}
void
TraceRecorder::stobj_set_slot(LIns* obj_ins, unsigned slot, LIns*& dslots_ins,
TraceRecorder::stobj_set_slot(JSObject *obj, LIns* obj_ins, unsigned slot, LIns*& dslots_ins,
const Value &v, LIns* v_ins)
{
if (slot < JS_INITIAL_NSLOTS)
/*
* 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());
stobj_set_fslot(obj_ins, slot, v, v_ins);
else
stobj_set_dslot(obj_ins, slot - JS_INITIAL_NSLOTS, dslots_ins, v, v_ins);
} else {
stobj_set_dslot(obj_ins, slot, dslots_ins, v, v_ins);
}
}
#if JS_BITS_PER_WORD == 32 || JS_BITS_PER_WORD == 64
void
TraceRecorder::set_array_fslot(LIns *obj_ins, unsigned slot, uint32 val)
{
/*
* 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)
TraceRecorder::stobj_get_slot_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);
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);
}
#endif
@ -9634,12 +9614,14 @@ TraceRecorder::unbox_slot(JSObject *obj, LIns *obj_ins, uint32 slot, VMSideExit
{
LIns *vaddr_ins;
ptrdiff_t offset;
if (slot < JS_INITIAL_NSLOTS) {
/* Same guarantee about fixed slots as stobj_set_slot. */
if (!obj->hasSlotsArray()) {
vaddr_ins = obj_ins;
offset = offsetof(JSObject, fslots) + slot * sizeof(Value);
offset = JSObject::getFixedSlotOffset(slot);
} else {
vaddr_ins = lir->insLoad(LIR_ldp, obj_ins, offsetof(JSObject, dslots), ACCSET_OTHER);
offset = (slot - JS_INITIAL_NSLOTS) * sizeof(Value);
vaddr_ins = lir->insLoad(LIR_ldp, obj_ins, offsetof(JSObject, slots), ACCSET_OTHER);
offset = slot * sizeof(Value);
}
const Value &v = obj->getSlot(slot);
@ -9649,12 +9631,11 @@ TraceRecorder::unbox_slot(JSObject *obj, LIns *obj_ins, uint32 slot, VMSideExit
#if JS_BITS_PER_WORD == 32
LIns*
TraceRecorder::stobj_get_fslot_private_ptr(LIns *obj_ins, unsigned slot)
TraceRecorder::stobj_get_const_private_ptr(LIns *obj_ins, unsigned slot)
{
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);
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);
}
void
@ -9818,13 +9799,12 @@ TraceRecorder::box_value_for_native_call(const Value &v, LIns *v_ins)
#elif JS_BITS_PER_WORD == 64
LIns*
TraceRecorder::stobj_get_fslot_private_ptr(LIns *obj_ins, unsigned slot)
TraceRecorder::stobj_get_const_private_ptr(LIns *obj_ins, unsigned slot)
{
/* N.B. On 64-bit, privates are encoded differently from other pointers. */
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);
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);
return lir->ins2ImmI(LIR_lshq, v_ins, 1);
}
@ -10002,8 +9982,17 @@ TraceRecorder::stobj_get_parent(nanojit::LIns* obj_ins)
LIns*
TraceRecorder::stobj_get_private(nanojit::LIns* obj_ins)
{
JS_STATIC_ASSERT(JSSLOT_PRIVATE == 0);
return lir->insLoad(LIR_ldp, obj_ins, offsetof(JSObject, fslots), ACCSET_OTHER);
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);
}
LIns*
@ -10567,7 +10556,7 @@ TraceRecorder::newArguments(LIns* callee_ins, bool strict)
guard(false, lir->insEqP_0(argsobj_ins), OOM_EXIT);
if (strict) {
LIns* argsData_ins = stobj_get_fslot_private_ptr(argsobj_ins, JSObject::JSSLOT_ARGS_DATA);
LIns* argsData_ins = stobj_get_const_private_ptr(argsobj_ins, JSObject::JSSLOT_ARGS_DATA);
ptrdiff_t slotsOffset = offsetof(ArgumentsData, slots);
cx->fp()->forEachCanonicalActualArg(BoxArg(this, slotsOffset, argsData_ins));
}
@ -10960,7 +10949,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->emptyShape->getClass() == clasp);
JS_ASSERT_IF(clasp != &js_ArrayClass, proto->emptyShapes[0]->getClass() == clasp);
proto_ins = INS_CONSTOBJ(proto);
return RECORD_CONTINUE;
@ -10984,7 +10973,8 @@ 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());
EmptyShape *empty = proto->emptyShape;
JS_ASSERT(proto->emptyShapes);
EmptyShape *empty = proto->emptyShapes[0];
JS_ASSERT(empty);
JS_ASSERT(JSCLASS_CACHED_PROTO_KEY(empty->getClass()) == key);
}
@ -11919,7 +11909,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_ins, slot, dslots_ins, v, v_ins);
stobj_set_slot(obj, obj_ins, slot, dslots_ins, v, v_ins);
}
}
@ -12088,7 +12078,7 @@ TraceRecorder::setCallProp(JSObject *callobj, LIns *callobj_ins, const Shape *sh
JS_ASSERT(shape->hasShortID());
LIns* dslots_ins = NULL;
stobj_set_slot(callobj_ins, slot, dslots_ins, v, v_ins);
stobj_set_dslot(callobj_ins, slot, dslots_ins, v, v_ins);
return RECORD_CONTINUE;
}
@ -12626,8 +12616,8 @@ static bool OkToTraceTypedArrays = false;
JS_REQUIRES_STACK void
TraceRecorder::guardNotHole(LIns *argsobj_ins, LIns *idx_ins)
{
// vp = &argsobj->fslots[JSSLOT_ARGS_DATA].slots[idx]
LIns* argsData_ins = stobj_get_fslot_private_ptr(argsobj_ins, JSObject::JSSLOT_ARGS_DATA);
// vp = &argsobj->slots[JSSLOT_ARGS_DATA].slots[idx]
LIns* argsData_ins = stobj_get_const_private_ptr(argsobj_ins, JSObject::JSSLOT_ARGS_DATA);
LIns* slotOffset_ins = lir->ins2(LIR_addp,
INS_CONSTWORD(offsetof(ArgumentsData, slots)),
lir->insUI2P(lir->ins2ImmI(LIR_muli, idx_ins, sizeof(Value))));
@ -13070,22 +13060,14 @@ TraceRecorder::setElem(int lval_spindex, int idx_spindex, int v_spindex)
// be an integer.
CHECK_STATUS_A(makeNumberInt32(idx_ins, &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(stobj_get_fslot_uint32(obj_ins, JSObject::JSSLOT_DENSE_ARRAY_CAPACITY),
addName(lir->insLoad(LIR_ldi, obj_ins,
offsetof(JSObject, capacity), ACCSET_OTHER),
"capacity");
LIns* br = lir->insBranch(LIR_jt, lir->ins2(LIR_ltui, idx_ins, capacity_ins), NULL);
LIns* args[] = { idx_ins, obj_ins, cx_ins };
@ -13095,7 +13077,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, dslots), ACCSET_OTHER), "dslots");
addName(lir->insLoad(LIR_ldp, obj_ins, offsetof(JSObject, slots), 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));
@ -13301,7 +13283,7 @@ TraceRecorder::record_JSOP_GETFCSLOT()
JSObject& callee = cx->fp()->callee();
LIns* callee_ins = get(&cx->fp()->calleeValue());
LIns* upvars_ins = stobj_get_fslot_private_ptr(callee_ins,
LIns* upvars_ins = stobj_get_const_private_ptr(callee_ins,
JSObject::JSSLOT_FLAT_CLOSURE_UPVARS);
unsigned index = GET_UINT16(cx->regs->pc);
@ -13566,7 +13548,7 @@ TraceRecorder::record_JSOP_APPLY()
length = aobj->getArrayLength();
guard(true,
lir->ins2ImmI(LIR_eqi,
stobj_get_fslot_uint32(aobj_ins, JSObject::JSSLOT_ARRAY_LENGTH),
stobj_get_private_uint32(aobj_ins),
length),
BRANCH_EXIT);
} else if (aobj->isArguments()) {
@ -13947,8 +13929,10 @@ TraceRecorder::denseArrayElement(Value& oval, Value& ival, Value*& vp, LIns*& v_
* the correct value.
*/
LIns* capacity_ins =
addName(stobj_get_fslot_uint32(obj_ins, JSObject::JSSLOT_DENSE_ARRAY_CAPACITY),
addName(lir->insLoad(LIR_ldi, obj_ins,
offsetof(JSObject, capacity), ACCSET_OTHER),
"capacity");
jsuint capacity = obj->getDenseArrayCapacity();
bool within = (jsuint(idx) < capacity);
if (!within) {
@ -13968,9 +13952,9 @@ 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, dslots), ACCSET_OTHER), "dslots");
vp = &obj->dslots[jsuint(idx)];
JS_ASSERT(sizeof(Value) == 8); // The |3| in the following statement requires this.
addName(lir->insLoad(LIR_ldp, obj_ins, offsetof(JSObject, slots), ACCSET_OTHER), "dslots");
vp = &obj->slots[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));
v_ins = unbox_value(*vp, addr_ins, 0, branchExit);
@ -14281,20 +14265,19 @@ TraceRecorder::record_JSOP_UINT16()
JS_REQUIRES_STACK AbortableRecordingStatus
TraceRecorder::record_JSOP_NEWINIT()
{
JSProtoKey key = JSProtoKey(GET_INT8(cx->regs->pc));
JSProtoKey key = JSProtoKey(GET_UINT16(cx->regs->pc));
uint32 count = GET_UINT16(cx->regs->pc + UINT16_LEN);
LIns* proto_ins;
CHECK_STATUS_A(getClassPrototype(key, proto_ins));
LIns *v_ins;
if (key == JSProto_Array) {
LIns *args[] = { lir->insImmI(0), proto_ins, cx_ins };
v_ins = lir->insCall(&js_NewEmptyArray_ci, args);
LIns *args[] = { lir->insImmI(count), cx_ins };
v_ins = lir->insCall(&js_InitializerArray_ci, args);
} else {
LIns *args[] = { proto_ins, cx_ins };
v_ins = lir->insCall((cx->regs->pc[JSOP_NEWINIT_LENGTH] != JSOP_ENDINIT)
? &js_NonEmptyObject_ci
: &js_Object_tn_ci,
args);
LIns *args[] = { lir->insImmI(count), cx_ins };
v_ins = lir->insCall(&js_InitializerObject_ci, args);
}
guard(false, lir->insEqP_0(v_ins), OOM_EXIT);
stack(0, v_ins);
@ -15256,7 +15239,7 @@ TraceRecorder::record_JSOP_LAMBDA_FC()
if (fun->u.i.nupvars) {
JSUpvarArray *uva = fun->u.i.script->upvars();
LIns* upvars_ins = stobj_get_fslot_private_ptr(closure_ins,
LIns* upvars_ins = stobj_get_const_private_ptr(closure_ins,
JSObject::JSSLOT_FLAT_CLOSURE_UPVARS);
for (uint32 i = 0, n = uva->length; i < n; i++) {
@ -15340,7 +15323,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_fslot_uint32(argsobj_ins, JSObject::JSSLOT_ARGS_LENGTH);
LIns *len_ins = stobj_get_slot_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(MISMATCH_EXIT));
return len_ins;
@ -16044,7 +16027,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_fslot_uint32(obj_ins, JSObject::JSSLOT_ARRAY_LENGTH));
v_ins = lir->ins1(LIR_i2d, stobj_get_private_uint32(obj_ins));
} 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);

Просмотреть файл

@ -1068,7 +1068,7 @@ class TraceRecorder
* entries of the tracker accordingly.
*/
JS_REQUIRES_STACK void checkForGlobalObjectReallocation() {
if (global_dslots != globalObj->dslots)
if (global_dslots != globalObj->getSlots())
checkForGlobalObjectReallocationHelper();
}
JS_REQUIRES_STACK void checkForGlobalObjectReallocationHelper();
@ -1176,21 +1176,20 @@ 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(nanojit::LIns* obj_ins, unsigned slot,
void stobj_set_slot(JSObject *obj, 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_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* stobj_get_slot_uint32(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,

Просмотреть файл

@ -828,6 +828,18 @@ 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();
}
}
/******************************************************************************/
/*

Просмотреть файл

@ -179,14 +179,9 @@ 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) {
if (slot < JS_INITIAL_NSLOTS) {
void *vp = &obj->getSlotRef(slot);
move(ImmPtr(vp), reg);
return Address(reg, 0);
}
move(ImmPtr(&obj->dslots), reg);
move(ImmPtr(&obj->slots), reg);
loadPtr(reg, reg);
return Address(reg, (slot - JS_INITIAL_NSLOTS) * sizeof(Value));
return Address(reg, slot * sizeof(Value));
}
#ifdef JS_CPU_X86

Просмотреть файл

@ -50,6 +50,7 @@
#include "assembler/jit/ExecutableAllocator.h"
#include "assembler/assembler/LinkBuffer.h"
#include "FrameState-inl.h"
#include "jsobjinlines.h"
#include "jsscriptinlines.h"
#include "InlineFrameAssembler.h"
#include "jscompartment.h"
@ -1261,10 +1262,13 @@ mjit::Compiler::generateMethod()
BEGIN_CASE(JSOP_NEWINIT)
{
jsint i = GET_INT8(PC);
jsint i = GET_UINT16(PC);
uint32 count = GET_UINT16(PC + UINT16_LEN);
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
@ -1490,8 +1494,8 @@ mjit::Compiler::generateMethod()
RegisterID reg = frame.allocReg();
masm.loadPayload(Address(JSFrameReg, JSStackFrame::offsetOfCallee(fun)), reg);
// obj->getFlatClosureUpvars()
Address upvarAddress(reg, offsetof(JSObject, fslots) +
JSObject::JSSLOT_FLAT_CLOSURE_UPVARS * sizeof(Value));
masm.loadPtr(Address(reg, offsetof(JSObject, slots)), reg);
Address upvarAddress(reg, JSObject::JSSLOT_FLAT_CLOSURE_UPVARS * sizeof(Value));
masm.loadPrivate(upvarAddress, reg);
// push ((Value *) reg)[index]
frame.freeReg(reg);
@ -2514,7 +2518,7 @@ mjit::Compiler::jsop_getprop(JSAtom *atom, bool doTypeCheck)
#elif defined JS_PUNBOX64
Label dslotsLoadLabel = masm.label();
#endif
masm.loadPtr(Address(objReg, offsetof(JSObject, dslots)), objReg);
masm.loadPtr(Address(objReg, offsetof(JSObject, slots)), objReg);
/* Copy the slot value to the expression stack. */
Address slot(objReg, 1 << 24);
@ -2615,7 +2619,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, dslots)), objReg);
masm.loadPtr(Address(objReg, offsetof(JSObject, slots)), objReg);
/* Copy the slot value to the expression stack. */
Address slot(objReg, 1 << 24);
@ -2746,7 +2750,7 @@ mjit::Compiler::jsop_callprop_generic(JSAtom *atom)
#elif defined JS_PUNBOX64
Label dslotsLoadLabel = masm.label();
#endif
masm.loadPtr(Address(objReg, offsetof(JSObject, dslots)), objReg);
masm.loadPtr(Address(objReg, offsetof(JSObject, slots)), objReg);
/* Copy the slot value to the expression stack. */
Address slot(objReg, 1 << 24);
@ -2884,7 +2888,7 @@ mjit::Compiler::jsop_callprop_obj(JSAtom *atom)
#elif defined JS_PUNBOX64
Label dslotsLoadLabel = masm.label();
#endif
masm.loadPtr(Address(objReg, offsetof(JSObject, dslots)), objReg);
masm.loadPtr(Address(objReg, offsetof(JSObject, slots)), objReg);
/* Copy the slot value to the expression stack. */
Address slot(objReg, 1 << 24);
@ -3052,7 +3056,7 @@ mjit::Compiler::jsop_setprop(JSAtom *atom)
#elif defined JS_PUNBOX64
Label dslotsLoadLabel = masm.label();
#endif
masm.loadPtr(Address(objReg, offsetof(JSObject, dslots)), objReg);
masm.loadPtr(Address(objReg, offsetof(JSObject, slots)), objReg);
/* Store RHS into object slot. */
Address slot(objReg, 1 << 24);
@ -3616,8 +3620,7 @@ mjit::Compiler::iter(uintN flags)
stubcc.linkExit(nullIterator, Uses(1));
/* Get NativeIterator from iter obj. :FIXME: X64, also most of this function */
Address privSlot(ioreg, offsetof(JSObject, fslots) + sizeof(Value) * JSSLOT_PRIVATE);
masm.loadPtr(privSlot, nireg);
masm.loadPtr(Address(ioreg, offsetof(JSObject, privateData)), nireg);
/* Test for active iterator. */
Address flagsAddr(nireg, offsetof(NativeIterator, flags));
@ -3801,8 +3804,7 @@ mjit::Compiler::iterEnd()
stubcc.linkExit(notIterator, Uses(1));
/* Get private from iter obj. :FIXME: X64 */
Address privSlot(reg, offsetof(JSObject, fslots) + sizeof(Value) * JSSLOT_PRIVATE);
masm.loadPtr(privSlot, T1);
masm.loadPtr(Address(reg, offsetof(JSObject, privateData)), T1);
RegisterID T2 = frame.allocReg();
@ -3916,7 +3918,7 @@ mjit::Compiler::jsop_getgname(uint32 index)
/* Garbage value. */
uint32 slot = 1 << 24;
masm.loadPtr(Address(objReg, offsetof(JSObject, dslots)), objReg);
masm.loadPtr(Address(objReg, offsetof(JSObject, slots)), objReg);
Address address(objReg, slot);
/*
@ -4036,7 +4038,7 @@ mjit::Compiler::jsop_setgname(uint32 index)
v = fe->getValue();
}
masm.loadPtr(Address(objReg, offsetof(JSObject, dslots)), objReg);
masm.loadPtr(Address(objReg, offsetof(JSObject, slots)), objReg);
Address address(objReg, slot);
mic.load = masm.label();

Просмотреть файл

@ -1207,26 +1207,21 @@ mjit::Compiler::jsop_setelem()
stubcc.linkExit(guardDense, Uses(3));
/* guard within capacity */
Address capacity(objReg, offsetof(JSObject, fslots) +
JSObject::JSSLOT_DENSE_ARRAY_CAPACITY * sizeof(Value));
Address capacity(objReg, offsetof(JSObject, capacity));
Jump inRange;
MaybeRegisterID maybeIdReg;
if (id->isConstant()) {
inRange = masm.branch32(Assembler::LessThanOrEqual,
masm.payloadOf(capacity),
inRange = masm.branch32(Assembler::LessThanOrEqual, capacity,
Imm32(id->getValue().toInt32()));
} else {
maybeIdReg = frame.copyDataIntoReg(id);
inRange = masm.branch32(Assembler::AboveOrEqual, maybeIdReg.reg(),
masm.payloadOf(capacity));
inRange = masm.branch32(Assembler::AboveOrEqual, maybeIdReg.reg(), capacity);
}
stubcc.linkExit(inRange, Uses(3));
/* dslots non-NULL */
masm.loadPtr(Address(objReg, offsetof(JSObject, dslots)), objReg);
Jump guardSlots = masm.branchTestPtr(Assembler::Zero, objReg, objReg);
stubcc.linkExit(guardSlots, Uses(3));
/* load dslots */
masm.loadPtr(Address(objReg, offsetof(JSObject, slots)), objReg);
/* guard within capacity */
if (id->isConstant()) {
@ -1297,7 +1292,7 @@ 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, fslots[JSObject::JSSLOT_ARRAY_LENGTH]));
Address arrayLength(baseReg, offsetof(JSObject, privateData));
stubcc.masm.load32(arrayLength, T1);
Jump underLength = stubcc.masm.branch32(Assembler::LessThan, idReg, T1);
stubcc.masm.move(idReg, T1);
@ -1307,7 +1302,7 @@ mjit::Compiler::jsop_setelem()
/* Restore the dslots register if we clobbered it with the object. */
if (baseReg == objReg)
stubcc.masm.loadPtr(Address(objReg, offsetof(JSObject, dslots)), objReg);
stubcc.masm.loadPtr(Address(objReg, offsetof(JSObject, slots)), objReg);
/* Rejoin OOL path with inline path to do the store itself. */
Jump jmpHoleExit = stubcc.masm.jump();
@ -1360,22 +1355,17 @@ mjit::Compiler::jsop_getelem_dense(FrameEntry *obj, FrameEntry *id, RegisterID o
/* Guard within capacity. */
Jump inRange;
Address capacity(objReg, offsetof(JSObject, fslots) +
JSObject::JSSLOT_DENSE_ARRAY_CAPACITY * sizeof(Value));
Address capacity(objReg, offsetof(JSObject, capacity));
if (id->isConstant()) {
inRange = masm.branch32(Assembler::LessThanOrEqual,
masm.payloadOf(capacity),
inRange = masm.branch32(Assembler::LessThanOrEqual, capacity,
Imm32(id->getValue().toInt32()));
} else {
inRange = masm.branch32(Assembler::AboveOrEqual, idReg.reg(),
masm.payloadOf(capacity));
inRange = masm.branch32(Assembler::AboveOrEqual, idReg.reg(), capacity);
}
stubcc.linkExit(inRange, Uses(2));
/* dslots non-NULL */
masm.loadPtr(Address(objReg, offsetof(JSObject, dslots)), objReg);
Jump guardSlots = masm.branchTestPtr(Assembler::Zero, objReg, objReg);
stubcc.linkExit(guardSlots, Uses(2));
/* load dslots */
masm.loadPtr(Address(objReg, offsetof(JSObject, slots)), objReg);
/* guard within capacity */
if (id->isConstant()) {

Просмотреть файл

@ -108,8 +108,6 @@ ic::GetGlobalName(VMFrame &f, ic::MICInfo *ic)
repatch.repatch(ic->shape, obj->shape());
/* Patch loads. */
JS_ASSERT(slot >= JS_INITIAL_NSLOTS);
slot -= JS_INITIAL_NSLOTS;
slot *= sizeof(Value);
JSC::RepatchBuffer loads(ic->load.executableAddress(), 32, false);
#if defined JS_CPU_X86
@ -189,8 +187,6 @@ ic::SetGlobalName(VMFrame &f, ic::MICInfo *ic)
repatch.repatch(ic->shape, obj->shape());
/* Patch loads. */
JS_ASSERT(slot >= JS_INITIAL_NSLOTS);
slot -= JS_INITIAL_NSLOTS;
slot *= sizeof(Value);
JSC::RepatchBuffer stores(ic->load.executableAddress(), 32, false);

Просмотреть файл

@ -90,13 +90,14 @@ class Assembler : public BaseAssembler
return BaseIndex(address.base, address.index, address.scale, address.offset + TAG_OFFSET);
}
void loadSlot(RegisterID obj, RegisterID clobber, uint32 slot, RegisterID type, RegisterID data) {
void loadSlot(RegisterID obj, RegisterID clobber, uint32 slot, bool inlineAccess,
RegisterID type, RegisterID data) {
JS_ASSERT(type != data);
Address address(obj, offsetof(JSObject, fslots) + slot * sizeof(Value));
Address address(obj, JSObject::getFixedSlotOffset(slot));
RegisterID activeAddressReg = obj;
if (slot >= JS_INITIAL_NSLOTS) {
loadPtr(Address(obj, offsetof(JSObject, dslots)), clobber);
address = Address(clobber, (slot - JS_INITIAL_NSLOTS) * sizeof(Value));
if (!inlineAccess) {
loadPtr(Address(obj, offsetof(JSObject, slots)), clobber);
address = Address(clobber, slot * sizeof(Value));
activeAddressReg = clobber;
}
if (activeAddressReg == type) {
@ -202,9 +203,8 @@ class Assembler : public BaseAssembler
}
void loadFunctionPrivate(RegisterID base, RegisterID to) {
Address privSlot(base, offsetof(JSObject, fslots) +
JSSLOT_PRIVATE * sizeof(Value));
loadPtr(privSlot, to);
Address priv(base, offsetof(JSObject, privateData));
loadPtr(priv, to);
}
Jump testNull(Assembler::Condition cond, RegisterID reg) {

Просмотреть файл

@ -250,7 +250,7 @@ class SetPropCompiler : public PICStubCompiler
repatcher.relinkCallerToTrampoline(retPtr, target);
}
bool patchInline(const Shape *shape)
bool patchInline(const Shape *shape, bool inlineSlot)
{
JS_ASSERT(!pic.inlinePathPatched);
JaegerSpew(JSpew_PICs, "patch setprop inline at %p\n", pic.fastPathStart.executableAddress());
@ -258,7 +258,7 @@ class SetPropCompiler : public PICStubCompiler
PICRepatchBuffer repatcher(pic, pic.fastPathStart);
int32 offset;
if (shape->slot < JS_INITIAL_NSLOTS) {
if (inlineSlot) {
JSC::CodeLocationInstruction istr;
istr = pic.storeBack.instructionAtOffset(dslotsLoadOffset());
repatcher.repatchLoadPtrToLEA(istr);
@ -270,12 +270,12 @@ class SetPropCompiler : public PICStubCompiler
// Because the offset is wrong, it's necessary to correct it
// below.
//
int32 diff = int32(offsetof(JSObject, fslots)) -
int32(offsetof(JSObject, dslots));
int32 diff = int32(JSObject::getFixedSlotOffset(0)) -
int32(offsetof(JSObject, slots));
JS_ASSERT(diff != 0);
offset = (int32(shape->slot) * sizeof(Value)) + diff;
} else {
offset = (shape->slot - JS_INITIAL_NSLOTS) * sizeof(Value);
offset = shape->slot * sizeof(Value);
}
uint32 shapeOffs = pic.shapeGuard + inlineShapeOffset();
@ -311,7 +311,7 @@ class SetPropCompiler : public PICStubCompiler
repatcher.relink(lastStubSecondShapeGuard, cs);
}
bool generateStub(uint32 initialShape, const Shape *shape, bool adding)
bool generateStub(uint32 initialShape, const Shape *shape, bool adding, bool inlineSlot)
{
/* Exits to the slow path. */
Vector<Jump, 8> slowExits(cx);
@ -384,28 +384,21 @@ class SetPropCompiler : public PICStubCompiler
}
}
if (shape->slot < JS_INITIAL_NSLOTS) {
if (inlineSlot) {
Address address(pic.objReg,
offsetof(JSObject, fslots) + shape->slot * sizeof(Value));
JSObject::getFixedSlotOffset(shape->slot));
masm.storeValue(pic.u.vr, 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.shapeReg, -ptrdiff_t(sizeof(Value)));
Address capacity(pic.objReg, offsetof(JSObject, capacity));
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, dslots)), pic.shapeReg);
Address address(pic.shapeReg,
(shape->slot - JS_INITIAL_NSLOTS) * sizeof(Value));
masm.loadPtr(Address(pic.objReg, offsetof(JSObject, slots)), pic.shapeReg);
Address address(pic.shapeReg, shape->slot * sizeof(Value));
masm.storeValue(pic.u.vr, address);
}
@ -426,10 +419,10 @@ class SetPropCompiler : public PICStubCompiler
masm.store32(pic.shapeReg, flags);
}
} else if (shape->hasDefaultSetter()) {
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));
Address address(pic.objReg, JSObject::getFixedSlotOffset(shape->slot));
if (!inlineSlot) {
masm.loadPtr(Address(pic.objReg, offsetof(JSObject, slots)), pic.objReg);
address = Address(pic.objReg, shape->slot * sizeof(Value));
}
// If the scope is branded, or has a method barrier. It's now necessary
@ -473,9 +466,9 @@ class SetPropCompiler : public PICStubCompiler
{
if (shape->setterOp() == SetCallVar)
slot += fun->nargs;
masm.loadPtr(Address(pic.objReg, offsetof(JSObject, dslots)), pic.objReg);
masm.loadPtr(Address(pic.objReg, offsetof(JSObject, slots)), pic.objReg);
Address dslot(pic.objReg, slot * sizeof(Value));
Address dslot(pic.objReg, (slot + JSObject::CALL_RESERVED_SLOTS) * sizeof(Value));
masm.storeValue(pic.u.vr, dslot);
}
@ -658,7 +651,7 @@ class SetPropCompiler : public PICStubCompiler
if (obj->numSlots() != slots)
return disable("insufficient slot capacity");
return generateStub(initialShape, shape, true);
return generateStub(initialShape, shape, true, !obj->hasSlotsArray());
}
AutoPropertyDropper dropper(cx, holder, prop);
@ -686,10 +679,10 @@ class SetPropCompiler : public PICStubCompiler
!obj->brandedOrHasMethodBarrier() &&
shape->hasDefaultSetter() &&
!obj->isDenseArray()) {
return patchInline(shape);
return patchInline(shape, !obj->hasSlotsArray());
}
return generateStub(obj->shape(), shape, false);
return generateStub(obj->shape(), shape, false, !obj->hasSlotsArray());
}
};
@ -793,9 +786,8 @@ class GetPropCompiler : public PICStubCompiler
Address clasp(pic.objReg, offsetof(JSObject, clasp));
Jump notArgs = masm.branchPtr(Assembler::NotEqual, clasp, ImmPtr(obj->getClass()));
masm.load32(Address(pic.objReg,
offsetof(JSObject, fslots)
+ JSObject::JSSLOT_ARGS_LENGTH * sizeof(Value)),
masm.loadPtr(Address(pic.objReg, offsetof(JSObject, slots)), pic.objReg);
masm.load32(Address(pic.objReg, JSObject::JSSLOT_ARGS_LENGTH * sizeof(Value)),
pic.objReg);
masm.move(pic.objReg, pic.shapeReg);
Jump overridden = masm.branchTest32(Assembler::NonZero, pic.shapeReg, Imm32(1));
@ -834,10 +826,7 @@ class GetPropCompiler : public PICStubCompiler
ImmPtr(&js_SlowArrayClass));
isDense.linkTo(masm.label(), &masm);
masm.load32(Address(pic.objReg,
offsetof(JSObject, fslots)
+ JSObject::JSSLOT_ARRAY_LENGTH * sizeof(Value)),
pic.objReg);
masm.load32(Address(pic.objReg, offsetof(JSObject, privateData)), 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();
@ -920,7 +909,8 @@ class GetPropCompiler : public PICStubCompiler
Jump shapeMismatch = masm.branch32(Assembler::NotEqual, pic.shapeReg,
Imm32(obj->shape()));
if (!shape->isMethod()) {
masm.loadSlot(pic.objReg, pic.objReg, shape->slot, pic.shapeReg, pic.objReg);
masm.loadSlot(pic.objReg, pic.objReg, shape->slot, !obj->hasSlotsArray(),
pic.shapeReg, pic.objReg);
} else {
masm.loadValueAsComponents(ObjectValue(shape->methodObject()), pic.shapeReg,
pic.objReg);
@ -992,7 +982,7 @@ class GetPropCompiler : public PICStubCompiler
PICRepatchBuffer repatcher(pic, pic.fastPathStart);
int32 offset;
if (shape->slot < JS_INITIAL_NSLOTS) {
if (!holder->hasSlotsArray()) {
JSC::CodeLocationInstruction istr;
istr = pic.storeBack.instructionAtOffset(dslotsLoad());
repatcher.repatchLoadPtrToLEA(istr);
@ -1004,12 +994,12 @@ class GetPropCompiler : public PICStubCompiler
// Because the offset is wrong, it's necessary to correct it
// below.
//
int32 diff = int32(offsetof(JSObject, fslots)) -
int32(offsetof(JSObject, dslots));
int32 diff = int32(JSObject::getFixedSlotOffset(0)) -
int32(offsetof(JSObject, slots));
JS_ASSERT(diff != 0);
offset = (int32(shape->slot) * sizeof(Value)) + diff;
} else {
offset = (shape->slot - JS_INITIAL_NSLOTS) * sizeof(Value);
offset = shape->slot * sizeof(Value);
}
uint32 shapeOffs = pic.shapeGuard + inlineShapeOffset();
@ -1116,7 +1106,8 @@ class GetPropCompiler : public PICStubCompiler
/* Load the value out of the object. */
if (!shape->isMethod()) {
masm.loadSlot(pic.objReg, pic.objReg, shape->slot, pic.shapeReg, pic.objReg);
masm.loadSlot(pic.objReg, pic.objReg, shape->slot, !holder->hasSlotsArray(),
pic.shapeReg, pic.objReg);
} else {
masm.loadValueAsComponents(ObjectValue(shape->methodObject()), pic.shapeReg,
pic.objReg);
@ -1323,7 +1314,7 @@ class GetElemCompiler : public PICStubCompiler
PICRepatchBuffer repatcher(pic, pic.fastPathStart);
int32 offset;
if (shape->slot < JS_INITIAL_NSLOTS) {
if (!holder->hasSlotsArray()) {
JSC::CodeLocationInstruction istr = pic.storeBack.instructionAtOffset(dslotsLoad());
repatcher.repatchLoadPtrToLEA(istr);
@ -1334,11 +1325,11 @@ class GetElemCompiler : public PICStubCompiler
// Because the offset is wrong, it's necessary to correct it
// below.
//
int32 diff = int32(offsetof(JSObject, fslots)) - int32(offsetof(JSObject, dslots));
int32 diff = int32(JSObject::getFixedSlotOffset(0)) - int32(offsetof(JSObject, slots));
JS_ASSERT(diff != 0);
offset = (int32(shape->slot) * sizeof(Value)) + diff;
} else {
offset = (shape->slot - JS_INITIAL_NSLOTS) * sizeof(Value);
offset = shape->slot * sizeof(Value);
}
uint32 shapeOffset = pic.shapeGuard + inlineShapeOffset();
@ -1468,7 +1459,8 @@ class GetElemCompiler : public PICStubCompiler
/* Load the value out of the object. */
if (!shape->isMethod()) {
masm.loadSlot(pic.objReg, pic.objReg, shape->slot, pic.shapeReg, pic.objReg);
masm.loadSlot(pic.objReg, pic.objReg, shape->slot, !holder->hasSlotsArray(),
pic.shapeReg, pic.objReg);
} else {
masm.loadValueAsComponents(ObjectValue(shape->methodObject()), pic.shapeReg,
pic.objReg);
@ -1662,7 +1654,7 @@ class ScopeNameCompiler : public PICStubCompiler
Jump finalShape = masm.branch32(Assembler::NotEqual, pic.shapeReg, Imm32(holder->shape()));
if (!shape->isMethod()) {
masm.loadSlot(pic.objReg, pic.objReg, shape->slot, pic.shapeReg, pic.objReg);
masm.loadSlot(pic.objReg, pic.objReg, shape->slot, false, pic.shapeReg, pic.objReg);
} else {
masm.loadValueAsComponents(ObjectValue(shape->methodObject()), pic.shapeReg,
pic.objReg);
@ -1764,11 +1756,11 @@ class ScopeNameCompiler : public PICStubCompiler
escapedFrame.linkTo(masm.label(), &masm);
{
masm.loadPtr(Address(pic.objReg, offsetof(JSObject, dslots)), pic.objReg);
masm.loadPtr(Address(pic.objReg, offsetof(JSObject, slots)), pic.objReg);
if (kind == VAR)
slot += fun->nargs;
Address dslot(pic.objReg, slot * sizeof(Value));
Address dslot(pic.objReg, (slot + JSObject::CALL_RESERVED_SLOTS) * sizeof(Value));
/* Safe because type is loaded first. */
masm.loadValueAsComponents(dslot, pic.shapeReg, pic.objReg);

Просмотреть файл

@ -93,12 +93,13 @@ class Assembler : public BaseAssembler
return address;
}
void loadSlot(RegisterID obj, RegisterID clobber, uint32 slot, RegisterID type, RegisterID data) {
void loadSlot(RegisterID obj, RegisterID clobber, uint32 slot, bool inlineAccess,
RegisterID type, RegisterID data) {
JS_ASSERT(type != data);
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));
Address address(obj, JSObject::getFixedSlotOffset(slot));
if (!inlineAccess) {
loadPtr(Address(obj, offsetof(JSObject, slots)), clobber);
address = Address(clobber, slot * sizeof(Value));
}
loadValueAsComponents(address, type, data);
@ -222,9 +223,8 @@ class Assembler : public BaseAssembler
}
void loadFunctionPrivate(RegisterID base, RegisterID to) {
Address privSlot(base, offsetof(JSObject, fslots) +
JSSLOT_PRIVATE * sizeof(Value));
loadPtr(privSlot, to);
Address priv(base, offsetof(JSObject, privateData));
loadPtr(priv, to);
}
Jump testNull(Assembler::Condition cond, RegisterID reg) {

Просмотреть файл

@ -1436,21 +1436,25 @@ stubs::Neg(VMFrame &f)
}
JSObject * JS_FASTCALL
stubs::NewInitArray(VMFrame &f)
stubs::NewInitArray(VMFrame &f, uint32 count)
{
JSObject *obj = js_NewArrayObject(f.cx, 0, NULL);
if (!obj)
JSContext *cx = f.cx;
gc::FinalizeKind kind = GuessObjectGCKind(count, true);
JSObject *obj = NewArrayWithKind(cx, kind);
if (!obj || !obj->ensureSlots(cx, count))
THROWV(NULL);
return obj;
}
JSObject * JS_FASTCALL
stubs::NewInitObject(VMFrame &f)
stubs::NewInitObject(VMFrame &f, uint32 count)
{
JSContext *cx = f.cx;
gc::FinalizeKind kind = GuessObjectGCKind(count, false);
JSObject *obj = NewBuiltinClassInstance(cx, &js_ObjectClass);
if (!obj)
JSObject *obj = NewBuiltinClassInstance(cx, &js_ObjectClass, kind);
if (!obj || !obj->ensureSlots(cx, count))
THROWV(NULL);
return obj;

Просмотреть файл

@ -48,8 +48,8 @@ namespace mjit {
namespace stubs {
void JS_FASTCALL This(VMFrame &f);
JSObject * JS_FASTCALL NewInitArray(VMFrame &f);
JSObject * JS_FASTCALL NewInitObject(VMFrame &f);
JSObject * JS_FASTCALL NewInitArray(VMFrame &f, uint32 count);
JSObject * JS_FASTCALL NewInitObject(VMFrame &f, uint32 count);
JSObject * JS_FASTCALL NewArray(VMFrame &f, uint32 len);
void JS_FASTCALL Trap(VMFrame &f, jsbytecode *pc);
void JS_FASTCALL Debugger(VMFrame &f, jsbytecode *pc);

Просмотреть файл

@ -5398,7 +5398,7 @@ main(int argc, char **argv, char **envp)
CALIBRATION_DELAY_COUNT = 0;
#endif
rt = JS_NewRuntime(128L * 1024L * 1024L);
rt = JS_NewRuntime(160L * 1024L * 1024L);
if (!rt)
return 1;

Просмотреть файл

@ -6,8 +6,8 @@ function leak_test() {
// To make sure that we have no references to the function f after this
// function returns due via the conservative scan of the native stack we
// loop here twice overwriting the stack and registers with new garabge.
for (var j = 0; j != 2; ++j) {
// loop here multiple times overwriting the stack and registers with new garabge.
for (var j = 0; j != 8; ++j) {
var f = Function("a", "var s = 0; for (var i = 0; i != 100; ++i) s += a.b; return s;");
var c = {b: 1, f: f, leakDetection: makeFinalizeObserver()};
f({ __proto__: { __proto__: c}});
@ -26,7 +26,7 @@ function test()
gc();
gc();
var n = finalizeCount();
assertEq(base < finalizeCount(), true, "Some finalizations must happen");
assertEq(base + 4 < finalizeCount(), true, "Some finalizations must happen");
}
test();

Просмотреть файл

@ -8,7 +8,8 @@ function f(i) {
return 1;
}
var arr = [ false, false, false, false, false, , , , ];
/* trailing 'true' ensures array has capacity >= 10 */
var arr = [ false, false, false, false, false, , , , , , true ];
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, 20, "x = 'success'; nop()");
trap(caller, 23, "x = 'success'; nop()");
assertEq(caller(this), "success");

Просмотреть файл

@ -1382,10 +1382,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(JSSLOT_START(obj->getClass())).isUndefined())
obj->getSlot(0).isUndefined())
#define IS_SLIM_WRAPPER_OBJECT(obj) \
(DebugCheckWrapperClass(obj) && \
!obj->getSlot(JSSLOT_START(obj->getClass())).isUndefined())
!obj->getSlot(0).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
@ -2289,7 +2289,7 @@ extern JSBool MorphSlimWrapper(JSContext *cx, JSObject *obj);
static inline XPCWrappedNativeProto*
GetSlimWrapperProto(JSObject *obj)
{
const js::Value &v = obj->getSlot(JSSLOT_START(obj->getClass()));
const js::Value &v = obj->getSlot(0);
return static_cast<XPCWrappedNativeProto*>(v.toPrivate());
}

Просмотреть файл

@ -53,9 +53,9 @@ namespace xpc {
using namespace js;
static const uint32 JSSLOT_WN_OBJ = JSSLOT_PRIVATE;
static const uint32 JSSLOT_RESOLVING = JSSLOT_PRIVATE + 1;
static const uint32 JSSLOT_EXPANDO = JSSLOT_PRIVATE + 2;
static const uint32 JSSLOT_WN_OBJ = 0;
static const uint32 JSSLOT_RESOLVING = 1;
static const uint32 JSSLOT_EXPANDO = 2;
class ResolvingId
{