mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-02-01 11:27:55 +00:00
- Add JS_GetReservedSlot, JS_SetReservedSlot, and JSCLASS_HAS_RESERVED_SLOTS(n)
to the JS API, for per class extra slots beyond JSSLOT_PRIVATE (or starting there for a class that lacks JSCLASS_HAS_PRIVATE). To avoid penalizing all instances, these slots are allocated only upon first property-owned slot allocation, or upon first JS_SetReservedSlot. This entailed adding getRequiredSlot and setRequiredSlot hooks to the JSObjectOps struct, and making obj->slots self-describing, a la BSTR. It also afforded me a chance to clean up obj->slots locking so that non-native JSObjectOps didn't risk unlocked accesses! Now there are thread-safe hooks for all uses of obj. First consumer is the new, DOM-glue-unifying XPConnect, which needs two slots per wrapped function. Hence the change to js_FunctionClass.flags' initializer. - Commented the heck out of JSClass and JSObjectOps function typedefs in jspubtd.h. I hope embedders see these comments! - Fix JS_XDRValue's default case to handle int exclusively, there is no other possible type (and therefore no JSMSG_BAD_JVAL_TYPE error). - Clean up tabs in select old, tab-ridden files and sections. - s/\<fh\>/file/g for stdio FILE * canonical variable names.
This commit is contained in:
parent
23699ce01d
commit
cd37f8447b
1073
js/src/js.c
1073
js/src/js.c
File diff suppressed because it is too large
Load Diff
@ -140,7 +140,7 @@ MSG_DEF(JSMSG_SEEK_BEYOND_START, 64, 0, JSEXN_NONE, "illegal seek beyond s
|
||||
MSG_DEF(JSMSG_SEEK_BEYOND_END, 65, 0, JSEXN_NONE, "illegal seek beyond end")
|
||||
MSG_DEF(JSMSG_END_SEEK, 66, 0, JSEXN_NONE, "illegal end-based seek")
|
||||
MSG_DEF(JSMSG_WHITHER_WHENCE, 67, 1, JSEXN_NONE, "unknown seek whence: {0}")
|
||||
MSG_DEF(JSMSG_BAD_JVAL_TYPE, 68, 1, JSEXN_NONE, "unknown jsval type {0} for XDR")
|
||||
MSG_DEF(JSMSG_BAD_SCRIPT_MAGIC, 68, 0, JSEXN_NONE, "bad script XDR magic number")
|
||||
MSG_DEF(JSMSG_PAREN_BEFORE_FORMAL, 69, 0, JSEXN_SYNTAXERR, "missing ( before formal parameters")
|
||||
MSG_DEF(JSMSG_MISSING_FORMAL, 70, 0, JSEXN_SYNTAXERR, "missing formal parameter")
|
||||
MSG_DEF(JSMSG_PAREN_AFTER_FORMAL, 71, 0, JSEXN_SYNTAXERR, "missing ) after formal parameters")
|
||||
@ -238,3 +238,4 @@ MSG_DEF(JSMSG_UNDEFINED_PROP, 162, 1, JSEXN_TYPEERR, "reference to undef
|
||||
MSG_DEF(JSMSG_USELESS_EXPR, 163, 0, JSEXN_TYPEERR, "useless expression")
|
||||
MSG_DEF(JSMSG_REDECLARED_PARAM, 164, 1, JSEXN_TYPEERR, "redeclaration of formal parameter {0}")
|
||||
MSG_DEF(JSMSG_NEWREGEXP_FLAGGED, 165, 0, JSEXN_TYPEERR, "can't supply flags when constructing one RegExp from another")
|
||||
MSG_DEF(JSMSG_RESERVED_SLOT_RANGE, 166, 0, JSEXN_RANGEERR, "reserved slot index out of range")
|
||||
|
@ -2678,6 +2678,42 @@ JS_CheckAccess(JSContext *cx, JSObject *obj, jsid id, JSAccessMode mode,
|
||||
return OBJ_CHECK_ACCESS(cx, obj, id, mode, vp, attrsp);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(JSBool)
|
||||
JS_GetReservedSlot(JSContext *cx, JSObject *obj, uint32 index, jsval *vp)
|
||||
{
|
||||
JSClass *clasp;
|
||||
uint32 slot;
|
||||
|
||||
CHECK_REQUEST(cx);
|
||||
clasp = OBJ_GET_CLASS(cx, obj);
|
||||
if (index >= JSCLASS_RESERVED_SLOTS(clasp)) {
|
||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
|
||||
JSMSG_RESERVED_SLOT_RANGE);
|
||||
return JS_FALSE;
|
||||
}
|
||||
slot = JSSLOT_START(clasp) + index;
|
||||
*vp = OBJ_GET_REQUIRED_SLOT(cx, obj, slot);
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(JSBool)
|
||||
JS_SetReservedSlot(JSContext *cx, JSObject *obj, uint32 index, jsval v)
|
||||
{
|
||||
JSClass *clasp;
|
||||
uint32 slot;
|
||||
|
||||
CHECK_REQUEST(cx);
|
||||
clasp = OBJ_GET_CLASS(cx, obj);
|
||||
if (index >= JSCLASS_RESERVED_SLOTS(clasp)) {
|
||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
|
||||
JSMSG_RESERVED_SLOT_RANGE);
|
||||
return JS_FALSE;
|
||||
}
|
||||
slot = JSSLOT_START(clasp) + index;
|
||||
OBJ_SET_REQUIRED_SLOT(cx, obj, slot, v);
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(JSFunction *)
|
||||
JS_NewFunction(JSContext *cx, JSNative native, uintN nargs, uintN flags,
|
||||
JSObject *parent, const char *name)
|
||||
@ -2910,14 +2946,14 @@ JS_CompileFile(JSContext *cx, JSObject *obj, const char *filename)
|
||||
|
||||
JS_PUBLIC_API(JSScript *)
|
||||
JS_CompileFileHandle(JSContext *cx, JSObject *obj, const char *filename,
|
||||
FILE *fh)
|
||||
FILE *file)
|
||||
{
|
||||
return JS_CompileFileHandleForPrincipals(cx, obj, filename, fh, NULL);
|
||||
return JS_CompileFileHandleForPrincipals(cx, obj, filename, file, NULL);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(JSScript *)
|
||||
JS_CompileFileHandleForPrincipals(JSContext *cx, JSObject *obj,
|
||||
const char *filename, FILE *fh,
|
||||
const char *filename, FILE *file,
|
||||
JSPrincipals *principals)
|
||||
{
|
||||
void *mark;
|
||||
@ -2925,7 +2961,7 @@ JS_CompileFileHandleForPrincipals(JSContext *cx, JSObject *obj,
|
||||
|
||||
CHECK_REQUEST(cx);
|
||||
mark = JS_ARENA_MARK(&cx->tempPool);
|
||||
ts = js_NewFileTokenStream(cx, NULL, fh);
|
||||
ts = js_NewFileTokenStream(cx, NULL, file);
|
||||
if (!ts)
|
||||
return NULL;
|
||||
ts->filename = filename;
|
||||
|
@ -640,6 +640,8 @@ JS_NewExternalString(JSContext *cx, jschar *chars, size_t length, intN type);
|
||||
/*
|
||||
* Classes, objects, and properties.
|
||||
*/
|
||||
|
||||
/* For detailed comments on the function pointer types, see jspubtd.h. */
|
||||
struct JSClass {
|
||||
const char *name;
|
||||
uint32 flags;
|
||||
@ -665,15 +667,30 @@ struct JSClass {
|
||||
jsword spare;
|
||||
};
|
||||
|
||||
#define JSCLASS_HAS_PRIVATE 0x01 /* objects have private slot */
|
||||
#define JSCLASS_NEW_ENUMERATE 0x02 /* has JSNewEnumerateOp hook */
|
||||
#define JSCLASS_NEW_RESOLVE 0x04 /* has JSNewResolveOp hook */
|
||||
#define JSCLASS_PRIVATE_IS_NSISUPPORTS 0x08 /* private is (nsISupports *) */
|
||||
#define JSCLASS_SHARE_ALL_PROPERTIES 0x10 /* all properties are SHARED */
|
||||
#define JSCLASS_HAS_PRIVATE (1<<0) /* objects have private slot */
|
||||
#define JSCLASS_NEW_ENUMERATE (1<<1) /* has JSNewEnumerateOp hook */
|
||||
#define JSCLASS_NEW_RESOLVE (1<<2) /* has JSNewResolveOp hook */
|
||||
#define JSCLASS_PRIVATE_IS_NSISUPPORTS (1<<3) /* private is (nsISupports *) */
|
||||
#define JSCLASS_SHARE_ALL_PROPERTIES (1<<4) /* all properties are SHARED */
|
||||
|
||||
/*
|
||||
* To reserve slots fetched and stored via JS_Get/SetReservedSlot, bitwise-or
|
||||
* JSCLASS_HAS_RESERVED_SLOTS(n) into the initializer for JSClass.flags, where
|
||||
* n is a constant in [1, 255]. Reserved slots are indexed from 0 to n-1.
|
||||
*/
|
||||
#define JSCLASS_RESERVED_SLOTS_SHIFT 8 /* room for 8 flags below */
|
||||
#define JSCLASS_RESERVED_SLOTS_WIDTH 8 /* and 16 above this field */
|
||||
#define JSCLASS_RESERVED_SLOTS_MASK JS_BITMASK(JSCLASS_RESERVED_SLOTS_WIDTH)
|
||||
#define JSCLASS_HAS_RESERVED_SLOTS(n) (((n) & JSCLASS_RESERVED_SLOTS_MASK) \
|
||||
<< JSCLASS_RESERVED_SLOTS_SHIFT)
|
||||
#define JSCLASS_RESERVED_SLOTS(clasp) (((clasp)->flags \
|
||||
>> JSCLASS_RESERVED_SLOTS_SHIFT) \
|
||||
& JSCLASS_RESERVED_SLOTS_MASK)
|
||||
|
||||
/* Initializer for unused members of statically initialized JSClass structs. */
|
||||
#define JSCLASS_NO_OPTIONAL_MEMBERS 0,0,0,0,0,0,0,0
|
||||
|
||||
/* For detailed comments on these function pointer types, see jspubtd.h. */
|
||||
struct JSObjectOps {
|
||||
/* Mandatory non-null function pointer members. */
|
||||
JSNewObjectMapOp newObjectMap;
|
||||
@ -700,8 +717,8 @@ struct JSObjectOps {
|
||||
JSSetObjectSlotOp setParent;
|
||||
JSMarkOp mark;
|
||||
JSFinalizeOp clear;
|
||||
jsword spare1;
|
||||
jsword spare2;
|
||||
JSGetRequiredSlotOp getRequiredSlot;
|
||||
JSSetRequiredSlotOp setRequiredSlot;
|
||||
};
|
||||
|
||||
/*
|
||||
@ -994,6 +1011,12 @@ extern JS_PUBLIC_API(JSBool)
|
||||
JS_CheckAccess(JSContext *cx, JSObject *obj, jsid id, JSAccessMode mode,
|
||||
jsval *vp, uintN *attrsp);
|
||||
|
||||
extern JS_PUBLIC_API(JSBool)
|
||||
JS_GetReservedSlot(JSContext *cx, JSObject *obj, uint32 index, jsval *vp);
|
||||
|
||||
extern JS_PUBLIC_API(JSBool)
|
||||
JS_SetReservedSlot(JSContext *cx, JSObject *obj, uint32 index, jsval v);
|
||||
|
||||
/************************************************************************/
|
||||
|
||||
/*
|
||||
|
@ -1114,9 +1114,14 @@ fun_mark(JSContext *cx, JSObject *obj, void *arg)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Reserve two slots in all function objects for XPConnect. Note that this
|
||||
* does not bloat every instance, only those on which reserved slots are set,
|
||||
* and those on which ad-hoc properties are defined.
|
||||
*/
|
||||
JSClass js_FunctionClass = {
|
||||
js_Function_str,
|
||||
JSCLASS_HAS_PRIVATE | JSCLASS_NEW_RESOLVE,
|
||||
JSCLASS_HAS_PRIVATE | JSCLASS_NEW_RESOLVE | JSCLASS_HAS_RESERVED_SLOTS(2),
|
||||
JS_PropertyStub, JS_PropertyStub,
|
||||
fun_getProperty, JS_PropertyStub,
|
||||
JS_EnumerateStub, (JSResolveOp)fun_resolve,
|
||||
|
@ -116,7 +116,7 @@ js_FlushPropertyCacheByProp(JSContext *cx, JSProperty *prop)
|
||||
/*
|
||||
* Class for for/in loop property iterator objects.
|
||||
*/
|
||||
#define JSSLOT_ITER_STATE (JSSLOT_START)
|
||||
#define JSSLOT_ITER_STATE JSSLOT_PRIVATE
|
||||
|
||||
static void
|
||||
prop_iterator_finalize(JSContext *cx, JSObject *obj)
|
||||
|
@ -449,7 +449,8 @@ ClaimScope(JSScope *scope, JSContext *cx)
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
jsval
|
||||
/* Exported to js.c, which calls it via OBJ_GET_* and JSVAL_IS_* macros. */
|
||||
JS_FRIEND_API(jsval)
|
||||
js_GetSlotThreadSafe(JSContext *cx, JSObject *obj, uint32 slot)
|
||||
{
|
||||
jsval v;
|
||||
@ -459,7 +460,23 @@ js_GetSlotThreadSafe(JSContext *cx, JSObject *obj, uint32 slot)
|
||||
jsword me;
|
||||
#endif
|
||||
|
||||
JS_ASSERT(OBJ_IS_NATIVE(obj));
|
||||
/*
|
||||
* We handle non-native objects via JSObjectOps.getRequiredSlot, treating
|
||||
* all slots starting from 0 as required slots. A property definition or
|
||||
* some prior arrangement must have allocated slot.
|
||||
*
|
||||
* Note once again (see jspubtd.h, before JSGetRequiredSlotOp's typedef)
|
||||
* the crucial distinction between a |required slot number| that's passed
|
||||
* to the get/setRequiredSlot JSObjectOps, and a |reserved slot index|
|
||||
* passed to the JS_Get/SetReservedSlot APIs.
|
||||
*/
|
||||
if (!OBJ_IS_NATIVE(obj))
|
||||
return OBJ_GET_REQUIRED_SLOT(cx, obj, slot);
|
||||
|
||||
/*
|
||||
* Native object locking is inlined here to optimize the single-threaded
|
||||
* and contention-free multi-threaded cases.
|
||||
*/
|
||||
scope = OBJ_SCOPE(obj);
|
||||
JS_ASSERT(scope->ownercx != cx);
|
||||
JS_ASSERT(obj->slots && slot < obj->map->freeslot);
|
||||
@ -523,7 +540,19 @@ js_SetSlotThreadSafe(JSContext *cx, JSObject *obj, uint32 slot, jsval v)
|
||||
jsword me;
|
||||
#endif
|
||||
|
||||
JS_ASSERT(OBJ_IS_NATIVE(obj));
|
||||
/*
|
||||
* We handle non-native objects via JSObjectOps.setRequiredSlot, as above
|
||||
* for the Get case.
|
||||
*/
|
||||
if (!OBJ_IS_NATIVE(obj)) {
|
||||
OBJ_SET_REQUIRED_SLOT(cx, obj, slot, v);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Native object locking is inlined here to optimize the single-threaded
|
||||
* and contention-free multi-threaded cases.
|
||||
*/
|
||||
scope = OBJ_SCOPE(obj);
|
||||
JS_ASSERT(scope->ownercx != cx);
|
||||
JS_ASSERT(obj->slots && slot < obj->map->freeslot);
|
||||
|
@ -158,7 +158,8 @@ extern int js_SetupLocks(int,int);
|
||||
extern void js_CleanupLocks();
|
||||
extern void js_InitContextForLocking(JSContext *);
|
||||
extern void js_TransferScopeLock(JSContext *, JSScope *, JSScope *);
|
||||
extern jsval js_GetSlotThreadSafe(JSContext *, JSObject *, uint32);
|
||||
extern JS_FRIEND_API(jsval)
|
||||
js_GetSlotThreadSafe(JSContext *, JSObject *, uint32);
|
||||
extern void js_SetSlotThreadSafe(JSContext *, JSObject *, uint32, jsval);
|
||||
extern void js_InitLock(JSThinLock *);
|
||||
extern void js_FinishLock(JSThinLock *);
|
||||
|
178
js/src/jsobj.c
178
js/src/jsobj.c
@ -92,7 +92,7 @@ JS_FRIEND_DATA(JSObjectOps) js_ObjectOps = {
|
||||
NULL, js_HasInstance,
|
||||
js_SetProtoOrParent, js_SetProtoOrParent,
|
||||
js_Mark, js_Clear,
|
||||
0, 0
|
||||
js_GetRequiredSlot, js_SetRequiredSlot
|
||||
};
|
||||
|
||||
#ifdef XP_MAC
|
||||
@ -1370,7 +1370,7 @@ JS_FRIEND_DATA(JSObjectOps) js_WithObjectOps = {
|
||||
NULL, NULL,
|
||||
js_SetProtoOrParent, js_SetProtoOrParent,
|
||||
js_Mark, js_Clear,
|
||||
0, 0
|
||||
NULL, NULL
|
||||
};
|
||||
|
||||
static JSObjectOps *
|
||||
@ -1467,7 +1467,7 @@ js_InitObjectMap(JSObjectMap *map, jsrefcount nrefs, JSObjectOps *ops,
|
||||
{
|
||||
map->nrefs = nrefs;
|
||||
map->ops = ops;
|
||||
map->nslots = 0;
|
||||
map->nslots = JS_INITIAL_NSLOTS;
|
||||
map->freeslot = JSSLOT_FREE(clasp);
|
||||
}
|
||||
|
||||
@ -1513,7 +1513,8 @@ js_NewObject(JSContext *cx, JSClass *clasp, JSObject *proto, JSObject *parent)
|
||||
JSObjectOps *ops;
|
||||
JSObjectMap *map;
|
||||
jsval cval;
|
||||
uint32 i;
|
||||
uint32 nslots, i;
|
||||
jsval *newslots;
|
||||
|
||||
/* Allocate an object from the GC heap and zero it. */
|
||||
obj = (JSObject *) js_AllocGCThing(cx, GCX_OBJECT);
|
||||
@ -1547,29 +1548,41 @@ js_NewObject(JSContext *cx, JSClass *clasp, JSObject *proto, JSObject *parent)
|
||||
|
||||
/* Share the given prototype's map. */
|
||||
obj->map = js_HoldObjectMap(cx, map);
|
||||
|
||||
/* Ensure that obj starts with the minimum slots for clasp. */
|
||||
nslots = JS_INITIAL_NSLOTS;
|
||||
} else {
|
||||
/* Leave parent alone. Allocate a new map for obj. */
|
||||
map = ops->newObjectMap(cx, 1, ops, clasp, obj);
|
||||
if (!map)
|
||||
goto bad;
|
||||
if (map->nslots == 0)
|
||||
map->nslots = JS_INITIAL_NSLOTS;
|
||||
obj->map = map;
|
||||
|
||||
/* Let ops->newObjectMap set nslots so as to reserve slots. */
|
||||
nslots = map->nslots;
|
||||
}
|
||||
|
||||
/* Allocate a slots vector, with a -1'st element telling its length. */
|
||||
newslots = (jsval *) JS_malloc(cx, (nslots + 1) * sizeof(jsval));
|
||||
if (!newslots)
|
||||
goto bad;
|
||||
newslots[0] = nslots;
|
||||
newslots++;
|
||||
|
||||
/* Set the proto, parent, and class properties. */
|
||||
obj->slots = (jsval *) JS_malloc(cx, JS_INITIAL_NSLOTS * sizeof(jsval));
|
||||
if (!obj->slots)
|
||||
goto bad;
|
||||
obj->slots[JSSLOT_PROTO] = OBJECT_TO_JSVAL(proto);
|
||||
obj->slots[JSSLOT_PARENT] = OBJECT_TO_JSVAL(parent);
|
||||
obj->slots[JSSLOT_CLASS] = PRIVATE_TO_JSVAL(clasp);
|
||||
for (i = JSSLOT_CLASS+1; i < JS_INITIAL_NSLOTS; i++)
|
||||
obj->slots[i] = JSVAL_VOID;
|
||||
newslots[JSSLOT_PROTO] = OBJECT_TO_JSVAL(proto);
|
||||
newslots[JSSLOT_PARENT] = OBJECT_TO_JSVAL(parent);
|
||||
newslots[JSSLOT_CLASS] = PRIVATE_TO_JSVAL(clasp);
|
||||
|
||||
if (cx->runtime->objectHook) {
|
||||
/* Clear above JSSLOT_CLASS so the GC doesn't load uninitialized memory. */
|
||||
for (i = JSSLOT_CLASS + 1; i < nslots; i++)
|
||||
newslots[i] = JSVAL_VOID;
|
||||
|
||||
/* Store newslots after initializing all of 'em, just in case. */
|
||||
obj->slots = newslots;
|
||||
|
||||
if (cx->runtime->objectHook)
|
||||
cx->runtime->objectHook(cx, obj, JS_TRUE, cx->runtime->objectHookData);
|
||||
}
|
||||
|
||||
return obj;
|
||||
|
||||
@ -1666,10 +1679,10 @@ js_FinalizeObject(JSContext *cx, JSObject *obj)
|
||||
map = obj->map;
|
||||
if (!map)
|
||||
return;
|
||||
JS_ASSERT(obj->slots);
|
||||
|
||||
if (cx->runtime->objectHook) {
|
||||
if (cx->runtime->objectHook)
|
||||
cx->runtime->objectHook(cx, obj, JS_FALSE, cx->runtime->objectHookData);
|
||||
}
|
||||
|
||||
#if JS_HAS_OBJ_WATCHPOINT
|
||||
/* Remove all watchpoints with weak links to obj. */
|
||||
@ -1682,7 +1695,7 @@ js_FinalizeObject(JSContext *cx, JSObject *obj)
|
||||
/* Drop map and free slots. */
|
||||
js_DropObjectMap(cx, map, obj);
|
||||
obj->map = NULL;
|
||||
JS_free(cx, obj->slots);
|
||||
JS_free(cx, obj->slots - 1);
|
||||
obj->slots = NULL;
|
||||
}
|
||||
|
||||
@ -1690,20 +1703,19 @@ JSBool
|
||||
js_AllocSlot(JSContext *cx, JSObject *obj, uint32 *slotp)
|
||||
{
|
||||
JSObjectMap *map;
|
||||
uint32 nslots;
|
||||
uint32 nslots, i;
|
||||
size_t nbytes;
|
||||
jsval *newslots;
|
||||
|
||||
map = obj->map;
|
||||
JS_ASSERT(!MAP_IS_NATIVE(map) || ((JSScope *)map)->object == obj);
|
||||
nslots = map->nslots;
|
||||
if (map->freeslot >= nslots) {
|
||||
nslots = JS_MAX(map->freeslot, nslots);
|
||||
if (nslots < JS_INITIAL_NSLOTS)
|
||||
nslots = JS_INITIAL_NSLOTS;
|
||||
else
|
||||
nslots += (nslots + 1) / 2;
|
||||
JS_ASSERT(nslots >= JS_INITIAL_NSLOTS);
|
||||
nslots += (nslots + 1) / 2;
|
||||
|
||||
nbytes = (size_t)nslots * sizeof(jsval);
|
||||
nbytes = (nslots + 1) * sizeof(jsval);
|
||||
#if defined(XP_PC) && defined _MSC_VER && _MSC_VER <= 800
|
||||
if (nbytes > 60000U) {
|
||||
JS_ReportOutOfMemory(cx);
|
||||
@ -1711,16 +1723,13 @@ js_AllocSlot(JSContext *cx, JSObject *obj, uint32 *slotp)
|
||||
}
|
||||
#endif
|
||||
|
||||
if (obj->slots) {
|
||||
newslots = (jsval *) JS_realloc(cx, obj->slots, nbytes);
|
||||
} else {
|
||||
/* obj must be newborn and unshared at this point. */
|
||||
newslots = (jsval *) JS_malloc(cx, nbytes);
|
||||
}
|
||||
newslots = (jsval *) JS_realloc(cx, obj->slots - 1, nbytes);
|
||||
if (!newslots)
|
||||
return JS_FALSE;
|
||||
obj->slots = newslots;
|
||||
map->nslots = nslots;
|
||||
for (i = 1 + newslots[0]; i <= nslots; i++)
|
||||
newslots[i] = JSVAL_VOID;
|
||||
newslots[0] = map->nslots = nslots;
|
||||
obj->slots = newslots + 1;
|
||||
}
|
||||
|
||||
#ifdef TOO_MUCH_GC
|
||||
@ -1741,18 +1750,19 @@ js_FreeSlot(JSContext *cx, JSObject *obj, uint32 slot)
|
||||
OBJ_CHECK_SLOT(obj, slot);
|
||||
obj->slots[slot] = JSVAL_VOID;
|
||||
map = obj->map;
|
||||
JS_ASSERT(!MAP_IS_NATIVE(map) || ((JSScope *)map)->object == obj);
|
||||
if (map->freeslot == slot + 1)
|
||||
map->freeslot = slot;
|
||||
nslots = map->nslots;
|
||||
if (nslots > JS_INITIAL_NSLOTS && map->freeslot < nslots / 2) {
|
||||
nslots = map->freeslot;
|
||||
nslots += nslots / 2;
|
||||
nbytes = (size_t)nslots * sizeof(jsval);
|
||||
newslots = (jsval *) JS_realloc(cx, obj->slots, nbytes);
|
||||
nbytes = (nslots + 1) * sizeof(jsval);
|
||||
newslots = (jsval *) JS_realloc(cx, obj->slots - 1, nbytes);
|
||||
if (!newslots)
|
||||
return;
|
||||
obj->slots = newslots;
|
||||
map->nslots = nslots;
|
||||
newslots[0] = map->nslots = nslots;
|
||||
obj->slots = newslots + 1;
|
||||
}
|
||||
}
|
||||
|
||||
@ -2115,17 +2125,17 @@ js_GetProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
|
||||
JSScope *scope;
|
||||
uint32 slot;
|
||||
|
||||
/*
|
||||
* Handle old bug that took empty string as zero index. Also convert
|
||||
* string indices to integers if appropriate.
|
||||
*/
|
||||
CHECK_FOR_FUNNY_INDEX(id);
|
||||
|
||||
if (!js_LookupProperty(cx, obj, id, &obj2, (JSProperty **)&sprop))
|
||||
return JS_FALSE;
|
||||
if (!sprop) {
|
||||
jsval default_val;
|
||||
|
||||
/*
|
||||
* Handle old bug that took empty string as zero index. Also convert
|
||||
* string indices to integers if appropriate.
|
||||
*/
|
||||
CHECK_FOR_FUNNY_INDEX(id);
|
||||
|
||||
#if JS_BUG_NULL_INDEX_PROPS
|
||||
/* Indexed properties defaulted to null in old versions. */
|
||||
default_val = (JSVAL_IS_INT(id) && JSVAL_TO_INT(id) >= 0)
|
||||
@ -2244,9 +2254,6 @@ js_SetProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
|
||||
sprop = sym_property(sym);
|
||||
#if JS_HAS_OBJ_WATCHPOINT
|
||||
if (!sprop && scope->object == obj) {
|
||||
uint32 nslots;
|
||||
jsval *slots;
|
||||
|
||||
/*
|
||||
* Deleted property place-holder, could have a watchpoint that
|
||||
* holds the deleted-but-watched property. If so, slots may have
|
||||
@ -2258,15 +2265,18 @@ js_SetProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
|
||||
(slot = sprop->slot) != SPROP_INVALID_SLOT &&
|
||||
slot >= scope->map.freeslot) {
|
||||
if (slot >= scope->map.nslots) {
|
||||
uint32 nslots;
|
||||
jsval *slots;
|
||||
|
||||
nslots = slot + slot / 2;
|
||||
slots = (jsval *)
|
||||
JS_realloc(cx, obj->slots, nslots * sizeof(jsval));
|
||||
slots = (jsval *) JS_realloc(cx, obj->slots - 1,
|
||||
(nslots + 1) * sizeof(jsval));
|
||||
if (!slots) {
|
||||
JS_UNLOCK_OBJ(cx, obj);
|
||||
return JS_FALSE;
|
||||
}
|
||||
scope->map.nslots = nslots;
|
||||
obj->slots = slots;
|
||||
slots[0] = scope->map.nslots = nslots;
|
||||
obj->slots = slots + 1;
|
||||
}
|
||||
scope->map.freeslot = slot + 1;
|
||||
}
|
||||
@ -2289,7 +2299,7 @@ js_SetProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
|
||||
sprop->nrefs++;
|
||||
JS_UNLOCK_SCOPE(cx, scope);
|
||||
|
||||
ok = SPROP_SET(cx, sprop, obj, obj, vp);
|
||||
ok = SPROP_SET(cx, sprop, obj, proto, vp);
|
||||
JS_LOCK_OBJ_VOID(cx, proto,
|
||||
js_DropScopeProperty(cx, scope, sprop));
|
||||
return ok;
|
||||
@ -2335,7 +2345,7 @@ js_SetProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
|
||||
sprop->nrefs++;
|
||||
JS_UNLOCK_SCOPE(cx, scope);
|
||||
|
||||
ok = SPROP_SET(cx, sprop, obj, obj, vp);
|
||||
ok = SPROP_SET(cx, sprop, obj, proto, vp);
|
||||
JS_LOCK_OBJ_VOID(cx, proto,
|
||||
js_DropScopeProperty(cx, scope, sprop));
|
||||
return ok;
|
||||
@ -2533,7 +2543,6 @@ JSBool
|
||||
js_DeleteProperty(JSContext *cx, JSObject *obj, jsid id, jsval *rval)
|
||||
{
|
||||
#if JS_HAS_PROP_DELETE
|
||||
JSRuntime *rt;
|
||||
JSObject *proto;
|
||||
JSProperty *prop;
|
||||
JSScopeProperty *sprop;
|
||||
@ -2541,8 +2550,6 @@ js_DeleteProperty(JSContext *cx, JSObject *obj, jsid id, jsval *rval)
|
||||
JSScope *scope;
|
||||
JSSymbol *sym;
|
||||
|
||||
rt = cx->runtime;
|
||||
|
||||
*rval = JSVERSION_IS_ECMA(cx->version) ? JSVAL_TRUE : JSVAL_VOID;
|
||||
|
||||
/*
|
||||
@ -2611,7 +2618,7 @@ js_DeleteProperty(JSContext *cx, JSObject *obj, jsid id, jsval *rval)
|
||||
* js_DestroyScopeProperty purges for us).
|
||||
*/
|
||||
if (sprop->nrefs != 1) {
|
||||
PROPERTY_CACHE_FILL(cx, &rt->propertyCache, obj, id, NULL);
|
||||
PROPERTY_CACHE_FILL(cx, &cx->runtime->propertyCache, obj, id, NULL);
|
||||
}
|
||||
|
||||
#if JS_HAS_OBJ_WATCHPOINT
|
||||
@ -3256,7 +3263,16 @@ js_Mark(JSContext *cx, JSObject *obj, void *arg)
|
||||
clasp = LOCKED_OBJ_GET_CLASS(obj);
|
||||
if (clasp->mark)
|
||||
(void) clasp->mark(cx, obj, arg);
|
||||
return (scope->object == obj) ? obj->map->freeslot : JS_INITIAL_NSLOTS;
|
||||
|
||||
if (scope->object != obj) {
|
||||
/*
|
||||
* An unmutated object that shares a prototype's scope. We can't tell
|
||||
* how many slots are allocated and in use at obj->slots by looking at
|
||||
* scope, so we get obj->slots' length from its -1'st element.
|
||||
*/
|
||||
return (uint32) obj->slots[-1];
|
||||
}
|
||||
return obj->map->freeslot;
|
||||
}
|
||||
|
||||
void
|
||||
@ -3267,7 +3283,8 @@ js_Clear(JSContext *cx, JSObject *obj)
|
||||
|
||||
/*
|
||||
* Clear our scope of all symbols and properties, only if we own the scope
|
||||
* (i.e., not if obj is unmutated and sharing its prototype's scope).
|
||||
* (i.e., not if obj is unmutated and sharing its prototype's scope). We
|
||||
* do not clear any reserved slots that lie below JSSLOT_FREE(clasp).
|
||||
*/
|
||||
JS_LOCK_OBJ(cx, obj);
|
||||
scope = OBJ_SCOPE(obj);
|
||||
@ -3284,6 +3301,51 @@ js_Clear(JSContext *cx, JSObject *obj)
|
||||
JS_UNLOCK_OBJ(cx, obj);
|
||||
}
|
||||
|
||||
jsval
|
||||
js_GetRequiredSlot(JSContext *cx, JSObject *obj, uint32 slot)
|
||||
{
|
||||
jsval v;
|
||||
|
||||
JS_LOCK_OBJ(cx, obj);
|
||||
v = (slot < (uint32) obj->slots[-1]) ? obj->slots[slot] : JSVAL_VOID;
|
||||
JS_UNLOCK_OBJ(cx, obj);
|
||||
return v;
|
||||
}
|
||||
|
||||
void
|
||||
js_SetRequiredSlot(JSContext *cx, JSObject *obj, uint32 slot, jsval v)
|
||||
{
|
||||
uint32 nslots, rlimit, i;
|
||||
JSClass *clasp;
|
||||
jsval *newslots;
|
||||
|
||||
JS_LOCK_OBJ(cx, obj);
|
||||
nslots = (uint32) obj->slots[-1];
|
||||
if (slot >= nslots) {
|
||||
clasp = LOCKED_OBJ_GET_CLASS(obj);
|
||||
rlimit = JSSLOT_START(clasp) + JSCLASS_RESERVED_SLOTS(clasp);
|
||||
JS_ASSERT(slot < rlimit);
|
||||
if (rlimit > nslots)
|
||||
nslots = rlimit;
|
||||
|
||||
newslots = (jsval *)
|
||||
JS_realloc(cx, obj->slots - 1, (nslots + 1) * sizeof(jsval));
|
||||
if (!newslots) {
|
||||
JS_UNLOCK_OBJ(cx, obj);
|
||||
return;
|
||||
}
|
||||
for (i = 1 + newslots[0]; i <= rlimit; i++)
|
||||
newslots[i] = JSVAL_VOID;
|
||||
newslots[0] = nslots;
|
||||
if (OBJ_SCOPE(obj)->object == obj)
|
||||
obj->map->nslots = nslots;
|
||||
obj->slots = newslots + 1;
|
||||
}
|
||||
|
||||
obj->slots[slot] = v;
|
||||
JS_UNLOCK_OBJ(cx, obj);
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
|
||||
/* Routines to print out values during debugging. */
|
||||
|
@ -82,7 +82,7 @@ struct JSObjectMap {
|
||||
#define OBJ_CHECK_ACCESS(cx,obj,id,mode,vp,attrsp) \
|
||||
(obj)->map->ops->checkAccess(cx,obj,id,mode,vp,attrsp)
|
||||
|
||||
/* These two are time-optimized to avoid stub calls. */
|
||||
/* These four are time-optimized to avoid stub calls. */
|
||||
#define OBJ_THIS_OBJECT(cx,obj) \
|
||||
((obj)->map->ops->thisObject \
|
||||
? (obj)->map->ops->thisObject(cx,obj) \
|
||||
@ -91,7 +91,31 @@ struct JSObjectMap {
|
||||
((obj)->map->ops->dropProperty \
|
||||
? (obj)->map->ops->dropProperty(cx,obj,prop) \
|
||||
: (void)0)
|
||||
#define OBJ_GET_REQUIRED_SLOT(cx,obj,slot) \
|
||||
((obj)->map->ops->getRequiredSlot \
|
||||
? (obj)->map->ops->getRequiredSlot(cx, obj, slot) \
|
||||
: JSVAL_VOID)
|
||||
#define OBJ_SET_REQUIRED_SLOT(cx,obj,slot,v) \
|
||||
((obj)->map->ops->setRequiredSlot \
|
||||
? (obj)->map->ops->setRequiredSlot(cx, obj, slot, v) \
|
||||
: (void)0)
|
||||
|
||||
/*
|
||||
* In the original JS engine design, obj->slots pointed to a vector of length
|
||||
* JS_INITIAL_NSLOTS words if obj->map was shared with a prototype object,
|
||||
* else of length obj->map->nslots. With the advent of JS_GetReservedSlot,
|
||||
* JS_SetReservedSlot, and JSCLASS_HAS_RESERVED_SLOTS (see jsapi.h), the size
|
||||
* of the minimum length slots vector in the case where map is shared cannot
|
||||
* be constant. This length starts at JS_INITIAL_NSLOTS, but may advance to
|
||||
* include all the reserved slots.
|
||||
*
|
||||
* Therefore slots must be self-describing. Rather than tag its low order bit
|
||||
* (a bit is all we need) to distinguish initial length from reserved length,
|
||||
* we do "the BSTR thing": over-allocate slots by one jsval, and store the
|
||||
* *net* length (counting usable slots, which have non-negative obj->slots[]
|
||||
* indices) in obj->slots[-1]. All code that sets obj->slots must be aware of
|
||||
* this hack -- you have been warned, and jsobj.c has been updated!
|
||||
*/
|
||||
struct JSObject {
|
||||
JSObjectMap *map;
|
||||
jsval *slots;
|
||||
@ -101,11 +125,12 @@ struct JSObject {
|
||||
#define JSSLOT_PARENT 1
|
||||
#define JSSLOT_CLASS 2
|
||||
#define JSSLOT_PRIVATE 3
|
||||
#define JSSLOT_START 3
|
||||
#define JSSLOT_START(clasp) (((clasp)->flags & JSCLASS_HAS_PRIVATE) \
|
||||
? JSSLOT_PRIVATE + 1 \
|
||||
: JSSLOT_CLASS + 1)
|
||||
|
||||
#define JSSLOT_FREE(clasp) (((clasp)->flags & JSCLASS_HAS_PRIVATE) \
|
||||
? JSSLOT_PRIVATE + 1 \
|
||||
: JSSLOT_START)
|
||||
#define JSSLOT_FREE(clasp) (JSSLOT_START(clasp) \
|
||||
+ JSCLASS_RESERVED_SLOTS(clasp))
|
||||
|
||||
#define JS_INITIAL_NSLOTS 5
|
||||
|
||||
@ -133,13 +158,13 @@ struct JSObject {
|
||||
/* Thread-safe functions and wrapper macros for accessing obj->slots. */
|
||||
#define OBJ_GET_SLOT(cx,obj,slot) \
|
||||
(OBJ_CHECK_SLOT(obj, slot), \
|
||||
(!OBJ_IS_NATIVE(obj) || OBJ_SCOPE(obj)->ownercx == cx) \
|
||||
(OBJ_IS_NATIVE(obj) && OBJ_SCOPE(obj)->ownercx == cx) \
|
||||
? LOCKED_OBJ_GET_SLOT(obj, slot) \
|
||||
: js_GetSlotThreadSafe(cx, obj, slot))
|
||||
|
||||
#define OBJ_SET_SLOT(cx,obj,slot,value) \
|
||||
(OBJ_CHECK_SLOT(obj, slot), \
|
||||
(!OBJ_IS_NATIVE(obj) || OBJ_SCOPE(obj)->ownercx == cx) \
|
||||
(OBJ_IS_NATIVE(obj) && OBJ_SCOPE(obj)->ownercx == cx) \
|
||||
? (void) LOCKED_OBJ_SET_SLOT(obj, slot, value) \
|
||||
: js_SetSlotThreadSafe(cx, obj, slot, value))
|
||||
|
||||
@ -368,6 +393,12 @@ js_Mark(JSContext *cx, JSObject *obj, void *arg);
|
||||
extern void
|
||||
js_Clear(JSContext *cx, JSObject *obj);
|
||||
|
||||
extern jsval
|
||||
js_GetRequiredSlot(JSContext *cx, JSObject *obj, uint32 slot);
|
||||
|
||||
extern void
|
||||
js_SetRequiredSlot(JSContext *cx, JSObject *obj, uint32 slot, jsval v);
|
||||
|
||||
JS_END_EXTERN_C
|
||||
|
||||
#endif /* jsobj_h___ */
|
||||
|
250
js/src/jspubtd.h
250
js/src/jspubtd.h
@ -118,8 +118,16 @@ typedef struct JSLocaleCallbacks JSLocaleCallbacks;
|
||||
|
||||
/* JSClass (and JSObjectOps where appropriate) function pointer typedefs. */
|
||||
|
||||
/*
|
||||
* Add, delete, get or set a property named by id in obj. Note the jsval id
|
||||
* type -- id may be a string (Unicode property identifier) or an int (element
|
||||
* index). The *vp out parameter, on success, is the new property value after
|
||||
* an add, get, or set. After a successful delete, *vp is JSVAL_FALSE iff
|
||||
* obj[id] can't be deleted (because it's permanent).
|
||||
*/
|
||||
typedef JSBool
|
||||
(* JS_DLL_CALLBACK JSPropertyOp)(JSContext *cx, JSObject *obj, jsval id, jsval *vp);
|
||||
(* JS_DLL_CALLBACK JSPropertyOp)(JSContext *cx, JSObject *obj, jsval id,
|
||||
jsval *vp);
|
||||
|
||||
/*
|
||||
* This function type is used for callbacks that enumerate the properties of
|
||||
@ -153,56 +161,179 @@ typedef JSBool
|
||||
JSIterateOp enum_op,
|
||||
jsval *statep, jsid *idp);
|
||||
|
||||
/*
|
||||
* The old-style JSClass.enumerate op should define all lazy properties not
|
||||
* yet reflected in obj.
|
||||
*/
|
||||
typedef JSBool
|
||||
(* JS_DLL_CALLBACK JSEnumerateOp)(JSContext *cx, JSObject *obj);
|
||||
|
||||
/*
|
||||
* Resolve a lazy property named by id in obj by defining it directly in obj.
|
||||
* Lazy properties are those reflected from some peer native property space
|
||||
* (e.g., the DOM attributes for a given node reflected as obj) on demand.
|
||||
*
|
||||
* JS looks for a property in an object, and if not found, tries to resolve
|
||||
* the given id. If resolve succeeds, the engine looks again in case resolve
|
||||
* defined obj[id]. If no such property exists directly in obj, the process
|
||||
* is repeated with obj's prototype, etc.
|
||||
*
|
||||
* NB: JSNewResolveOp provides a cheaper way to resolve lazy properties.
|
||||
*/
|
||||
typedef JSBool
|
||||
(* JS_DLL_CALLBACK JSResolveOp)(JSContext *cx, JSObject *obj, jsval id);
|
||||
|
||||
/*
|
||||
* Like JSResolveOp, but flags provide contextual information as follows:
|
||||
*
|
||||
* JSRESOLVE_QUALIFIED a qualified property id: obj.id or obj[id], not id
|
||||
* JSRESOLVE_ASSIGNING obj[id] is on the left-hand side of an assignment
|
||||
*
|
||||
* The *objp out parameter, on success, should be null to indicate that id
|
||||
* was not resolved; and non-null, referring to obj or one of its prototypes,
|
||||
* if id was resolved.
|
||||
*/
|
||||
typedef JSBool
|
||||
(* JS_DLL_CALLBACK JSNewResolveOp)(JSContext *cx, JSObject *obj, jsval id, uintN flags,
|
||||
JSObject **objp);
|
||||
(* JS_DLL_CALLBACK JSNewResolveOp)(JSContext *cx, JSObject *obj, jsval id,
|
||||
uintN flags, JSObject **objp);
|
||||
|
||||
/*
|
||||
* Convert obj to the given type, returning true with the resulting value in
|
||||
* *vp on success, and returning false on error or exception.
|
||||
*/
|
||||
typedef JSBool
|
||||
(* JS_DLL_CALLBACK JSConvertOp)(JSContext *cx, JSObject *obj, JSType type, jsval *vp);
|
||||
(* JS_DLL_CALLBACK JSConvertOp)(JSContext *cx, JSObject *obj, JSType type,
|
||||
jsval *vp);
|
||||
|
||||
/*
|
||||
* Finalize obj, which the garbage collector has determined to be unreachable
|
||||
* from other live objects or from GC roots. Obviously, finalizers must never
|
||||
* store a reference to obj.
|
||||
*/
|
||||
typedef void
|
||||
(* JS_DLL_CALLBACK JSFinalizeOp)(JSContext *cx, JSObject *obj);
|
||||
|
||||
/*
|
||||
* Used by JS_AddExternalStringFinalizer and JS_RemoveExternalStringFinalizer
|
||||
* to extend and reduce the set of string types finalized by the GC.
|
||||
*/
|
||||
typedef void
|
||||
(* JS_DLL_CALLBACK JSStringFinalizeOp)(JSContext *cx, JSString *str);
|
||||
|
||||
/*
|
||||
* The signature for JSClass.getObjectOps, used by JS_NewObject's internals
|
||||
* to discover the set of high-level object operations to use for new objects
|
||||
* of the given class. All native objects have a JSClass, which is stored as
|
||||
* a private (int-tagged) pointer in obj->slots[JSSLOT_CLASS]. In contrast,
|
||||
* all native and host objects have a JSObjectMap at obj->map, which may be
|
||||
* shared among a number of objects, and which contains the JSObjectOps *ops
|
||||
* pointer used to dispatch object operations from API calls.
|
||||
*
|
||||
* Thus JSClass (which pre-dates JSObjectOps in the API) provides a low-level
|
||||
* interface to class-specific code and data, while JSObjectOps allows for a
|
||||
* higher level of operation, which does not use the object's class except to
|
||||
* find the class's JSObjectOps struct, by calling clasp->getObjectOps.
|
||||
*
|
||||
* If this seems backwards, that's because it is! API compatibility requires
|
||||
* a JSClass *clasp parameter to JS_NewObject, etc. Most host objects do not
|
||||
* need to implement the larger JSObjectOps, and can share the common JSScope
|
||||
* code and data used by the native (js_ObjectOps, see jsobj.c) ops.
|
||||
*/
|
||||
typedef JSObjectOps *
|
||||
(* JS_DLL_CALLBACK JSGetObjectOps)(JSContext *cx, JSClass *clasp);
|
||||
|
||||
/*
|
||||
* JSClass.checkAccess type: check whether obj[id] may be accessed per mode,
|
||||
* returning false on error/exception, true on success with obj[id]'s last-got
|
||||
* value in *vp, and its attributes in *attrsp. As for JSPropertyOp above, id
|
||||
* is either a string or an int jsval.
|
||||
*
|
||||
* See JSCheckAccessIdOp, below, for the JSObjectOps counterpart, which takes
|
||||
* a jsid (a tagged int or aligned, unique identifier pointer) rather than a
|
||||
* jsval. The native js_ObjectOps.checkAccess simply forwards to the object's
|
||||
* clasp->checkAccess, so that both JSClass and JSObjectOps implementors may
|
||||
* specialize access checks.
|
||||
*/
|
||||
typedef JSBool
|
||||
(* JS_DLL_CALLBACK JSCheckAccessOp)(JSContext *cx, JSObject *obj, jsval id,
|
||||
JSAccessMode mode, jsval *vp);
|
||||
|
||||
/*
|
||||
* Encode or decode an object, given an XDR state record representing external
|
||||
* data. See jsxdrapi.h.
|
||||
*/
|
||||
typedef JSBool
|
||||
(* JS_DLL_CALLBACK JSXDRObjectOp)(JSXDRState *xdr, JSObject **objp);
|
||||
|
||||
/*
|
||||
* Check whether v is an instance of obj. Return false on error or exception,
|
||||
* true on success with JS_TRUE in *bp if v is an instance of obj, JS_FALSE in
|
||||
* *bp otherwise.
|
||||
*/
|
||||
typedef JSBool
|
||||
(* JS_DLL_CALLBACK JSHasInstanceOp)(JSContext *cx, JSObject *obj, jsval v,
|
||||
JSBool *bp);
|
||||
|
||||
typedef JSBool
|
||||
(* JS_DLL_CALLBACK JSSetObjectSlotOp)(JSContext *cx, JSObject *obj, uint32 slot,
|
||||
JSObject *pobj);
|
||||
|
||||
/*
|
||||
* Function type for JSClass.mark and JSObjectOps.mark, called from the GC
|
||||
* to scan live GC-things reachable from obj's private data. For each such
|
||||
* private thing, an implementation must call js_MarkGCThing(cx, thing, arg).
|
||||
* The trailing arg is used for GC_MARK_DEBUG-mode heap dumping and ref-path
|
||||
* tracing.
|
||||
*
|
||||
* For the JSObjectOps.mark hook, the return value is the number of slots at
|
||||
* obj->slots to scan. For JSClass.mark, the return value is ignored.
|
||||
*
|
||||
* NB: JSMarkOp implementations cannot allocate new GC-things (JS_NewObject
|
||||
* called from a mark function will fail silently, e.g.).
|
||||
*/
|
||||
typedef uint32
|
||||
(* JS_DLL_CALLBACK JSMarkOp)(JSContext *cx, JSObject *obj, void *arg);
|
||||
|
||||
/* 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 *
|
||||
(* JS_DLL_CALLBACK 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
|
||||
(* JS_DLL_CALLBACK 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
|
||||
* not found. If id was found, return the first object searching from obj
|
||||
* along its prototype chain in which id names a direct property in *objp, and
|
||||
* return a non-null, opaque property pointer in *propp.
|
||||
*
|
||||
* If JSLookupPropOp succeeds and returns with *propp non-null, that pointer
|
||||
* may be passed as the prop parameter to a JSAttributesOp, as a short-cut
|
||||
* that bypasses id re-lookup. In any case, a non-null *propp result after a
|
||||
* successful lookup must be dropped via JSObjectOps.dropProperty.
|
||||
*
|
||||
* NB: successful return with non-null *propp means the implementation may
|
||||
* have locked *objp and added a reference count associated with *propp, so
|
||||
* callers should not risk deadlock by nesting or interleaving other lookups
|
||||
* or any obj-bearing ops before dropping *propp.
|
||||
*/
|
||||
typedef JSBool
|
||||
(* JS_DLL_CALLBACK JSLookupPropOp)(JSContext *cx, JSObject *obj, jsid id,
|
||||
JSObject **objp, JSProperty **propp
|
||||
@ -211,33 +342,109 @@ typedef JSBool
|
||||
#endif
|
||||
);
|
||||
|
||||
/*
|
||||
* Define obj[id], a direct property of obj named id, having the given initial
|
||||
* value, with the specified getter, setter, and attributes. If the propp out
|
||||
* param is non-null, *propp on successful return contains an opaque property
|
||||
* pointer usable as a speedup hint with JSAttributesOp. But note that propp
|
||||
* may be null, indicating that the caller is not interested in recovering an
|
||||
* opaque pointer to the newly-defined property.
|
||||
*
|
||||
* If propp is non-null and JSDefinePropOp succeeds, its caller must be sure
|
||||
* to drop *propp using JSObjectOps.dropProperty in short order, just as with
|
||||
* JSLookupPropOp.
|
||||
*/
|
||||
typedef JSBool
|
||||
(* JS_DLL_CALLBACK JSDefinePropOp)(JSContext *cx, JSObject *obj, jsid id, jsval value,
|
||||
(* JS_DLL_CALLBACK JSDefinePropOp)(JSContext *cx, JSObject *obj,
|
||||
jsid id, jsval value,
|
||||
JSPropertyOp getter, JSPropertyOp setter,
|
||||
uintN attrs, JSProperty **propp);
|
||||
|
||||
/*
|
||||
* Get, set, or delete obj[id], returning false on error or exception, true
|
||||
* on success. If getting or setting, the new value is returned in *vp on
|
||||
* success. If deleting without error, *vp will be JSVAL_FALSE if obj[id] is
|
||||
* permanent, and JSVAL_TRUE if id named a direct property of obj that was in
|
||||
* fact deleted, or if id names no direct property of obj (id could name a
|
||||
* prototype property, or no property in obj or its prototype chain).
|
||||
*/
|
||||
typedef JSBool
|
||||
(* JS_DLL_CALLBACK JSPropertyIdOp)(JSContext *cx, JSObject *obj, jsid id, jsval *vp);
|
||||
(* JS_DLL_CALLBACK JSPropertyIdOp)(JSContext *cx, JSObject *obj, jsid id,
|
||||
jsval *vp);
|
||||
|
||||
/*
|
||||
* Get or set attributes of the property obj[id]. Return false on error or
|
||||
* exception, true with current attributes in *attrsp. If prop is non-null,
|
||||
* it must come from the *propp out parameter of a prior JSDefinePropOp or
|
||||
* JSLookupPropOp call.
|
||||
*/
|
||||
typedef JSBool
|
||||
(* JS_DLL_CALLBACK JSAttributesOp)(JSContext *cx, JSObject *obj, jsid id,
|
||||
JSProperty *prop, uintN *attrsp);
|
||||
|
||||
/*
|
||||
* JSObjectOps.checkAccess type: check whether obj[id] may be accessed per
|
||||
* mode, returning false on error/exception, true on success with obj[id]'s
|
||||
* last-got value in *vp, and its attributes in *attrsp.
|
||||
*/
|
||||
typedef JSBool
|
||||
(* JS_DLL_CALLBACK JSCheckAccessIdOp)(JSContext *cx, JSObject *obj, jsid id,
|
||||
JSAccessMode mode, jsval *vp, uintN *attrsp);
|
||||
JSAccessMode mode, jsval *vp,
|
||||
uintN *attrsp);
|
||||
|
||||
/*
|
||||
* A generic type for functions mapping an object to another object, or null
|
||||
* if an error or exception was thrown on cx. Used by JSObjectOps.thisObject
|
||||
* at present.
|
||||
*/
|
||||
typedef JSObject *
|
||||
(* JS_DLL_CALLBACK JSObjectOp)(JSContext *cx, JSObject *obj);
|
||||
|
||||
/*
|
||||
* A generic type for functions taking a context, object, and property, with
|
||||
* no return value. Used by JSObjectOps.dropProperty currently (see above,
|
||||
* JSDefinePropOp and JSLookupPropOp, for the object-locking protocol in which
|
||||
* dropProperty participates).
|
||||
*/
|
||||
typedef void
|
||||
(* JS_DLL_CALLBACK JSPropertyRefOp)(JSContext *cx, JSObject *obj, JSProperty *prop);
|
||||
(* JS_DLL_CALLBACK JSPropertyRefOp)(JSContext *cx, JSObject *obj,
|
||||
JSProperty *prop);
|
||||
|
||||
/*
|
||||
* Function type for JSObjectOps.setProto and JSObjectOps.setParent. These
|
||||
* hooks must check for cycles without deadlocking, and otherwise take special
|
||||
* steps. See jsobj.c, js_SetProtoOrParent, for an example.
|
||||
*/
|
||||
typedef JSBool
|
||||
(* JS_DLL_CALLBACK JSSetObjectSlotOp)(JSContext *cx, JSObject *obj,
|
||||
uint32 slot, JSObject *pobj);
|
||||
|
||||
/*
|
||||
* Get and set a required slot, one that should already have been allocated.
|
||||
* These operations are infallible, so required slots must be pre-allocated,
|
||||
* or implementations must suppress out-of-memory errors. The native ops
|
||||
* (js_ObjectOps, see jsobj.c) access slots reserved by including a call to
|
||||
* the JSCLASS_HAS_RESERVED_SLOTS(n) macro in the JSClass.flags initializer.
|
||||
*
|
||||
* NB: the slot parameter is a zero-based index into obj->slots[], unlike the
|
||||
* index parameter to the JS_GetReservedSlot and JS_SetReservedSlot API entry
|
||||
* points, which is a zero-based index into the JSCLASS_RESERVED_SLOTS(clasp)
|
||||
* reserved slots that come after the initial well-known slots: proto, parent,
|
||||
* class, and optionally, the private data slot.
|
||||
*/
|
||||
typedef jsval
|
||||
(* JS_DLL_CALLBACK JSGetRequiredSlotOp)(JSContext *cx, JSObject *obj,
|
||||
uint32 slot);
|
||||
|
||||
typedef void
|
||||
(* JS_DLL_CALLBACK JSSetRequiredSlotOp)(JSContext *cx, JSObject *obj,
|
||||
uint32 slot, jsval v);
|
||||
|
||||
/* Typedef for native functions called by the JS VM. */
|
||||
|
||||
typedef JSBool
|
||||
(* JS_DLL_CALLBACK JSNative)(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
|
||||
jsval *rval);
|
||||
(* JS_DLL_CALLBACK JSNative)(JSContext *cx, JSObject *obj, uintN argc,
|
||||
jsval *argv, jsval *rval);
|
||||
|
||||
/* Callbacks and their arguments. */
|
||||
|
||||
@ -271,19 +478,22 @@ typedef const JSErrorFormatString *
|
||||
|
||||
typedef JSBool
|
||||
(* JS_DLL_CALLBACK JSArgumentFormatter)(JSContext *cx, const char *format,
|
||||
JSBool fromJS, jsval **vpp, va_list *app);
|
||||
JSBool fromJS, jsval **vpp,
|
||||
va_list *app);
|
||||
#endif
|
||||
|
||||
typedef JSBool
|
||||
(* JS_DLL_CALLBACK JSLocaleToUpperCase)(JSContext *cx, JSString *src, jsval *rval);
|
||||
(* JS_DLL_CALLBACK JSLocaleToUpperCase)(JSContext *cx, JSString *src,
|
||||
jsval *rval);
|
||||
|
||||
typedef JSBool
|
||||
(* JS_DLL_CALLBACK JSLocaleToLowerCase)(JSContext *cx, JSString *src, jsval *rval);
|
||||
(* JS_DLL_CALLBACK JSLocaleToLowerCase)(JSContext *cx, JSString *src,
|
||||
jsval *rval);
|
||||
|
||||
typedef JSBool
|
||||
(* JS_DLL_CALLBACK JSLocaleCompare)(JSContext *cx, JSString *src1, JSString *src2, jsval *rval);
|
||||
|
||||
|
||||
(* JS_DLL_CALLBACK JSLocaleCompare)(JSContext *cx,
|
||||
JSString *src1, JSString *src2,
|
||||
jsval *rval);
|
||||
|
||||
JS_END_EXTERN_C
|
||||
|
||||
|
@ -77,14 +77,14 @@ typedef struct JSXDRMemState {
|
||||
#define MEM_NEED(xdr, bytes) \
|
||||
JS_BEGIN_MACRO \
|
||||
if ((xdr)->mode == JSXDR_ENCODE) { \
|
||||
uint32 new_limit_ = JS_ROUNDUP(MEM_COUNT(xdr) + bytes, MEM_BLOCK);\
|
||||
if (MEM_LIMIT(xdr) && \
|
||||
MEM_COUNT(xdr) + bytes > MEM_LIMIT(xdr)) { \
|
||||
void *data_ = JS_realloc((xdr)->cx, (xdr)->data, new_limit_); \
|
||||
uint32 limit_ = JS_ROUNDUP(MEM_COUNT(xdr) + bytes, MEM_BLOCK);\
|
||||
void *data_ = JS_realloc((xdr)->cx, (xdr)->data, limit_); \
|
||||
if (!data_) \
|
||||
return 0; \
|
||||
(xdr)->data = data_; \
|
||||
MEM_LIMIT(xdr) = new_limit_; \
|
||||
MEM_LIMIT(xdr) = limit_; \
|
||||
} \
|
||||
} else { \
|
||||
MEM_LEFT(xdr, bytes); \
|
||||
@ -275,6 +275,8 @@ JS_XDRDestroy(JSXDRState *xdr)
|
||||
if (xdr->reghash)
|
||||
JS_DHashTableDestroy(xdr->reghash);
|
||||
}
|
||||
if (xdr->data)
|
||||
JS_free(cx, xdr->data);
|
||||
JS_free(cx, xdr);
|
||||
}
|
||||
|
||||
@ -470,7 +472,7 @@ JS_XDRDouble(JSXDRState *xdr, jsdouble **dp)
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
/* These are magic: see jsapi.h, near the top, for the real jsval tags. */
|
||||
/* These are magic pseudo-tags: see jsapi.h, near the top, for real tags. */
|
||||
#define JSVAL_XDRNULL 0x8
|
||||
#define JSVAL_XDRVOID 0xA
|
||||
|
||||
@ -498,7 +500,9 @@ JS_XDRValue(JSXDRState *xdr, jsval *vp)
|
||||
*vp = JSVAL_VOID;
|
||||
break;
|
||||
case JSVAL_STRING: {
|
||||
JSString *str = JSVAL_TO_STRING(*vp);
|
||||
JSString *str;
|
||||
if (xdr->mode == JSXDR_ENCODE)
|
||||
str = JSVAL_TO_STRING(*vp);
|
||||
if (!JS_XDRString(xdr, &str))
|
||||
return JS_FALSE;
|
||||
if (xdr->mode == JSXDR_DECODE)
|
||||
@ -528,29 +532,24 @@ JS_XDRValue(JSXDRState *xdr, jsval *vp)
|
||||
case JSVAL_BOOLEAN: {
|
||||
uint32 b;
|
||||
if (xdr->mode == JSXDR_ENCODE)
|
||||
b = (uint32)JSVAL_TO_BOOLEAN(*vp);
|
||||
b = (uint32) JSVAL_TO_BOOLEAN(*vp);
|
||||
if (!JS_XDRUint32(xdr, &b))
|
||||
return JS_FALSE;
|
||||
if (xdr->mode == JSXDR_DECODE)
|
||||
*vp = BOOLEAN_TO_JSVAL((JSBool)b);
|
||||
*vp = BOOLEAN_TO_JSVAL((JSBool) b);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
char numBuf[12];
|
||||
if (type & JSVAL_INT) {
|
||||
uint32 i;
|
||||
if (xdr->mode == JSXDR_ENCODE)
|
||||
i = (uint32) JSVAL_TO_INT(*vp);
|
||||
if (!JS_XDRUint32(xdr, &i))
|
||||
return JS_FALSE;
|
||||
if (xdr->mode == JSXDR_DECODE)
|
||||
*vp = INT_TO_JSVAL((int32) i);
|
||||
break;
|
||||
}
|
||||
JS_snprintf(numBuf, sizeof numBuf, "%#lx", type);
|
||||
JS_ReportErrorNumber(xdr->cx, js_GetErrorMessage, NULL,
|
||||
JSMSG_BAD_JVAL_TYPE, type);
|
||||
return JS_FALSE;
|
||||
uint32 i;
|
||||
|
||||
JS_ASSERT(type & JSVAL_INT);
|
||||
if (xdr->mode == JSXDR_ENCODE)
|
||||
i = (uint32) JSVAL_TO_INT(*vp);
|
||||
if (!JS_XDRUint32(xdr, &i))
|
||||
return JS_FALSE;
|
||||
if (xdr->mode == JSXDR_DECODE)
|
||||
*vp = INT_TO_JSVAL((int32) i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return JS_TRUE;
|
||||
@ -561,7 +560,14 @@ JS_XDRScript(JSXDRState *xdr, JSScript **scriptp)
|
||||
{
|
||||
JSBool hasMagic;
|
||||
|
||||
return js_XDRScript(xdr, scriptp, &hasMagic);
|
||||
if (!js_XDRScript(xdr, scriptp, &hasMagic))
|
||||
return JS_FALSE;
|
||||
if (!hasMagic) {
|
||||
JS_ReportErrorNumber(xdr->cx, js_GetErrorMessage, NULL,
|
||||
JSMSG_BAD_SCRIPT_MAGIC);
|
||||
return JS_FALSE;
|
||||
}
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
#define CLASS_REGISTRY_MIN 8
|
||||
|
Loading…
x
Reference in New Issue
Block a user