Backed out changeset 09ffb30caa47

This commit is contained in:
Brian Hackett 2010-09-20 12:05:21 -07:00
Родитель 03fb86d8a2
Коммит 2e0c76a3ce
42 изменённых файлов: 1022 добавлений и 983 удалений

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

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

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

@ -3031,6 +3031,8 @@ JS_SealObject(JSContext *cx, JSObject *obj, JSBool deep)
/* Walk slots in obj and if any value is a non-null object, seal it. */
for (uint32 i = 0, n = obj->slotSpan(); i != n; ++i) {
const Value &v = obj->getSlot(i);
if (i == JSSLOT_PRIVATE && (obj->getClass()->flags & JSCLASS_HAS_PRIVATE))
continue;
if (v.isPrimitive())
continue;
if (!JS_SealObject(cx, &v.toObject(), deep))
@ -3829,7 +3831,8 @@ JS_Enumerate(JSContext *cx, JSObject *obj)
* + native case here uses a Shape *, but that iterates in reverse!
* + so we make non-native match, by reverse-iterating after JS_Enumerating
*/
const uint32 JSSLOT_ITER_INDEX = 0;
const uint32 JSSLOT_ITER_INDEX = JSSLOT_PRIVATE + 1;
JS_STATIC_ASSERT(JSSLOT_ITER_INDEX < JS_INITIAL_NSLOTS);
static void
prop_iter_finalize(JSContext *cx, JSObject *obj)
@ -3838,7 +3841,7 @@ prop_iter_finalize(JSContext *cx, JSObject *obj)
if (!pdata)
return;
if (obj->getSlot(JSSLOT_ITER_INDEX).toInt32() >= 0) {
if (obj->fslots[JSSLOT_ITER_INDEX].toInt32() >= 0) {
/* Non-native case: destroy the ida enumerated when obj was created. */
JSIdArray *ida = (JSIdArray *) pdata;
JS_DestroyIdArray(cx, ida);
@ -3852,7 +3855,7 @@ prop_iter_trace(JSTracer *trc, JSObject *obj)
if (!pdata)
return;
if (obj->getSlot(JSSLOT_ITER_INDEX).toInt32() < 0) {
if (obj->fslots[JSSLOT_ITER_INDEX].toInt32() < 0) {
/* Native case: just mark the next property to visit. */
((Shape *) pdata)->trace(trc);
} else {
@ -3918,7 +3921,7 @@ JS_NewPropertyIterator(JSContext *cx, JSObject *obj)
/* iterobj cannot escape to other threads here. */
iterobj->setPrivate(const_cast<void *>(pdata));
iterobj->getSlotRef(JSSLOT_ITER_INDEX).setInt32(index);
iterobj->fslots[JSSLOT_ITER_INDEX].setInt32(index);
return iterobj;
}
@ -3932,7 +3935,7 @@ JS_NextProperty(JSContext *cx, JSObject *iterobj, jsid *idp)
CHECK_REQUEST(cx);
assertSameCompartment(cx, iterobj);
i = iterobj->getSlot(JSSLOT_ITER_INDEX).toInt32();
i = iterobj->fslots[JSSLOT_ITER_INDEX].toInt32();
if (i < 0) {
/* Native case: private data is a property tree node pointer. */
obj = iterobj->getParent();

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

@ -310,6 +310,109 @@ BigIndexToId(JSContext *cx, JSObject *obj, jsuint index, JSBool createAtom,
return JS_TRUE;
}
bool
JSObject::growDenseArrayElements(JSContext *cx, uint32 oldcap, uint32 newcap)
{
JS_ASSERT(isDenseArray());
JS_ASSERT(newcap >= ARRAY_CAPACITY_MIN);
JS_ASSERT(newcap >= oldcap);
if (newcap > MAX_DSLOTS_LENGTH32) {
if (!JS_ON_TRACE(cx))
js_ReportAllocationOverflow(cx);
return JS_FALSE;
}
/* dslots can be NULL during array creation. */
Value *slots = dslots ? dslots - 1 : NULL;
Value *newslots = (Value *) cx->realloc(slots, (size_t(newcap) + 1) * sizeof(Value));
if (!newslots)
return false;
dslots = newslots + 1;
setDenseArrayCapacity(newcap);
Value *base = addressOfDenseArrayElement(0);
for (Value *vp = base + oldcap, *end = base + newcap; vp < end; ++vp)
vp->setMagic(JS_ARRAY_HOLE);
return true;
}
bool
JSObject::ensureDenseArrayElements(JSContext *cx, uint32 newcap)
{
/*
* When a dense array with CAPACITY_DOUBLING_MAX or fewer slots needs to
* grow, double its capacity, to push() N elements in amortized O(N) time.
*
* Above this limit, grow by 12.5% each time. Speed is still amortized
* O(N), with a higher constant factor, and we waste less space.
*/
static const size_t CAPACITY_DOUBLING_MAX = 1024 * 1024;
/*
* Round up all large allocations to a multiple of this (1MB), so as not
* to waste space if malloc gives us 1MB-sized chunks (as jemalloc does).
*/
static const size_t CAPACITY_CHUNK = 1024 * 1024 / sizeof(Value);
uint32 oldcap = getDenseArrayCapacity();
if (newcap > oldcap) {
/*
* If this overflows uint32, newcap is very large. nextsize will end
* up being less than newcap, the code below will thus disregard it,
* and resizeDenseArrayElements() will fail.
*
* The way we use dslots[-1] forces a few +1s and -1s here. For
* example, (oldcap * 2 + 1) produces the sequence 7, 15, 31, 63, ...
* which makes the total allocation size (with dslots[-1]) a power
* of two.
*/
uint32 nextsize = (oldcap <= CAPACITY_DOUBLING_MAX)
? oldcap * 2 + 1
: oldcap + (oldcap >> 3);
uint32 actualCapacity = JS_MAX(newcap, nextsize);
if (actualCapacity >= CAPACITY_CHUNK)
actualCapacity = JS_ROUNDUP(actualCapacity + 1, CAPACITY_CHUNK) - 1; /* -1 for dslots[-1] */
else if (actualCapacity < ARRAY_CAPACITY_MIN)
actualCapacity = ARRAY_CAPACITY_MIN;
if (!growDenseArrayElements(cx, oldcap, actualCapacity))
return false;
}
return true;
}
bool
JSObject::shrinkDenseArrayElements(JSContext *cx, uint32 newcap)
{
JS_ASSERT(isDenseArray());
JS_ASSERT(newcap < getDenseArrayCapacity());
JS_ASSERT(dslots);
uint32 fill = newcap;
if (newcap < ARRAY_CAPACITY_MIN)
newcap = ARRAY_CAPACITY_MIN;
Value *newslots = (Value *) cx->realloc(dslots - 1, (size_t(newcap) + 1) * sizeof(Value));
if (!newslots)
return false;
dslots = newslots + 1;
setDenseArrayCapacity(newcap);
/* we refuse to shrink below a minimum value, so we have to clear the excess space */
Value *base = addressOfDenseArrayElement(0);
while (fill < newcap)
base[fill++].setMagic(JS_ARRAY_HOLE);
return true;
}
static bool
ReallyBigIndexToId(JSContext* cx, jsdouble index, jsid* idp)
{
@ -426,8 +529,8 @@ js_EnsureDenseArrayCapacity(JSContext *cx, JSObject *obj, jsint i)
return true;
if (INDEX_TOO_SPARSE(obj, u))
return false;
return obj->ensureDenseArrayElements(cx, u + 1);
return obj->ensureDenseArrayElements(cx, u + 1);
}
JS_DEFINE_CALLINFO_3(extern, BOOL, js_EnsureDenseArrayCapacity, CONTEXT, OBJECT, INT32, 0,
nanojit::ACCSET_STORE_ANY)
@ -556,13 +659,13 @@ array_length_setter(JSContext *cx, JSObject *obj, jsid id, Value *vp, JSBool str
if (obj->isDenseArray()) {
/*
* Don't reallocate if we're not actually shrinking our slots. If we do
* shrink slots here, ensureDenseArrayElements will fill all slots to the
* shrink slots here, resizeDenseArrayElements will fill all slots to the
* right of newlen with JS_ARRAY_HOLE. This permits us to disregard
* length when reading from arrays as long we are within the capacity.
*/
jsuint oldcap = obj->getDenseArrayCapacity();
if (oldcap > newlen)
obj->shrinkDenseArrayElements(cx, newlen);
if (oldcap > newlen && !obj->shrinkDenseArrayElements(cx, newlen))
return false;
obj->setArrayLength(newlen);
} else if (oldlen - newlen < (1 << 24)) {
do {
@ -870,11 +973,20 @@ array_deleteProperty(JSContext *cx, JSObject *obj, jsid id, Value *rval, JSBool
return JS_TRUE;
}
static void
array_finalize(JSContext *cx, JSObject *obj)
{
obj->freeDenseArrayElements(cx);
}
static void
array_trace(JSTracer *trc, JSObject *obj)
{
JS_ASSERT(obj->isDenseArray());
if (!obj->dslots)
return;
size_t holes = 0;
uint32 capacity = obj->getDenseArrayCapacity();
for (uint32 i = 0; i < capacity; i++) {
@ -894,7 +1006,7 @@ array_trace(JSTracer *trc, JSObject *obj)
Class js_ArrayClass = {
"Array",
Class::NON_NATIVE |
JSCLASS_HAS_PRIVATE |
JSCLASS_HAS_RESERVED_SLOTS(JSObject::DENSE_ARRAY_CLASS_RESERVED_SLOTS) |
JSCLASS_HAS_CACHED_PROTO(JSProto_Array),
PropertyStub, /* addProperty */
PropertyStub, /* delProperty */
@ -903,7 +1015,7 @@ Class js_ArrayClass = {
EnumerateStub,
ResolveStub,
js_TryValueOf,
NULL,
array_finalize,
NULL, /* reserved0 */
NULL, /* checkAccess */
NULL, /* call */
@ -987,18 +1099,26 @@ JSObject::makeDenseArraySlow(JSContext *cx)
* the same initial shape.
*/
JSObject *arrayProto = getProto();
if (!InitScopeForObject(cx, this, &js_SlowArrayClass, arrayProto, FINALIZE_OBJECT0))
if (!InitScopeForObject(cx, this, &js_SlowArrayClass, arrayProto))
return false;
uint32 capacity = getDenseArrayCapacity();
uint32 capacity;
/*
* Begin with the length property to share more of the property tree.
* The getter/setter here will directly access the object's private value.
*/
if (dslots) {
capacity = getDenseArrayCapacity();
dslots[-1].setPrivateUint32(JS_INITIAL_NSLOTS + capacity);
} else {
/*
* Array.prototype is constructed as a dense array, but is immediately slowified before
* we have time to set capacity.
*/
capacity = 0;
}
/* Begin with the length property to share more of the property tree. */
if (!addProperty(cx, ATOM_TO_JSID(cx->runtime->atomState.lengthAtom),
array_length_getter, NULL,
SHAPE_INVALID_SLOT, JSPROP_PERMANENT | JSPROP_SHARED, 0, 0)) {
JSSLOT_ARRAY_LENGTH, JSPROP_PERMANENT | JSPROP_SHARED, 0, 0)) {
setMap(oldMap);
return false;
}
@ -1016,12 +1136,24 @@ JSObject::makeDenseArraySlow(JSContext *cx)
continue;
}
if (!addDataProperty(cx, id, i, JSPROP_ENUMERATE)) {
/* Assert that the length covering i fits in the alloted bits. */
JS_ASSERT(JS_INITIAL_NSLOTS + i + 1 < NSLOTS_LIMIT);
if (!addDataProperty(cx, id, JS_INITIAL_NSLOTS + i, JSPROP_ENUMERATE)) {
setMap(oldMap);
return false;
}
}
/*
* Render our formerly-reserved non-private properties GC-safe. We do not
* need to make the length slot GC-safe because it is the private slot
* (this is statically asserted within JSObject) where the implementation
* can store an arbitrary value.
*/
JS_ASSERT(js_SlowArrayClass.flags & JSCLASS_HAS_PRIVATE);
voidDenseOnlyArraySlots();
/*
* Finally, update class. If |this| is Array.prototype, then js_InitClass
* will create an emptyShape whose class is &js_SlowArrayClass, to ensure
@ -1363,6 +1495,7 @@ InitArrayObject(JSContext *cx, JSObject *obj, jsuint length, const Value *vector
JS_ASSERT(obj->isDenseArray());
obj->setArrayLength(length);
obj->setDenseArrayCapacity(0);
if (!vector || !length)
return true;
if (!obj->ensureDenseArrayElements(cx, length))
@ -2321,8 +2454,10 @@ array_concat(JSContext *cx, uintN argc, Value *vp)
/*
* Clone aobj but pass the minimum of its length and capacity, to
* handle a = [1,2,3]; a.length = 10000 "dense" cases efficiently. In
* the normal case where length is <= capacity, nobj and aobj will have
* the same capacity.
* such a case we'll pass 8 (not 3) due to ARRAY_CAPACITY_MIN, which
* will cause nobj to be over-allocated to 16. But in the normal case
* where length is <= capacity, nobj and aobj will have the same
* capacity.
*/
length = aobj->getArrayLength();
jsuint capacity = aobj->getDenseArrayCapacity();
@ -2842,12 +2977,10 @@ static JSFunctionSpec array_static_methods[] = {
JS_FS_END
};
/* The count here is a guess for the final capacity. */
static inline JSObject *
NewDenseArrayObject(JSContext *cx, jsuint count)
NewDenseArrayObject(JSContext *cx)
{
JSFinalizeGCThingKind kind = GuessObjectGCKind(count);
return NewNonFunction<WithProto::Class>(cx, &js_ArrayClass, NULL, NULL, kind);
return NewNonFunction<WithProto::Class>(cx, &js_ArrayClass, NULL, NULL);
}
JSBool
@ -2856,6 +2989,12 @@ js_Array(JSContext *cx, uintN argc, Value *vp)
jsuint length;
const Value *vector;
/* Whether called with 'new' or not, use a new Array object. */
JSObject *obj = NewDenseArrayObject(cx);
if (!obj)
return JS_FALSE;
vp->setObject(*obj);
if (argc == 0) {
length = 0;
vector = NULL;
@ -2872,12 +3011,6 @@ js_Array(JSContext *cx, uintN argc, Value *vp)
vector = NULL;
}
/* Whether called with 'new' or not, use a new Array object. */
JSObject *obj = NewDenseArrayObject(cx, length);
if (!obj)
return JS_FALSE;
vp->setObject(*obj);
return InitArrayObject(cx, obj, length, vector);
}
@ -2889,15 +3022,15 @@ js_NewEmptyArray(JSContext* cx, JSObject* proto, int32 len)
JS_ASSERT(proto->isArray());
JSFinalizeGCThingKind kind = js_GetGCObjectKind(len);
JSObject* obj = js_NewGCObject(cx, kind);
JSObject* obj = js_NewGCObject(cx);
if (!obj)
return NULL;
/* Initialize all fields of JSObject. */
obj->init(cx, &js_ArrayClass, proto, proto->getParent(),
(void*) len, true);
/* Initialize all fields, calling init before setting obj->map. */
obj->init(&js_ArrayClass, proto, proto->getParent(), NullValue(), cx);
obj->setSharedNonNativeMap();
obj->setArrayLength(len);
obj->setDenseArrayCapacity(0);
return obj;
}
#ifdef JS_TRACER
@ -2911,7 +3044,7 @@ js_NewPreallocatedArray(JSContext* cx, JSObject* proto, int32 len)
JSObject *obj = js_NewEmptyArray(cx, proto, len);
if (!obj)
return NULL;
if (!obj->ensureDenseArrayElements(cx, len))
if (!obj->growDenseArrayElements(cx, 0, JS_MAX(len, ARRAY_CAPACITY_MIN)))
return NULL;
return obj;
}
@ -2932,7 +3065,7 @@ js_InitArrayClass(JSContext *cx, JSObject *obj)
* Assert that js_InitClass used the correct (slow array, not dense array)
* class for proto's emptyShape class.
*/
JS_ASSERT(proto->emptyShapes && proto->emptyShapes[0]->getClass() == proto->getClass());
JS_ASSERT(proto->emptyShape->getClass() == proto->getClass());
proto->setArrayLength(0);
return proto;
@ -2941,7 +3074,7 @@ js_InitArrayClass(JSContext *cx, JSObject *obj)
JSObject *
js_NewArrayObject(JSContext *cx, jsuint length, const Value *vector)
{
JSObject *obj = NewDenseArrayObject(cx, length);
JSObject *obj = NewDenseArrayObject(cx);
if (!obj)
return NULL;
@ -3062,7 +3195,7 @@ js_IsDensePrimitiveArray(JSObject *obj)
jsuint capacity = obj->getDenseArrayCapacity();
for (jsuint i = 0; i < capacity; i++) {
if (obj->getDenseArrayElement(i).isObject())
if (obj->dslots[i].isObject())
return JS_FALSE;
}
@ -3086,9 +3219,10 @@ js_CloneDensePrimitiveArray(JSContext *cx, JSObject *obj, JSObject **clone)
/*
* Must use the minimum of original array's length and capacity, to handle
* |a = [1,2,3]; a.length = 10000| "dense" cases efficiently. In the normal
* case where length is <= capacity, the clone and original array will have
* the same capacity.
* |a = [1,2,3]; a.length = 10000| "dense" cases efficiently. In such a case
* we would use ARRAY_CAPACITY_MIN (not 3), which will cause the clone to be
* over-allocated. In the normal case where length is <= capacity the
* clone and original array will have the same capacity.
*/
jsuint jsvalCount = JS_MIN(obj->getDenseArrayCapacity(), length);
@ -3097,7 +3231,7 @@ js_CloneDensePrimitiveArray(JSContext *cx, JSObject *obj, JSObject **clone)
return JS_FALSE;
for (jsuint i = 0; i < jsvalCount; i++) {
const Value &val = obj->getDenseArrayElement(i);
const Value &val = obj->dslots[i];
if (val.isString()) {
// Strings must be made immutable before being copied to a clone.

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

@ -46,6 +46,8 @@
#include "jspubtd.h"
#include "jsobj.h"
#define ARRAY_CAPACITY_MIN 7
extern JSBool
js_StringIsIndex(JSString *str, jsuint *indexp);
@ -137,6 +139,13 @@ js_InitArrayClass(JSContext *cx, JSObject *obj);
extern bool
js_InitContextBusyArrayTable(JSContext *cx);
/*
* Creates a new array with the given length and proto (NB: NULL is not
* translated to Array.prototype), with len slots preallocated.
*/
extern JSObject * JS_FASTCALL
js_NewArrayWithSlots(JSContext* cx, JSObject* proto, uint32 len);
extern JSObject *
js_NewArrayObject(JSContext *cx, jsuint length, const js::Value *vector);

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

@ -302,14 +302,11 @@ js_NewNullClosure(JSContext* cx, JSObject* funobj, JSObject* proto, JSObject* pa
JSFunction *fun = (JSFunction*) funobj;
JS_ASSERT(GET_FUNCTION_PRIVATE(cx, funobj) == fun);
JSObject* closure = js_NewGCObject(cx, FINALIZE_OBJECT2);
JSObject* closure = js_NewGCObject(cx);
if (!closure)
return NULL;
if (!closure->initSharingEmptyShape(cx, &js_FunctionClass, proto, parent,
fun, FINALIZE_OBJECT2)) {
return NULL;
}
closure->initSharingEmptyShape(&js_FunctionClass, proto, parent, fun, cx);
return closure;
}
JS_DEFINE_CALLINFO_4(extern, OBJECT, js_NewNullClosure, CONTEXT, OBJECT, OBJECT, OBJECT,

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

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

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

@ -1645,7 +1645,15 @@ JS_SetDebugErrorHook(JSRuntime *rt, JSDebugErrorHook hook, void *closure)
JS_PUBLIC_API(size_t)
JS_GetObjectTotalSize(JSContext *cx, JSObject *obj)
{
return obj->slotsAndStructSize();
size_t nbytes = (obj->isFunction() && obj->getPrivate() == obj)
? sizeof(JSFunction)
: sizeof *obj;
if (obj->dslots) {
nbytes += (obj->dslots[-1].toPrivateUint32() - JS_INITIAL_NSLOTS + 1)
* sizeof obj->dslots[0];
}
return nbytes;
}
static size_t

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

@ -235,7 +235,7 @@ UpdateDepth(JSContext *cx, JSCodeGenerator *cg, ptrdiff_t target)
JS_ASSERT(nuses == 0);
blockObj = cg->objectList.lastbox->object;
JS_ASSERT(blockObj->isStaticBlock());
JS_ASSERT(blockObj->getSlot(JSSLOT_BLOCK_DEPTH).isUndefined());
JS_ASSERT(blockObj->fslots[JSSLOT_BLOCK_DEPTH].isUndefined());
OBJ_SET_BLOCK_DEPTH(cx, blockObj, cg->stackDepth);
ndefs = OBJ_BLOCK_COUNT(cx, blockObj);
@ -1599,8 +1599,9 @@ js_LexicalLookup(JSTreeContext *tc, JSAtom *atom, jsint *slotp, JSStmtInfo *stmt
JS_ASSERT(shape->hasShortID());
if (slotp) {
JS_ASSERT(obj->getSlot(JSSLOT_BLOCK_DEPTH).isInt32());
*slotp = obj->getSlot(JSSLOT_BLOCK_DEPTH).toInt32() + shape->shortid;
JS_ASSERT(obj->fslots[JSSLOT_BLOCK_DEPTH].isInt32());
*slotp = obj->fslots[JSSLOT_BLOCK_DEPTH].toInt32() +
shape->shortid;
}
return stmt;
}
@ -1867,12 +1868,11 @@ EmitEnterBlock(JSContext *cx, JSParseNode *pn, JSCodeGenerator *cg)
}
/*
* Clear blockObj->dslots and ensure a prompt safe crash if by accident
* some code tries to get a slot from a compiler-created Block prototype
* instead of from a clone.
* Shrink slots to free blockObj->dslots and ensure a prompt safe crash if
* by accident some code tries to get a slot from a compiler-created Block
* prototype instead of from a clone.
*/
if (blockObj->hasSlotsArray())
blockObj->removeSlotsArray(cx);
blockObj->shrinkSlots(cx, base);
return true;
}
@ -4353,17 +4353,8 @@ EmitFunctionDefNop(JSContext *cx, JSCodeGenerator *cg, uintN index)
static bool
EmitNewInit(JSContext *cx, JSCodeGenerator *cg, JSProtoKey key, JSParseNode *pn, int sharpnum)
{
/*
* Watch for overflow on the initializer size. This isn't problematic because
* (a) we'll be reporting an error for the initializer shortly, and (b)
* the count is only used as a hint for the interpreter and JITs, and does not
* need to be correct.
*/
uint16 count = pn->pn_count;
if (count >= JS_BIT(16))
count = JS_BIT(16) - 1;
EMIT_UINT16PAIR_IMM_OP(JSOP_NEWINIT, (uint16) key, count);
if (js_Emit2(cx, cg, JSOP_NEWINIT, (jsbytecode) key) < 0)
return false;
#if JS_HAS_SHARP_VARS
if (cg->hasSharps()) {
if (pn->pn_count != 0)

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

@ -182,8 +182,7 @@ NewArguments(JSContext *cx, JSObject *parent, uint32 argc, JSObject &callee)
if (!js_GetClassPrototype(cx, parent, JSProto_Object, &proto))
return NULL;
JS_ASSERT(js_GetGCKindSlots(FINALIZE_OBJECT2) == JSObject::ARGS_CLASS_RESERVED_SLOTS);
JSObject *argsobj = js_NewGCObject(cx, FINALIZE_OBJECT2);
JSObject *argsobj = js_NewGCObject(cx);
if (!argsobj)
return NULL;
@ -194,10 +193,10 @@ NewArguments(JSContext *cx, JSObject *parent, uint32 argc, JSObject &callee)
SetValueRangeToUndefined(data->slots, argc);
/* Can't fail from here on, so initialize everything in argsobj. */
argsobj->init(cx, callee.getFunctionPrivate()->inStrictMode()
argsobj->init(callee.getFunctionPrivate()->inStrictMode()
? &StrictArgumentsClass
: &js_ArgumentsClass,
proto, parent, NULL, false);
proto, parent, NULL, cx);
argsobj->setMap(cx->runtime->emptyArgumentsShape);
@ -965,20 +964,15 @@ CalleeGetter(JSContext *cx, JSObject *obj, jsid id, Value *vp)
static JSObject *
NewCallObject(JSContext *cx, JSFunction *fun, JSObject &scopeChain, JSObject &callee)
{
size_t vars = fun->countArgsAndVars();
size_t slots = JSObject::CALL_RESERVED_SLOTS + vars;
JSFinalizeGCThingKind kind = js_GetGCObjectKind(slots);
JSObject *callobj = js_NewGCObject(cx, kind);
JSObject *callobj = js_NewGCObject(cx);
if (!callobj)
return NULL;
/* Init immediately to avoid GC seeing a half-init'ed object. */
callobj->init(cx, &js_CallClass, NULL, &scopeChain, NULL, false);
callobj->init(&js_CallClass, NULL, &scopeChain, NULL, cx);
callobj->setMap(fun->u.i.names);
/* This must come after callobj->lastProp has been set. */
if (!callobj->ensureInstanceReservedSlots(cx, vars))
if (!callobj->ensureInstanceReservedSlots(cx, fun->countArgsAndVars()))
return NULL;
#ifdef DEBUG
@ -998,11 +992,11 @@ NewCallObject(JSContext *cx, JSFunction *fun, JSObject &scopeChain, JSObject &ca
static inline JSObject *
NewDeclEnvObject(JSContext *cx, JSStackFrame *fp)
{
JSObject *envobj = js_NewGCObject(cx, FINALIZE_OBJECT2);
JSObject *envobj = js_NewGCObject(cx);
if (!envobj)
return NULL;
envobj->init(cx, &js_DeclEnvClass, NULL, &fp->scopeChain(), fp, false);
envobj->init(&js_DeclEnvClass, NULL, &fp->scopeChain(), fp, cx);
envobj->setMap(cx->runtime->emptyDeclEnvShape);
return envobj;
}
@ -1077,9 +1071,34 @@ JS_DEFINE_CALLINFO_4(extern, OBJECT, js_CreateCallObjectOnTrace, CONTEXT, FUNCTI
inline static void
CopyValuesToCallObject(JSObject &callobj, uintN nargs, Value *argv, uintN nvars, Value *slots)
{
Value *base = callobj.getSlots() + JSObject::CALL_RESERVED_SLOTS;
memcpy(base, argv, nargs * sizeof(Value));
memcpy(base + nargs, slots, nvars * sizeof(Value));
/* Copy however many args fit into fslots. */
uintN first = JSSLOT_PRIVATE + JSObject::CALL_RESERVED_SLOTS + 1;
JS_ASSERT(first <= JS_INITIAL_NSLOTS);
Value *vp = &callobj.fslots[first];
uintN len = Min(nargs, uintN(JS_INITIAL_NSLOTS) - first);
memcpy(vp, argv, len * sizeof(Value));
vp += len;
nargs -= len;
if (nargs != 0) {
/* Copy any remaining args into dslots. */
vp = callobj.dslots;
memcpy(vp, argv + len, nargs * sizeof(Value));
vp += nargs;
} else {
/* Copy however many vars fit into any remaining fslots. */
first += len;
len = JS_MIN(nvars, JS_INITIAL_NSLOTS - first);
memcpy(vp, slots, len * sizeof(Value));
slots += len;
nvars -= len;
vp = callobj.dslots;
}
/* Copy any remaining vars into dslots. */
memcpy(vp, slots, nvars * sizeof(Value));
}
void
@ -1098,23 +1117,28 @@ js_PutCallObject(JSContext *cx, JSStackFrame *fp)
JS_ASSERT(fun == callobj.getCallObjCalleeFunction());
uintN n = fun->countArgsAndVars();
/*
* Since for a call object all fixed slots happen to be taken, we can copy
* arguments and variables straight into JSObject.dslots.
*/
JS_STATIC_ASSERT(JS_INITIAL_NSLOTS - JSSLOT_PRIVATE ==
1 + JSObject::CALL_RESERVED_SLOTS);
if (n != 0) {
JS_ASSERT(JSFunction::CLASS_RESERVED_SLOTS + n <= callobj.numSlots());
JS_ASSERT(JSFunction::FIRST_FREE_SLOT + n <= callobj.numSlots());
uint32 nargs = fun->nargs;
uint32 nvars = fun->u.i.nvars;
Value *base = callobj.getSlots() + JSObject::CALL_RESERVED_SLOTS;
#ifdef JS_METHODJIT
JS_STATIC_ASSERT(JS_INITIAL_NSLOTS == JSSLOT_PRIVATE + JSObject::CALL_RESERVED_SLOTS + 1);
JSScript *script = fun->u.i.script;
memcpy(base, fp->formalArgs(), nargs * sizeof(Value));
memcpy(callobj.dslots, fp->formalArgs(), nargs * sizeof(Value));
if (!script->jit || script->usesEval) {
memcpy(base + nargs, fp->slots(), nvars * sizeof(Value));
memcpy(callobj.dslots + nargs, fp->slots(), nvars * sizeof(Value));
} else if (script->jit) {
for (uint32 i = 0; i < script->jit->nescaping; i++) {
uint32 e = script->jit->escaping[i];
base[nargs + e] = fp->slots()[e];
callobj.dslots[nargs + e] = fp->slots()[e];
}
}
#else
@ -1209,13 +1233,16 @@ CallPropertyOp(JSContext *cx, JSObject *obj, jsid id, Value *vp,
}
if (!fp) {
i += JSObject::CALL_RESERVED_SLOTS;
if (kind == JSCPK_VAR)
i += fun->nargs;
else
JS_ASSERT(kind == JSCPK_ARG);
array = obj->getSlots();
const uintN first = JSSLOT_PRIVATE + JSObject::CALL_RESERVED_SLOTS + 1;
JS_ASSERT(first == JSSLOT_FREE(&js_CallClass));
JS_ASSERT(first <= JS_INITIAL_NSLOTS);
array = (i < JS_INITIAL_NSLOTS - first) ? obj->fslots : obj->dslots;
} else if (kind == JSCPK_ARG) {
array = fp->formalArgs();
} else {
@ -1357,11 +1384,14 @@ call_trace(JSTracer *trc, JSObject *obj)
* cycles involving Call objects whose frames are active without this
* hiding hack.
*/
uintN first = JSObject::CALL_RESERVED_SLOTS;
uintN count = fp->fun()->countArgsAndVars();
uintN first = JSSLOT_PRIVATE + JSObject::CALL_RESERVED_SLOTS + 1;
JS_ASSERT(first <= JS_INITIAL_NSLOTS);
JS_ASSERT(obj->numSlots() >= first + count);
SetValueRangeToUndefined(obj->getSlots() + first, count);
uintN count = fp->fun()->countArgsAndVars();
uintN fixed = JS_MIN(count, JS_INITIAL_NSLOTS - first);
SetValueRangeToUndefined(&obj->fslots[first], fixed);
SetValueRangeToUndefined(obj->dslots, count - fixed);
}
MaybeMarkGenerator(trc, obj);
@ -2375,8 +2405,8 @@ JSObject::initBoundFunction(JSContext *cx, const Value &thisArg,
JS_ASSERT(isFunction());
flags |= JSObject::BOUND_FUNCTION;
getSlotRef(JSSLOT_BOUND_FUNCTION_THIS) = thisArg;
getSlotRef(JSSLOT_BOUND_FUNCTION_ARGS_COUNT).setPrivateUint32(argslen);
fslots[JSSLOT_BOUND_FUNCTION_THIS] = thisArg;
fslots[JSSLOT_BOUND_FUNCTION_ARGS_COUNT].setPrivateUint32(argslen);
if (argslen != 0) {
/* FIXME? Burn memory on an empty scope whose shape covers the args slots. */
EmptyShape *empty = EmptyShape::create(cx, clasp);
@ -2389,8 +2419,9 @@ JSObject::initBoundFunction(JSContext *cx, const Value &thisArg,
if (!ensureInstanceReservedSlots(cx, argslen))
return false;
JS_ASSERT(numSlots() >= argslen + FUN_CLASS_RESERVED_SLOTS);
memcpy(getSlots() + FUN_CLASS_RESERVED_SLOTS, args, argslen * sizeof(Value));
JS_ASSERT(dslots);
JS_ASSERT(dslots[-1].toPrivateUint32() >= argslen);
memcpy(&dslots[0], args, argslen * sizeof(Value));
}
return true;
}
@ -2411,7 +2442,7 @@ JSObject::getBoundFunctionThis() const
JS_ASSERT(isFunction());
JS_ASSERT(isBoundFunction());
return getSlot(JSSLOT_BOUND_FUNCTION_THIS);
return fslots[JSSLOT_BOUND_FUNCTION_THIS];
}
inline const js::Value *
@ -2420,10 +2451,10 @@ JSObject::getBoundFunctionArguments(uintN &argslen) const
JS_ASSERT(isFunction());
JS_ASSERT(isBoundFunction());
argslen = getSlot(JSSLOT_BOUND_FUNCTION_ARGS_COUNT).toPrivateUint32();
JS_ASSERT_IF(argslen > 0, numSlots() >= argslen);
return getSlots() + FUN_CLASS_RESERVED_SLOTS;
argslen = fslots[JSSLOT_BOUND_FUNCTION_ARGS_COUNT].toPrivateUint32();
JS_ASSERT_IF(argslen > 0, dslots);
JS_ASSERT_IF(argslen > 0, dslots[-1].toPrivateUint32() >= argslen);
return &dslots[0];
}
namespace {
@ -3110,7 +3141,7 @@ JSFunction::addLocal(JSContext *cx, JSAtom *atom, JSLocalKind kind)
uintN attrs = JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED;
uint16 *indexp;
PropertyOp getter, setter;
uint32 slot = JSObject::CALL_RESERVED_SLOTS;
uint32 slot = JSSLOT_START(&js_CallClass) + JSObject::CALL_RESERVED_SLOTS;
if (kind == JSLOCAL_ARG) {
JS_ASSERT(u.i.nupvars == 0);

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

@ -134,8 +134,6 @@ enum JSLocalKind {
struct JSFunction : public JSObject
{
/* Functions always have two fixed slots (FUN_CLASS_RESERVED_SLOTS). */
uint16 nargs; /* maximum number of specified arguments,
reflected as f.length/f.arity */
uint16 flags; /* flags, see JSFUN_* below and in jsapi.h */
@ -271,7 +269,7 @@ struct JSFunction : public JSObject
public:
void setJoinable() {
JS_ASSERT(FUN_INTERPRETED(this));
getSlotRef(METHOD_ATOM_SLOT).setNull();
fslots[METHOD_ATOM_SLOT].setNull();
flags |= JSFUN_JOINABLE;
}
@ -281,14 +279,14 @@ struct JSFunction : public JSObject
* flattened upvars.
*/
JSAtom *methodAtom() const {
return (joinable() && getSlot(METHOD_ATOM_SLOT).isString())
? STRING_TO_ATOM(getSlot(METHOD_ATOM_SLOT).toString())
return (joinable() && fslots[METHOD_ATOM_SLOT].isString())
? STRING_TO_ATOM(fslots[METHOD_ATOM_SLOT].toString())
: NULL;
}
void setMethodAtom(JSAtom *atom) {
JS_ASSERT(joinable());
getSlotRef(METHOD_ATOM_SLOT).setString(ATOM_TO_STRING(atom));
fslots[METHOD_ATOM_SLOT].setString(ATOM_TO_STRING(atom));
}
js::Native maybeNative() const {
@ -300,8 +298,9 @@ struct JSFunction : public JSObject
return u.i.script;
}
/* Number of extra fixed function object slots. */
/* Number of extra fixed function object slots besides JSSLOT_PRIVATE. */
static const uint32 CLASS_RESERVED_SLOTS = JSObject::FUN_CLASS_RESERVED_SLOTS;
static const uint32 FIRST_FREE_SLOT = JSSLOT_PRIVATE + CLASS_RESERVED_SLOTS + 1;
};
JS_STATIC_ASSERT(sizeof(JSFunction) % JS_GCTHING_ALIGN == 0);

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

@ -235,7 +235,7 @@ const size_t GC_MARK_BITMAP_WORDS = GC_CELLS_PER_ARENA / JS_BITS_PER_WORD;
JS_STATIC_ASSERT(sizeof(jsbitmap) == sizeof(jsuword));
JS_STATIC_ASSERT(sizeof(JSString) % GC_CELL_SIZE == 0);
JS_STATIC_ASSERT(JSOBJECT_SIZE % GC_CELL_SIZE == 0);
JS_STATIC_ASSERT(sizeof(JSObject) % GC_CELL_SIZE == 0);
JS_STATIC_ASSERT(sizeof(JSFunction) % GC_CELL_SIZE == 0);
#ifdef JSXML
JS_STATIC_ASSERT(sizeof(JSXML) % GC_CELL_SIZE == 0);
@ -771,15 +771,9 @@ static inline size_t
GetFinalizableThingSize(unsigned thingKind)
{
JS_STATIC_ASSERT(JS_EXTERNAL_STRING_LIMIT == 8);
JS_STATIC_ASSERT(FINALIZE_OBJECT_LAST - FINALIZE_OBJECT0 == 5);
static const uint8 map[FINALIZE_LIMIT] = {
JSOBJECT_SIZE, /* FINALIZE_OBJECT0 */
JSOBJECT_SIZE + 2 * sizeof(Value), /* FINALIZE_OBJECT2 */
JSOBJECT_SIZE + 4 * sizeof(Value), /* FINALIZE_OBJECT4 */
JSOBJECT_SIZE + 8 * sizeof(Value), /* FINALIZE_OBJECT8 */
JSOBJECT_SIZE + 12 * sizeof(Value), /* FINALIZE_OBJECT12 */
JSOBJECT_SIZE + 16 * sizeof(Value), /* FINALIZE_OBJECT16 */
sizeof(JSObject), /* FINALIZE_OBJECT */
sizeof(JSFunction), /* FINALIZE_FUNCTION */
#if JS_HAS_XML_SUPPORT
sizeof(JSXML), /* FINALIZE_XML */
@ -806,12 +800,7 @@ GetFinalizableTraceKind(size_t thingKind)
JS_STATIC_ASSERT(JS_EXTERNAL_STRING_LIMIT == 8);
static const uint8 map[FINALIZE_LIMIT] = {
JSTRACE_OBJECT, /* FINALIZE_OBJECT0 */
JSTRACE_OBJECT, /* FINALIZE_OBJECT2 */
JSTRACE_OBJECT, /* FINALIZE_OBJECT4 */
JSTRACE_OBJECT, /* FINALIZE_OBJECT8 */
JSTRACE_OBJECT, /* FINALIZE_OBJECT12 */
JSTRACE_OBJECT, /* FINALIZE_OBJECT16 */
JSTRACE_OBJECT, /* FINALIZE_OBJECT */
JSTRACE_OBJECT, /* FINALIZE_FUNCTION */
#if JS_HAS_XML_SUPPORT /* FINALIZE_XML */
JSTRACE_XML,
@ -1560,22 +1549,8 @@ CheckGCFreeListLink(JSGCThing *thing)
JS_ASSERT_IF(thing->link, thing < thing->link);
}
JSFinalizeGCThingKind js_GCObjectSlotsToThingKind[] = {
/* 0 */ FINALIZE_OBJECT0, FINALIZE_OBJECT2, FINALIZE_OBJECT2, FINALIZE_OBJECT4,
/* 4 */ FINALIZE_OBJECT4, FINALIZE_OBJECT8, FINALIZE_OBJECT8, FINALIZE_OBJECT8,
/* 8 */ FINALIZE_OBJECT8, FINALIZE_OBJECT12, FINALIZE_OBJECT12, FINALIZE_OBJECT12,
/* 12 */ FINALIZE_OBJECT12, FINALIZE_OBJECT16, FINALIZE_OBJECT16, FINALIZE_OBJECT16,
/* 16 */ FINALIZE_OBJECT16, FINALIZE_OBJECT0, FINALIZE_OBJECT0, FINALIZE_OBJECT0,
/* 20 */ FINALIZE_OBJECT0, FINALIZE_OBJECT0, FINALIZE_OBJECT0, FINALIZE_OBJECT0,
/* 24 */ FINALIZE_OBJECT0, FINALIZE_OBJECT0, FINALIZE_OBJECT0, FINALIZE_OBJECT0,
/* 28 */ FINALIZE_OBJECT0, FINALIZE_OBJECT0, FINALIZE_OBJECT0, FINALIZE_OBJECT0,
/* 32 */ FINALIZE_OBJECT0
};
JS_STATIC_ASSERT(JS_ARRAY_LENGTH(js_GCObjectSlotsToThingKind) == SLOTS_TO_THING_KIND_LIMIT);
void *
js_NewFinalizableGCThing(JSContext *cx, JSFinalizeGCThingKind thingKind)
js_NewFinalizableGCThing(JSContext *cx, unsigned thingKind)
{
JS_ASSERT(thingKind < FINALIZE_LIMIT);
#ifdef JS_THREADSAFE
@ -1613,13 +1588,6 @@ js_NewFinalizableGCThing(JSContext *cx, JSFinalizeGCThingKind thingKind)
return thing;
}
JSFinalizeGCThingKind
js_KindFromGCThing(const void *thing)
{
JSGCArenaInfo *info = JSGCArenaInfo::fromGCThing((void*)thing);
return (JSFinalizeGCThingKind) info->list->thingKind;
}
JSBool
js_LockGCThingRT(JSRuntime *rt, void *thing)
{
@ -1676,14 +1644,8 @@ JS_TraceChildren(JSTracer *trc, void *thing, uint32 kind)
JS_CALL_OBJECT_TRACER(trc, proto, "proto");
if (JSObject *parent = obj->getParent())
JS_CALL_OBJECT_TRACER(trc, parent, "parent");
if (obj->emptyShapes) {
int count = FINALIZE_OBJECT_LAST - FINALIZE_OBJECT0 + 1;
for (int i = 0; i < count; i++) {
if (obj->emptyShapes[i])
obj->emptyShapes[i]->trace(trc);
}
}
if (obj->emptyShape)
obj->emptyShape->trace(trc);
/* Delegate to ops or the native marking op. */
JSTraceOp op = obj->getOps()->trace;
@ -2387,7 +2349,7 @@ js_DestroyScriptsToGC(JSContext *cx, JSThreadData *data)
inline void
FinalizeObject(JSContext *cx, JSObject *obj, unsigned thingKind)
{
JS_ASSERT((thingKind >= FINALIZE_OBJECT0 && thingKind <= FINALIZE_OBJECT_LAST) ||
JS_ASSERT(thingKind == FINALIZE_OBJECT ||
thingKind == FINALIZE_FUNCTION);
/* Cope with stillborn objects that have no map. */
@ -2526,14 +2488,14 @@ js_FinalizeStringRT(JSRuntime *rt, JSString *str)
}
}
template<typename T, unsigned SIZE,
template<typename T,
void finalizer(JSContext *cx, T *thing, unsigned thingKind)>
static void
FinalizeArenaList(JSContext *cx, unsigned thingKind)
{
JS_STATIC_ASSERT(!(SIZE & GC_CELL_MASK));
JS_STATIC_ASSERT(!(sizeof(T) & GC_CELL_MASK));
JSGCArenaList *arenaList = &cx->runtime->gcArenaList[thingKind];
JS_ASSERT(SIZE == arenaList->thingSize);
JS_ASSERT(sizeof(T) == arenaList->thingSize);
JSGCArena **ap = &arenaList->head;
JSGCArena *a = *ap;
@ -2554,8 +2516,7 @@ FinalizeArenaList(JSContext *cx, unsigned thingKind)
bool allClear = true;
jsuword thing = a->toPageStart();
jsuword thingsEnd = thing + GC_ARENA_SIZE - (GC_ARENA_SIZE % SIZE);
JS_ASSERT((thingsEnd - thing) % SIZE == 0);
jsuword thingsEnd = thing + GC_ARENA_SIZE / sizeof(T) * sizeof(T);
jsuword nextFree = reinterpret_cast<jsuword>(ainfo->freeList);
if (!nextFree) {
@ -2567,7 +2528,7 @@ FinalizeArenaList(JSContext *cx, unsigned thingKind)
jsuword gcCellIndex = 0;
jsbitmap *bitmap = a->getMarkBitmap();
for (;; thing += SIZE, gcCellIndex += SIZE >> GC_CELL_SHIFT) {
for (;; thing += sizeof(T), gcCellIndex += sizeof(T) >> GC_CELL_SHIFT) {
if (thing == nextFree) {
if (thing == thingsEnd)
break;
@ -2587,7 +2548,7 @@ FinalizeArenaList(JSContext *cx, unsigned thingKind)
T *t = reinterpret_cast<T *>(thing);
finalizer(cx, t, thingKind);
#ifdef DEBUG
memset(t, JS_FREE_PATTERN, SIZE);
memset(t, JS_FREE_PATTERN, sizeof(T));
#endif
}
JSGCThing *t = reinterpret_cast<JSGCThing *>(thing);
@ -2615,12 +2576,12 @@ FinalizeArenaList(JSContext *cx, unsigned thingKind)
* Forget just assembled free list head for the arena and
* add the arena itself to the destroy list.
*/
JS_ASSERT(nfree == ThingsPerArena(SIZE));
JS_ASSERT(nfree == ThingsPerArena(sizeof(T)));
*ap = ainfo->prev;
ReleaseGCArena(cx->runtime, a);
METER(nkilledarenas++);
} else {
JS_ASSERT(nfree < ThingsPerArena(SIZE));
JS_ASSERT(nfree < ThingsPerArena(sizeof(T)));
*tailp = NULL;
ainfo->freeList = freeList;
ap = &ainfo->prev;
@ -2923,21 +2884,10 @@ MarkAndSweep(JSContext *cx GCTIMER_PARAM)
* object's finalizer can access them even if they will be freed.
*/
JS_ASSERT(!rt->gcEmptyArenaList);
FinalizeArenaList<JSObject, JSOBJECT_SIZE,
FinalizeObject>(cx, FINALIZE_OBJECT0);
FinalizeArenaList<JSObject, JSOBJECT_SIZE + sizeof(Value) * 2,
FinalizeObject>(cx, FINALIZE_OBJECT2);
FinalizeArenaList<JSObject, JSOBJECT_SIZE + sizeof(Value) * 4,
FinalizeObject>(cx, FINALIZE_OBJECT4);
FinalizeArenaList<JSObject, JSOBJECT_SIZE + sizeof(Value) * 8,
FinalizeObject>(cx, FINALIZE_OBJECT8);
FinalizeArenaList<JSObject, JSOBJECT_SIZE + sizeof(Value) * 12,
FinalizeObject>(cx, FINALIZE_OBJECT12);
FinalizeArenaList<JSObject, JSOBJECT_SIZE + sizeof(Value) * 16,
FinalizeObject>(cx, FINALIZE_OBJECT16);
FinalizeArenaList<JSFunction, sizeof(JSFunction), FinalizeFunction>(cx, FINALIZE_FUNCTION);
FinalizeArenaList<JSObject, FinalizeObject>(cx, FINALIZE_OBJECT);
FinalizeArenaList<JSFunction, FinalizeFunction>(cx, FINALIZE_FUNCTION);
#if JS_HAS_XML_SUPPORT
FinalizeArenaList<JSXML, sizeof(JSXML), FinalizeXML>(cx, FINALIZE_XML);
FinalizeArenaList<JSXML, FinalizeXML>(cx, FINALIZE_XML);
#endif
TIMESTAMP(sweepObjectEnd);
@ -2947,13 +2897,12 @@ MarkAndSweep(JSContext *cx GCTIMER_PARAM)
*/
rt->deflatedStringCache->sweep(cx);
FinalizeArenaList<JSShortString, sizeof(JSShortString),
FinalizeShortString>(cx, FINALIZE_SHORT_STRING);
FinalizeArenaList<JSString, sizeof(JSString), FinalizeString>(cx, FINALIZE_STRING);
FinalizeArenaList<JSShortString, FinalizeShortString>(cx, FINALIZE_SHORT_STRING);
FinalizeArenaList<JSString, FinalizeString>(cx, FINALIZE_STRING);
for (unsigned i = FINALIZE_EXTERNAL_STRING0;
i <= FINALIZE_EXTERNAL_STRING_LAST;
++i) {
FinalizeArenaList<JSString, sizeof(JSString), FinalizeExternalString>(cx, i);
FinalizeArenaList<JSString, FinalizeExternalString>(cx, i);
}
rt->gcNewArenaTriggerBytes = rt->gcBytes < GC_ARENA_ALLOCATION_TRIGGER ?

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

@ -236,13 +236,7 @@ js_WaitForGC(JSRuntime *rt);
* ordinary string to simplify js_GetExternalStringGCType.
*/
enum JSFinalizeGCThingKind {
FINALIZE_OBJECT0,
FINALIZE_OBJECT2,
FINALIZE_OBJECT4,
FINALIZE_OBJECT8,
FINALIZE_OBJECT12,
FINALIZE_OBJECT16,
FINALIZE_OBJECT_LAST = FINALIZE_OBJECT16,
FINALIZE_OBJECT,
FINALIZE_FUNCTION,
#if JS_HAS_XML_SUPPORT
FINALIZE_XML,
@ -275,61 +269,12 @@ IsFinalizableStringKind(unsigned thingKind)
* in the partially initialized thing.
*/
extern void *
js_NewFinalizableGCThing(JSContext *cx, JSFinalizeGCThingKind thingKind);
/* Get the kind which was used when making a GC thing. */
extern JSFinalizeGCThingKind
js_KindFromGCThing(const void *thing);
/* Maximum number of fixed slots for an object. */
const size_t JSOBJECT_FIXED_SLOTS_LIMIT = 16;
/* Capacity for js_GCObjectSlotsToThingKind */
const size_t SLOTS_TO_THING_KIND_LIMIT = 33;
/* Get the best kind to use when making an object with the given slot count. */
static inline JSFinalizeGCThingKind
js_GetGCObjectKind(size_t numSlots)
{
extern JSFinalizeGCThingKind js_GCObjectSlotsToThingKind[];
if (numSlots >= SLOTS_TO_THING_KIND_LIMIT)
return FINALIZE_OBJECT0;
return js_GCObjectSlotsToThingKind[numSlots];
}
/* Get the number of fixed slots and initial capacity associated with a kind. */
static inline size_t
js_GetGCKindSlots(JSFinalizeGCThingKind thingKind)
{
/* Using a switch in hopes that thingKind will usually be a compile-time constant. */
switch (thingKind) {
case FINALIZE_OBJECT0:
return 0;
case FINALIZE_OBJECT2:
return 2;
case FINALIZE_OBJECT4:
return 4;
case FINALIZE_OBJECT8:
return 8;
case FINALIZE_OBJECT12:
return 12;
case FINALIZE_OBJECT16:
return 16;
default:
JS_NOT_REACHED("Bad object finalize kind");
return 0;
}
}
js_NewFinalizableGCThing(JSContext *cx, unsigned thingKind);
static inline JSObject *
js_NewGCObject(JSContext *cx, JSFinalizeGCThingKind thingKind)
js_NewGCObject(JSContext *cx)
{
JS_ASSERT(thingKind >= FINALIZE_OBJECT0 && thingKind <= FINALIZE_OBJECT_LAST);
JSObject *obj = (JSObject *) js_NewFinalizableGCThing(cx, thingKind);
if (obj)
obj->capacity = js_GetGCKindSlots(thingKind);
return obj;
return (JSObject *) js_NewFinalizableGCThing(cx, FINALIZE_OBJECT);
}
static inline JSString *
@ -351,7 +296,7 @@ js_NewGCExternalString(JSContext *cx, uintN type)
{
JS_ASSERT(type < JS_EXTERNAL_STRING_LIMIT);
type += FINALIZE_EXTERNAL_STRING0;
return (JSString *) js_NewFinalizableGCThing(cx, JSFinalizeGCThingKind(type));
return (JSString *) js_NewFinalizableGCThing(cx, type);
}
static inline JSFunction *
@ -359,13 +304,12 @@ js_NewGCFunction(JSContext *cx)
{
JSFunction* obj = (JSFunction *)js_NewFinalizableGCThing(cx, FINALIZE_FUNCTION);
if (obj) {
obj->capacity = JSObject::FUN_CLASS_RESERVED_SLOTS;
#ifdef DEBUG
if (obj) {
memset((uint8 *) obj + sizeof(JSObject), JS_FREE_PATTERN,
sizeof(JSFunction) - sizeof(JSObject));
#endif
}
#endif
return obj;
}
@ -472,13 +416,10 @@ class GCHelperThread {
void freeLater(void *ptr) {
JS_ASSERT(!sweeping);
js_free(ptr);
/*
if (freeCursor != freeCursorEnd)
*freeCursor++ = ptr;
else
replenishAndFreeLater(ptr);
*/
}
};

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

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

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

@ -288,7 +288,7 @@ EnumerateDenseArrayProperties(JSContext *cx, JSObject *obj, JSObject *pobj, uint
if (pobj->getArrayLength() > 0) {
size_t capacity = pobj->getDenseArrayCapacity();
Value *vp = pobj->getDenseArrayElements();
Value *vp = pobj->dslots;
for (size_t i = 0; i < capacity; ++i, ++vp) {
if (!vp->isMagic(JS_ARRAY_HOLE)) {
/* Dense arrays never get so large that i would not fit into an integer id. */
@ -455,10 +455,10 @@ NewIteratorObject(JSContext *cx, uintN flags)
* helper objects) expect it to have a non-null map pointer, so we
* share an empty Enumerator scope in the runtime.
*/
JSObject *obj = js_NewGCObject(cx, FINALIZE_OBJECT0);
JSObject *obj = js_NewGCObject(cx);
if (!obj)
return false;
obj->init(cx, &js_IteratorClass, NULL, NULL, NULL, false);
obj->init(&js_IteratorClass, NULL, NULL, NullValue(), cx);
obj->setMap(cx->runtime->emptyEnumeratorShape);
return obj;
}

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

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

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

@ -2610,17 +2610,15 @@ js_NewInstance(JSContext *cx, JSObject *callee)
static JS_ALWAYS_INLINE JSObject*
NewObjectWithClassProto(JSContext *cx, Class *clasp, JSObject *proto,
/*JSFinalizeGCThingKind*/ unsigned _kind)
const Value &privateSlotValue)
{
JS_ASSERT(clasp->isNative());
JSFinalizeGCThingKind kind = JSFinalizeGCThingKind(_kind);
JSObject* obj = js_NewGCObject(cx, kind);
JSObject* obj = js_NewGCObject(cx);
if (!obj)
return NULL;
if (!obj->initSharingEmptyShape(cx, clasp, proto, proto->getParent(), NULL, kind))
return NULL;
obj->initSharingEmptyShape(clasp, proto, proto->getParent(), privateSlotValue, cx);
return obj;
}
@ -2628,7 +2626,8 @@ JSObject* FASTCALL
js_Object_tn(JSContext* cx, JSObject* proto)
{
JS_ASSERT(!(js_ObjectClass.flags & JSCLASS_HAS_PRIVATE));
return NewObjectWithClassProto(cx, &js_ObjectClass, proto, FINALIZE_OBJECT8);
return NewObjectWithClassProto(cx, &js_ObjectClass, proto, UndefinedValue());
}
JS_DEFINE_TRCINFO_1(js_Object,
@ -2640,7 +2639,7 @@ js_NonEmptyObject(JSContext* cx, JSObject* proto)
{
JS_ASSERT(!(js_ObjectClass.flags & JSCLASS_HAS_PRIVATE));
JSObject *obj = NewObjectWithClassProto(cx, &js_ObjectClass, proto, FINALIZE_OBJECT8);
JSObject *obj = NewObjectWithClassProto(cx, &js_ObjectClass, proto, UndefinedValue());
return (obj && obj->ensureClassReservedSlotsForEmptyObject(cx)) ? obj : NULL;
}
@ -2651,11 +2650,7 @@ JSObject* FASTCALL
js_String_tn(JSContext* cx, JSObject* proto, JSString* str)
{
JS_ASSERT(JS_ON_TRACE(cx));
JSObject *obj = NewObjectWithClassProto(cx, &js_StringClass, proto, FINALIZE_OBJECT2);
if (!obj)
return NULL;
obj->setPrimitiveThis(StringValue(str));
return obj;
return NewObjectWithClassProto(cx, &js_StringClass, proto, StringValue(str));
}
JS_DEFINE_CALLINFO_3(extern, OBJECT, js_String_tn, CONTEXT, CALLEE_PROTOTYPE, STRING, 0,
nanojit::ACCSET_STORE_ANY)
@ -2930,13 +2925,11 @@ js_NewWithObject(JSContext *cx, JSObject *proto, JSObject *parent, jsint depth)
{
JSObject *obj;
obj = js_NewGCObject(cx, FINALIZE_OBJECT2);
obj = js_NewGCObject(cx);
if (!obj)
return NULL;
JSStackFrame *priv = js_FloatingFrameIfGenerator(cx, cx->fp());
obj->init(cx, &js_WithClass, proto, parent, priv, false);
obj->init(&js_WithClass, proto, parent, js_FloatingFrameIfGenerator(cx, cx->fp()), cx);
obj->setMap(cx->runtime->emptyWithShape);
OBJ_SET_BLOCK_DEPTH(cx, obj, depth);
@ -2956,11 +2949,11 @@ js_NewBlockObject(JSContext *cx)
* Null obj's proto slot so that Object.prototype.* does not pollute block
* scopes and to give the block object its own scope.
*/
JSObject *blockObj = js_NewGCObject(cx, FINALIZE_OBJECT2);
JSObject *blockObj = js_NewGCObject(cx);
if (!blockObj)
return NULL;
blockObj->init(cx, &js_BlockClass, NULL, NULL, NULL, false);
blockObj->init(&js_BlockClass, NULL, NULL, NullValue(), cx);
blockObj->setMap(cx->runtime->emptyBlockShape);
return blockObj;
}
@ -2970,24 +2963,20 @@ js_CloneBlockObject(JSContext *cx, JSObject *proto, JSStackFrame *fp)
{
JS_ASSERT(proto->isStaticBlock());
size_t count = OBJ_BLOCK_COUNT(cx, proto);
JSFinalizeGCThingKind kind = js_GetGCObjectKind(count + 1);
JSObject *clone = js_NewGCObject(cx, kind);
JSObject *clone = js_NewGCObject(cx);
if (!clone)
return NULL;
JSStackFrame *priv = js_FloatingFrameIfGenerator(cx, fp);
/* The caller sets parent on its own. */
clone->init(cx, &js_BlockClass, proto, NULL, priv, false);
clone->init(&js_BlockClass, proto, NULL, priv, cx);
clone->fslots[JSSLOT_BLOCK_DEPTH] = proto->fslots[JSSLOT_BLOCK_DEPTH];
clone->setMap(proto->map);
if (!clone->ensureInstanceReservedSlots(cx, count + 1))
if (!clone->ensureInstanceReservedSlots(cx, OBJ_BLOCK_COUNT(cx, proto)))
return NULL;
clone->setSlot(JSSLOT_BLOCK_DEPTH, proto->getSlot(JSSLOT_BLOCK_DEPTH));
JS_ASSERT(clone->isClonedBlock());
return clone;
}
@ -2995,6 +2984,9 @@ js_CloneBlockObject(JSContext *cx, JSObject *proto, JSStackFrame *fp)
JS_REQUIRES_STACK JSBool
js_PutBlockObject(JSContext *cx, JSBool normalUnwind)
{
/* Blocks have one fixed slot available for the first local.*/
JS_STATIC_ASSERT(JS_INITIAL_NSLOTS == JSSLOT_BLOCK_DEPTH + 2);
JSStackFrame *const fp = cx->fp();
JSObject *obj = &fp->scopeChain();
JS_ASSERT(obj->isClonedBlock());
@ -3002,7 +2994,7 @@ js_PutBlockObject(JSContext *cx, JSBool normalUnwind)
/* Block objects should have all reserved slots allocated early. */
uintN count = OBJ_BLOCK_COUNT(cx, obj);
JS_ASSERT(obj->numSlots() >= JSSLOT_BLOCK_DEPTH + 1 + count);
JS_ASSERT(obj->numSlots() == JSSLOT_BLOCK_DEPTH + 1 + count);
/* The block and its locals must be on the current stack for GC safety. */
uintN depth = OBJ_BLOCK_DEPTH(cx, obj);
@ -3014,8 +3006,15 @@ js_PutBlockObject(JSContext *cx, JSBool normalUnwind)
if (normalUnwind) {
uintN slot = JSSLOT_BLOCK_DEPTH + 1;
uintN flen = JS_MIN(count, JS_INITIAL_NSLOTS - slot);
uintN stop = slot + flen;
depth += fp->numFixed();
memcpy(obj->getSlots() + slot, fp->slots() + depth, count * sizeof(Value));
while (slot < stop)
obj->fslots[slot++] = fp->slots()[depth++];
count -= flen;
if (count != 0)
memcpy(obj->dslots, fp->slots() + depth, count * sizeof(Value));
}
/* We must clear the private slot even with errors. */
@ -3096,7 +3095,7 @@ GetObjectSize(JSObject *obj)
{
return (obj->isFunction() && !obj->getPrivate())
? sizeof(JSFunction)
: JSOBJECT_SIZE + obj->numFixedSlots() * sizeof(Value);
: sizeof(JSObject);
}
/*
@ -3105,31 +3104,17 @@ GetObjectSize(JSObject *obj)
* transitions are inherently not thread-safe. Don't perform a swap operation on objects
* shared across threads or, or bad things will happen. You have been warned.
*/
bool
JSObject::swap(JSContext *cx, JSObject *other)
void
JSObject::swap(JSObject *other)
{
size_t size = GetObjectSize(this);
JS_ASSERT(size == GetObjectSize(other));
bool thisInline = !hasSlotsArray();
bool otherInline = !other->hasSlotsArray();
char tmp[tl::Max<sizeof(JSFunction),
JSOBJECT_SIZE + JSOBJECT_FIXED_SLOTS_LIMIT * sizeof(Value)>::result];
JS_ASSERT(size <= sizeof(tmp));
/* Trade the guts of the objects. */
char tmp[tl::Max<sizeof(JSFunction), sizeof(JSObject)>::result];
memcpy(tmp, this, size);
memcpy(this, other, size);
memcpy(other, tmp, size);
/* Fixup pointers for inline slots on the objects. */
if (thisInline)
other->slots = other->fixedSlots;
if (otherInline)
this->slots = this->fixedSlots;
return true;
}
#if JS_HAS_XDR
@ -3315,12 +3300,13 @@ DefineStandardSlot(JSContext *cx, JSObject *obj, JSProtoKey key, JSAtom *atom,
const Shape *shape = obj->nativeLookup(id);
if (!shape) {
uint32 slot = 2 * JSProto_LIMIT + key;
if (!js_SetReservedSlot(cx, obj, slot, v)) {
uint32 index = 2 * JSProto_LIMIT + key;
if (!js_SetReservedSlot(cx, obj, index, v)) {
JS_UNLOCK_OBJ(cx, obj);
return false;
}
uint32 slot = JSSLOT_START(obj->getClass()) + index;
shape = obj->addProperty(cx, id, PropertyStub, PropertyStub, slot, attrs, 0, 0);
JS_UNLOCK_OBJ(cx, obj);
@ -3486,7 +3472,7 @@ js_InitClass(JSContext *cx, JSObject *obj, JSObject *parent_proto,
*/
JS_ASSERT_IF(proto->clasp != clasp,
clasp == &js_ArrayClass && proto->clasp == &js_SlowArrayClass);
if (!proto->getEmptyShape(cx, proto->clasp, FINALIZE_OBJECT0))
if (!proto->getEmptyShape(cx, proto->clasp))
goto bad;
/* If this is a standard class, cache its prototype. */
@ -3504,103 +3490,111 @@ bad:
}
bool
JSObject::allocSlots(JSContext *cx, size_t newcap)
JSObject::allocSlots(JSContext *cx, size_t nslots)
{
uint32 oldcap = numSlots();
JS_ASSERT(!dslots);
JS_ASSERT(nslots > JS_INITIAL_NSLOTS);
JS_ASSERT(newcap >= oldcap && !hasSlotsArray());
if (newcap > NSLOTS_LIMIT) {
if (!JS_ON_TRACE(cx))
js_ReportAllocationOverflow(cx);
size_t nwords = slotsToDynamicWords(nslots);
dslots = (Value*) cx->malloc(nwords * sizeof(Value));
if (!dslots)
return false;
}
Value *tmpslots = (Value*) cx->malloc(newcap * sizeof(Value));
if (!tmpslots)
return false; /* Leave slots at inline buffer. */
slots = tmpslots;
capacity = newcap;
/* Copy over anything from the inline buffer. */
memcpy(slots, fixedSlots, oldcap * sizeof(Value));
ClearValueRange(slots + oldcap, newcap - oldcap, isDenseArray());
dslots++;
dslots[-1].setPrivateUint32(nslots);
SetValueRangeToUndefined(dslots, nslots - JS_INITIAL_NSLOTS);
return true;
}
bool
JSObject::growSlots(JSContext *cx, size_t newcap)
JSObject::growSlots(JSContext *cx, size_t nslots)
{
/*
* When an object with CAPACITY_DOUBLING_MAX or fewer slots needs to
* grow, double its capacity, to add N elements in amortized O(N) time.
*
* Above this limit, grow by 12.5% each time. Speed is still amortized
* O(N), with a higher constant factor, and we waste less space.
* Minimal number of dynamic slots to allocate.
*/
static const size_t CAPACITY_DOUBLING_MAX = 1024 * 1024;
static const size_t CAPACITY_CHUNK = CAPACITY_DOUBLING_MAX / sizeof(Value);
const size_t MIN_DYNAMIC_WORDS = 4;
uint32 oldcap = numSlots();
JS_ASSERT(oldcap < newcap);
/*
* The limit to switch to linear allocation strategy from the power of 2
* growth no to waste too much memory.
*/
const size_t LINEAR_GROWTH_STEP = JS_BIT(16);
uint32 nextsize = (oldcap <= CAPACITY_DOUBLING_MAX)
? oldcap * 2
: oldcap + (oldcap >> 3);
uint32 actualCapacity = JS_MAX(newcap, nextsize);
if (actualCapacity >= CAPACITY_CHUNK)
actualCapacity = JS_ROUNDUP(actualCapacity, CAPACITY_CHUNK);
else if (actualCapacity < SLOT_CAPACITY_MIN)
actualCapacity = SLOT_CAPACITY_MIN;
/* If we are allocating fslots, there is nothing to do. */
if (nslots <= JS_INITIAL_NSLOTS)
return true;
/* Don't let nslots get close to wrapping around uint32. */
if (actualCapacity >= NSLOTS_LIMIT) {
if (nslots >= NSLOTS_LIMIT) {
JS_ReportOutOfMemory(cx);
return false;
}
/* If nothing was allocated yet, treat it as initial allocation. */
if (!hasSlotsArray())
return allocSlots(cx, actualCapacity);
size_t nwords = slotsToDynamicWords(nslots);
Value *tmpslots = (Value*) cx->realloc(slots, actualCapacity * sizeof(Value));
if (!tmpslots)
return false; /* Leave dslots as its old size. */
slots = tmpslots;
capacity = actualCapacity;
/*
* Round up nslots so the number of bytes in dslots array is power
* of 2 to ensure exponential grouth.
*/
uintN log;
if (nwords <= MIN_DYNAMIC_WORDS) {
nwords = MIN_DYNAMIC_WORDS;
} else if (nwords < LINEAR_GROWTH_STEP) {
JS_CEILING_LOG2(log, nwords);
nwords = JS_BIT(log);
} else {
nwords = JS_ROUNDUP(nwords, LINEAR_GROWTH_STEP);
}
nslots = dynamicWordsToSlots(nwords);
/*
* If nothing was allocated yet, treat it as initial allocation (but with
* the exponential growth algorithm applied).
*/
if (!dslots)
return allocSlots(cx, nslots);
size_t oldnslots = dslots[-1].toPrivateUint32();
Value *tmpdslots = (Value*) cx->realloc(dslots - 1, nwords * sizeof(Value));
if (!tmpdslots)
return false; /* leave dslots at its old size */
dslots = tmpdslots;
dslots++;
dslots[-1].setPrivateUint32(nslots);
/* Initialize the additional slots we added. */
ClearValueRange(slots + oldcap, actualCapacity - oldcap, isDenseArray());
JS_ASSERT(nslots > oldnslots);
Value *beg = dslots + (oldnslots - JS_INITIAL_NSLOTS);
Value *end = dslots + (nslots - JS_INITIAL_NSLOTS);
SetValueRangeToUndefined(beg, end);
return true;
}
void
JSObject::shrinkSlots(JSContext *cx, size_t newcap)
JSObject::shrinkSlots(JSContext *cx, size_t nslots)
{
uint32 oldcap = numSlots();
JS_ASSERT(newcap <= oldcap);
JS_ASSERT(newcap >= slotSpan());
if (oldcap <= SLOT_CAPACITY_MIN || !hasSlotsArray()) {
/* We won't shrink the slots any more. Clear excess holes. */
ClearValueRange(slots + newcap, oldcap - newcap, isDenseArray());
/* Nothing to shrink? */
if (!dslots)
return;
}
uint32 fill = newcap;
if (newcap < SLOT_CAPACITY_MIN)
newcap = SLOT_CAPACITY_MIN;
JS_ASSERT(dslots[-1].toPrivateUint32() > JS_INITIAL_NSLOTS);
JS_ASSERT(nslots <= dslots[-1].toPrivateUint32());
Value *tmpslots = (Value*) cx->realloc(slots, newcap * sizeof(Value));
if (!tmpslots)
return; /* Leave slots at its old size. */
slots = tmpslots;
capacity = newcap;
if (nslots <= JS_INITIAL_NSLOTS) {
freeSlotsArray(cx);
dslots = NULL;
} else {
size_t nwords = slotsToDynamicWords(nslots);
Value *tmpdslots = (Value*) cx->realloc(dslots - 1, nwords * sizeof(Value));
if (!tmpdslots)
return; /* leave dslots at its old size */
if (fill < newcap) {
/* Clear any excess holes if we tried to shrink below SLOT_CAPACITY_MIN. */
ClearValueRange(slots + fill, newcap - fill, isDenseArray());
dslots = tmpdslots;
dslots++;
dslots[-1].setPrivateUint32(nslots);
}
}
@ -4676,12 +4670,10 @@ js_NativeGet(JSContext *cx, JSObject *obj, JSObject *pobj, const Shape *shape, u
JS_ASSERT(JS_IS_OBJ_LOCKED(cx, pobj));
slot = shape->slot;
if (slot != SHAPE_INVALID_SLOT) {
if (slot != SHAPE_INVALID_SLOT)
*vp = pobj->lockedGetSlot(slot);
JS_ASSERT(!vp->isMagic());
} else {
else
vp->setUndefined();
}
if (shape->hasDefaultGetter())
return true;
@ -5919,6 +5911,7 @@ js_PrintObjectSlotName(JSTracer *trc, char *buf, size_t bufsize)
JSObject *obj = (JSObject *)trc->debugPrintArg;
uint32 slot = (uint32)trc->debugPrintIndex;
JS_ASSERT(slot >= JSSLOT_START(obj->getClass()));
const Shape *shape;
if (obj->isNative()) {
@ -5933,8 +5926,9 @@ js_PrintObjectSlotName(JSTracer *trc, char *buf, size_t bufsize)
const char *slotname = NULL;
Class *clasp = obj->getClass();
if (clasp->flags & JSCLASS_IS_GLOBAL) {
uint32 key = slot - JSSLOT_START(clasp);
#define JS_PROTO(name,code,init) \
if ((code) == slot) { slotname = js_##name##_str; goto found; }
if ((code) == key) { slotname = js_##name##_str; goto found; }
#include "jsproto.tbl"
#undef JS_PROTO
}
@ -5962,7 +5956,7 @@ js_TraceObject(JSTracer *trc, JSObject *obj)
JS_ASSERT(obj->isNative());
JSContext *cx = trc->context;
if (obj->hasSlotsArray() && !obj->nativeEmpty() && IS_GC_MARKING_TRACER(trc)) {
if (!obj->nativeEmpty() && IS_GC_MARKING_TRACER(trc)) {
/*
* Trim overlong dslots allocations from the GC, to avoid thrashing in
* case of delete-happy code that settles down at a given population.
@ -6009,8 +6003,9 @@ js_TraceObject(JSTracer *trc, JSObject *obj)
uint32 nslots = obj->numSlots();
if (!obj->nativeEmpty() && obj->slotSpan() < nslots)
nslots = obj->slotSpan();
JS_ASSERT(nslots >= JSSLOT_START(clasp));
for (uint32 i = 0; i != nslots; ++i) {
for (uint32 i = JSSLOT_START(clasp); i != nslots; ++i) {
const Value &v = obj->getSlot(i);
JS_SET_TRACING_DETAILS(trc, js_PrintObjectSlotName, obj, i);
MarkValueRaw(trc, v);
@ -6039,13 +6034,14 @@ js_ClearNative(JSContext *cx, JSObject *obj)
}
bool
js_GetReservedSlot(JSContext *cx, JSObject *obj, uint32 slot, Value *vp)
js_GetReservedSlot(JSContext *cx, JSObject *obj, uint32 index, Value *vp)
{
if (!obj->isNative()) {
vp->setUndefined();
return true;
}
uint32 slot = JSSLOT_START(obj->getClass()) + index;
JS_LOCK_OBJ(cx, obj);
if (slot < obj->numSlots())
*vp = obj->getSlot(slot);
@ -6056,12 +6052,13 @@ js_GetReservedSlot(JSContext *cx, JSObject *obj, uint32 slot, Value *vp)
}
bool
js_SetReservedSlot(JSContext *cx, JSObject *obj, uint32 slot, const Value &v)
js_SetReservedSlot(JSContext *cx, JSObject *obj, uint32 index, const Value &v)
{
if (!obj->isNative())
return true;
Class *clasp = obj->getClass();
uint32 slot = JSSLOT_START(clasp) + index;
JS_LOCK_OBJ(cx, obj);
if (slot >= obj->numSlots()) {
@ -6371,8 +6368,11 @@ js_DumpObject(JSObject *obj)
dumpValue(ObjectOrNullValue(obj->getParent()));
fputc('\n', stderr);
if (clasp->flags & JSCLASS_HAS_PRIVATE)
i = JSSLOT_PRIVATE;
if (clasp->flags & JSCLASS_HAS_PRIVATE) {
i = JSSLOT_PRIVATE + 1;
fprintf(stderr, "private %p\n", obj->getPrivate());
}
fprintf(stderr, "slots:\n");
reservedEnd = i + JSCLASS_RESERVED_SLOTS(clasp);

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

@ -235,6 +235,17 @@ js_TypeOf(JSContext *cx, JSObject *obj);
struct NativeIterator;
const uint32 JS_INITIAL_NSLOTS = 3;
/*
* The first available slot to store generic value. For JSCLASS_HAS_PRIVATE
* classes the slot stores a pointer to private data stuffed in a Value.
* Such pointer is stored as is without an overhead of PRIVATE_TO_JSVAL
* tagging and should be accessed using the (get|set)Private methods of
* JSObject.
*/
const uint32 JSSLOT_PRIVATE = 0;
struct JSFunction;
/*
@ -263,9 +274,9 @@ struct JSFunction;
* Both these flag bits are initially zero; they may be set or queried using
* the (is|set)(Delegate|System) inline methods.
*
* The dslots member is a pointer to the slot vector for the object,
* either an inline array starting at data or a dynamically allocated array.
* In both cases, capacity gives the number of available slots.
* The dslots member is null or a pointer into a dynamically allocated vector
* of Values for reserved and dynamic slots. If dslots is not null, dslots[-1]
* records the number of available slots.
*/
struct JSObject {
/*
@ -333,22 +344,18 @@ struct JSObject {
uint32 flags; /* flags */
uint32 objShape; /* copy of lastProp->shape, or override if different */
JSObject *proto; /* object's prototype */
JSObject *parent; /* object's parent */
js::Value *dslots; /* dynamically allocated slots */
/* Empty shape of kids if prototype, located here to align fslots on 32 bit targets. */
js::EmptyShape *emptyShape;
js::Value fslots[JS_INITIAL_NSLOTS]; /* small number of fixed slots */
#ifdef JS_THREADSAFE
JSTitle title;
#endif
/* If prototype, lazily filled array of empty shapes for each object size. */
js::EmptyShape **emptyShapes;
JSObject *proto; /* object's prototype */
JSObject *parent; /* object's parent */
void *privateData; /* private data */
jsuword capacity; /* capacity of slots */
js::Value *slots; /* dynamically allocated slots,
or pointer to fixedSlots */
js::Value fixedSlots[2]; /* inline slots for object. count is not fixed,
may be less or greater than two */
/*
* Return an immutable, shareable, empty shape with the same clasp as this
* and the same slotSpan as this had when empty.
@ -357,8 +364,7 @@ struct JSObject {
* used as the scope of a new object whose prototype is |proto|.
*/
inline bool canProvideEmptyShape(js::Class *clasp);
inline js::EmptyShape *getEmptyShape(JSContext *cx, js::Class *aclasp,
/* JSFinalizeGCThingKind */ unsigned kind);
inline js::EmptyShape *getEmptyShape(JSContext *cx, js::Class *aclasp);
bool isNative() const { return map->isNative(); }
@ -524,27 +530,29 @@ struct JSObject {
inline bool hasPropertyTable() const;
uint32 numSlots() const { return capacity; }
uint32 numSlots(void) const {
return dslots ? dslots[-1].toPrivateUint32() : uint32(JS_INITIAL_NSLOTS);
}
size_t slotsAndStructSize(uint32 nslots) const;
size_t slotsAndStructSize() const { return slotsAndStructSize(numSlots()); }
inline size_t numFixedSlots() const;
private:
static size_t slotsToDynamicWords(size_t nslots) {
JS_ASSERT(nslots > JS_INITIAL_NSLOTS);
return nslots + 1 - JS_INITIAL_NSLOTS;
}
static size_t dynamicWordsToSlots(size_t nwords) {
JS_ASSERT(nwords > 1);
return nwords - 1 + JS_INITIAL_NSLOTS;
}
public:
/* Minimum size for dynamically allocated slots. */
static const uint32 SLOT_CAPACITY_MIN = 8;
bool allocSlots(JSContext *cx, size_t nslots);
bool growSlots(JSContext *cx, size_t nslots);
void shrinkSlots(JSContext *cx, size_t nslots);
bool ensureSlots(JSContext *cx, size_t nslots) {
if (numSlots() < nslots)
return growSlots(cx, nslots);
return true;
}
/*
* Ensure that the object has at least JSCLASS_RESERVED_SLOTS(clasp) +
* nreserved slots.
@ -563,14 +571,6 @@ struct JSObject {
*/
bool ensureInstanceReservedSlots(JSContext *cx, size_t nreserved);
/*
* Get a direct pointer to the object's slots.
* This can be reallocated if the object is modified, watch out!
*/
js::Value *getSlots() const {
return slots;
}
/*
* NB: ensureClassReservedSlotsForEmptyObject asserts that nativeEmpty()
* Use ensureClassReservedSlots for any object, either empty or already
@ -585,18 +585,26 @@ struct JSObject {
bool containsSlot(uint32 slot) const { return slot < slotSpan(); }
js::Value& getSlotRef(uintN slot) {
JS_ASSERT(slot < capacity);
return slots[slot];
return (slot < JS_INITIAL_NSLOTS)
? fslots[slot]
: (JS_ASSERT(slot < dslots[-1].toPrivateUint32()),
dslots[slot - JS_INITIAL_NSLOTS]);
}
const js::Value &getSlot(uintN slot) const {
JS_ASSERT(slot < capacity);
return slots[slot];
return (slot < JS_INITIAL_NSLOTS)
? fslots[slot]
: (JS_ASSERT(slot < dslots[-1].toPrivateUint32()),
dslots[slot - JS_INITIAL_NSLOTS]);
}
void setSlot(uintN slot, const js::Value &value) {
JS_ASSERT(slot < capacity);
slots[slot] = value;
if (slot < JS_INITIAL_NSLOTS) {
fslots[slot] = value;
} else {
JS_ASSERT(slot < dslots[-1].toPrivateUint32());
dslots[slot - JS_INITIAL_NSLOTS] = value;
}
}
inline const js::Value &lockedGetSlot(uintN slot) const;
@ -605,7 +613,8 @@ struct JSObject {
/*
* These ones are for multi-threaded ("MT") objects. Use getSlot(),
* getSlotRef(), setSlot() to directly manipulate slots in obj when only
* one thread can access obj.
* one thread can access obj, or when accessing read-only slots within
* JS_INITIAL_NSLOTS.
*/
inline js::Value getSlotMT(JSContext *cx, uintN slot);
inline void setSlotMT(JSContext *cx, uintN slot, const js::Value &value);
@ -656,12 +665,12 @@ struct JSObject {
void *getPrivate() const {
JS_ASSERT(getClass()->flags & JSCLASS_HAS_PRIVATE);
return privateData;
return *(void **)&fslots[JSSLOT_PRIVATE];
}
void setPrivate(void *data) {
JS_ASSERT(getClass()->flags & JSCLASS_HAS_PRIVATE);
privateData = data;
*(void **)&fslots[JSSLOT_PRIVATE] = data;
}
/*
@ -669,7 +678,7 @@ struct JSObject {
*/
private:
static const uint32 JSSLOT_PRIMITIVE_THIS = 0;
static const uint32 JSSLOT_PRIMITIVE_THIS = JSSLOT_PRIVATE;
public:
inline const js::Value &getPrimitiveThis() const;
@ -679,16 +688,36 @@ struct JSObject {
* Array-specific getters and setters (for both dense and slow arrays).
*/
// Used by dense and slow arrays.
static const uint32 JSSLOT_ARRAY_LENGTH = JSSLOT_PRIVATE;
static const uint32 JSSLOT_DENSE_ARRAY_CAPACITY = JSSLOT_PRIVATE + 1;
// This assertion must remain true; see comment in js_MakeArraySlow().
// (Nb: This method is never called, it just contains a static assertion.
// The static assertion isn't inline because that doesn't work on Mac.)
inline void staticAssertArrayLengthIsInPrivateSlot();
public:
static const uint32 DENSE_ARRAY_CLASS_RESERVED_SLOTS = 3;
inline uint32 getArrayLength() const;
inline void setArrayLength(uint32 length);
inline uint32 getDenseArrayCapacity();
inline js::Value* getDenseArrayElements();
inline const js::Value &getDenseArrayElement(uintN idx);
inline js::Value* addressOfDenseArrayElement(uintN idx);
inline void setDenseArrayElement(uintN idx, const js::Value &val);
inline bool ensureDenseArrayElements(JSContext *cx, uintN cap);
inline void shrinkDenseArrayElements(JSContext *cx, uintN cap);
inline uint32 getDenseArrayCapacity() const;
inline void setDenseArrayCapacity(uint32 capacity);
inline const js::Value &getDenseArrayElement(uint32 i) const;
inline js::Value *addressOfDenseArrayElement(uint32 i);
inline void setDenseArrayElement(uint32 i, const js::Value &v);
inline js::Value *getDenseArrayElements() const; // returns pointer to the Array's elements array
bool growDenseArrayElements(JSContext *cx, uint32 oldcap, uint32 newcap);
bool ensureDenseArrayElements(JSContext *cx, uint32 newcap);
bool shrinkDenseArrayElements(JSContext *cx, uint32 newcap);
inline void freeDenseArrayElements(JSContext *cx);
inline void voidDenseOnlyArraySlots(); // used when converting a dense array to a slow array
JSBool makeDenseArraySlow(JSContext *cx);
@ -700,7 +729,7 @@ struct JSObject {
/*
* Reserved slot structure for Arguments objects:
*
* private - the function's stack frame until the function
* JSSLOT_PRIVATE - the function's stack frame until the function
* returns; also, JS_ARGUMENTS_OBJECT_ON_TRACE if
* arguments was created on trace
* JSSLOT_ARGS_LENGTH - the number of actual arguments and a flag
@ -718,13 +747,13 @@ struct JSObject {
* Argument index i is stored in ArgumentsData.slots[i], accessible via
* {get,set}ArgsElement().
*/
static const uint32 JSSLOT_ARGS_DATA = 1;
static const uint32 JSSLOT_ARGS_DATA = JSSLOT_PRIVATE + 2;
public:
/* Number of extra fixed arguments object slots besides JSSLOT_PRIVATE. */
static const uint32 JSSLOT_ARGS_LENGTH = 0;
static const uint32 JSSLOT_ARGS_LENGTH = JSSLOT_PRIVATE + 1;
static const uint32 ARGS_CLASS_RESERVED_SLOTS = 2;
static const uint32 ARGS_FIRST_FREE_SLOT = ARGS_CLASS_RESERVED_SLOTS + 1;
static const uint32 ARGS_FIRST_FREE_SLOT = JSSLOT_PRIVATE + ARGS_CLASS_RESERVED_SLOTS + 1;
/* Lower-order bit stolen from the length slot. */
static const uint32 ARGS_LENGTH_OVERRIDDEN_BIT = 0x1;
@ -751,18 +780,19 @@ struct JSObject {
inline void setArgsCallee(const js::Value &callee);
inline const js::Value &getArgsElement(uint32 i) const;
inline js::Value *addressOfArgsElement(uint32 i);
inline js::Value *addressOfArgsElement(uint32 i) const;
inline void setArgsElement(uint32 i, const js::Value &v);
private:
/*
* Reserved slot structure for Arguments objects:
*
*/
static const uint32 JSSLOT_CALL_CALLEE = 0;
static const uint32 JSSLOT_CALL_ARGUMENTS = 1;
static const uint32 JSSLOT_CALL_CALLEE = JSSLOT_PRIVATE + 1;
static const uint32 JSSLOT_CALL_ARGUMENTS = JSSLOT_PRIVATE + 2;
public:
/* Number of reserved slots. */
/* Number of extra fixed slots besides JSSLOT_PRIVATE. */
static const uint32 CALL_RESERVED_SLOTS = 2;
inline JSObject &getCallObjCallee() const;
@ -776,23 +806,23 @@ struct JSObject {
* Date-specific getters and setters.
*/
static const uint32 JSSLOT_DATE_UTC_TIME = 0;
static const uint32 JSSLOT_DATE_UTC_TIME = JSSLOT_PRIVATE;
/*
* Cached slots holding local properties of the date.
* These are undefined until the first actual lookup occurs
* and are reset to undefined whenever the date's time is modified.
*/
static const uint32 JSSLOT_DATE_COMPONENTS_START = 1;
static const uint32 JSSLOT_DATE_COMPONENTS_START = JSSLOT_PRIVATE + 1;
static const uint32 JSSLOT_DATE_LOCAL_TIME = 1;
static const uint32 JSSLOT_DATE_LOCAL_YEAR = 2;
static const uint32 JSSLOT_DATE_LOCAL_MONTH = 3;
static const uint32 JSSLOT_DATE_LOCAL_DATE = 4;
static const uint32 JSSLOT_DATE_LOCAL_DAY = 5;
static const uint32 JSSLOT_DATE_LOCAL_HOURS = 6;
static const uint32 JSSLOT_DATE_LOCAL_MINUTES = 7;
static const uint32 JSSLOT_DATE_LOCAL_SECONDS = 8;
static const uint32 JSSLOT_DATE_LOCAL_TIME = JSSLOT_PRIVATE + 1;
static const uint32 JSSLOT_DATE_LOCAL_YEAR = JSSLOT_PRIVATE + 2;
static const uint32 JSSLOT_DATE_LOCAL_MONTH = JSSLOT_PRIVATE + 3;
static const uint32 JSSLOT_DATE_LOCAL_DATE = JSSLOT_PRIVATE + 4;
static const uint32 JSSLOT_DATE_LOCAL_DAY = JSSLOT_PRIVATE + 5;
static const uint32 JSSLOT_DATE_LOCAL_HOURS = JSSLOT_PRIVATE + 6;
static const uint32 JSSLOT_DATE_LOCAL_MINUTES = JSSLOT_PRIVATE + 7;
static const uint32 JSSLOT_DATE_LOCAL_SECONDS = JSSLOT_PRIVATE + 8;
static const uint32 DATE_CLASS_RESERVED_SLOTS = 9;
@ -811,18 +841,17 @@ struct JSObject {
* Flat closures with one or more upvars snapshot the upvars' values into a
* vector of js::Values referenced from this slot.
*/
static const uint32 JSSLOT_FLAT_CLOSURE_UPVARS = 0;
static const uint32 JSSLOT_FLAT_CLOSURE_UPVARS = JSSLOT_PRIVATE + 1;
/*
* Null closures set or initialized as methods have these slots. See the
* "method barrier" comments and methods.
*/
static const uint32 JSSLOT_FUN_METHOD_ATOM = JSSLOT_PRIVATE + 1;
static const uint32 JSSLOT_FUN_METHOD_OBJ = JSSLOT_PRIVATE + 2;
static const uint32 JSSLOT_FUN_METHOD_ATOM = 0;
static const uint32 JSSLOT_FUN_METHOD_OBJ = 1;
static const uint32 JSSLOT_BOUND_FUNCTION_THIS = 0;
static const uint32 JSSLOT_BOUND_FUNCTION_ARGS_COUNT = 1;
static const uint32 JSSLOT_BOUND_FUNCTION_THIS = JSSLOT_PRIVATE + 1;
static const uint32 JSSLOT_BOUND_FUNCTION_ARGS_COUNT = JSSLOT_PRIVATE + 2;
public:
static const uint32 FUN_CLASS_RESERVED_SLOTS = 2;
@ -848,7 +877,7 @@ struct JSObject {
*/
private:
static const uint32 JSSLOT_REGEXP_LAST_INDEX = 0;
static const uint32 JSSLOT_REGEXP_LAST_INDEX = JSSLOT_PRIVATE + 1;
public:
static const uint32 REGEXP_CLASS_RESERVED_SLOTS = 1;
@ -877,12 +906,12 @@ struct JSObject {
* - Others (js_XMLClass, js_XMLFilterClass) don't reserve any slots.
*/
private:
static const uint32 JSSLOT_NAME_PREFIX = 0; // shared
static const uint32 JSSLOT_NAME_URI = 1; // shared
static const uint32 JSSLOT_NAME_PREFIX = JSSLOT_PRIVATE; // shared
static const uint32 JSSLOT_NAME_URI = JSSLOT_PRIVATE + 1; // shared
static const uint32 JSSLOT_NAMESPACE_DECLARED = 2;
static const uint32 JSSLOT_NAMESPACE_DECLARED = JSSLOT_PRIVATE + 2;
static const uint32 JSSLOT_QNAME_LOCAL_NAME = 2;
static const uint32 JSSLOT_QNAME_LOCAL_NAME = JSSLOT_PRIVATE + 2;
public:
static const uint32 NAMESPACE_CLASS_RESERVED_SLOTS = 3;
@ -920,8 +949,14 @@ struct JSObject {
inline bool isCallable();
/* The map field is not initialized here and should be set separately. */
void init(JSContext *cx, js::Class *aclasp, JSObject *proto, JSObject *parent,
void *priv, bool useHoles);
inline void initCommon(js::Class *aclasp, JSObject *proto, JSObject *parent,
JSContext *cx);
inline void init(js::Class *aclasp, JSObject *proto, JSObject *parent,
JSContext *cx);
inline void init(js::Class *aclasp, JSObject *proto, JSObject *parent,
void *priv, JSContext *cx);
inline void init(js::Class *aclasp, JSObject *proto, JSObject *parent,
const js::Value &privateSlotValue, JSContext *cx);
inline void finish(JSContext *cx);
@ -929,24 +964,22 @@ struct JSObject {
* Like init, but also initializes map. The catch: proto must be the result
* of a call to js_InitClass(...clasp, ...).
*/
inline bool initSharingEmptyShape(JSContext *cx,
js::Class *clasp,
inline void initSharingEmptyShape(js::Class *clasp,
JSObject *proto,
JSObject *parent,
const js::Value &privateSlotValue,
JSContext *cx);
inline void initSharingEmptyShape(js::Class *clasp,
JSObject *proto,
JSObject *parent,
void *priv,
/* JSFinalizeGCThingKind */ unsigned kind);
JSContext *cx);
inline bool hasSlotsArray() const { return (slots != &fixedSlots[0]); }
inline bool hasSlotsArray() const { return !!dslots; }
/* This method can only be called when hasSlotsArray() returns true. */
inline void freeSlotsArray(JSContext *cx);
/*
* Frees slots array and cleans up object so it may continue to be used,
* although slotSpan may exceed numSlots.
*/
inline void removeSlotsArray(JSContext *cx);
inline bool hasProperty(JSContext *cx, jsid id, bool *foundp, uintN flags = 0);
bool allocSlot(JSContext *cx, uint32 *slotp);
@ -1058,10 +1091,10 @@ struct JSObject {
inline JSObject *getThrowTypeError() const;
bool swap(JSContext *cx, JSObject *obj);
const js::Shape *defineBlockVariable(JSContext *cx, jsid id, intN index);
void swap(JSObject *obj);
inline bool canHaveMethodBarrier() const;
inline bool isArguments() const;
@ -1098,17 +1131,23 @@ struct JSObject {
inline void initArrayClass();
};
JS_STATIC_ASSERT(offsetof(JSObject, fslots) % sizeof(js::Value) == 0);
JS_STATIC_ASSERT(sizeof(JSObject) % JS_GCTHING_ALIGN == 0);
#define JSSLOT_START(clasp) (((clasp)->flags & JSCLASS_HAS_PRIVATE) \
? JSSLOT_PRIVATE + 1 \
: JSSLOT_PRIVATE)
#define JSSLOT_FREE(clasp) (JSSLOT_START(clasp) \
+ JSCLASS_RESERVED_SLOTS(clasp))
/*
* Base size of an object, excluding any fixed slots. Use instead of sizeof.
* fixedSlots has a declared capacity of two to match FUN_CLASS_RESERVED_SLOTS,
* and because some compilers don't like empty arrays in superclasses.
* Maximum capacity of the obj->dslots vector, net of the hidden slot at
* obj->dslots[-1] that is used to store the length of the vector biased by
* JS_INITIAL_NSLOTS (and again net of the slot at index -1).
*/
static const size_t JSOBJECT_SIZE = offsetof(JSObject, fixedSlots);
JS_STATIC_ASSERT(JSOBJECT_SIZE % sizeof(js::Value) == 0);
JS_STATIC_ASSERT(JSOBJECT_SIZE % JS_GCTHING_ALIGN == 0);
#define JSSLOT_FREE(clasp) JSCLASS_RESERVED_SLOTS(clasp)
#define MAX_DSLOTS_LENGTH (~size_t(0) / sizeof(js::Value) - 1)
#define MAX_DSLOTS_LENGTH32 (~uint32(0) / sizeof(js::Value) - 1)
#define OBJ_CHECK_SLOT(obj,slot) JS_ASSERT((obj)->containsSlot(slot))
@ -1168,7 +1207,7 @@ inline bool JSObject::isBlock() const { return getClass() == &js_BlockClass; }
/*
* Block scope object macros. The slots reserved by js_BlockClass are:
*
* private JSStackFrame * active frame pointer or null
* JSSLOT_PRIVATE JSStackFrame * active frame pointer or null
* JSSLOT_BLOCK_DEPTH int depth of block slots in frame
*
* After JSSLOT_BLOCK_DEPTH come one or more slots for the block locals.
@ -1180,7 +1219,7 @@ inline bool JSObject::isBlock() const { return getClass() == &js_BlockClass; }
* whose activation they were created (or null if the with or block object
* outlives the frame).
*/
static const uint32 JSSLOT_BLOCK_DEPTH = 0;
static const uint32 JSSLOT_BLOCK_DEPTH = JSSLOT_PRIVATE + 1;
inline bool
JSObject::isStaticBlock() const
@ -1194,7 +1233,7 @@ JSObject::isClonedBlock() const
return isBlock() && !!getProto();
}
static const uint32 JSSLOT_WITH_THIS = 1;
static const uint32 JSSLOT_WITH_THIS = JSSLOT_PRIVATE + 2;
#define OBJ_BLOCK_COUNT(cx,obj) \
(obj)->propertyCount()

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

@ -224,7 +224,8 @@ JSObject::setSlotMT(JSContext *cx, uintN slot, const js::Value &value)
inline js::Value
JSObject::getReservedSlot(uintN index) const
{
return (index < numSlots()) ? getSlot(index) : js::UndefinedValue();
uint32 slot = JSSLOT_START(getClass()) + index;
return (slot < numSlots()) ? getSlot(slot) : js::UndefinedValue();
}
inline bool
@ -243,100 +244,115 @@ inline const js::Value &
JSObject::getPrimitiveThis() const
{
JS_ASSERT(isPrimitive());
return getSlot(JSSLOT_PRIMITIVE_THIS);
return fslots[JSSLOT_PRIMITIVE_THIS];
}
inline void
JSObject::setPrimitiveThis(const js::Value &pthis)
{
JS_ASSERT(isPrimitive());
setSlot(JSSLOT_PRIMITIVE_THIS, pthis);
fslots[JSSLOT_PRIMITIVE_THIS] = pthis;
}
inline size_t
JSObject::numFixedSlots() const
inline void
JSObject::staticAssertArrayLengthIsInPrivateSlot()
{
if (isFunction())
return JSObject::FUN_CLASS_RESERVED_SLOTS;
if (!hasSlotsArray())
return capacity;
JSFinalizeGCThingKind kind = js_KindFromGCThing(this);
return js_GetGCKindSlots(kind);
}
inline size_t
JSObject::slotsAndStructSize(uint32 nslots) const
{
bool isFun = isFunction() && this == (JSObject*) getPrivate();
int ndslots = hasSlotsArray() ? nslots : 0;
int nfslots = isFun ? 0 : numFixedSlots();
return sizeof(js::Value) * (ndslots + nfslots)
+ isFun ? sizeof(JSFunction) : sizeof(JSObject);
JS_STATIC_ASSERT(JSSLOT_ARRAY_LENGTH == JSSLOT_PRIVATE);
}
inline uint32
JSObject::getArrayLength() const
{
JS_ASSERT(isArray());
return (uint32)(size_t) getPrivate();
return fslots[JSSLOT_ARRAY_LENGTH].toPrivateUint32();
}
inline void
JSObject::setArrayLength(uint32 length)
{
JS_ASSERT(isArray());
setPrivate((void*) length);
fslots[JSSLOT_ARRAY_LENGTH].setPrivateUint32(length);
}
inline uint32
JSObject::getDenseArrayCapacity()
JSObject::getDenseArrayCapacity() const
{
JS_ASSERT(isDenseArray());
return numSlots();
return fslots[JSSLOT_DENSE_ARRAY_CAPACITY].toPrivateUint32();
}
inline js::Value*
JSObject::getDenseArrayElements()
inline void
JSObject::setDenseArrayCapacity(uint32 capacity)
{
JS_ASSERT(isDenseArray());
return getSlots();
JS_ASSERT(!capacity == !dslots);
fslots[JSSLOT_DENSE_ARRAY_CAPACITY].setPrivateUint32(capacity);
}
inline size_t
JSObject::slotsAndStructSize(uint32 nslots) const
{
int ndslots;
if (isDenseArray())
ndslots = getDenseArrayCapacity() + 1;
else {
ndslots = nslots - JS_INITIAL_NSLOTS;
if (ndslots <= 0)
ndslots = 0;
else
ndslots++; /* number of total slots is stored at index -1 */
}
return sizeof(js::Value) * ndslots
+ (isFunction() && !getPrivate()) ? sizeof(JSFunction) : sizeof(JSObject);
}
inline const js::Value &
JSObject::getDenseArrayElement(uintN idx)
JSObject::getDenseArrayElement(uint32 i) const
{
JS_ASSERT(isDenseArray());
return getSlot(idx);
JS_ASSERT(i < getDenseArrayCapacity());
return dslots[i];
}
inline js::Value *
JSObject::addressOfDenseArrayElement(uintN idx)
JSObject::addressOfDenseArrayElement(uint32 i)
{
JS_ASSERT(isDenseArray());
return &getSlotRef(idx);
JS_ASSERT(i < getDenseArrayCapacity());
return &dslots[i];
}
inline void
JSObject::setDenseArrayElement(uintN idx, const js::Value &val)
JSObject::setDenseArrayElement(uint32 i, const js::Value &v)
{
JS_ASSERT(isDenseArray());
setSlot(idx, val);
JS_ASSERT(i < getDenseArrayCapacity());
dslots[i] = v;
}
inline bool
JSObject::ensureDenseArrayElements(JSContext *cx, uintN cap)
inline js::Value *
JSObject::getDenseArrayElements() const
{
JS_ASSERT(isDenseArray());
return ensureSlots(cx, cap);
return dslots;
}
inline void
JSObject::shrinkDenseArrayElements(JSContext *cx, uintN cap)
JSObject::freeDenseArrayElements(JSContext *cx)
{
JS_ASSERT(isDenseArray());
shrinkSlots(cx, cap);
if (dslots) {
cx->free(dslots - 1);
dslots = NULL;
}
}
inline void
JSObject::voidDenseOnlyArraySlots()
{
JS_ASSERT(isDenseArray());
fslots[JSSLOT_DENSE_ARRAY_CAPACITY].setUndefined();
}
inline void
@ -345,7 +361,7 @@ JSObject::setArgsLength(uint32 argc)
JS_ASSERT(isArguments());
JS_ASSERT(argc <= JS_ARGS_LENGTH_MAX);
JS_ASSERT(UINT32_MAX > (uint64(argc) << ARGS_PACKED_BITS_COUNT));
getSlotRef(JSSLOT_ARGS_LENGTH).setInt32(argc << ARGS_PACKED_BITS_COUNT);
fslots[JSSLOT_ARGS_LENGTH].setInt32(argc << ARGS_PACKED_BITS_COUNT);
JS_ASSERT(!isArgsLengthOverridden());
}
@ -353,7 +369,7 @@ inline uint32
JSObject::getArgsInitialLength() const
{
JS_ASSERT(isArguments());
uint32 argc = uint32(getSlot(JSSLOT_ARGS_LENGTH).toInt32()) >> ARGS_PACKED_BITS_COUNT;
uint32 argc = uint32(fslots[JSSLOT_ARGS_LENGTH].toInt32()) >> ARGS_PACKED_BITS_COUNT;
JS_ASSERT(argc <= JS_ARGS_LENGTH_MAX);
return argc;
}
@ -362,14 +378,14 @@ inline void
JSObject::setArgsLengthOverridden()
{
JS_ASSERT(isArguments());
getSlotRef(JSSLOT_ARGS_LENGTH).getInt32Ref() |= ARGS_LENGTH_OVERRIDDEN_BIT;
fslots[JSSLOT_ARGS_LENGTH].getInt32Ref() |= ARGS_LENGTH_OVERRIDDEN_BIT;
}
inline bool
JSObject::isArgsLengthOverridden() const
{
JS_ASSERT(isArguments());
const js::Value &v = getSlot(JSSLOT_ARGS_LENGTH);
const js::Value &v = fslots[JSSLOT_ARGS_LENGTH];
return v.toInt32() & ARGS_LENGTH_OVERRIDDEN_BIT;
}
@ -377,14 +393,14 @@ inline js::ArgumentsData *
JSObject::getArgsData() const
{
JS_ASSERT(isArguments());
return (js::ArgumentsData *) getSlot(JSSLOT_ARGS_DATA).toPrivate();
return (js::ArgumentsData *) fslots[JSSLOT_ARGS_DATA].toPrivate();
}
inline void
JSObject::setArgsData(js::ArgumentsData *data)
{
JS_ASSERT(isArguments());
getSlotRef(JSSLOT_ARGS_DATA).setPrivate(data);
fslots[JSSLOT_ARGS_DATA].setPrivate(data);
}
inline const js::Value &
@ -408,7 +424,7 @@ JSObject::getArgsElement(uint32 i) const
}
inline js::Value *
JSObject::addressOfArgsElement(uint32 i)
JSObject::addressOfArgsElement(uint32 i) const
{
JS_ASSERT(isArguments());
JS_ASSERT(i < getArgsInitialLength());
@ -428,49 +444,49 @@ JSObject::setCallObjCallee(JSObject &callee)
{
JS_ASSERT(isCall());
JS_ASSERT(callee.isFunction());
return getSlotRef(JSSLOT_CALL_CALLEE).setObject(callee);
return fslots[JSSLOT_CALL_CALLEE].setObject(callee);
}
inline JSObject &
JSObject::getCallObjCallee() const
{
JS_ASSERT(isCall());
return getSlot(JSSLOT_CALL_CALLEE).toObject();
return fslots[JSSLOT_CALL_CALLEE].toObject();
}
inline JSFunction *
JSObject::getCallObjCalleeFunction() const
{
JS_ASSERT(isCall());
return getSlot(JSSLOT_CALL_CALLEE).toObject().getFunctionPrivate();
return fslots[JSSLOT_CALL_CALLEE].toObject().getFunctionPrivate();
}
inline const js::Value &
JSObject::getCallObjArguments() const
{
JS_ASSERT(isCall());
return getSlot(JSSLOT_CALL_ARGUMENTS);
return fslots[JSSLOT_CALL_ARGUMENTS];
}
inline void
JSObject::setCallObjArguments(const js::Value &v)
{
JS_ASSERT(isCall());
setSlot(JSSLOT_CALL_ARGUMENTS, v);
fslots[JSSLOT_CALL_ARGUMENTS] = v;
}
inline const js::Value &
JSObject::getDateUTCTime() const
{
JS_ASSERT(isDate());
return getSlot(JSSLOT_DATE_UTC_TIME);
return fslots[JSSLOT_DATE_UTC_TIME];
}
inline void
JSObject::setDateUTCTime(const js::Value &time)
{
JS_ASSERT(isDate());
setSlot(JSSLOT_DATE_UTC_TIME, time);
fslots[JSSLOT_DATE_UTC_TIME] = time;
}
inline js::Value *
@ -478,7 +494,7 @@ JSObject::getFlatClosureUpvars() const
{
JS_ASSERT(isFunction());
JS_ASSERT(FUN_FLAT_CLOSURE(getFunctionPrivate()));
return (js::Value *) getSlot(JSSLOT_FLAT_CLOSURE_UPVARS).toPrivate();
return (js::Value *) fslots[JSSLOT_FLAT_CLOSURE_UPVARS].toPrivate();
}
inline js::Value
@ -492,21 +508,20 @@ JSObject::setFlatClosureUpvars(js::Value *upvars)
{
JS_ASSERT(isFunction());
JS_ASSERT(FUN_FLAT_CLOSURE(getFunctionPrivate()));
getSlotRef(JSSLOT_FLAT_CLOSURE_UPVARS).setPrivate(upvars);
fslots[JSSLOT_FLAT_CLOSURE_UPVARS].setPrivate(upvars);
}
inline bool
JSObject::hasMethodObj(const JSObject& obj) const
{
return JSSLOT_FUN_METHOD_OBJ < numSlots() &&
getSlot(JSSLOT_FUN_METHOD_OBJ).isObject() &&
&getSlot(JSSLOT_FUN_METHOD_OBJ).toObject() == &obj;
return fslots[JSSLOT_FUN_METHOD_OBJ].isObject() &&
&fslots[JSSLOT_FUN_METHOD_OBJ].toObject() == &obj;
}
inline void
JSObject::setMethodObj(JSObject& obj)
{
getSlotRef(JSSLOT_FUN_METHOD_OBJ).setObject(obj);
fslots[JSSLOT_FUN_METHOD_OBJ].setObject(obj);
}
inline NativeIterator *
@ -525,74 +540,76 @@ inline jsval
JSObject::getNamePrefix() const
{
JS_ASSERT(isNamespace() || isQName());
return js::Jsvalify(getSlot(JSSLOT_NAME_PREFIX));
return js::Jsvalify(fslots[JSSLOT_NAME_PREFIX]);
}
inline void
JSObject::setNamePrefix(jsval prefix)
{
JS_ASSERT(isNamespace() || isQName());
setSlot(JSSLOT_NAME_PREFIX, js::Valueify(prefix));
fslots[JSSLOT_NAME_PREFIX] = js::Valueify(prefix);
}
inline jsval
JSObject::getNameURI() const
{
JS_ASSERT(isNamespace() || isQName());
return js::Jsvalify(getSlot(JSSLOT_NAME_URI));
return js::Jsvalify(fslots[JSSLOT_NAME_URI]);
}
inline void
JSObject::setNameURI(jsval uri)
{
JS_ASSERT(isNamespace() || isQName());
setSlot(JSSLOT_NAME_URI, js::Valueify(uri));
fslots[JSSLOT_NAME_URI] = js::Valueify(uri);
}
inline jsval
JSObject::getNamespaceDeclared() const
{
JS_ASSERT(isNamespace());
return js::Jsvalify(getSlot(JSSLOT_NAMESPACE_DECLARED));
return js::Jsvalify(fslots[JSSLOT_NAMESPACE_DECLARED]);
}
inline void
JSObject::setNamespaceDeclared(jsval decl)
{
JS_ASSERT(isNamespace());
setSlot(JSSLOT_NAMESPACE_DECLARED, js::Valueify(decl));
fslots[JSSLOT_NAMESPACE_DECLARED] = js::Valueify(decl);
}
inline jsval
JSObject::getQNameLocalName() const
{
JS_ASSERT(isQName());
return js::Jsvalify(getSlot(JSSLOT_QNAME_LOCAL_NAME));
return js::Jsvalify(fslots[JSSLOT_QNAME_LOCAL_NAME]);
}
inline void
JSObject::setQNameLocalName(jsval name)
{
JS_ASSERT(isQName());
setSlot(JSSLOT_QNAME_LOCAL_NAME, js::Valueify(name));
fslots[JSSLOT_QNAME_LOCAL_NAME] = js::Valueify(name);
}
inline JSObject *
JSObject::getWithThis() const
{
return &getSlot(JSSLOT_WITH_THIS).toObject();
return &fslots[JSSLOT_WITH_THIS].toObject();
}
inline void
JSObject::setWithThis(JSObject *thisp)
{
getSlotRef(JSSLOT_WITH_THIS).setObject(*thisp);
fslots[JSSLOT_WITH_THIS].setObject(*thisp);
}
inline void
JSObject::init(JSContext *cx, js::Class *aclasp, JSObject *proto, JSObject *parent,
void *priv, bool useHoles)
JSObject::initCommon(js::Class *aclasp, JSObject *proto, JSObject *parent,
JSContext *cx)
{
JS_STATIC_ASSERT(JSSLOT_PRIVATE + 3 == JS_INITIAL_NSLOTS);
clasp = aclasp;
flags = 0;
@ -609,22 +626,43 @@ JSObject::init(JSContext *cx, js::Class *aclasp, JSObject *proto, JSObject *pare
setProto(proto);
setParent(parent);
fslots[JSSLOT_PRIVATE + 1].setUndefined();
fslots[JSSLOT_PRIVATE + 2].setUndefined();
privateData = priv;
slots = &fixedSlots[0];
/*
* Fill the fixed slots with undefined or array holes. This object must
* already have its capacity filled in, as by js_NewGCObject.
*/
JS_ASSERT(capacity == numFixedSlots());
ClearValueRange(fixedSlots, capacity, useHoles);
dslots = NULL;
#ifdef JS_THREADSAFE
js_InitTitle(cx, &title);
#endif
emptyShapes = NULL;
emptyShape = NULL;
}
inline void
JSObject::init(js::Class *aclasp, JSObject *proto, JSObject *parent,
const js::Value &privateSlotValue, JSContext *cx)
{
initCommon(aclasp, proto, parent, cx);
fslots[JSSLOT_PRIVATE] = privateSlotValue;
}
inline void
JSObject::init(js::Class *aclasp, JSObject *proto, JSObject *parent,
void *priv, JSContext *cx)
{
initCommon(aclasp, proto, parent, cx);
*(void **)&fslots[JSSLOT_PRIVATE] = priv;
}
inline void
JSObject::init(js::Class *aclasp, JSObject *proto, JSObject *parent,
JSContext *cx)
{
initCommon(aclasp, proto, parent, cx);
if (clasp->flags & JSCLASS_HAS_PRIVATE)
*(void **)&fslots[JSSLOT_PRIVATE] = NULL;
else
fslots[JSSLOT_PRIVATE].setUndefined();
}
inline void
@ -641,45 +679,40 @@ JSObject::finish(JSContext *cx)
#endif
}
inline bool
JSObject::initSharingEmptyShape(JSContext *cx,
js::Class *aclasp,
inline void
JSObject::initSharingEmptyShape(js::Class *aclasp,
JSObject *proto,
JSObject *parent,
void *privateValue,
/* JSFinalizeGCThingKind */ unsigned kind)
const js::Value &privateSlotValue,
JSContext *cx)
{
init(cx, aclasp, proto, parent, privateValue, false);
JS_ASSERT(!isDenseArray());
js::EmptyShape *empty = proto->getEmptyShape(cx, aclasp, JSFinalizeGCThingKind(kind));
if (!empty)
return false;
init(aclasp, proto, parent, privateSlotValue, cx);
js::EmptyShape *empty = proto->emptyShape;
JS_ASSERT(empty->getClass() == aclasp);
setMap(empty);
}
inline void
JSObject::initSharingEmptyShape(js::Class *aclasp,
JSObject *proto,
JSObject *parent,
void *priv,
JSContext *cx)
{
init(aclasp, proto, parent, priv, cx);
js::EmptyShape *empty = proto->emptyShape;
JS_ASSERT(empty->getClass() == aclasp);
setMap(empty);
return true;
}
inline void
JSObject::freeSlotsArray(JSContext *cx)
{
JS_ASSERT(hasSlotsArray());
cx->free(slots);
}
inline void
JSObject::removeSlotsArray(JSContext *cx)
{
JS_ASSERT(hasSlotsArray());
size_t fixed = numFixedSlots();
JS_ASSERT(fixed <= capacity);
memcpy(fixedSlots, slots, fixed * sizeof(js::Value));
freeSlotsArray(cx);
slots = &fixedSlots[0];
capacity = fixed;
JS_ASSERT(dslots[-1].toPrivateUint32() > JS_INITIAL_NSLOTS);
cx->free(dslots - 1);
}
inline bool
@ -758,8 +791,7 @@ class AutoPropertyDescriptorRooter : private AutoGCRooter, public PropertyDescri
};
static inline bool
InitScopeForObject(JSContext* cx, JSObject* obj, js::Class *clasp, JSObject* proto,
JSFinalizeGCThingKind kind)
InitScopeForObject(JSContext* cx, JSObject* obj, js::Class *clasp, JSObject* proto)
{
JS_ASSERT(clasp->isNative());
JS_ASSERT(proto == obj->getProto());
@ -770,7 +802,7 @@ InitScopeForObject(JSContext* cx, JSObject* obj, js::Class *clasp, JSObject* pro
if (proto) {
JS_LOCK_OBJ(cx, proto);
if (proto->canProvideEmptyShape(clasp)) {
empty = proto->getEmptyShape(cx, clasp, kind);
empty = proto->getEmptyShape(cx, clasp);
JS_UNLOCK_OBJ(cx, proto);
if (!empty)
goto bad;
@ -780,11 +812,13 @@ InitScopeForObject(JSContext* cx, JSObject* obj, js::Class *clasp, JSObject* pro
}
if (!empty) {
uint32 freeslot = JSSLOT_FREE(clasp);
JS_ASSERT(freeslot >= JSSLOT_PRIVATE);
empty = js::EmptyShape::create(cx, clasp);
if (!empty)
goto bad;
uint32 freeslot = JSSLOT_FREE(clasp);
if (freeslot > obj->numSlots() && !obj->allocSlots(cx, freeslot))
if (freeslot > JS_INITIAL_NSLOTS && !obj->allocSlots(cx, freeslot))
goto bad;
}
@ -804,8 +838,7 @@ InitScopeForObject(JSContext* cx, JSObject* obj, js::Class *clasp, JSObject* pro
* and its parent global as parent.
*/
static inline JSObject *
NewNativeClassInstance(JSContext *cx, Class *clasp, JSObject *proto,
JSObject *parent, JSFinalizeGCThingKind kind)
NewNativeClassInstance(JSContext *cx, Class *clasp, JSObject *proto, JSObject *parent)
{
JS_ASSERT(proto);
JS_ASSERT(proto->isNative());
@ -815,19 +848,18 @@ NewNativeClassInstance(JSContext *cx, Class *clasp, JSObject *proto,
* Allocate an object from the GC heap and initialize all its fields before
* doing any operation that can potentially trigger GC.
*/
JSObject* obj = js_NewGCObject(cx, kind);
JSObject* obj = js_NewGCObject(cx);
if (obj) {
/*
* Default parent to the parent of the prototype, which was set from
* the parent of the prototype's constructor.
*/
bool useHoles = (clasp == &js_ArrayClass);
obj->init(cx, clasp, proto, parent, NULL, useHoles);
obj->init(clasp, proto, parent, cx);
JS_LOCK_OBJ(cx, proto);
JS_ASSERT(proto->canProvideEmptyShape(clasp));
js::EmptyShape *empty = proto->getEmptyShape(cx, clasp, kind);
js::EmptyShape *empty = proto->getEmptyShape(cx, clasp);
JS_UNLOCK_OBJ(cx, proto);
if (empty)
@ -839,13 +871,6 @@ NewNativeClassInstance(JSContext *cx, Class *clasp, JSObject *proto,
return obj;
}
static inline JSObject *
NewNativeClassInstance(JSContext *cx, Class *clasp, JSObject *proto, JSObject *parent)
{
JSFinalizeGCThingKind kind = js_GetGCObjectKind(JSCLASS_RESERVED_SLOTS(clasp));
return NewNativeClassInstance(cx, clasp, proto, parent, kind);
}
bool
FindClassPrototype(JSContext *cx, JSObject *scope, JSProtoKey protoKey, JSObject **protop,
Class *clasp);
@ -857,7 +882,7 @@ FindClassPrototype(JSContext *cx, JSObject *scope, JSProtoKey protoKey, JSObject
* right default proto and parent for clasp in cx.
*/
static inline JSObject *
NewBuiltinClassInstance(JSContext *cx, Class *clasp, JSFinalizeGCThingKind kind)
NewBuiltinClassInstance(JSContext *cx, Class *clasp)
{
VOUCH_DOES_NOT_REQUIRE_STACK();
@ -886,14 +911,7 @@ NewBuiltinClassInstance(JSContext *cx, Class *clasp, JSFinalizeGCThingKind kind)
return NULL;
}
return NewNativeClassInstance(cx, clasp, proto, global, kind);
}
static inline JSObject *
NewBuiltinClassInstance(JSContext *cx, Class *clasp)
{
JSFinalizeGCThingKind kind = js_GetGCObjectKind(JSCLASS_RESERVED_SLOTS(clasp));
return NewBuiltinClassInstance(cx, clasp, kind);
return NewNativeClassInstance(cx, clasp, proto, global);
}
static inline JSProtoKey
@ -944,8 +962,7 @@ namespace detail
{
template <bool withProto, bool isFunction>
static JS_ALWAYS_INLINE JSObject *
NewObject(JSContext *cx, js::Class *clasp, JSObject *proto, JSObject *parent,
JSFinalizeGCThingKind kind)
NewObject(JSContext *cx, js::Class *clasp, JSObject *proto, JSObject *parent)
{
/* Bootstrap the ur-object, and make it the default prototype object. */
if (withProto == WithProto::Class && !proto) {
@ -954,7 +971,8 @@ NewObject(JSContext *cx, js::Class *clasp, JSObject *proto, JSObject *parent,
return NULL;
if (!proto && !js_GetClassPrototype(cx, parent, JSProto_Object, &proto))
return NULL;
}
}
/*
* Allocate an object from the GC heap and initialize all its fields before
@ -963,23 +981,18 @@ NewObject(JSContext *cx, js::Class *clasp, JSObject *proto, JSObject *parent,
*
* The should be specialized by the template.
*/
JSObject* obj = isFunction ? js_NewGCFunction(cx) : js_NewGCObject(cx, kind);
JSObject* obj = isFunction ? js_NewGCFunction(cx) : js_NewGCObject(cx);
if (!obj)
goto out;
/* This needs to match up with the size of JSFunction::data_padding. */
JS_ASSERT_IF(isFunction, kind == FINALIZE_OBJECT2);
/*
* Default parent to the parent of the prototype, which was set from
* the parent of the prototype's constructor.
*/
obj->init(cx, clasp, proto,
(!parent && proto) ? proto->getParent() : parent,
NULL, clasp == &js_ArrayClass);
obj->init(clasp, proto, (!parent && proto) ? proto->getParent() : parent, cx);
if (clasp->isNative()) {
if (!InitScopeForObject(cx, obj, clasp, proto, kind)) {
if (!InitScopeForObject(cx, obj, clasp, proto)) {
obj = NULL;
goto out;
}
@ -991,73 +1004,28 @@ out:
Probes::createObject(cx, obj);
return obj;
}
} /* namespace detail */
}
static JS_ALWAYS_INLINE JSObject *
NewFunction(JSContext *cx, JSObject *parent)
{
return detail::NewObject<WithProto::Class, true>(cx, &js_FunctionClass, NULL, parent,
FINALIZE_OBJECT2);
}
template <WithProto::e withProto>
static JS_ALWAYS_INLINE JSObject *
NewNonFunction(JSContext *cx, js::Class *clasp, JSObject *proto, JSObject *parent,
JSFinalizeGCThingKind kind)
{
return detail::NewObject<withProto, false>(cx, clasp, proto, parent, kind);
return detail::NewObject<WithProto::Class, true>(cx, &js_FunctionClass, NULL, parent);
}
template <WithProto::e withProto>
static JS_ALWAYS_INLINE JSObject *
NewNonFunction(JSContext *cx, js::Class *clasp, JSObject *proto, JSObject *parent)
{
JSFinalizeGCThingKind kind = js_GetGCObjectKind(JSCLASS_RESERVED_SLOTS(clasp));
return detail::NewObject<withProto, false>(cx, clasp, proto, parent, kind);
return detail::NewObject<withProto, false>(cx, clasp, proto, parent);
}
template <WithProto::e withProto>
static JS_ALWAYS_INLINE JSObject *
NewObject(JSContext *cx, js::Class *clasp, JSObject *proto, JSObject *parent)
{
if (clasp == &js_FunctionClass) {
return detail::NewObject<withProto, true>(cx, clasp, proto, parent,
FINALIZE_OBJECT2);
} else {
JSFinalizeGCThingKind kind = js_GetGCObjectKind(JSCLASS_RESERVED_SLOTS(clasp));
return detail::NewObject<withProto, false>(cx, clasp, proto, parent, kind);
}
}
/* Creates a new array with a zero length and the given finalize kind. */
static inline JSObject *
NewArrayWithKind(JSContext* cx, JSFinalizeGCThingKind kind)
{
return NewNonFunction<WithProto::Class>(cx, &js_ArrayClass, NULL, NULL, kind);
}
/*
* As for js_GetGCObjectKind, where numSlots is a guess at the final size of
* the object, zero if the final size is unknown.
*/
static inline JSFinalizeGCThingKind
GuessObjectGCKind(size_t numSlots)
{
return numSlots ? js_GetGCObjectKind(numSlots) : FINALIZE_OBJECT8;
}
/*
* Get the GC kind to use for scripted 'new' on the given class.
* FIXME bug 547327: estimate the size from the allocation site.
*/
static inline JSFinalizeGCThingKind
NewObjectGCKind(JSContext *cx, js::Class *clasp)
{
if (clasp == &js_ArrayClass || clasp == &js_SlowArrayClass)
return FINALIZE_OBJECT8;
if (clasp == &js_FunctionClass)
return FINALIZE_OBJECT2;
return FINALIZE_OBJECT4;
return (clasp == &js_FunctionClass)
? detail::NewObject<withProto, true>(cx, clasp, proto, parent)
: detail::NewObject<withProto, false>(cx, clasp, proto, parent);
}
} /* namespace js */

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

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

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

@ -244,7 +244,7 @@ OPDEF(JSOP_SETLOCAL, 87,"setlocal", NULL, 3, 1, 1, 3, JOF_LOCAL|
OPDEF(JSOP_UINT16, 88, "uint16", NULL, 3, 0, 1, 16, JOF_UINT16)
/* Object and array literal support. */
OPDEF(JSOP_NEWINIT, 89, "newinit", NULL, 5, 0, 1, 19, JOF_UINT16PAIR)
OPDEF(JSOP_NEWINIT, 89, "newinit", NULL, 2, 0, 1, 19, JOF_INT8)
OPDEF(JSOP_ENDINIT, 90, "endinit", NULL, 1, 0, 0, 19, JOF_BYTE)
OPDEF(JSOP_INITPROP, 91, "initprop", NULL, 3, 2, 1, 3, JOF_ATOM|JOF_PROP|JOF_SET|JOF_DETECTING)
OPDEF(JSOP_INITELEM, 92, "initelem", NULL, 1, 3, 1, 3, JOF_BYTE |JOF_ELEM|JOF_SET|JOF_DETECTING)

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

@ -1207,8 +1207,8 @@ static JSFunctionSpec static_methods[] = {
extern Class CallableObjectClass;
static const uint32 JSSLOT_CALLABLE_CALL = 0;
static const uint32 JSSLOT_CALLABLE_CONSTRUCT = 1;
static const uint32 JSSLOT_CALLABLE_CALL = JSSLOT_PRIVATE;
static const uint32 JSSLOT_CALLABLE_CONSTRUCT = JSSLOT_PRIVATE + 1;
static JSBool
callable_Call(JSContext *cx, uintN argc, Value *vp)
@ -1219,7 +1219,7 @@ callable_Call(JSContext *cx, uintN argc, Value *vp)
JSObject *callable = &JS_CALLEE(cx, vp).toObject();
JS_ASSERT(callable->getClass() == &CallableObjectClass);
const Value &fval = callable->getSlot(JSSLOT_CALLABLE_CALL);
const Value &fval = callable->fslots[JSSLOT_CALLABLE_CALL];
Value rval;
bool ok = ExternalInvoke(cx, thisobj, fval, argc, JS_ARGV(cx, vp), &rval);
*vp = rval;
@ -1235,10 +1235,10 @@ callable_Construct(JSContext *cx, uintN argc, Value *vp)
JSObject *callable = &vp[0].toObject();
JS_ASSERT(callable->getClass() == &CallableObjectClass);
Value fval = callable->getSlot(JSSLOT_CALLABLE_CONSTRUCT);
Value fval = callable->fslots[JSSLOT_CALLABLE_CONSTRUCT];
if (fval.isUndefined()) {
/* We don't have an explicit constructor so allocate a new object and use the call. */
fval = callable->getSlot(JSSLOT_CALLABLE_CALL);
fval = callable->fslots[JSSLOT_CALLABLE_CALL];
JS_ASSERT(fval.isObject());
/* callable is the constructor, so get callable.prototype is the proto of the new object. */
@ -1260,7 +1260,7 @@ callable_Construct(JSContext *cx, uintN argc, Value *vp)
/* If the call returns an object, return that, otherwise the original newobj. */
Value rval;
if (!ExternalInvoke(cx, newobj, callable->getSlot(JSSLOT_CALLABLE_CALL),
if (!ExternalInvoke(cx, newobj, callable->fslots[JSSLOT_CALLABLE_CALL],
argc, vp + 2, &rval)) {
return false;
}
@ -1318,19 +1318,15 @@ FixProxy(JSContext *cx, JSObject *proxy, JSBool *bp)
JSObject *parent = proxy->getParent();
Class *clasp = proxy->isFunctionProxy() ? &CallableObjectClass : &js_ObjectClass;
/*
* Make a blank object from the recipe fix provided to us. This must have
* number of fixed slots as the proxy so that we can swap their contents.
*/
JSFinalizeGCThingKind kind = js_KindFromGCThing(proxy);
JSObject *newborn = NewNonFunction<WithProto::Given>(cx, clasp, proto, parent, kind);
/* Make a blank object from the recipe fix provided to us. */
JSObject *newborn = NewNonFunction<WithProto::Given>(cx, clasp, proto, parent);
if (!newborn)
return NULL;
AutoObjectRooter tvr2(cx, newborn);
if (clasp == &CallableObjectClass) {
newborn->setSlot(JSSLOT_CALLABLE_CALL, GetCall(proxy));
newborn->setSlot(JSSLOT_CALLABLE_CONSTRUCT, GetConstruct(proxy));
newborn->fslots[JSSLOT_CALLABLE_CALL] = GetCall(proxy);
newborn->fslots[JSSLOT_CALLABLE_CONSTRUCT] = GetConstruct(proxy);
}
{
@ -1340,8 +1336,7 @@ FixProxy(JSContext *cx, JSObject *proxy, JSBool *bp)
}
/* Trade spaces between the newborn object and the proxy. */
if (!proxy->swap(cx, newborn))
return false;
proxy->swap(newborn);
/* The GC will dispose of the proxy object. */

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

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

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

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

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

@ -1128,22 +1128,6 @@ JSObject::removeProperty(JSContext *cx, jsid id)
*/
JS_ASSERT(shape == lastProp);
removeLastProperty();
/*
* Revert to fixed slots if this was the first dynamically allocated slot,
* preserving invariant that objects with the same shape use the fixed
* slots in the same way.
*/
size_t fixed = numFixedSlots();
if (shape->slot == fixed) {
JS_ASSERT(hasSlotsArray());
JS_ASSERT_IF(!lastProp->isEmptyShape() && lastProp->hasSlot(),
lastProp->slot == fixed - 1);
memcpy(fixedSlots, slots, fixed * sizeof(Value));
freeSlotsArray(cx);
slots = fixedSlots;
capacity = fixed;
}
}
updateShape(cx);

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

@ -60,45 +60,19 @@ js::Shape::freeTable(JSContext *cx)
}
inline js::EmptyShape *
JSObject::getEmptyShape(JSContext *cx, js::Class *aclasp,
/* JSFinalizeGCThingKind */ unsigned kind)
JSObject::getEmptyShape(JSContext *cx, js::Class *aclasp)
{
JS_ASSERT(kind >= FINALIZE_OBJECT0 && kind <= FINALIZE_OBJECT_LAST);
int i = kind - FINALIZE_OBJECT0;
if (!emptyShapes) {
int count = FINALIZE_OBJECT_LAST - FINALIZE_OBJECT0 + 1;
emptyShapes = (js::EmptyShape**) cx->calloc(sizeof(js::EmptyShape*) * count);
if (!emptyShapes)
return NULL;
/*
* Always fill in emptyShapes[0], so canProvideEmptyShape works.
* Other empty shapes are filled in lazily.
*/
emptyShapes[0] = js::EmptyShape::create(cx, aclasp);
if (!emptyShapes[0]) {
cx->free(emptyShapes);
emptyShapes = NULL;
return NULL;
}
}
JS_ASSERT(aclasp == emptyShapes[0]->getClass());
if (!emptyShapes[i]) {
emptyShapes[i] = js::EmptyShape::create(cx, aclasp);
if (!emptyShapes[i])
return NULL;
}
return emptyShapes[i];
if (emptyShape)
JS_ASSERT(aclasp == emptyShape->getClass());
else
emptyShape = js::EmptyShape::create(cx, aclasp);
return emptyShape;
}
inline bool
JSObject::canProvideEmptyShape(js::Class *aclasp)
{
return !emptyShapes || emptyShapes[0]->getClass() == aclasp;
return !emptyShape || emptyShape->getClass() == aclasp;
}
inline void

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

@ -2673,7 +2673,9 @@ ptrdiff_t
TraceRecorder::nativeGlobalSlot(const Value* p) const
{
JS_ASSERT(isGlobal(p));
return ptrdiff_t(p - globalObj->slots);
if (size_t(p - globalObj->fslots) < JS_INITIAL_NSLOTS)
return ptrdiff_t(p - globalObj->fslots);
return ptrdiff_t((p - globalObj->dslots) + JS_INITIAL_NSLOTS);
}
/* Determine the offset in the native global frame for a jsval we track. */
@ -2687,7 +2689,8 @@ TraceRecorder::nativeGlobalOffset(const Value* p) const
bool
TraceRecorder::isGlobal(const Value* p) const
{
return (size_t(p - globalObj->slots) < globalObj->numSlots());
return ((size_t(p - globalObj->fslots) < JS_INITIAL_NSLOTS) ||
(size_t(p - globalObj->dslots) < (globalObj->numSlots() - JS_INITIAL_NSLOTS)));
}
bool
@ -3444,7 +3447,7 @@ struct ArgClosureTraits
// Get the offset of our object slots from the object's dslots pointer.
static inline uint32 slot_offset(JSObject* obj) {
return JSObject::CALL_RESERVED_SLOTS;
return JSSLOT_START(&js_CallClass) + JSObject::CALL_RESERVED_SLOTS;
}
// Get the maximum slot index of this type that should be allowed
@ -3475,7 +3478,7 @@ struct VarClosureTraits
}
static inline uint32 slot_offset(JSObject* obj) {
return JSObject::CALL_RESERVED_SLOTS +
return JSSLOT_START(&js_CallClass) + JSObject::CALL_RESERVED_SLOTS +
obj->getCallObjCalleeFunction()->nargs;
}
@ -3940,7 +3943,7 @@ TraceRecorder::known(JSObject** p)
}
/*
* The slots of the global object are sometimes reallocated by the interpreter.
* The dslots of the global object are sometimes reallocated by the interpreter.
* This function check for that condition and re-maps the entries of the tracker
* accordingly.
*/
@ -3949,8 +3952,8 @@ TraceRecorder::checkForGlobalObjectReallocationHelper()
{
debug_only_print0(LC_TMTracer, "globalObj->dslots relocated, updating tracker\n");
Value* src = global_dslots;
Value* dst = globalObj->getSlots();
jsuint length = globalObj->capacity;
Value* dst = globalObj->dslots;
jsuint length = globalObj->dslots[-1].toPrivateUint32() - JS_INITIAL_NSLOTS;
LIns** map = (LIns**)alloca(sizeof(LIns*) * length);
for (jsuint n = 0; n < length; ++n) {
map[n] = tracker.get(src);
@ -3958,7 +3961,7 @@ TraceRecorder::checkForGlobalObjectReallocationHelper()
}
for (jsuint n = 0; n < length; ++n)
tracker.set(dst++, map[n]);
global_dslots = globalObj->getSlots();
global_dslots = globalObj->dslots;
}
/* Determine whether the current branch is a loop edge (taken or not taken). */
@ -8720,7 +8723,7 @@ TraceRecorder::incProp(jsint incr, bool pre)
CHECK_STATUS_A(inc(v, v_ins, incr, pre));
LIns* dslots_ins = NULL;
stobj_set_slot(obj, obj_ins, slot, dslots_ins, v, v_ins);
stobj_set_slot(obj_ins, slot, dslots_ins, v, v_ins);
return ARECORD_CONTINUE;
}
@ -9458,7 +9461,7 @@ TraceRecorder::guardPropertyCacheHit(LIns* obj_ins,
void
TraceRecorder::stobj_set_fslot(LIns *obj_ins, unsigned slot, const Value &v, LIns* v_ins)
{
box_value_into(v, v_ins, obj_ins, offsetof(JSObject, fixedSlots) + slot * sizeof(Value), ACCSET_OTHER);
box_value_into(v, v_ins, obj_ins, offsetof(JSObject, fslots) + slot * sizeof(Value), ACCSET_OTHER);
}
void
@ -9466,32 +9469,49 @@ TraceRecorder::stobj_set_dslot(LIns *obj_ins, unsigned slot, LIns*& dslots_ins,
const Value &v, LIns* v_ins)
{
if (!dslots_ins)
dslots_ins = lir->insLoad(LIR_ldp, obj_ins, offsetof(JSObject, slots), ACCSET_OTHER);
dslots_ins = lir->insLoad(LIR_ldp, obj_ins, offsetof(JSObject, dslots), ACCSET_OTHER);
box_value_into(v, v_ins, dslots_ins, slot * sizeof(Value), ACCSET_OTHER);
}
void
TraceRecorder::stobj_set_slot(JSObject *obj, LIns* obj_ins, unsigned slot, LIns*& dslots_ins,
TraceRecorder::stobj_set_slot(LIns* obj_ins, unsigned slot, LIns*& dslots_ins,
const Value &v, LIns* v_ins)
{
/*
* A shape guard must have already been generated for obj, which will
* ensure that future objects have the same number of fixed slots.
*/
if (!obj->hasSlotsArray()) {
JS_ASSERT(slot < obj->numSlots());
if (slot < JS_INITIAL_NSLOTS)
stobj_set_fslot(obj_ins, slot, v, v_ins);
} else {
stobj_set_dslot(obj_ins, slot, dslots_ins, v, v_ins);
}
else
stobj_set_dslot(obj_ins, slot - JS_INITIAL_NSLOTS, dslots_ins, v, v_ins);
}
#if JS_BITS_PER_WORD == 32 || JS_BITS_PER_WORD == 64
LIns*
TraceRecorder::stobj_get_slot_uint32(LIns* obj_ins, unsigned slot)
void
TraceRecorder::set_array_fslot(LIns *obj_ins, unsigned slot, uint32 val)
{
LIns *vaddr_ins = lir->insLoad(LIR_ldp, obj_ins, offsetof(JSObject, slots), ACCSET_OTHER);
return lir->insLoad(LIR_ldi, vaddr_ins, slot * sizeof(Value) + sPayloadOffset, ACCSET_OTHER);
/*
* We can assume the destination fslot has been appropriately tagged so we
* can just overwrite the 32-bit payload.
*/
lir->insStore(INS_CONSTU(val), obj_ins,
offsetof(JSObject, fslots) + slot * sizeof(Value) + sPayloadOffset,
ACCSET_OTHER);
}
LIns*
TraceRecorder::stobj_get_fslot_uint32(LIns* obj_ins, unsigned slot)
{
JS_ASSERT(slot < JS_INITIAL_NSLOTS);
return lir->insLoad(LIR_ldi, obj_ins,
offsetof(JSObject, fslots) + slot * sizeof(Value) + sPayloadOffset,
ACCSET_OTHER);
}
LIns*
TraceRecorder::stobj_set_fslot_uint32(LIns* value_ins, LIns* obj_ins, unsigned slot)
{
JS_ASSERT(slot < JS_INITIAL_NSLOTS);
return lir->insStore(LIR_sti, value_ins, obj_ins,
offsetof(JSObject, fslots) + slot * sizeof(Value) + sPayloadOffset,
ACCSET_OTHER);
}
#endif
@ -9500,14 +9520,12 @@ TraceRecorder::unbox_slot(JSObject *obj, LIns *obj_ins, uint32 slot, VMSideExit
{
LIns *vaddr_ins;
ptrdiff_t offset;
/* Same guarantee about fixed slots as stobj_set_slot. */
if (!obj->hasSlotsArray()) {
if (slot < JS_INITIAL_NSLOTS) {
vaddr_ins = obj_ins;
offset = offsetof(JSObject, fixedSlots) + slot * sizeof(Value);
offset = offsetof(JSObject, fslots) + slot * sizeof(Value);
} else {
vaddr_ins = lir->insLoad(LIR_ldp, obj_ins, offsetof(JSObject, slots), ACCSET_OTHER);
offset = slot * sizeof(Value);
vaddr_ins = lir->insLoad(LIR_ldp, obj_ins, offsetof(JSObject, dslots), ACCSET_OTHER);
offset = (slot - JS_INITIAL_NSLOTS) * sizeof(Value);
}
const Value &v = obj->getSlot(slot);
@ -9517,11 +9535,12 @@ TraceRecorder::unbox_slot(JSObject *obj, LIns *obj_ins, uint32 slot, VMSideExit
#if JS_BITS_PER_WORD == 32
LIns*
TraceRecorder::stobj_get_const_private_ptr(LIns *obj_ins, unsigned slot)
TraceRecorder::stobj_get_fslot_private_ptr(LIns *obj_ins, unsigned slot)
{
LIns *vaddr_ins = lir->insLoad(LIR_ldp, obj_ins, offsetof(JSObject, slots), ACCSET_OTHER);
return lir->insLoad(LIR_ldi, vaddr_ins,
slot * sizeof(Value) + sPayloadOffset, ACCSET_OTHER, LOAD_CONST);
JS_ASSERT(slot < JS_INITIAL_NSLOTS && slot != JSSLOT_PRIVATE);
return lir->insLoad(LIR_ldi, obj_ins,
offsetof(JSObject, fslots) + slot * sizeof(Value) + sPayloadOffset,
ACCSET_OTHER, LOAD_CONST);
}
void
@ -9678,12 +9697,13 @@ TraceRecorder::box_value_for_native_call(const Value &v, LIns *v_ins)
#elif JS_BITS_PER_WORD == 64
LIns*
TraceRecorder::stobj_get_const_private_ptr(LIns *obj_ins, unsigned slot)
TraceRecorder::stobj_get_fslot_private_ptr(LIns *obj_ins, unsigned slot)
{
/* N.B. On 64-bit, privates are encoded differently from other pointers. */
LIns *vaddr_ins = lir->insLoad(LIR_ldp, obj_ins, offsetof(JSObject, slots), ACCSET_OTHER);
LIns *v_ins = lir->insLoad(LIR_ldq, vaddr_ins,
slot * sizeof(Value) + sPayloadOffset, ACCSET_OTHER, LOAD_CONST);
JS_ASSERT(slot < JS_INITIAL_NSLOTS && slot != JSSLOT_PRIVATE);
LIns *v_ins = lir->insLoad(LIR_ldq, obj_ins,
offsetof(JSObject, fslots) + slot * sizeof(Value),
ACCSET_OTHER, LOAD_CONST);
return lir->ins2ImmI(LIR_lshq, v_ins, 1);
}
@ -9854,17 +9874,8 @@ TraceRecorder::stobj_get_parent(nanojit::LIns* obj_ins)
LIns*
TraceRecorder::stobj_get_private(nanojit::LIns* obj_ins)
{
return lir->insLoad(LIR_ldp, obj_ins,
offsetof(JSObject, privateData),
ACCSET_OTHER);
}
LIns*
TraceRecorder::stobj_get_private_uint32(nanojit::LIns* obj_ins)
{
return lir->insLoad(LIR_ldi, obj_ins,
offsetof(JSObject, privateData),
ACCSET_OTHER);
JS_STATIC_ASSERT(JSSLOT_PRIVATE == 0);
return lir->insLoad(LIR_ldp, obj_ins, offsetof(JSObject, fslots), ACCSET_OTHER);
}
LIns*
@ -10410,7 +10421,7 @@ TraceRecorder::newArguments(LIns* callee_ins, bool strict)
guard(false, lir->insEqP_0(argsobj_ins), OOM_EXIT);
if (strict) {
LIns* argsData_ins = stobj_get_const_private_ptr(argsobj_ins, JSObject::JSSLOT_ARGS_DATA);
LIns* argsData_ins = stobj_get_fslot_private_ptr(argsobj_ins, JSObject::JSSLOT_ARGS_DATA);
ptrdiff_t slotsOffset = offsetof(ArgumentsData, slots);
cx->fp()->forEachCanonicalActualArg(BoxArg(this, slotsOffset, argsData_ins));
}
@ -10805,7 +10816,7 @@ TraceRecorder::getClassPrototype(JSObject* ctor, LIns*& proto_ins)
// that pval is usable.
JS_ASSERT(!pval.isPrimitive());
JSObject *proto = &pval.toObject();
JS_ASSERT_IF(clasp != &js_ArrayClass, proto->emptyShapes[0]->getClass() == clasp);
JS_ASSERT_IF(clasp != &js_ArrayClass, proto->emptyShape->getClass() == clasp);
proto_ins = INS_CONSTOBJ(proto);
return RECORD_CONTINUE;
@ -10829,8 +10840,7 @@ TraceRecorder::getClassPrototype(JSProtoKey key, LIns*& proto_ins)
/* Double-check that a native proto has a matching emptyShape. */
if (key != JSProto_Array) {
JS_ASSERT(proto->isNative());
JS_ASSERT(proto->emptyShapes);
EmptyShape *empty = proto->emptyShapes[0];
EmptyShape *empty = proto->emptyShape;
JS_ASSERT(empty);
JS_ASSERT(JSCLASS_CACHED_PROTO_KEY(empty->getClass()) == key);
}
@ -11744,7 +11754,7 @@ TraceRecorder::nativeSet(JSObject* obj, LIns* obj_ins, const Shape* shape,
set(&obj->getSlotRef(slot), v_ins);
} else {
LIns* dslots_ins = NULL;
stobj_set_slot(obj, obj_ins, slot, dslots_ins, v, v_ins);
stobj_set_slot(obj_ins, slot, dslots_ins, v, v_ins);
}
}
@ -11913,7 +11923,7 @@ TraceRecorder::setCallProp(JSObject *callobj, LIns *callobj_ins, const Shape *sh
JS_ASSERT(shape->hasShortID());
LIns* dslots_ins = NULL;
stobj_set_dslot(callobj_ins, slot, dslots_ins, v, v_ins);
stobj_set_slot(callobj_ins, slot, dslots_ins, v, v_ins);
return RECORD_CONTINUE;
}
@ -12866,14 +12876,22 @@ TraceRecorder::setElem(int lval_spindex, int idx_spindex, int v_spindex)
// be an integer.
idx_ins = makeNumberInt32(idx_ins);
if (MAX_DSLOTS_LENGTH > MAX_DSLOTS_LENGTH32) {
/*
* Check for negative values bleeding through on 64-bit machines only,
* since we can't allocate large enough arrays for this on 32-bit
* machines.
*/
guard(true, lir->ins2ImmI(LIR_gei, idx_ins, 0), mismatchExit);
}
if (!js_EnsureDenseArrayCapacity(cx, obj, idx.toInt32()))
RETURN_STOP_A("couldn't ensure dense array capacity for setelem");
// Grow the array if the index exceeds the capacity. This happens
// rarely, eg. less than 1% of the time in SunSpider.
LIns* capacity_ins =
addName(lir->insLoad(LIR_ldi, obj_ins,
offsetof(JSObject, capacity), ACCSET_OTHER),
addName(stobj_get_fslot_uint32(obj_ins, JSObject::JSSLOT_DENSE_ARRAY_CAPACITY),
"capacity");
LIns* br = lir->insBranch(LIR_jt, lir->ins2(LIR_ltui, idx_ins, capacity_ins), NULL);
LIns* args[] = { idx_ins, obj_ins, cx_ins };
@ -12883,7 +12901,7 @@ TraceRecorder::setElem(int lval_spindex, int idx_spindex, int v_spindex)
// Get the address of the element.
LIns *dslots_ins =
addName(lir->insLoad(LIR_ldp, obj_ins, offsetof(JSObject, slots), ACCSET_OTHER), "dslots");
addName(lir->insLoad(LIR_ldp, obj_ins, offsetof(JSObject, dslots), ACCSET_OTHER), "dslots");
JS_ASSERT(sizeof(Value) == 8); // The |3| in the following statement requires this.
LIns *addr_ins = lir->ins2(LIR_addp, dslots_ins,
lir->ins2ImmI(LIR_lshp, lir->insUI2P(idx_ins), 3));
@ -13089,7 +13107,7 @@ TraceRecorder::record_JSOP_GETFCSLOT()
JSObject& callee = cx->fp()->callee();
LIns* callee_ins = get(&cx->fp()->calleeValue());
LIns* upvars_ins = stobj_get_const_private_ptr(callee_ins,
LIns* upvars_ins = stobj_get_fslot_private_ptr(callee_ins,
JSObject::JSSLOT_FLAT_CLOSURE_UPVARS);
unsigned index = GET_UINT16(cx->regs->pc);
@ -13349,7 +13367,7 @@ TraceRecorder::record_JSOP_APPLY()
length = aobj->getArrayLength();
guard(true,
lir->ins2ImmI(LIR_eqi,
stobj_get_private_uint32(aobj_ins),
stobj_get_fslot_uint32(aobj_ins, JSObject::JSSLOT_ARRAY_LENGTH),
length),
BRANCH_EXIT);
} else if (aobj->isArguments()) {
@ -13726,10 +13744,8 @@ TraceRecorder::denseArrayElement(Value& oval, Value& ival, Value*& vp, LIns*& v_
* the correct value.
*/
LIns* capacity_ins =
addName(lir->insLoad(LIR_ldi, obj_ins,
offsetof(JSObject, capacity), ACCSET_OTHER),
addName(stobj_get_fslot_uint32(obj_ins, JSObject::JSSLOT_DENSE_ARRAY_CAPACITY),
"capacity");
jsuint capacity = obj->getDenseArrayCapacity();
bool within = (jsuint(idx) < capacity);
if (!within) {
@ -13749,8 +13765,8 @@ TraceRecorder::denseArrayElement(Value& oval, Value& ival, Value*& vp, LIns*& v_
/* Load the value and guard on its type to unbox it. */
LIns* dslots_ins =
addName(lir->insLoad(LIR_ldp, obj_ins, offsetof(JSObject, slots), ACCSET_OTHER), "dslots");
vp = &obj->slots[jsuint(idx)];
addName(lir->insLoad(LIR_ldp, obj_ins, offsetof(JSObject, dslots), ACCSET_OTHER), "dslots");
vp = &obj->dslots[jsuint(idx)];
JS_ASSERT(sizeof(Value) == 8); // The |3| in the following statement requires this.
addr_ins = lir->ins2(LIR_addp, dslots_ins,
lir->ins2ImmI(LIR_lshp, lir->insUI2P(idx_ins), 3));
@ -14061,7 +14077,7 @@ TraceRecorder::record_JSOP_UINT16()
JS_REQUIRES_STACK AbortableRecordingStatus
TraceRecorder::record_JSOP_NEWINIT()
{
JSProtoKey key = JSProtoKey(GET_UINT16(cx->regs->pc));
JSProtoKey key = JSProtoKey(GET_INT8(cx->regs->pc));
LIns* proto_ins;
CHECK_STATUS_A(getClassPrototype(key, proto_ins));
@ -15022,7 +15038,7 @@ TraceRecorder::record_JSOP_LAMBDA_FC()
if (fun->u.i.nupvars) {
JSUpvarArray *uva = fun->u.i.script->upvars();
LIns* upvars_ins = stobj_get_const_private_ptr(closure_ins,
LIns* upvars_ins = stobj_get_fslot_private_ptr(closure_ins,
JSObject::JSSLOT_FLAT_CLOSURE_UPVARS);
for (uint32 i = 0, n = uva->length; i < n; i++) {
@ -15106,7 +15122,7 @@ TraceRecorder::guardArgsLengthNotAssigned(LIns* argsobj_ins)
{
// The following implements JSObject::isArgsLengthOverridden on trace.
// ARGS_LENGTH_OVERRIDDEN_BIT is set if length was overridden.
LIns *len_ins = stobj_get_slot_uint32(argsobj_ins, JSObject::JSSLOT_ARGS_LENGTH);
LIns *len_ins = stobj_get_fslot_uint32(argsobj_ins, JSObject::JSSLOT_ARGS_LENGTH);
LIns *ovr_ins = lir->ins2(LIR_andi, len_ins, INS_CONST(JSObject::ARGS_LENGTH_OVERRIDDEN_BIT));
guard(true, lir->insEqI_0(ovr_ins), snapshot(BRANCH_EXIT));
return len_ins;
@ -15813,7 +15829,7 @@ TraceRecorder::record_JSOP_LENGTH()
JS_ASSERT(obj->isSlowArray());
guardClass(obj_ins, &js_SlowArrayClass, snapshot(BRANCH_EXIT), LOAD_NORMAL);
}
v_ins = lir->ins1(LIR_i2d, stobj_get_private_uint32(obj_ins));
v_ins = lir->ins1(LIR_i2d, stobj_get_fslot_uint32(obj_ins, JSObject::JSSLOT_ARRAY_LENGTH));
} else if (OkToTraceTypedArrays && js_IsTypedArray(obj)) {
// Ensure array is a typed array and is the same type as what was written
guardClass(obj_ins, obj->getClass(), snapshot(BRANCH_EXIT), LOAD_NORMAL);

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

@ -1067,7 +1067,7 @@ class TraceRecorder
* entries of the tracker accordingly.
*/
JS_REQUIRES_STACK void checkForGlobalObjectReallocation() {
if (global_dslots != globalObj->getSlots())
if (global_dslots != globalObj->dslots)
checkForGlobalObjectReallocationHelper();
}
JS_REQUIRES_STACK void checkForGlobalObjectReallocationHelper();
@ -1173,20 +1173,21 @@ class TraceRecorder
nanojit::LIns* v_ins);
void stobj_set_dslot(nanojit::LIns *obj_ins, unsigned slot,
nanojit::LIns*& dslots_ins, const Value &v, nanojit::LIns* v_ins);
void stobj_set_slot(JSObject *obj, nanojit::LIns* obj_ins, unsigned slot,
void stobj_set_slot(nanojit::LIns* obj_ins, unsigned slot,
nanojit::LIns*& dslots_ins, const Value &v, nanojit::LIns* v_ins);
void set_array_fslot(nanojit::LIns *obj_ins, unsigned slot, uint32 val);
nanojit::LIns* stobj_get_slot_uint32(nanojit::LIns* obj_ins, unsigned slot);
nanojit::LIns* stobj_get_fslot_private_ptr(nanojit::LIns* obj_ins,
unsigned slot);
nanojit::LIns* stobj_get_fslot_uint32(nanojit::LIns* obj_ins, unsigned slot);
nanojit::LIns* stobj_set_fslot_uint32(nanojit::LIns* value_ins, nanojit::LIns* obj_ins,
unsigned slot);
nanojit::LIns* unbox_slot(JSObject *obj, nanojit::LIns *obj_ins, uint32 slot,
VMSideExit *exit);
nanojit::LIns* stobj_get_parent(nanojit::LIns* obj_ins);
nanojit::LIns* stobj_get_private(nanojit::LIns* obj_ins);
nanojit::LIns* stobj_get_private_uint32(nanojit::LIns* obj_ins);
nanojit::LIns* stobj_get_proto(nanojit::LIns* obj_ins);
/* For slots holding private pointers. */
nanojit::LIns* stobj_get_const_private_ptr(nanojit::LIns *obj_ins, unsigned slot);
JS_REQUIRES_STACK AbortableRecordingStatus name(Value*& vp, nanojit::LIns*& ins, NameResult& nr);
JS_REQUIRES_STACK AbortableRecordingStatus prop(JSObject* obj, nanojit::LIns* obj_ins,
uint32 *slotp, nanojit::LIns** v_insp,

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

@ -818,18 +818,6 @@ PrivateValue(void *ptr)
return v;
}
static JS_ALWAYS_INLINE void
ClearValueRange(Value *vec, uintN len, bool useHoles)
{
if (useHoles) {
for (uintN i = 0; i < len; i++)
vec[i].setMagic(JS_ARRAY_HOLE);
} else {
for (uintN i = 0; i < len; i++)
vec[i].setUndefined();
}
}
/******************************************************************************/
/*

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

@ -166,9 +166,14 @@ static const JSC::MacroAssembler::RegisterID JSParamReg_Argc = JSC::ARMRegiste
* Finds and returns the address of a known object and slot.
*/
Address objSlotRef(JSObject *obj, RegisterID reg, uint32 slot) {
move(ImmPtr(&obj->slots), reg);
if (slot < JS_INITIAL_NSLOTS) {
void *vp = &obj->getSlotRef(slot);
move(ImmPtr(vp), reg);
return Address(reg, 0);
}
move(ImmPtr(&obj->dslots), reg);
loadPtr(reg, reg);
return Address(reg, slot * sizeof(Value));
return Address(reg, (slot - JS_INITIAL_NSLOTS) * sizeof(Value));
}
#ifdef JS_CPU_X86

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

@ -50,7 +50,6 @@
#include "assembler/jit/ExecutableAllocator.h"
#include "assembler/assembler/LinkBuffer.h"
#include "FrameState-inl.h"
#include "jsobjinlines.h"
#include "jsscriptinlines.h"
#include "InlineFrameAssembler.h"
@ -1226,13 +1225,10 @@ mjit::Compiler::generateMethod()
BEGIN_CASE(JSOP_NEWINIT)
{
jsint i = GET_UINT16(PC);
uint32 count = GET_UINT16(PC + UINT16_LEN);
jsint i = GET_INT8(PC);
JS_ASSERT(i == JSProto_Array || i == JSProto_Object);
prepareStubCall(Uses(0));
masm.move(Imm32(count), Registers::ArgReg1);
if (i == JSProto_Array)
stubCall(stubs::NewInitArray);
else
@ -1442,8 +1438,8 @@ mjit::Compiler::generateMethod()
RegisterID reg = frame.allocReg();
masm.loadPayload(Address(JSFrameReg, JSStackFrame::offsetOfCallee(fun)), reg);
// obj->getFlatClosureUpvars()
masm.loadPtr(Address(reg, offsetof(JSObject, slots)), reg);
Address upvarAddress(reg, JSObject::JSSLOT_FLAT_CLOSURE_UPVARS * sizeof(Value));
Address upvarAddress(reg, offsetof(JSObject, fslots) +
JSObject::JSSLOT_FLAT_CLOSURE_UPVARS * sizeof(Value));
masm.loadPrivate(upvarAddress, reg);
// push ((Value *) reg)[index]
frame.freeReg(reg);
@ -2406,7 +2402,7 @@ mjit::Compiler::jsop_getprop(JSAtom *atom, bool doTypeCheck)
#elif defined JS_PUNBOX64
Label dslotsLoadLabel = masm.label();
#endif
masm.loadPtr(Address(objReg, offsetof(JSObject, slots)), objReg);
masm.loadPtr(Address(objReg, offsetof(JSObject, dslots)), objReg);
/* Copy the slot value to the expression stack. */
Address slot(objReg, 1 << 24);
@ -2507,7 +2503,7 @@ mjit::Compiler::jsop_getelem_pic(FrameEntry *obj, FrameEntry *id, RegisterID obj
#elif defined JS_PUNBOX64
Label dslotsLoadLabel = masm.label();
#endif
masm.loadPtr(Address(objReg, offsetof(JSObject, slots)), objReg);
masm.loadPtr(Address(objReg, offsetof(JSObject, dslots)), objReg);
/* Copy the slot value to the expression stack. */
Address slot(objReg, 1 << 24);
@ -2639,7 +2635,7 @@ mjit::Compiler::jsop_callprop_generic(JSAtom *atom)
#elif defined JS_PUNBOX64
Label dslotsLoadLabel = masm.label();
#endif
masm.loadPtr(Address(objReg, offsetof(JSObject, slots)), objReg);
masm.loadPtr(Address(objReg, offsetof(JSObject, dslots)), objReg);
/* Copy the slot value to the expression stack. */
Address slot(objReg, 1 << 24);
@ -2797,7 +2793,7 @@ mjit::Compiler::jsop_callprop_obj(JSAtom *atom)
#elif defined JS_PUNBOX64
Label dslotsLoadLabel = masm.label();
#endif
masm.loadPtr(Address(objReg, offsetof(JSObject, slots)), objReg);
masm.loadPtr(Address(objReg, offsetof(JSObject, dslots)), objReg);
/* Copy the slot value to the expression stack. */
Address slot(objReg, 1 << 24);
@ -2966,7 +2962,7 @@ mjit::Compiler::jsop_setprop(JSAtom *atom)
#elif defined JS_PUNBOX64
Label dslotsLoadLabel = masm.label();
#endif
masm.loadPtr(Address(objReg, offsetof(JSObject, slots)), objReg);
masm.loadPtr(Address(objReg, offsetof(JSObject, dslots)), objReg);
/* Store RHS into object slot. */
Address slot(objReg, 1 << 24);
@ -3510,7 +3506,8 @@ mjit::Compiler::iter(uintN flags)
stubcc.linkExit(nullIterator, Uses(1));
/* Get NativeIterator from iter obj. :FIXME: X64, also most of this function */
masm.loadPtr(Address(ioreg, offsetof(JSObject, privateData)), nireg);
Address privSlot(ioreg, offsetof(JSObject, fslots) + sizeof(Value) * JSSLOT_PRIVATE);
masm.loadPtr(privSlot, nireg);
/* Test for active iterator. */
Address flagsAddr(nireg, offsetof(NativeIterator, flags));
@ -3694,7 +3691,8 @@ mjit::Compiler::iterEnd()
stubcc.linkExit(notIterator, Uses(1));
/* Get private from iter obj. :FIXME: X64 */
masm.loadPtr(Address(reg, offsetof(JSObject, privateData)), T1);
Address privSlot(reg, offsetof(JSObject, fslots) + sizeof(Value) * JSSLOT_PRIVATE);
masm.loadPtr(privSlot, T1);
RegisterID T2 = frame.allocReg();
@ -3808,7 +3806,7 @@ mjit::Compiler::jsop_getgname(uint32 index)
/* Garbage value. */
uint32 slot = 1 << 24;
masm.loadPtr(Address(objReg, offsetof(JSObject, slots)), objReg);
masm.loadPtr(Address(objReg, offsetof(JSObject, dslots)), objReg);
Address address(objReg, slot);
/*
@ -3929,7 +3927,7 @@ mjit::Compiler::jsop_setgname(uint32 index)
v = fe->getValue();
}
masm.loadPtr(Address(objReg, offsetof(JSObject, slots)), objReg);
masm.loadPtr(Address(objReg, offsetof(JSObject, dslots)), objReg);
Address address(objReg, slot);
mic.load = masm.label();

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

@ -1200,21 +1200,26 @@ mjit::Compiler::jsop_setelem()
stubcc.linkExit(guardDense, Uses(3));
/* guard within capacity */
Address capacity(objReg, offsetof(JSObject, capacity));
Address capacity(objReg, offsetof(JSObject, fslots) +
JSObject::JSSLOT_DENSE_ARRAY_CAPACITY * sizeof(Value));
Jump inRange;
MaybeRegisterID maybeIdReg;
if (id->isConstant()) {
inRange = masm.branch32(Assembler::LessThanOrEqual, capacity,
inRange = masm.branch32(Assembler::LessThanOrEqual,
masm.payloadOf(capacity),
Imm32(id->getValue().toInt32()));
} else {
maybeIdReg = frame.copyDataIntoReg(id);
inRange = masm.branch32(Assembler::AboveOrEqual, maybeIdReg.reg(), capacity);
inRange = masm.branch32(Assembler::AboveOrEqual, maybeIdReg.reg(),
masm.payloadOf(capacity));
}
stubcc.linkExit(inRange, Uses(3));
/* load dslots */
masm.loadPtr(Address(objReg, offsetof(JSObject, slots)), objReg);
/* dslots non-NULL */
masm.loadPtr(Address(objReg, offsetof(JSObject, dslots)), objReg);
Jump guardSlots = masm.branchTestPtr(Assembler::Zero, objReg, objReg);
stubcc.linkExit(guardSlots, Uses(3));
/* guard within capacity */
if (id->isConstant()) {
@ -1293,17 +1298,17 @@ mjit::Compiler::jsop_setelem()
extendedObject.linkTo(syncTarget, &stubcc.masm);
/* Update the array length if needed. Don't worry about overflow. */
Address arrayLength(baseReg, offsetof(JSObject, privateData));
stubcc.masm.load32(arrayLength, T1);
Address arrayLength(baseReg, offsetof(JSObject, fslots[JSObject::JSSLOT_ARRAY_LENGTH]));
stubcc.masm.loadPayload(arrayLength, T1);
Jump underLength = stubcc.masm.branch32(Assembler::LessThan, idReg, T1);
stubcc.masm.move(idReg, T1);
stubcc.masm.add32(Imm32(1), T1);
stubcc.masm.store32(T1, arrayLength);
stubcc.masm.storePayload(T1, arrayLength);
underLength.linkTo(stubcc.masm.label(), &stubcc.masm);
/* Restore the dslots register if we clobbered it with the object. */
if (baseReg == objReg)
stubcc.masm.loadPtr(Address(objReg, offsetof(JSObject, slots)), objReg);
stubcc.masm.loadPtr(Address(objReg, offsetof(JSObject, dslots)), objReg);
/* Rejoin OOL path with inline path to do the store itself. */
Jump jmpHoleExit = stubcc.masm.jump();
@ -1349,17 +1354,22 @@ mjit::Compiler::jsop_getelem_dense(FrameEntry *obj, FrameEntry *id, RegisterID o
/* Guard within capacity. */
Jump inRange;
Address capacity(objReg, offsetof(JSObject, capacity));
Address capacity(objReg, offsetof(JSObject, fslots) +
JSObject::JSSLOT_DENSE_ARRAY_CAPACITY * sizeof(Value));
if (id->isConstant()) {
inRange = masm.branch32(Assembler::LessThanOrEqual, capacity,
inRange = masm.branch32(Assembler::LessThanOrEqual,
masm.payloadOf(capacity),
Imm32(id->getValue().toInt32()));
} else {
inRange = masm.branch32(Assembler::AboveOrEqual, idReg.reg(), capacity);
inRange = masm.branch32(Assembler::AboveOrEqual, idReg.reg(),
masm.payloadOf(capacity));
}
stubcc.linkExit(inRange, Uses(2));
/* load dslots */
masm.loadPtr(Address(objReg, offsetof(JSObject, slots)), objReg);
/* dslots non-NULL */
masm.loadPtr(Address(objReg, offsetof(JSObject, dslots)), objReg);
Jump guardSlots = masm.branchTestPtr(Assembler::Zero, objReg, objReg);
stubcc.linkExit(guardSlots, Uses(2));
/* guard within capacity */
if (id->isConstant()) {

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

@ -237,8 +237,7 @@ stubs::NewObject(VMFrame &f, uint32 argc)
THROWV(JS_FALSE);
JSObject *proto = vp[1].isObject() ? &vp[1].toObject() : NULL;
JSObject *obj = NewNonFunction<WithProto::Class>(cx, &js_ObjectClass, proto, funobj->getParent(),
FINALIZE_OBJECT4);
JSObject *obj = NewNonFunction<WithProto::Class>(cx, &js_ObjectClass, proto, funobj->getParent());
if (!obj)
THROWV(JS_FALSE);

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

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

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

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

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

@ -253,7 +253,7 @@ class SetPropCompiler : public PICStubCompiler
repatcher.relinkCallerToTrampoline(retPtr, target);
}
bool patchInline(const Shape *shape, bool inlineSlot)
bool patchInline(const Shape *shape)
{
JS_ASSERT(!pic.inlinePathPatched);
JaegerSpew(JSpew_PICs, "patch setprop inline at %p\n", pic.fastPathStart.executableAddress());
@ -261,7 +261,7 @@ class SetPropCompiler : public PICStubCompiler
PICRepatchBuffer repatcher(pic, pic.fastPathStart);
int32 offset;
if (inlineSlot) {
if (shape->slot < JS_INITIAL_NSLOTS) {
JSC::CodeLocationInstruction istr;
istr = pic.storeBack.instructionAtOffset(dslotsLoadOffset());
repatcher.repatchLoadPtrToLEA(istr);
@ -273,12 +273,12 @@ class SetPropCompiler : public PICStubCompiler
// Because the offset is wrong, it's necessary to correct it
// below.
//
int32 diff = int32(offsetof(JSObject, fixedSlots)) -
int32(offsetof(JSObject, slots));
int32 diff = int32(offsetof(JSObject, fslots)) -
int32(offsetof(JSObject, dslots));
JS_ASSERT(diff != 0);
offset = (int32(shape->slot) * sizeof(Value)) + diff;
} else {
offset = shape->slot * sizeof(Value);
offset = (shape->slot - JS_INITIAL_NSLOTS) * sizeof(Value);
}
uint32 shapeOffs = pic.shapeGuard + inlineShapeOffset();
@ -326,7 +326,7 @@ class SetPropCompiler : public PICStubCompiler
}
}
bool generateStub(uint32 initialShape, const Shape *shape, bool adding, bool inlineSlot)
bool generateStub(uint32 initialShape, const Shape *shape, bool adding)
{
/* Exits to the slow path. */
Vector<Jump, 8> slowExits(f.cx);
@ -406,21 +406,28 @@ class SetPropCompiler : public PICStubCompiler
}
}
if (inlineSlot) {
if (shape->slot < JS_INITIAL_NSLOTS) {
Address address(pic.objReg,
offsetof(JSObject, fixedSlots) + shape->slot * sizeof(Value));
offsetof(JSObject, fslots) + shape->slot * sizeof(Value));
emitStore(masm, address);
} else {
/* Check dslots non-zero. */
masm.loadPtr(Address(pic.objReg, offsetof(JSObject, dslots)), pic.shapeReg);
Jump emptyDslots = masm.branchPtr(Assembler::Equal, pic.shapeReg, ImmPtr(0));
if (!slowExits.append(emptyDslots))
return false;
/* Check capacity. */
Address capacity(pic.objReg, offsetof(JSObject, capacity));
Address capacity(pic.shapeReg, -ptrdiff_t(sizeof(Value)));
masm.load32(masm.payloadOf(capacity), pic.shapeReg);
Jump overCapacity = masm.branch32(Assembler::LessThanOrEqual, pic.shapeReg,
Imm32(shape->slot));
if (!slowExits.append(overCapacity))
return false;
masm.loadPtr(Address(pic.objReg, offsetof(JSObject, slots)), pic.shapeReg);
Address address(pic.shapeReg, shape->slot * sizeof(Value));
masm.loadPtr(Address(pic.objReg, offsetof(JSObject, dslots)), pic.shapeReg);
Address address(pic.shapeReg,
(shape->slot - JS_INITIAL_NSLOTS) * sizeof(Value));
emitStore(masm, address);
}
@ -441,10 +448,10 @@ class SetPropCompiler : public PICStubCompiler
masm.store32(pic.shapeReg, flags);
}
} else if (shape->hasDefaultSetter()) {
Address address(pic.objReg, offsetof(JSObject, fixedSlots) + shape->slot * sizeof(Value));
if (!inlineSlot) {
masm.loadPtr(Address(pic.objReg, offsetof(JSObject, slots)), pic.objReg);
address = Address(pic.objReg, shape->slot * sizeof(Value));
Address address(pic.objReg, offsetof(JSObject, fslots) + shape->slot * sizeof(Value));
if (shape->slot >= JS_INITIAL_NSLOTS) {
masm.loadPtr(Address(pic.objReg, offsetof(JSObject, dslots)), pic.objReg);
address = Address(pic.objReg, (shape->slot - JS_INITIAL_NSLOTS) * sizeof(Value));
}
// If the scope is branded, or has a method barrier. It's now necessary
@ -486,9 +493,9 @@ class SetPropCompiler : public PICStubCompiler
{
if (shape->setterOp() == SetCallVar)
slot += fun->nargs;
masm.loadPtr(Address(pic.objReg, offsetof(JSObject, slots)), pic.objReg);
masm.loadPtr(Address(pic.objReg, offsetof(JSObject, dslots)), pic.objReg);
Address dslot(pic.objReg, (slot + JSObject::CALL_RESERVED_SLOTS) * sizeof(Value));
Address dslot(pic.objReg, slot * sizeof(Value));
emitStore(masm, dslot);
}
@ -668,7 +675,7 @@ class SetPropCompiler : public PICStubCompiler
if (obj->numSlots() != slots)
return disable("insufficient slot capacity");
return generateStub(initialShape, shape, true, !obj->hasSlotsArray());
return generateStub(initialShape, shape, true);
}
AutoPropertyDropper dropper(f.cx, holder, prop);
@ -696,10 +703,10 @@ class SetPropCompiler : public PICStubCompiler
!obj->brandedOrHasMethodBarrier() &&
shape->hasDefaultSetter() &&
!obj->isDenseArray()) {
return patchInline(shape, !obj->hasSlotsArray());
return patchInline(shape);
}
return generateStub(obj->shape(), shape, false, !obj->hasSlotsArray());
return generateStub(obj->shape(), shape, false);
}
};
@ -803,8 +810,9 @@ class GetPropCompiler : public PICStubCompiler
Address clasp(pic.objReg, offsetof(JSObject, clasp));
Jump notArgs = masm.branchPtr(Assembler::NotEqual, clasp, ImmPtr(obj->getClass()));
masm.loadPtr(Address(pic.objReg, offsetof(JSObject, slots)), pic.objReg);
masm.load32(Address(pic.objReg, JSObject::JSSLOT_ARGS_LENGTH * sizeof(Value)),
masm.load32(Address(pic.objReg,
offsetof(JSObject, fslots)
+ JSObject::JSSLOT_ARGS_LENGTH * sizeof(Value)),
pic.objReg);
masm.move(pic.objReg, pic.shapeReg);
Jump overridden = masm.branchTest32(Assembler::NonZero, pic.shapeReg, Imm32(1));
@ -848,7 +856,10 @@ class GetPropCompiler : public PICStubCompiler
ImmPtr(&js_SlowArrayClass));
isDense.linkTo(masm.label(), &masm);
masm.load32(Address(pic.objReg, offsetof(JSObject, privateData)), pic.objReg);
masm.load32(Address(pic.objReg,
offsetof(JSObject, fslots)
+ JSObject::JSSLOT_ARRAY_LENGTH * sizeof(Value)),
pic.objReg);
Jump oob = masm.branch32(Assembler::Above, pic.objReg, Imm32(JSVAL_INT_MAX));
masm.move(ImmType(JSVAL_TYPE_INT32), pic.shapeReg);
Jump done = masm.jump();
@ -933,8 +944,7 @@ class GetPropCompiler : public PICStubCompiler
masm.loadShape(pic.objReg, pic.shapeReg);
Jump shapeMismatch = masm.branch32(Assembler::NotEqual, pic.shapeReg,
Imm32(obj->shape()));
masm.loadSlot(pic.objReg, pic.objReg, shape->slot, !obj->hasSlotsArray(),
pic.shapeReg, pic.objReg);
masm.loadSlot(pic.objReg, pic.objReg, shape->slot, pic.shapeReg, pic.objReg);
Jump done = masm.jump();
@ -1013,7 +1023,7 @@ class GetPropCompiler : public PICStubCompiler
PICRepatchBuffer repatcher(pic, pic.fastPathStart);
int32 offset;
if (!holder->hasSlotsArray()) {
if (shape->slot < JS_INITIAL_NSLOTS) {
JSC::CodeLocationInstruction istr;
istr = pic.storeBack.instructionAtOffset(dslotsLoad());
repatcher.repatchLoadPtrToLEA(istr);
@ -1025,12 +1035,12 @@ class GetPropCompiler : public PICStubCompiler
// Because the offset is wrong, it's necessary to correct it
// below.
//
int32 diff = int32(offsetof(JSObject, fixedSlots)) -
int32(offsetof(JSObject, slots));
int32 diff = int32(offsetof(JSObject, fslots)) -
int32(offsetof(JSObject, dslots));
JS_ASSERT(diff != 0);
offset = (int32(shape->slot) * sizeof(Value)) + diff;
} else {
offset = shape->slot * sizeof(Value);
offset = (shape->slot - JS_INITIAL_NSLOTS) * sizeof(Value);
}
uint32 shapeOffs = pic.shapeGuard + inlineShapeOffset();
@ -1136,8 +1146,7 @@ class GetPropCompiler : public PICStubCompiler
}
/* Load the value out of the object. */
masm.loadSlot(pic.objReg, pic.objReg, shape->slot, !holder->hasSlotsArray(),
pic.shapeReg, pic.objReg);
masm.loadSlot(pic.objReg, pic.objReg, shape->slot, pic.shapeReg, pic.objReg);
Jump done = masm.jump();
JSC::ExecutablePool *ep = getExecPool(masm.size());
@ -1349,7 +1358,7 @@ class GetElemCompiler : public PICStubCompiler
PICRepatchBuffer repatcher(pic, pic.fastPathStart);
int32 offset;
if (!holder->hasSlotsArray()) {
if (shape->slot < JS_INITIAL_NSLOTS) {
JSC::CodeLocationInstruction istr = pic.storeBack.instructionAtOffset(dslotsLoad());
repatcher.repatchLoadPtrToLEA(istr);
@ -1360,11 +1369,11 @@ class GetElemCompiler : public PICStubCompiler
// Because the offset is wrong, it's necessary to correct it
// below.
//
int32 diff = int32(offsetof(JSObject, fixedSlots)) - int32(offsetof(JSObject, slots));
int32 diff = int32(offsetof(JSObject, fslots)) - int32(offsetof(JSObject, dslots));
JS_ASSERT(diff != 0);
offset = (int32(shape->slot) * sizeof(Value)) + diff;
} else {
offset = shape->slot * sizeof(Value);
offset = (shape->slot - JS_INITIAL_NSLOTS) * sizeof(Value);
}
uint32 shapeOffset = pic.shapeGuard + inlineShapeOffset();
@ -1493,8 +1502,7 @@ class GetElemCompiler : public PICStubCompiler
}
/* Load the value out of the object. */
masm.loadSlot(pic.objReg, pic.objReg, shape->slot, !holder->hasSlotsArray(),
pic.shapeReg, pic.objReg);
masm.loadSlot(pic.objReg, pic.objReg, shape->slot, pic.shapeReg, pic.objReg);
Jump done = masm.jump();
JSC::ExecutablePool *ep = getExecPool(masm.size());
@ -1683,7 +1691,7 @@ class ScopeNameCompiler : public PICStubCompiler
masm.loadShape(pic.objReg, pic.shapeReg);
Jump finalShape = masm.branch32(Assembler::NotEqual, pic.shapeReg, Imm32(holder->shape()));
masm.loadSlot(pic.objReg, pic.objReg, shape->slot, false, pic.shapeReg, pic.objReg);
masm.loadSlot(pic.objReg, pic.objReg, shape->slot, pic.shapeReg, pic.objReg);
Jump done = masm.jump();
@ -1786,11 +1794,11 @@ class ScopeNameCompiler : public PICStubCompiler
escapedFrame.linkTo(masm.label(), &masm);
{
masm.loadPtr(Address(pic.objReg, offsetof(JSObject, slots)), pic.objReg);
masm.loadPtr(Address(pic.objReg, offsetof(JSObject, dslots)), pic.objReg);
if (kind == VAR)
slot += fun->nargs;
Address dslot(pic.objReg, (slot + JSObject::CALL_RESERVED_SLOTS) * sizeof(Value));
Address dslot(pic.objReg, slot * sizeof(Value));
/* Safe because type is loaded first. */
masm.loadValueAsComponents(dslot, pic.shapeReg, pic.objReg);

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

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

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

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

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

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

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

@ -8,8 +8,7 @@ function f(i) {
return 1;
}
/* trailing 'true' ensures array has capacity >= 10 */
var arr = [ false, false, false, false, false, , , , , , true ];
var arr = [ false, false, false, false, false, , , , ];
for (var i = 0; i < 10; ++i) {
(s = arr[i]) + f(i);

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

@ -6,5 +6,5 @@ function caller(obj) {
var x = ({ dana : "zuul" });
return x;
}
trap(caller, 23, "x = 'success'; nop()");
trap(caller, 20, "x = 'success'; nop()");
assertEq(caller(this), "success");

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

@ -1373,10 +1373,10 @@ DebugCheckWrapperClass(JSObject* obj)
// Only use these macros if IS_WRAPPER_CLASS(obj->getClass()) is true.
#define IS_WN_WRAPPER_OBJECT(obj) \
(DebugCheckWrapperClass(obj) && \
obj->getSlot(0).isUndefined())
obj->getSlot(JSSLOT_START(obj->getClass())).isUndefined())
#define IS_SLIM_WRAPPER_OBJECT(obj) \
(DebugCheckWrapperClass(obj) && \
!obj->getSlot(0).isUndefined())
!obj->getSlot(JSSLOT_START(obj->getClass())).isUndefined())
// Use these macros if IS_WRAPPER_CLASS(obj->getClass()) might be false.
// Avoid calling them if IS_WRAPPER_CLASS(obj->getClass()) can only be
@ -2284,7 +2284,7 @@ extern JSBool MorphSlimWrapper(JSContext *cx, JSObject *obj);
static inline XPCWrappedNativeProto*
GetSlimWrapperProto(JSObject *obj)
{
const js::Value &v = obj->getSlot(0);
const js::Value &v = obj->getSlot(JSSLOT_START(obj->getClass()));
return static_cast<XPCWrappedNativeProto*>(v.toPrivate());
}

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

@ -52,7 +52,7 @@ namespace xpc {
using namespace js;
static const uint32 JSSLOT_WN_OBJ = 0;
static const uint32 JSSLOT_WN_OBJ = JSSLOT_PRIVATE;
static JSBool
holder_get(JSContext *cx, JSObject *holder, jsid id, jsval *vp);