bug 491126 - sharing object map for non-native objects. r=brendan

This commit is contained in:
Igor Bukanov 2009-05-14 12:35:23 +02:00
parent 6ffa7ccf08
commit 92f94e451c
21 changed files with 256 additions and 384 deletions

View File

@ -2953,7 +2953,7 @@ JS_SealObject(JSContext *cx, JSObject *obj, JSBool deep)
return JS_TRUE;
/* Walk slots in obj and if any value is a non-null object, seal it. */
nslots = scope->map.freeslot;
nslots = scope->freeslot;
for (i = 0; i != nslots; ++i) {
v = STOBJ_GET_SLOT(obj, i);
if (JSVAL_IS_PRIMITIVE(v))

View File

@ -1199,35 +1199,12 @@ array_trace(JSTracer *trc, JSObject *obj)
}
}
static JSObjectMap *
array_newObjectMap(JSContext *cx, jsrefcount nrefs, JSObjectOps *ops,
JSClass *clasp, JSObject *obj)
{
#ifdef DEBUG
extern JSClass js_ArrayClass;
extern JSObjectOps js_ArrayObjectOps;
#endif
JSObjectMap *map = (JSObjectMap *) JS_malloc(cx, sizeof(*map));
if (!map)
return NULL;
extern JSObjectOps js_ArrayObjectOps;
map->nrefs = nrefs;
JS_ASSERT(ops == &js_ArrayObjectOps);
map->ops = ops;
JS_ASSERT(clasp == &js_ArrayClass);
map->freeslot = JSSLOT_FREE(clasp);
return map;
}
void
array_destroyObjectMap(JSContext *cx, JSObjectMap *map)
{
JS_free(cx, map);
}
static const JSObjectMap SharedArrayMap = { &js_ArrayObjectOps };
JSObjectOps js_ArrayObjectOps = {
array_newObjectMap, array_destroyObjectMap,
&SharedArrayMap,
array_lookupProperty, array_defineProperty,
array_getProperty, array_setProperty,
array_getAttributes, array_setAttributes,
@ -1271,27 +1248,24 @@ JSClass js_SlowArrayClass = {
JSBool
js_MakeArraySlow(JSContext *cx, JSObject *obj)
{
JSObjectMap *map, *oldmap;
uint32 i, capacity;
JS_ASSERT(OBJ_GET_CLASS(cx, obj) == &js_ArrayClass);
/* Create a native scope. */
map = js_NewObjectMap(cx, obj->map->nrefs, &js_SlowArrayObjectOps,
&js_SlowArrayClass, obj);
if (!map)
JSScope *scope = js_NewScope(cx, &js_SlowArrayObjectOps,
&js_SlowArrayClass, obj);
if (!scope)
return JS_FALSE;
capacity = js_DenseArrayCapacity(obj);
uint32 capacity = js_DenseArrayCapacity(obj);
if (capacity) {
map->freeslot = STOBJ_NSLOTS(obj) + JS_INITIAL_NSLOTS;
scope->freeslot = STOBJ_NSLOTS(obj) + JS_INITIAL_NSLOTS;
obj->dslots[-1] = JS_INITIAL_NSLOTS + capacity;
} else {
map->freeslot = STOBJ_NSLOTS(obj);
scope->freeslot = STOBJ_NSLOTS(obj);
}
/* Create new properties pointing to existing values in dslots */
for (i = 0; i < capacity; i++) {
for (uint32 i = 0; i < capacity; i++) {
jsid id;
JSScopeProperty *sprop;
@ -1303,7 +1277,7 @@ js_MakeArraySlow(JSContext *cx, JSObject *obj)
continue;
}
sprop = js_AddScopeProperty(cx, (JSScope *)map, id, NULL, NULL,
sprop = js_AddScopeProperty(cx, scope, id, NULL, NULL,
i + JS_INITIAL_NSLOTS, JSPROP_ENUMERATE,
0, 0);
if (!sprop)
@ -1327,15 +1301,11 @@ js_MakeArraySlow(JSContext *cx, JSObject *obj)
obj->classword ^= (jsuword) &js_ArrayClass;
obj->classword |= (jsuword) &js_SlowArrayClass;
/* Swap in our new map. */
oldmap = obj->map;
obj->map = map;
array_destroyObjectMap(cx, oldmap);
obj->map = &scope->map;
return JS_TRUE;
out_bad:
js_DestroyObjectMap(cx, map);
out_bad:
js_DestroyScope(cx, scope);
return JS_FALSE;
}
@ -3387,9 +3357,9 @@ js_NewEmptyArray(JSContext* cx, JSObject* proto)
if (!obj)
return NULL;
JSClass* clasp = &js_ArrayClass;
obj->classword = jsuword(clasp);
/* Initialize all fields of JSObject. */
obj->map = const_cast<JSObjectMap *>(&SharedArrayMap);
obj->classword = jsuword(&js_ArrayClass);
obj->fslots[JSSLOT_PROTO] = OBJECT_TO_JSVAL(proto);
obj->fslots[JSSLOT_PARENT] = proto->fslots[JSSLOT_PARENT];
@ -3397,11 +3367,6 @@ js_NewEmptyArray(JSContext* cx, JSObject* proto)
obj->fslots[JSSLOT_ARRAY_COUNT] = 0;
for (unsigned i = JSSLOT_ARRAY_COUNT + 1; i != JS_INITIAL_NSLOTS; ++i)
obj->fslots[i] = JSVAL_VOID;
JSObjectOps* ops = clasp->getObjectOps(cx, clasp);
obj->map = ops->newObjectMap(cx, 1, ops, clasp, obj);
if (!obj->map)
return NULL;
obj->dslots = NULL;
return obj;
}

View File

@ -258,10 +258,10 @@ js_AddProperty(JSContext* cx, JSObject* obj, JSScopeProperty* sprop)
}
slot = sprop->slot;
if (!scope->table && sprop->parent == scope->lastProp && slot == scope->map.freeslot) {
if (!scope->table && sprop->parent == scope->lastProp && slot == scope->freeslot) {
if (slot < STOBJ_NSLOTS(obj) && !OBJ_GET_CLASS(cx, obj)->reserveSlots) {
JS_ASSERT(JSVAL_IS_VOID(STOBJ_GET_SLOT(obj, scope->map.freeslot)));
++scope->map.freeslot;
JS_ASSERT(JSVAL_IS_VOID(STOBJ_GET_SLOT(obj, scope->freeslot)));
++scope->freeslot;
} else {
if (!js_AllocSlot(cx, obj, &slot))
goto exit_trace;
@ -398,26 +398,27 @@ js_Arguments(JSContext* cx)
JS_DEFINE_CALLINFO_1(extern, OBJECT, js_Arguments, CONTEXT, 0, 0)
JSObject* FASTCALL
js_NewNullClosure(JSContext* cx, JSObject* funobj, JSObject* proto, JSObject *parent)
js_NewNullClosure(JSContext* cx, JSObject* funobj, JSObject* proto, JSObject* parent)
{
JS_ASSERT(HAS_FUNCTION_CLASS(funobj));
JS_ASSERT(HAS_FUNCTION_CLASS(proto));
JS_ASSERT(JS_ON_TRACE(cx));
JSFunction *fun = (JSFunction*) funobj;
JS_ASSERT(GET_FUNCTION_PRIVATE(cx, funobj) == fun);
JS_ASSERT(JS_ON_TRACE(cx));
JSObject* closure = (JSObject*) js_NewGCThing(cx, GCX_OBJECT, sizeof(JSObject));
if (!closure)
return NULL;
js_HoldScope(OBJ_SCOPE(proto));
closure->map = proto->map;
closure->classword = jsuword(&js_FunctionClass);
closure->fslots[JSSLOT_PROTO] = OBJECT_TO_JSVAL(proto);
closure->fslots[JSSLOT_PARENT] = OBJECT_TO_JSVAL(parent);
closure->fslots[JSSLOT_PRIVATE] = PRIVATE_TO_JSVAL(fun);
for (unsigned i = JSSLOT_PRIVATE + 1; i != JS_INITIAL_NSLOTS; ++i)
closure->fslots[i] = JSVAL_VOID;
closure->map = js_HoldObjectMap(cx, proto->map);
closure->dslots = NULL;
return closure;
}

View File

@ -1821,7 +1821,7 @@ EmitEnterBlock(JSContext *cx, JSParseNode *pn, JSCodeGenerator *cg)
#endif
}
blockObj->map->freeslot = JSSLOT_FREE(&js_BlockClass);
OBJ_SCOPE(blockObj)->freeslot = JSSLOT_FREE(&js_BlockClass);
js_ReallocSlots(cx, blockObj, JSSLOT_FREE(&js_BlockClass), JS_TRUE);
return true;
}

View File

@ -718,8 +718,8 @@ js_PutCallObject(JSContext *cx, JSStackFrame *fp)
memcpy(callobj->dslots, fp->argv, fun->nargs * sizeof(jsval));
memcpy(callobj->dslots + fun->nargs, fp->slots,
fun->u.i.nvars * sizeof(jsval));
if (scope->object == callobj && n > scope->map.freeslot)
scope->map.freeslot = n;
if (scope->object == callobj && n > scope->freeslot)
scope->freeslot = n;
}
JS_UNLOCK_SCOPE(cx, scope);
}

View File

@ -4164,7 +4164,7 @@ js_Interpret(JSContext *cx)
ASSERT_VALID_PROPERTY_CACHE_HIT(0, obj, obj2, entry);
if (obj == obj2 && PCVAL_IS_SLOT(entry->vword)) {
slot = PCVAL_TO_SLOT(entry->vword);
JS_ASSERT(slot < obj->map->freeslot);
JS_ASSERT(slot < OBJ_SCOPE(obj)->freeslot);
rval = LOCKED_OBJ_GET_SLOT(obj, slot);
if (JS_LIKELY(CAN_DO_FAST_INC_DEC(rval))) {
rtmp = rval;
@ -4420,7 +4420,7 @@ js_Interpret(JSContext *cx)
rval = PCVAL_OBJECT_TO_JSVAL(entry->vword);
} else if (PCVAL_IS_SLOT(entry->vword)) {
slot = PCVAL_TO_SLOT(entry->vword);
JS_ASSERT(slot < obj2->map->freeslot);
JS_ASSERT(slot < OBJ_SCOPE(obj2)->freeslot);
rval = LOCKED_OBJ_GET_SLOT(obj2, slot);
} else {
JS_ASSERT(PCVAL_IS_SPROP(entry->vword));
@ -4511,7 +4511,7 @@ js_Interpret(JSContext *cx)
rval = PCVAL_OBJECT_TO_JSVAL(entry->vword);
} else if (PCVAL_IS_SLOT(entry->vword)) {
slot = PCVAL_TO_SLOT(entry->vword);
JS_ASSERT(slot < obj2->map->freeslot);
JS_ASSERT(slot < OBJ_SCOPE(obj2)->freeslot);
rval = LOCKED_OBJ_GET_SLOT(obj2, slot);
} else {
JS_ASSERT(PCVAL_IS_SPROP(entry->vword));
@ -4656,7 +4656,7 @@ js_Interpret(JSContext *cx)
if (checkForAdd &&
SPROP_HAS_STUB_SETTER(sprop) &&
(slot = sprop->slot) == scope->map.freeslot) {
(slot = sprop->slot) == scope->freeslot) {
/*
* Fast path: adding a plain old property that
* was once at the frontier of the property
@ -4681,7 +4681,7 @@ js_Interpret(JSContext *cx)
*/
if (slot < STOBJ_NSLOTS(obj) &&
!OBJ_GET_CLASS(cx, obj)->reserveSlots) {
++scope->map.freeslot;
++scope->freeslot;
} else {
if (!js_AllocSlot(cx, obj, &slot)) {
JS_UNLOCK_SCOPE(cx, scope);
@ -5262,7 +5262,7 @@ js_Interpret(JSContext *cx)
if (PCVAL_IS_SLOT(entry->vword)) {
slot = PCVAL_TO_SLOT(entry->vword);
JS_ASSERT(slot < obj2->map->freeslot);
JS_ASSERT(slot < OBJ_SCOPE(obj2)->freeslot);
rval = LOCKED_OBJ_GET_SLOT(obj2, slot);
JS_UNLOCK_OBJ(cx, obj2);
goto do_push_rval;
@ -5742,7 +5742,7 @@ js_Interpret(JSContext *cx)
index = GET_UINT16(regs.pc);
JS_ASSERT(JS_INITIAL_NSLOTS + index < jsatomid(obj->dslots[-1]));
JS_ASSERT_IF(OBJ_SCOPE(obj)->object == obj,
JS_INITIAL_NSLOTS + index < obj->map->freeslot);
JS_INITIAL_NSLOTS + index < OBJ_SCOPE(obj)->freeslot);
PUSH_OPND(obj->dslots[index]);
if (op == JSOP_CALLDSLOT)
@ -6371,9 +6371,9 @@ js_Interpret(JSContext *cx)
!SCOPE_HAS_PROPERTY(scope, sprop));
slot = sprop->slot;
JS_ASSERT(slot == scope->map.freeslot);
JS_ASSERT(slot == scope->freeslot);
if (slot < STOBJ_NSLOTS(obj)) {
++scope->map.freeslot;
++scope->freeslot;
} else {
if (!js_AllocSlot(cx, obj, &slot)) {
JS_UNLOCK_SCOPE(cx, scope);

View File

@ -57,11 +57,6 @@
#include "jsscope.h"
#include "jsstr.h"
/*
* Check that we can cast the data after JSObjectMap as JSTitle.
*/
JS_STATIC_ASSERT(offsetof(JSScope, title) == sizeof(JSObjectMap));
#define ReadWord(W) (W)
/* Implement NativeCompareAndSwap. */
@ -456,7 +451,6 @@ ShareTitle(JSContext *cx, JSTitle *title)
static void
FinishSharingTitle(JSContext *cx, JSTitle *title)
{
JSObjectMap *map;
JSScope *scope;
JSObject *obj;
uint32 nslots, i;
@ -464,14 +458,10 @@ FinishSharingTitle(JSContext *cx, JSTitle *title)
js_InitLock(&title->lock);
title->u.count = 0; /* NULL may not pun as 0 */
map = TITLE_TO_MAP(title);
if (!MAP_IS_NATIVE(map))
return;
scope = (JSScope *)map;
scope = TITLE_TO_SCOPE(title);
obj = scope->object;
if (obj) {
nslots = scope->map.freeslot;
nslots = scope->freeslot;
for (i = 0; i != nslots; ++i) {
v = STOBJ_GET_SLOT(obj, i);
if (JSVAL_IS_STRING(v) &&
@ -617,9 +607,9 @@ ClaimTitle(JSTitle *title, JSContext *cx)
* non-null test, and avoid double-insertion bugs.
*/
if (!title->u.link) {
js_HoldScope(TITLE_TO_SCOPE(title));
title->u.link = rt->titleSharingTodo;
rt->titleSharingTodo = title;
js_HoldObjectMap(cx, TITLE_TO_MAP(title));
}
/*
@ -693,13 +683,13 @@ js_ShareWaitingTitles(JSContext *cx)
title->u.link = NULL; /* null u.link for sanity ASAP */
/*
* If js_DropObjectMap returns null, we held the last ref to scope.
* The waiting thread(s) must have been killed, after which the GC
* If js_DropScope returns false, we held the last ref to scope. The
* waiting thread(s) must have been killed, after which the GC
* collected the object that held this scope. Unlikely, because it
* requires that the GC ran (e.g., from an operation callback)
* during this request, but possible.
*/
if (js_DropObjectMap(cx, TITLE_TO_MAP(title), NULL)) {
if (js_DropScope(cx, TITLE_TO_SCOPE(title), NULL)) {
FinishSharingTitle(cx, title); /* set ownercx = NULL */
shared = true;
}
@ -740,7 +730,7 @@ js_GetSlotThreadSafe(JSContext *cx, JSObject *obj, uint32 slot)
scope = OBJ_SCOPE(obj);
title = &scope->title;
JS_ASSERT(title->ownercx != cx);
JS_ASSERT(slot < obj->map->freeslot);
JS_ASSERT(slot < scope->freeslot);
/*
* Avoid locking if called from the GC. Also avoid locking an object
@ -835,7 +825,7 @@ js_SetSlotThreadSafe(JSContext *cx, JSObject *obj, uint32 slot, jsval v)
scope = OBJ_SCOPE(obj);
title = &scope->title;
JS_ASSERT(title->ownercx != cx);
JS_ASSERT(slot < obj->map->freeslot);
JS_ASSERT(slot < scope->freeslot);
/*
* Avoid locking if called from the GC. Also avoid locking an object
@ -1478,9 +1468,7 @@ js_IsRuntimeLocked(JSRuntime *rt)
JSBool
js_IsObjLocked(JSContext *cx, JSObject *obj)
{
JSScope *scope = OBJ_SCOPE(obj);
return MAP_IS_NATIVE(&scope->map) && js_IsTitleLocked(cx, &scope->title);
return js_IsTitleLocked(cx, &OBJ_SCOPE(obj)->title);
}
JSBool

View File

@ -103,14 +103,10 @@ struct JSTitle {
};
/*
* Title structures must be immediately preceded by JSObjectMap structures for
* maps that use titles for threadsafety. This is enforced by assertion in
* jsscope.h; see bug 408416 for future remedies to this somewhat fragile
* architecture.
* Title structure is always allocated as a field of JSScope.
*/
#define TITLE_TO_MAP(title) \
((JSObjectMap *)((char *)(title) - sizeof(JSObjectMap)))
#define TITLE_TO_SCOPE(title) \
((JSScope *)((uint8 *) (title) - offsetof(JSScope, title)))
/*
* Atomic increment and decrement for a reference counter, given jsrefcount *p.

View File

@ -102,7 +102,7 @@ js_DropProperty(JSContext *cx, JSObject *obj, JSProperty *prop);
#endif
JS_FRIEND_DATA(JSObjectOps) js_ObjectOps = {
js_NewObjectMap, js_DestroyObjectMap,
NULL,
js_LookupProperty, js_DefineProperty,
js_GetProperty, js_SetProperty,
js_GetAttributes, js_SetAttributes,
@ -2033,9 +2033,12 @@ js_Object(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
}
static inline bool
CreateMapForObject(JSContext* cx, JSObject* obj, JSObject* proto, JSObjectOps* ops)
InitScopeForObject(JSContext* cx, JSObject* obj, JSObject* proto,
JSObjectOps* ops)
{
JSObjectMap* map;
JS_ASSERT(OPS_IS_NATIVE(ops));
JS_ASSERT(proto == OBJ_GET_PROTO(cx, obj));
JSClass* protoclasp;
JSClass* clasp = OBJ_GET_CLASS(cx, obj);
@ -2048,33 +2051,36 @@ CreateMapForObject(JSContext* cx, JSObject* obj, JSObject* proto, JSObjectOps* o
* object classes must have the same (null or not) reserveSlots hook.
*/
if (proto &&
((map = proto->map)->ops == ops &&
((protoclasp = OBJ_GET_CLASS(cx, proto)) == clasp ||
(!((protoclasp->flags ^ clasp->flags) &
(JSCLASS_HAS_PRIVATE |
(JSCLASS_RESERVED_SLOTS_MASK << JSCLASS_RESERVED_SLOTS_SHIFT))) &&
protoclasp->reserveSlots == clasp->reserveSlots))))
proto->map->ops == ops &&
((protoclasp = OBJ_GET_CLASS(cx, proto)) == clasp ||
(!((protoclasp->flags ^ clasp->flags) &
(JSCLASS_HAS_PRIVATE |
(JSCLASS_RESERVED_SLOTS_MASK << JSCLASS_RESERVED_SLOTS_SHIFT))) &&
protoclasp->reserveSlots == clasp->reserveSlots)))
{
/* Share the given prototype's map. */
obj->map = js_HoldObjectMap(cx, map);
js_HoldScope(OBJ_SCOPE(proto));
obj->map = proto->map;
return true;
}
map = ops->newObjectMap(cx, 1, ops, clasp, obj);
if (!map)
return false;
obj->map = map;
JSScope *scope = js_NewScope(cx, ops, clasp, obj);
if (!scope)
goto bad;
/* Let ops->newObjectMap set freeslot so as to reserve slots. */
uint32 nslots = map->freeslot;
JS_ASSERT(nslots >= JSSLOT_PRIVATE);
if (nslots > JS_INITIAL_NSLOTS &&
!js_ReallocSlots(cx, obj, nslots, JS_TRUE)) {
js_DropObjectMap(cx, map, obj);
return false;
/* Let js_NewScope set freeslot so as to reserve slots. */
JS_ASSERT(scope->freeslot >= JSSLOT_PRIVATE);
if (scope->freeslot > JS_INITIAL_NSLOTS &&
!js_ReallocSlots(cx, obj, scope->freeslot, JS_TRUE)) {
js_DestroyScope(cx, scope);
goto bad;
}
obj->map = &scope->map;
return true;
bad:
/* Ensure that the map field is initialized for GC. */
obj->map = NULL;
return false;
}
#ifdef JS_TRACER
@ -2093,11 +2099,8 @@ NewNativeObject(JSContext* cx, JSClass* clasp, JSObject* proto, JSObject *parent
for (unsigned i = JSSLOT_PRIVATE; i < JS_INITIAL_NSLOTS; ++i)
obj->fslots[i] = JSVAL_VOID;
if (!CreateMapForObject(cx, obj, proto, &js_ObjectOps))
return NULL;
obj->dslots = NULL;
return obj;
return InitScopeForObject(cx, obj, proto, &js_ObjectOps) ? obj : NULL;
}
JSObject* FASTCALL
@ -2363,7 +2366,7 @@ with_ThisObject(JSContext *cx, JSObject *obj)
}
JS_FRIEND_DATA(JSObjectOps) js_WithObjectOps = {
js_NewObjectMap, js_DestroyObjectMap,
NULL,
with_LookupProperty, js_DefineProperty,
with_GetProperty, with_SetProperty,
with_GetAttributes, with_SetAttributes,
@ -2455,7 +2458,7 @@ js_PutBlockObject(JSContext *cx, JSBool normalUnwind)
/*
* Block objects should never be exposed to scripts. Thus the clone should
* not own the property map and rather always share it with the prototype
* object. This allows to skip updating OBJ_SCOPE(obj)->map.freeslot after
* object. This allows us to skip updating OBJ_SCOPE(obj)->freeslot after
* we copy the stack slots into reserved slots.
*/
JS_ASSERT(OBJ_SCOPE(obj)->object != obj);
@ -2845,50 +2848,6 @@ bad:
goto out;
}
void
js_InitObjectMap(JSObjectMap *map, jsrefcount nrefs, JSObjectOps *ops,
JSClass *clasp)
{
map->nrefs = nrefs;
map->ops = ops;
map->freeslot = JSSLOT_FREE(clasp);
}
JSObjectMap *
js_NewObjectMap(JSContext *cx, jsrefcount nrefs, JSObjectOps *ops,
JSClass *clasp, JSObject *obj)
{
return (JSObjectMap *) js_NewScope(cx, nrefs, ops, clasp, obj);
}
void
js_DestroyObjectMap(JSContext *cx, JSObjectMap *map)
{
js_DestroyScope(cx, (JSScope *)map);
}
JSObjectMap *
js_HoldObjectMap(JSContext *cx, JSObjectMap *map)
{
JS_ASSERT(map->nrefs >= 0);
JS_ATOMIC_INCREMENT(&map->nrefs);
return map;
}
JSObjectMap *
js_DropObjectMap(JSContext *cx, JSObjectMap *map, JSObject *obj)
{
JS_ASSERT(map->nrefs > 0);
JS_ATOMIC_DECREMENT(&map->nrefs);
if (map->nrefs == 0) {
map->ops->destroyObjectMap(cx, map);
return NULL;
}
if (MAP_IS_NATIVE(map) && ((JSScope *)map)->object == obj)
((JSScope *)map)->object = NULL;
return map;
}
static void
FreeSlots(JSContext *cx, JSObject *obj)
{
@ -3072,11 +3031,6 @@ JSObject *
js_NewObjectWithGivenProto(JSContext *cx, JSClass *clasp, JSObject *proto,
JSObject *parent, uintN objectSize)
{
JSObject *obj;
JSObjectOps *ops;
uint32 i;
JSTempValueRooter tvr;
#ifdef INCLUDE_MOZILLA_DTRACE
if (JAVASCRIPT_OBJECT_CREATE_START_ENABLED())
jsdtrace_object_create_start(cx->fp, clasp);
@ -3097,16 +3051,18 @@ js_NewObjectWithGivenProto(JSContext *cx, JSClass *clasp, JSObject *proto,
JS_ASSERT_IF(clasp->flags & JSCLASS_IS_EXTENDED,
((JSExtendedClass *)clasp)->equality);
/* Always call the class's getObjectOps hook if it has one. */
JSObjectOps *ops = clasp->getObjectOps
? clasp->getObjectOps(cx, clasp)
: &js_ObjectOps;
/*
* Allocate an object from the GC heap and initialize all its fields before
* doing any operation that can potentially trigger GC.
*/
obj = (JSObject *) js_NewGCThing(cx, GCX_OBJECT, objectSize);
JSObject *obj = (JSObject *) js_NewGCThing(cx, GCX_OBJECT, objectSize);
if (!obj)
goto earlybad;
obj->map = NULL;
obj->dslots = NULL;
goto out;
/*
* Set the class slot with the initial value of the system and delegate
@ -3117,55 +3073,54 @@ js_NewObjectWithGivenProto(JSContext *cx, JSClass *clasp, JSObject *proto,
JS_ASSERT(!STOBJ_IS_DELEGATE(obj));
JS_ASSERT(!STOBJ_IS_SYSTEM(obj));
/* Set the proto and parent properties. */
STOBJ_SET_PROTO(obj, proto);
STOBJ_SET_PARENT(obj, parent);
obj->fslots[JSSLOT_PROTO] = OBJECT_TO_JSVAL(proto);
/*
* Default parent to the parent of the prototype, which was set from
* the parent of the prototype's constructor.
*/
obj->fslots[JSSLOT_PARENT] = OBJECT_TO_JSVAL((!parent && proto)
? OBJ_GET_PARENT(cx, proto)
: parent);
/* Initialize the remaining fixed slots. */
for (i = JSSLOT_PRIVATE; i < JS_INITIAL_NSLOTS; ++i)
for (uint32 i = JSSLOT_PRIVATE; i < JS_INITIAL_NSLOTS; ++i)
obj->fslots[i] = JSVAL_VOID;
obj->dslots = NULL;
if (OPS_IS_NATIVE(ops)) {
if (!InitScopeForObject(cx, obj, proto, ops)) {
obj = NULL;
goto out;
}
} else {
JS_ASSERT(ops->objectMap->ops == ops);
obj->map = const_cast<JSObjectMap *>(ops->objectMap);
}
#ifdef DEBUG
memset((uint8 *) obj + sizeof(JSObject), JS_FREE_PATTERN,
objectSize - sizeof(JSObject));
#endif
/*
* Root obj to prevent it from being collected out from under this call to
* js_NewObject. There's a possibilty of GC under the objectHook call-out
* further below.
*/
JS_PUSH_TEMP_ROOT_OBJECT(cx, obj, &tvr);
/* Always call the class's getObjectOps hook if it has one. */
ops = clasp->getObjectOps
? clasp->getObjectOps(cx, clasp)
: &js_ObjectOps;
/*
* Default parent to the parent of the prototype, which was set from
* the parent of the prototype's constructor.
*/
if (proto && !parent)
STOBJ_SET_PARENT(obj, OBJ_GET_PARENT(cx, proto));
if (!CreateMapForObject(cx, obj, proto, ops))
goto bad;
/* Check that the newborn root still holds the object. */
JS_ASSERT_IF(!cx->localRootStack, cx->weakRoots.newborn[GCX_OBJECT] == obj);
/*
* Do not call debug hooks on trace, because we might be in a non-_FAIL
* builtin. See bug 481444.
*/
if (cx->debugHooks->objectHook && !JS_ON_TRACE(cx)) {
JSAutoTempValueRooter tvr(cx, obj);
JS_KEEP_ATOMS(cx->runtime);
cx->debugHooks->objectHook(cx, obj, JS_TRUE,
cx->debugHooks->objectHookData);
JS_UNKEEP_ATOMS(cx->runtime);
cx->weakRoots.newborn[GCX_OBJECT] = obj;
}
out:
JS_POP_TEMP_ROOT(cx, &tvr);
cx->weakRoots.newborn[GCX_OBJECT] = obj;
#ifdef INCLUDE_MOZILLA_DTRACE
if (JAVASCRIPT_OBJECT_CREATE_ENABLED())
jsdtrace_object_create(cx, clasp, obj);
@ -3173,28 +3128,21 @@ out:
jsdtrace_object_create_done(cx->fp, clasp);
#endif
return obj;
bad:
obj = NULL;
goto out;
earlybad:
#ifdef INCLUDE_MOZILLA_DTRACE
if (JAVASCRIPT_OBJECT_CREATE_ENABLED())
jsdtrace_object_create(cx, clasp, NULL);
if (JAVASCRIPT_OBJECT_CREATE_DONE_ENABLED())
jsdtrace_object_create_done(cx->fp, clasp);
#endif
return NULL;
}
JSObject*
js_NewNativeObject(JSContext *cx, JSClass *clasp, JSObject *proto, uint32 slot)
{
JS_ASSERT(!clasp->getObjectOps);
JS_ASSERT(proto->map->ops == &js_ObjectOps);
JS_ASSERT(OBJ_GET_CLASS(cx, proto) == clasp);
JSObject* obj = (JSObject*) js_NewGCThing(cx, GCX_OBJECT, sizeof(JSObject));
if (!obj)
return NULL;
js_HoldScope(OBJ_SCOPE(proto));
obj->map = proto->map;
obj->classword = jsuword(clasp);
obj->fslots[JSSLOT_PROTO] = OBJECT_TO_JSVAL(proto);
obj->fslots[JSSLOT_PARENT] = proto->fslots[JSSLOT_PARENT];
@ -3203,9 +3151,6 @@ js_NewNativeObject(JSContext *cx, JSClass *clasp, JSObject *proto, uint32 slot)
while (slot < JS_INITIAL_NSLOTS)
obj->fslots[slot++] = JSVAL_VOID;
JS_ASSERT(!clasp->getObjectOps);
JS_ASSERT(proto->map->ops == &js_ObjectOps);
obj->map = js_HoldObjectMap(cx, proto->map);
obj->dslots = NULL;
return obj;
}
@ -3456,11 +3401,8 @@ bad:
void
js_FinalizeObject(JSContext *cx, JSObject *obj)
{
JSObjectMap *map;
/* Cope with stillborn objects that have no map. */
map = obj->map;
if (!map)
if (!obj->map)
return;
if (cx->debugHooks->objectHook) {
@ -3476,8 +3418,8 @@ js_FinalizeObject(JSContext *cx, JSObject *obj)
jsdtrace_object_finalize(obj);
#endif
/* Drop map and free slots. */
js_DropObjectMap(cx, map, obj);
if (OBJ_IS_NATIVE(obj))
js_DropScope(cx, OBJ_SCOPE(obj), obj);
FreeSlots(cx, obj);
}
@ -3486,38 +3428,35 @@ js_FinalizeObject(JSContext *cx, JSObject *obj)
JSBool
js_AllocSlot(JSContext *cx, JSObject *obj, uint32 *slotp)
{
JSObjectMap *map;
JSClass *clasp;
JS_ASSERT(OBJ_IS_NATIVE(obj));
map = obj->map;
JS_ASSERT(!MAP_IS_NATIVE(map) || ((JSScope *)map)->object == obj);
clasp = LOCKED_OBJ_GET_CLASS(obj);
if (map->freeslot == JSSLOT_FREE(clasp) && clasp->reserveSlots) {
/* Adjust map->freeslot to include computed reserved slots, if any. */
map->freeslot += clasp->reserveSlots(cx, obj);
JSScope *scope = OBJ_SCOPE(obj);
JSClass *clasp = LOCKED_OBJ_GET_CLASS(obj);
if (scope->freeslot == JSSLOT_FREE(clasp) && clasp->reserveSlots) {
/* Adjust scope->freeslot to include computed reserved slots, if any. */
scope->freeslot += clasp->reserveSlots(cx, obj);
}
if (map->freeslot >= STOBJ_NSLOTS(obj) &&
!js_ReallocSlots(cx, obj, map->freeslot + 1, JS_FALSE)) {
if (scope->freeslot >= STOBJ_NSLOTS(obj) &&
!js_ReallocSlots(cx, obj, scope->freeslot + 1, JS_FALSE)) {
return JS_FALSE;
}
/* js_ReallocSlots or js_FreeSlot should set the free slots to void. */
JS_ASSERT(JSVAL_IS_VOID(STOBJ_GET_SLOT(obj, map->freeslot)));
*slotp = map->freeslot++;
JS_ASSERT(JSVAL_IS_VOID(STOBJ_GET_SLOT(obj, scope->freeslot)));
*slotp = scope->freeslot++;
return JS_TRUE;
}
void
js_FreeSlot(JSContext *cx, JSObject *obj, uint32 slot)
{
JSObjectMap *map;
JS_ASSERT(OBJ_IS_NATIVE(obj));
map = obj->map;
JS_ASSERT(!MAP_IS_NATIVE(map) || ((JSScope *)map)->object == obj);
JSScope *scope = OBJ_SCOPE(obj);
LOCKED_OBJ_SET_SLOT(obj, slot, JSVAL_VOID);
if (map->freeslot == slot + 1) {
map->freeslot = slot;
if (scope->freeslot == slot + 1) {
scope->freeslot = slot;
/* When shrinking, js_ReallocSlots always returns true. */
js_ReallocSlots(cx, obj, slot, JS_FALSE);
@ -3914,8 +3853,7 @@ js_LookupPropertyWithFlags(JSContext *cx, JSObject *obj, jsid id, uintN flags,
proto = OBJ_GET_PROTO(cx, proto)) {
protoIndex++;
}
scope = OBJ_SCOPE(obj2);
if (!MAP_IS_NATIVE(&scope->map)) {
if (!OBJ_IS_NATIVE(obj2)) {
/* Whoops, newresolve handed back a foreign obj2. */
JS_ASSERT(obj2 != obj);
ok = OBJ_LOOKUP_PROPERTY(cx, obj2, id, objp, propp);
@ -3931,6 +3869,7 @@ js_LookupPropertyWithFlags(JSContext *cx, JSObject *obj, jsid id, uintN flags,
* not on obj's proto chain. That last case is a
* "too bad!" case.
*/
scope = OBJ_SCOPE(obj2);
if (scope->object == obj2)
sprop = SCOPE_GET_PROPERTY(scope, id);
}
@ -3953,8 +3892,8 @@ js_LookupPropertyWithFlags(JSContext *cx, JSObject *obj, jsid id, uintN flags,
if (!ok)
goto cleanup;
JS_LOCK_OBJ(cx, obj);
JS_ASSERT(OBJ_IS_NATIVE(obj));
scope = OBJ_SCOPE(obj);
JS_ASSERT(MAP_IS_NATIVE(&scope->map));
if (scope->object == obj)
sprop = SCOPE_GET_PROPERTY(scope, id);
}
@ -5842,8 +5781,8 @@ js_TraceObject(JSTracer *trc, JSObject *obj)
* above.
*/
nslots = STOBJ_NSLOTS(obj);
if (scope->object == obj && scope->map.freeslot < nslots)
nslots = scope->map.freeslot;
if (scope->object == obj && scope->freeslot < nslots)
nslots = scope->freeslot;
for (i = 0; i != nslots; ++i) {
v = STOBJ_GET_SLOT(obj, i);
@ -5877,7 +5816,7 @@ js_Clear(JSContext *cx, JSObject *obj)
n = JSSLOT_FREE(LOCKED_OBJ_GET_CLASS(obj));
while (--i >= n)
STOBJ_SET_SLOT(obj, i, JSVAL_VOID);
scope->map.freeslot = n;
scope->freeslot = n;
}
JS_UNLOCK_OBJ(cx, obj);
}
@ -5926,8 +5865,8 @@ js_SetRequiredSlot(JSContext *cx, JSObject *obj, uint32 slot, jsval v)
}
/* Whether or not we grew nslots, we may need to advance freeslot. */
if (scope->object == obj && slot >= scope->map.freeslot)
scope->map.freeslot = slot + 1;
if (scope->object == obj && slot >= scope->freeslot)
scope->freeslot = slot + 1;
STOBJ_SET_SLOT(obj, slot, v);
GC_POKE(cx, JS_NULL);
@ -6131,7 +6070,7 @@ js_DumpObject(JSObject *obj)
uint32 i, slots;
JSClass *clasp;
jsuint reservedEnd;
JSBool sharesScope = JS_FALSE;
bool sharesScope = false;
fprintf(stderr, "object %p\n", (void *) obj);
clasp = STOBJ_GET_CLASS(obj);
@ -6186,7 +6125,9 @@ js_DumpObject(JSObject *obj)
if (clasp->flags & JSCLASS_HAS_PRIVATE)
reservedEnd++;
reservedEnd += JSCLASS_RESERVED_SLOTS(clasp);
slots = sharesScope ? reservedEnd : obj->map->freeslot;
slots = (OBJ_IS_NATIVE(obj) && !sharesScope)
? OBJ_SCOPE(obj)->freeslot
: STOBJ_NSLOTS(obj);
for (i = 0; i < slots; i++) {
fprintf(stderr, " %3d ", i);
if (i == JSSLOT_PRIVATE && (clasp->flags & JSCLASS_HAS_PRIVATE)) {

View File

@ -56,9 +56,14 @@ JS_BEGIN_EXTERN_C
/* For detailed comments on these function pointer types, see jsprvtd.h. */
struct JSObjectOps {
/*
* Custom shared object map for non-native objects. For native objects
* this should be null indicating, that JSObject.map is an instance of
* JSScope.
*/
const JSObjectMap *objectMap;
/* Mandatory non-null function pointer members. */
JSNewObjectMapOp newObjectMap;
JSObjectMapOp destroyObjectMap;
JSLookupPropOp lookupProperty;
JSDefinePropOp defineProperty;
JSPropertyIdOp getProperty;
@ -83,9 +88,7 @@ struct JSObjectOps {
};
struct JSObjectMap {
jsrefcount nrefs; /* count of all referencing objects */
JSObjectOps *ops; /* high level object operation vtable */
uint32 freeslot; /* index of next free slot in object */
};
/* Shorthand macros for frequently-made calls. */
@ -206,8 +209,8 @@ struct JSObject {
/*
* STOBJ prefix means Single Threaded Object. Use the following fast macros to
* directly manipulate slots in obj when only one thread can access obj and
* when obj->map->freeslot can be inconsistent with slots.
* directly manipulate slots in obj when only one thread can access obj, or
* when accessing read-only slots within JS_INITIAL_NSLOTS.
*/
#define STOBJ_NSLOTS(obj) \
@ -266,7 +269,7 @@ STOBJ_GET_CLASS(const JSObject* obj)
JSVAL_TO_PRIVATE(STOBJ_GET_SLOT(obj, JSSLOT_PRIVATE)))
#define OBJ_CHECK_SLOT(obj,slot) \
JS_ASSERT(slot < (obj)->map->freeslot)
JS_ASSERT_IF(OBJ_IS_NATIVE(obj), slot < OBJ_SCOPE(obj)->freeslot)
#define LOCKED_OBJ_GET_SLOT(obj,slot) \
(OBJ_CHECK_SLOT(obj, slot), STOBJ_GET_SLOT(obj, slot))
@ -368,12 +371,14 @@ STOBJ_GET_CLASS(const JSObject* obj)
#define OBJ_GET_CLASS(cx,obj) STOBJ_GET_CLASS(obj)
#define OBJ_GET_PRIVATE(cx,obj) STOBJ_GET_PRIVATE(obj)
/* Test whether a map or object is native. */
#define MAP_IS_NATIVE(map) \
JS_LIKELY((map)->ops == &js_ObjectOps || \
(map)->ops->newObjectMap == js_ObjectOps.newObjectMap)
/*
* Test whether the object is native. FIXME bug 492938: consider how it would
* affect the performance to do just the !ops->objectMap check.
*/
#define OPS_IS_NATIVE(ops) \
JS_LIKELY((ops) == &js_ObjectOps || !(ops)->objectMap)
#define OBJ_IS_NATIVE(obj) MAP_IS_NATIVE((obj)->map)
#define OBJ_IS_NATIVE(obj) OPS_IS_NATIVE((obj)->map->ops)
extern JS_FRIEND_DATA(JSObjectOps) js_ObjectOps;
extern JS_FRIEND_DATA(JSObjectOps) js_WithObjectOps;
@ -502,23 +507,6 @@ extern const char js_defineSetter_str[];
extern const char js_lookupGetter_str[];
extern const char js_lookupSetter_str[];
extern void
js_InitObjectMap(JSObjectMap *map, jsrefcount nrefs, JSObjectOps *ops,
JSClass *clasp);
extern JSObjectMap *
js_NewObjectMap(JSContext *cx, jsrefcount nrefs, JSObjectOps *ops,
JSClass *clasp, JSObject *obj);
extern void
js_DestroyObjectMap(JSContext *cx, JSObjectMap *map);
extern JSObjectMap *
js_HoldObjectMap(JSContext *cx, JSObjectMap *map);
extern JSObjectMap *
js_DropObjectMap(JSContext *cx, JSObjectMap *map, JSObject *obj);
extern JSBool
js_GetClassId(JSContext *cx, JSClass *clasp, jsid *idp);

View File

@ -2973,7 +2973,7 @@ BindLet(JSContext *cx, BindData *data, JSAtom *atom, JSTreeContext *tc)
!js_ReallocSlots(cx, blockObj, slot + 1, JS_FALSE)) {
return JS_FALSE;
}
blockObj->map->freeslot = slot + 1;
OBJ_SCOPE(blockObj)->freeslot = slot + 1;
STOBJ_SET_SLOT(blockObj, slot, PRIVATE_TO_JSVAL(pn));
return JS_TRUE;
}

View File

@ -257,30 +257,6 @@ struct JSTempValueRooter {
/* JSObjectOps function pointer typedefs. */
/*
* Create a new subclass of JSObjectMap (see jsobj.h), with the nrefs and ops
* members initialized from the same-named parameters, and with the nslots and
* freeslot members initialized according to ops and clasp. Return null on
* error, non-null on success.
*
* JSObjectMaps are reference-counted by generic code in the engine. Usually,
* the nrefs parameter to JSObjectOps.newObjectMap will be 1, to count the ref
* returned to the caller on success. After a successful construction, some
* number of js_HoldObjectMap and js_DropObjectMap calls ensue. When nrefs
* reaches 0 due to a js_DropObjectMap call, JSObjectOps.destroyObjectMap will
* be called to dispose of the map.
*/
typedef JSObjectMap *
(* JSNewObjectMapOp)(JSContext *cx, jsrefcount nrefs, JSObjectOps *ops,
JSClass *clasp, JSObject *obj);
/*
* Generic type for an infallible JSObjectMap operation, used currently by
* JSObjectOps.destroyObjectMap.
*/
typedef void
(* JSObjectMapOp)(JSContext *cx, JSObjectMap *map);
/*
* Look for id in obj and its prototype chain, returning false on error or
* exception, true on success. On success, return null in *propp if id was

View File

@ -77,23 +77,23 @@ js_GetMutableScope(JSContext *cx, JSObject *obj)
* birth, and runtime clone of a block objects are never mutated.
*/
JS_ASSERT(STOBJ_GET_CLASS(obj) != &js_BlockClass);
newscope = js_NewScope(cx, 0, scope->map.ops, LOCKED_OBJ_GET_CLASS(obj),
obj);
newscope = js_NewScope(cx, scope->map.ops, LOCKED_OBJ_GET_CLASS(obj), obj);
if (!newscope)
return NULL;
JS_LOCK_SCOPE(cx, newscope);
obj->map = js_HoldObjectMap(cx, &newscope->map);
JS_ASSERT(newscope->map.freeslot == JSSLOT_FREE(STOBJ_GET_CLASS(obj)));
obj->map = &newscope->map;
JS_ASSERT(newscope->freeslot == JSSLOT_FREE(STOBJ_GET_CLASS(obj)));
clasp = STOBJ_GET_CLASS(obj);
if (clasp->reserveSlots) {
freeslot = JSSLOT_FREE(clasp) + clasp->reserveSlots(cx, obj);
if (freeslot > STOBJ_NSLOTS(obj))
freeslot = STOBJ_NSLOTS(obj);
if (newscope->map.freeslot < freeslot)
newscope->map.freeslot = freeslot;
if (newscope->freeslot < freeslot)
newscope->freeslot = freeslot;
}
scope = (JSScope *) js_DropObjectMap(cx, &scope->map, obj);
JS_TRANSFER_SCOPE_LOCK(cx, scope, newscope);
js_DropScope(cx, scope, obj);
return newscope;
}
@ -160,17 +160,19 @@ CreateScopeTable(JSContext *cx, JSScope *scope, JSBool report)
}
JSScope *
js_NewScope(JSContext *cx, jsrefcount nrefs, JSObjectOps *ops, JSClass *clasp,
JSObject *obj)
js_NewScope(JSContext *cx, JSObjectOps *ops, JSClass *clasp, JSObject *obj)
{
JSScope *scope;
JS_ASSERT(OPS_IS_NATIVE(ops));
JS_ASSERT(obj);
scope = (JSScope *) JS_malloc(cx, sizeof(JSScope));
JSScope *scope = (JSScope *) JS_malloc(cx, sizeof(JSScope));
if (!scope)
return NULL;
js_InitObjectMap(&scope->map, nrefs, ops, clasp);
scope->map.ops = ops;
scope->object = obj;
scope->nrefs = 1;
scope->freeslot = JSSLOT_FREE(clasp);
scope->flags = 0;
InitMinimalScope(cx, scope);
@ -203,6 +205,28 @@ js_DestroyScope(JSContext *cx, JSScope *scope)
JS_free(cx, scope);
}
void
js_HoldScope(JSScope *scope)
{
JS_ASSERT(scope->nrefs >= 0);
JS_ATOMIC_INCREMENT(&scope->nrefs);
}
JSBool
js_DropScope(JSContext *cx, JSScope *scope, JSObject *obj)
{
JS_ASSERT(scope->nrefs > 0);
JS_ATOMIC_DECREMENT(&scope->nrefs);
if (scope->nrefs == 0) {
js_DestroyScope(cx, scope);
return false;
}
if (scope->object == obj)
scope->object = NULL;
return true;
}
#ifdef JS_DUMP_PROPTREE_STATS
typedef struct JSScopeStats {
jsrefcount searches;

View File

@ -201,6 +201,8 @@ struct JSScope {
JSTitle title; /* lock state */
#endif
JSObject *object; /* object that owns this scope */
jsrefcount nrefs; /* count of all referencing objects */
uint32 freeslot; /* index of next free slot in object */
uint32 shape; /* property cache shape identifier */
uint8 flags; /* flags, see below */
int8 hashShift; /* multiplicative hash shift */
@ -213,7 +215,8 @@ struct JSScope {
#define JS_IS_SCOPE_LOCKED(cx, scope) JS_IS_TITLE_LOCKED(cx, &(scope)->title)
#define OBJ_SCOPE(obj) ((JSScope *)(obj)->map)
#define OBJ_SCOPE(obj) (JS_ASSERT(OBJ_IS_NATIVE(obj)), \
(JSScope *) (obj)->map)
#define OBJ_SHAPE(obj) (OBJ_SCOPE(obj)->shape)
/* By definition, hashShift = JS_DHASH_BITS - log2(capacity). */
@ -329,7 +332,7 @@ struct JSScopeProperty {
#define SPROP_INVALID_SLOT 0xffffffff
#define SLOT_IN_SCOPE(slot,scope) ((slot) < (scope)->map.freeslot)
#define SLOT_IN_SCOPE(slot,scope) ((slot) < (scope)->freeslot)
#define SPROP_HAS_VALID_SLOT(sprop,scope) SLOT_IN_SCOPE((sprop)->slot, scope)
#define SPROP_HAS_STUB_GETTER(sprop) (!(sprop)->getter)
@ -396,12 +399,17 @@ extern JSScope *
js_GetMutableScope(JSContext *cx, JSObject *obj);
extern JSScope *
js_NewScope(JSContext *cx, jsrefcount nrefs, JSObjectOps *ops, JSClass *clasp,
JSObject *obj);
js_NewScope(JSContext *cx, JSObjectOps *ops, JSClass *clasp, JSObject *obj);
extern void
js_DestroyScope(JSContext *cx, JSScope *scope);
extern void
js_HoldScope(JSScope *scope);
extern JSBool
js_DropScope(JSContext *cx, JSScope *scope, JSObject *obj);
extern JS_FRIEND_API(JSScopeProperty **)
js_SearchScope(JSScope *scope, jsid id, JSBool adding);

View File

@ -6301,21 +6301,25 @@ TraceRecorder::binary(LOpcode op)
return JSRS_STOP;
}
JS_STATIC_ASSERT(offsetof(JSObjectOps, newObjectMap) == 0);
JS_STATIC_ASSERT(offsetof(JSObjectOps, objectMap) == 0);
bool
TraceRecorder::map_is_native(JSObjectMap* map, LIns* map_ins, LIns*& ops_ins, size_t op_offset)
{
#define OP(ops) (*(JSObjectOp*) ((char*)(ops) + op_offset))
if (OP(map->ops) != OP(&js_ObjectOps))
return false;
JS_ASSERT(op_offset < sizeof(JSObjectOps));
JS_ASSERT(op_offset % sizeof(void *) == 0);
ops_ins = addName(lir->insLoad(LIR_ldp, map_ins, offsetof(JSObjectMap, ops)), "ops");
#define OP(ops) (*(void **) ((uint8 *) (ops) + op_offset))
void* ptr = OP(map->ops);
if (ptr != OP(&js_ObjectOps))
return false;
#undef OP
ops_ins = addName(lir->insLoad(LIR_ldp, map_ins, int(offsetof(JSObjectMap, ops))), "ops");
LIns* n = lir->insLoad(LIR_ldp, ops_ins, op_offset);
guard(true,
addName(lir->ins2(LIR_eq, n, INS_CONSTFUNPTR(OP(&js_ObjectOps))), "guard(native-map)"),
addName(lir->ins2(LIR_eq, n, INS_CONSTPTR(ptr)), "guard(native-map)"),
BRANCH_EXIT);
#undef OP
return true;
}
@ -6340,10 +6344,9 @@ TraceRecorder::test_property_cache(JSObject* obj, LIns* obj_ins, JSObject*& obj2
LIns* ops_ins;
// Interpreter calls to PROPERTY_CACHE_TEST guard on native object ops
// (newObjectMap == js_ObjectOps.newObjectMap) which is required to use
// native objects (those whose maps are scopes), or even more narrow
// conditions required because the cache miss case will call a particular
// object-op (js_GetProperty, js_SetProperty).
// which is required to use native objects (those whose maps are scopes),
// or even more narrow conditions required because the cache miss case
// will call a particular object-op (js_GetProperty, js_SetProperty).
//
// We parameterize using offsetof and guard on match against the hook at
// the given offset in js_ObjectOps. TraceRecorder::record_JSOP_SETPROP
@ -6354,7 +6357,7 @@ TraceRecorder::test_property_cache(JSObject* obj, LIns* obj_ins, JSObject*& obj2
// No need to guard native-ness of global object.
JS_ASSERT(OBJ_IS_NATIVE(globalObj));
if (aobj != globalObj) {
size_t op_offset = offsetof(JSObjectOps, newObjectMap);
size_t op_offset = offsetof(JSObjectOps, objectMap);
if (mode == JOF_PROP || mode == JOF_VARPROP) {
JS_ASSERT(!(format & JOF_SET));
op_offset = offsetof(JSObjectOps, getProperty);

View File

@ -4912,10 +4912,10 @@ xml_trace_vector(JSTracer *trc, JSXML **vec, uint32 len)
}
/*
* js_XMLObjectOps.newObjectMap == js_NewObjectMap, so XML objects appear to
* be native. Thus xml_lookupProperty must return a valid JSScopeProperty
* pointer parameter via *propp to signify "property found". Since the only
* call to xml_lookupProperty is via OBJ_LOOKUP_PROPERTY, and then only from
* js_XMLObjectOps.newObjectMap is null, so XML objects appear to be native.
* Thus xml_lookupProperty must return a valid JSScopeProperty pointer
* parameter via *propp to signify "property found". Since the only call to
* xml_lookupProperty is via OBJ_LOOKUP_PROPERTY, and then only from
* js_FindProperty (in jsobj.c, called from jsinterp.c) or from JSOP_IN case
* in the interpreter, the only time we add a JSScopeProperty here is when an
* unqualified name is being accessed or when "name in xml" is called.
@ -5428,9 +5428,9 @@ out:
return ok;
}
/* Use js_NewObjectMap so XML objects satisfy OBJ_IS_NATIVE tests. */
/* Use NULL for objectMap so XML objects satisfy OBJ_IS_NATIVE tests. */
JS_FRIEND_DATA(JSObjectOps) js_XMLObjectOps = {
js_NewObjectMap, js_DestroyObjectMap,
NULL,
xml_lookupProperty, xml_defineProperty,
xml_getProperty, xml_setProperty,
xml_getAttributes, xml_setAttributes,

View File

@ -404,10 +404,14 @@ JavaArray_checkAccess(JSContext *cx, JSObject *obj, jsid id,
}
}
extern JSObjectOps JavaArray_ops;
static const JSObjectMap JavaArrayMap = { &JavaArray_ops };
JSObjectOps JavaArray_ops = {
&JavaArrayMap, /* objectMap */
/* Mandatory non-null function pointer members. */
jsj_wrapper_newObjectMap, /* newObjectMap */
jsj_wrapper_destroyObjectMap, /* destroyObjectMap */
JavaArray_lookupProperty,
JavaArray_defineProperty,
JavaArray_getPropertyById, /* getProperty */

View File

@ -529,10 +529,14 @@ done:
return JS_TRUE;
}
extern JSObjectOps JavaClass_ops;
static const JSObjectMap JavaClassMap = { &JavaClass_ops };
JSObjectOps JavaClass_ops = {
&JavaClassMap, /* objectMap */
/* Mandatory non-null function pointer members. */
jsj_wrapper_newObjectMap, /* newObjectMap */
jsj_wrapper_destroyObjectMap, /* destroyObjectMap */
JavaClass_lookupProperty,
JavaClass_defineProperty,
JavaClass_getPropertyById, /* getProperty */

View File

@ -999,32 +999,10 @@ JavaObject_checkAccess(JSContext *cx, JSObject *obj, jsid id,
#define JSJ_SLOT_COUNT (JSSLOT_PRIVATE+1)
JSObjectMap *
jsj_wrapper_newObjectMap(JSContext *cx, jsrefcount nrefs, JSObjectOps *ops,
JSClass *clasp, JSObject *obj)
{
JSObjectMap * map;
map = (JSObjectMap *) JS_malloc(cx, sizeof(JSObjectMap));
if (map) {
map->nrefs = nrefs;
map->ops = ops;
map->freeslot = JSJ_SLOT_COUNT;
}
return map;
}
void
jsj_wrapper_destroyObjectMap(JSContext *cx, JSObjectMap *map)
{
JS_free(cx, map);
}
jsval
jsj_wrapper_getRequiredSlot(JSContext *cx, JSObject *obj, uint32 slot)
{
JS_ASSERT(slot < JSJ_SLOT_COUNT);
JS_ASSERT(obj->map->freeslot == JSJ_SLOT_COUNT);
return STOBJ_GET_SLOT(obj, slot);
}
@ -1032,15 +1010,18 @@ JSBool
jsj_wrapper_setRequiredSlot(JSContext *cx, JSObject *obj, uint32 slot, jsval v)
{
JS_ASSERT(slot < JSJ_SLOT_COUNT);
JS_ASSERT(obj->map->freeslot == JSJ_SLOT_COUNT);
STOBJ_SET_SLOT(obj, slot, v);
return JS_TRUE;
}
extern JSObjectOps JavaObject_ops;
static const JSObjectMap JavaObjectMap = { &JavaObject_ops };
JSObjectOps JavaObject_ops = {
&JavaObjectMap, /* objectMap */
/* Mandatory non-null function pointer members. */
jsj_wrapper_newObjectMap, /* newObjectMap */
jsj_wrapper_destroyObjectMap, /* destroyObjectMap */
JavaObject_lookupProperty,
JavaObject_defineProperty,
JavaObject_getPropertyById, /* getProperty */

View File

@ -643,13 +643,6 @@ jsj_EnterJava(JSContext *cx, JNIEnv **envp);
extern void
jsj_ExitJava(JSJavaThreadState *jsj_env);
extern JSObjectMap *
jsj_wrapper_newObjectMap(JSContext *cx, jsrefcount nrefs, JSObjectOps *ops,
JSClass *clasp, JSObject *obj);
extern void
jsj_wrapper_destroyObjectMap(JSContext *cx, JSObjectMap *map);
extern jsval
jsj_wrapper_getRequiredSlot(JSContext *cx, JSObject *obj, uint32 slot);

View File

@ -1399,7 +1399,7 @@ XPC_WN_GetObjectOpsWithCall(JSContext *cx, JSClass *clazz)
JSBool xpc_InitWrappedNativeJSOps()
{
if(!XPC_WN_NoCall_JSOps.newObjectMap)
if(!XPC_WN_NoCall_JSOps.lookupProperty)
{
memcpy(&XPC_WN_NoCall_JSOps, &js_ObjectOps, sizeof(JSObjectOps));
XPC_WN_NoCall_JSOps.enumerate = XPC_WN_JSOp_Enumerate;