- 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:
brendan%mozilla.org 2001-04-05 01:53:24 +00:00
parent 23699ce01d
commit cd37f8447b
12 changed files with 1066 additions and 663 deletions

File diff suppressed because it is too large Load Diff

View File

@ -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")

View File

@ -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;

View File

@ -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);
/************************************************************************/
/*

View File

@ -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,

View File

@ -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)

View File

@ -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);

View File

@ -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 *);

View File

@ -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. */

View File

@ -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___ */

View File

@ -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

View File

@ -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