From 69ab37f337ab85fa1bdf3eb12cbf24d4bd36ccf7 Mon Sep 17 00:00:00 2001 From: "brendan%mozilla.org" Date: Tue, 6 Mar 2001 01:56:30 +0000 Subject: [PATCH] bugs 31003 and (mostly) 68045, r=rogerl, sr=shaver&hyatt - Fix bug where script jssrcnote vector terminator was not XDRed. - Ensure that memory is cleared by serializing zero padding bytes as needed under JS_XDRBytes and JS_XDRString. - Fix JS_XDRValue to handle undefined and null JS types properly (bug 31003). Also make it cast from jsint to uint32 and back carefully, so as to work with negative numbers even on targets where jsval is a signed 64 bit type. - Add JS_XDRScript public API. - Optimize the per-JSXDRState class registry so it uses a JSDHashTable upon searching for a class-id by name in an overpopulated (for linear search) registry table. - Clean up API nits such as JS_XDRNewBase => JS_XDRInitBase, with parameter list rotation to put cx last (JS_XDRInitBase is an infallible init helper, not an error-reporting, cx-comes-first, API entry point). - Fix some XXX comments, unneeded masks, other nits. - Make sure all JS XDR API functions start with JS_XDR. --- js/src/jsobj.c | 9 +- js/src/jsscript.c | 367 +++++++++++++++---------------- js/src/jsxdrapi.c | 544 ++++++++++++++++++++++++++-------------------- js/src/jsxdrapi.h | 30 ++- 4 files changed, 520 insertions(+), 430 deletions(-) diff --git a/js/src/jsobj.c b/js/src/jsobj.c index e20ea166cd55..76360ebba8bc 100644 --- a/js/src/jsobj.c +++ b/js/src/jsobj.c @@ -3096,9 +3096,9 @@ js_XDRObject(JSXDRState *xdr, JSObject **objp) if (xdr->mode == JSXDR_ENCODE) { clasp = OBJ_GET_CLASS(cx, *objp); className = clasp->name; - classId = JS_FindClassIdByName(xdr, className); + classId = JS_XDRFindClassIdByName(xdr, className); classDef = !classId; - if (classDef && !JS_RegisterClass(xdr, clasp, &classId)) + if (classDef && !JS_XDRRegisterClass(xdr, clasp, &classId)) return JS_FALSE; } else { classDef = 0; @@ -3123,11 +3123,11 @@ js_XDRObject(JSXDRState *xdr, JSObject **objp) if (!ok) goto out; clasp = OBJ_GET_CLASS(cx, proto); - ok = JS_RegisterClass(xdr, clasp, &classId); + ok = JS_XDRRegisterClass(xdr, clasp, &classId); if (!ok) goto out; } else { - clasp = JS_FindClassById(xdr, classId); + clasp = JS_XDRFindClassById(xdr, classId); if (!clasp) { char numBuf[12]; JS_snprintf(numBuf, sizeof numBuf, "%ld", (long)classId); @@ -3312,4 +3312,3 @@ void printAtom(JSAtom *atom) { } #endif - diff --git a/js/src/jsscript.c b/js/src/jsscript.c index efe4990088e8..4d489fee1106 100644 --- a/js/src/jsscript.c +++ b/js/src/jsscript.c @@ -60,7 +60,7 @@ #if JS_HAS_TOSOURCE static JSBool script_toSource(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) + jsval *rval) { JSScript *script; size_t i, j, k, n; @@ -70,40 +70,40 @@ script_toSource(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, JSString *str; if (!JS_InstanceOf(cx, obj, &js_ScriptClass, argv)) - return JS_FALSE; + return JS_FALSE; script = (JSScript *) JS_GetPrivate(cx, obj); /* Let n count the source string length, j the "front porch" length. */ j = JS_snprintf(buf, sizeof buf, "(new %s(", js_ScriptClass.name); n = j + 2; if (!script) { - /* Let k count the constructor argument string length. */ - k = 0; + /* Let k count the constructor argument string length. */ + k = 0; s = NULL; /* quell GCC overwarning */ } else { - indent = 0; - if (argc && !js_ValueToECMAUint32(cx, argv[0], &indent)) - return JS_FALSE; - str = JS_DecompileScript(cx, script, "Script.prototype.toSource", - (uintN)indent); - if (!str) - return JS_FALSE; - str = js_QuoteString(cx, str, '\''); - if (!str) - return JS_FALSE; - s = str->chars; - k = str->length; - n += k; + indent = 0; + if (argc && !js_ValueToECMAUint32(cx, argv[0], &indent)) + return JS_FALSE; + str = JS_DecompileScript(cx, script, "Script.prototype.toSource", + (uintN)indent); + if (!str) + return JS_FALSE; + str = js_QuoteString(cx, str, '\''); + if (!str) + return JS_FALSE; + s = str->chars; + k = str->length; + n += k; } /* Allocate the source string and copy into it. */ t = (jschar *) JS_malloc(cx, (n + 1) * sizeof(jschar)); if (!t) - return JS_FALSE; + return JS_FALSE; for (i = 0; i < j; i++) - t[i] = buf[i]; + t[i] = buf[i]; for (j = 0; j < k; i++, j++) - t[i] = s[j]; + t[i] = s[j]; t[i++] = ')'; t[i++] = ')'; t[i] = 0; @@ -111,8 +111,8 @@ script_toSource(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, /* Create and return a JS string for t. */ str = JS_NewUCString(cx, t, n); if (!str) { - JS_free(cx, t); - return JS_FALSE; + JS_free(cx, t); + return JS_FALSE; } *rval = STRING_TO_JSVAL(str); return JS_TRUE; @@ -121,34 +121,34 @@ script_toSource(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, static JSBool script_toString(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) + jsval *rval) { JSScript *script; uint32 indent; JSString *str; if (!JS_InstanceOf(cx, obj, &js_ScriptClass, argv)) - return JS_FALSE; + return JS_FALSE; script = (JSScript *) JS_GetPrivate(cx, obj); if (!script) { - *rval = STRING_TO_JSVAL(cx->runtime->emptyString); - return JS_TRUE; + *rval = STRING_TO_JSVAL(cx->runtime->emptyString); + return JS_TRUE; } indent = 0; if (argc && !js_ValueToECMAUint32(cx, argv[0], &indent)) - return JS_FALSE; + return JS_FALSE; str = JS_DecompileScript(cx, script, "Script.prototype.toString", - (uintN)indent); + (uintN)indent); if (!str) - return JS_FALSE; + return JS_FALSE; *rval = STRING_TO_JSVAL(str); return JS_TRUE; } static JSBool script_compile(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) + jsval *rval) { JSScript *oldscript, *script; JSString *str; @@ -160,12 +160,12 @@ script_compile(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, /* If no args, leave private undefined and return early. */ if (argc == 0) - goto out; + goto out; /* Otherwise, the first arg is the script source to compile. */ str = js_ValueToString(cx, argv[0]); if (!str) - return JS_FALSE; + return JS_FALSE; /* Compile using the caller's scope chain, which js_Invoke passes to fp. */ fp = cx->fp; @@ -174,38 +174,38 @@ script_compile(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, scopeobj = NULL; if (argc >= 2) { - if (!js_ValueToObject(cx, argv[1], &scopeobj)) - return JS_FALSE; - argv[1] = OBJECT_TO_JSVAL(scopeobj); + if (!js_ValueToObject(cx, argv[1], &scopeobj)) + return JS_FALSE; + argv[1] = OBJECT_TO_JSVAL(scopeobj); } if (!scopeobj) - scopeobj = caller->scopeChain; + scopeobj = caller->scopeChain; if (caller->script) { - file = caller->script->filename; - line = js_PCToLineNumber(caller->script, caller->pc); - principals = caller->script->principals; + file = caller->script->filename; + line = js_PCToLineNumber(caller->script, caller->pc); + principals = caller->script->principals; } else { - file = NULL; - line = 0; - principals = NULL; + file = NULL; + line = 0; + principals = NULL; } /* Compile the new script using the caller's scope chain, a la eval(). */ script = JS_CompileUCScriptForPrincipals(cx, scopeobj, principals, - str->chars, str->length, - file, line); + str->chars, str->length, + file, line); if (!script) - return JS_FALSE; + return JS_FALSE; /* Swap script for obj's old script, if any. */ oldscript = (JSScript *) JS_GetPrivate(cx, obj); if (!JS_SetPrivate(cx, obj, script)) { - js_DestroyScript(cx, script); - return JS_FALSE; + js_DestroyScript(cx, script); + return JS_FALSE; } if (oldscript) - js_DestroyScript(cx, oldscript); + js_DestroyScript(cx, oldscript); script->object = obj; out: @@ -222,16 +222,16 @@ script_exec(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) JSObject *scopeobj; if (!JS_InstanceOf(cx, obj, &js_ScriptClass, argv)) - return JS_FALSE; + return JS_FALSE; script = (JSScript *) JS_GetPrivate(cx, obj); if (!script) - return JS_TRUE; + return JS_TRUE; scopeobj = NULL; if (argc) { - if (!js_ValueToObject(cx, argv[0], &scopeobj)) - return JS_FALSE; - argv[0] = OBJECT_TO_JSVAL(scopeobj); + if (!js_ValueToObject(cx, argv[0], &scopeobj)) + return JS_FALSE; + argv[0] = OBJECT_TO_JSVAL(scopeobj); } /* Emulate eval() by using caller's this, scope chain, and sharp array. */ @@ -247,25 +247,25 @@ script_exec(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) #if JS_HAS_XDR static JSBool -XDRAtom1(JSXDRState *xdr, JSAtomListElement *ale) +XDRAtomListElement(JSXDRState *xdr, JSAtomListElement *ale) { jsval value; jsatomid index; if (xdr->mode == JSXDR_ENCODE) - value = ATOM_KEY(ALE_ATOM(ale)); + value = ATOM_KEY(ALE_ATOM(ale)); index = ALE_INDEX(ale); if (!JS_XDRUint32(xdr, &index)) - return JS_FALSE; + return JS_FALSE; ALE_SET_INDEX(ale, index); if (!JS_XDRValue(xdr, &value)) - return JS_FALSE; + return JS_FALSE; if (xdr->mode == JSXDR_DECODE) { - if (!ALE_SET_ATOM(ale, js_AtomizeValue(xdr->cx, value, 0))) - return JS_FALSE; + if (!ALE_SET_ATOM(ale, js_AtomizeValue(xdr->cx, value, 0))) + return JS_FALSE; } return JS_TRUE; } @@ -278,47 +278,47 @@ XDRAtomMap(JSXDRState *xdr, JSAtomMap *map) JSBool ok; if (xdr->mode == JSXDR_ENCODE) - length = map->length; + length = map->length; if (!JS_XDRUint32(xdr, &length)) - return JS_FALSE; + return JS_FALSE; if (xdr->mode == JSXDR_DECODE) { - JSContext *cx; - void *mark; - JSAtomList al; - JSAtomListElement *ale; + JSContext *cx; + void *mark; + JSAtomList al; + JSAtomListElement *ale; - cx = xdr->cx; - mark = JS_ARENA_MARK(&cx->tempPool); - ATOM_LIST_INIT(&al); - for (i = 0; i < length; i++) { - JS_ARENA_ALLOCATE_TYPE(ale, JSAtomListElement, &cx->tempPool); - if (!ale || - !XDRAtom1(xdr, ale)) { - if (!ale) - JS_ReportOutOfMemory(cx); - JS_ARENA_RELEASE(&cx->tempPool, mark); - return JS_FALSE; - } - ALE_SET_NEXT(ale, al.list); - al.count++; - al.list = ale; - } + cx = xdr->cx; + mark = JS_ARENA_MARK(&cx->tempPool); + ATOM_LIST_INIT(&al); + for (i = 0; i < length; i++) { + JS_ARENA_ALLOCATE_TYPE(ale, JSAtomListElement, &cx->tempPool); + if (!ale || + !XDRAtomListElement(xdr, ale)) { + if (!ale) + JS_ReportOutOfMemory(cx); + JS_ARENA_RELEASE(&cx->tempPool, mark); + return JS_FALSE; + } + ALE_SET_NEXT(ale, al.list); + al.count++; + al.list = ale; + } ok = js_InitAtomMap(cx, map, &al); JS_ARENA_RELEASE(&cx->tempPool, mark); return ok; } if (xdr->mode == JSXDR_ENCODE) { - JSAtomListElement ale; + JSAtomListElement ale; - for (i = 0; i < map->length; i++) { - ALE_SET_ATOM(&ale, map->vector[i]); - ALE_SET_INDEX(&ale, i); - if (!XDRAtom1(xdr, &ale)) - return JS_FALSE; - } + for (i = 0; i < map->length; i++) { + ALE_SET_ATOM(&ale, map->vector[i]); + ALE_SET_INDEX(&ale, i); + if (!XDRAtomListElement(xdr, &ale)) + return JS_FALSE; + } } return JS_TRUE; } @@ -348,7 +348,7 @@ js_XDRScript(JSXDRState *xdr, JSScript **scriptp, JSBool *hasMagic) *hasMagic = JS_TRUE; if (xdr->mode == JSXDR_ENCODE) { - jssrcnote *end = script->notes; + jssrcnote *sn = script->notes; length = script->length; prologLength = script->main - script->code; version = (int32) script->version; @@ -363,9 +363,10 @@ js_XDRScript(JSXDRState *xdr, JSScript **scriptp, JSBool *hasMagic) } /* Count the src notes. */ - while (!SN_IS_TERMINATOR(end)) - end = SN_NEXT(end); - notelen = end - script->notes; + while (!SN_IS_TERMINATOR(sn)) + sn = SN_NEXT(sn); + notelen = sn - script->notes; + notelen++; /* room for the terminator */ } if (!JS_XDRUint32(xdr, &length)) @@ -441,7 +442,7 @@ js_XDRScript(JSXDRState *xdr, JSScript **scriptp, JSBool *hasMagic) static JSBool script_freeze(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) + jsval *rval) { JSXDRState *xdr; JSScript *script; @@ -451,37 +452,37 @@ script_freeze(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, JSString *str; if (!JS_InstanceOf(cx, obj, &js_ScriptClass, argv)) - return JS_FALSE; + return JS_FALSE; script = (JSScript *) JS_GetPrivate(cx, obj); if (!script) - return JS_TRUE; + return JS_TRUE; /* create new XDR */ xdr = JS_XDRNewMem(cx, JSXDR_ENCODE); if (!xdr) - return JS_FALSE; + return JS_FALSE; /* write */ ok = js_XDRScript(xdr, &script, &hasMagic); if (!ok) - goto out; + goto out; if (!hasMagic) { - *rval = JSVAL_VOID; - goto out; + *rval = JSVAL_VOID; + goto out; } buf = JS_XDRMemGetData(xdr, &len); if (!buf) { - ok = JS_FALSE; - goto out; + ok = JS_FALSE; + goto out; } JS_ASSERT((jsword)buf % sizeof(jschar) == 0); len /= sizeof(jschar); str = JS_NewUCStringCopyN(cx, (jschar *)buf, len); if (!str) { - ok = JS_FALSE; - goto out; + ok = JS_FALSE; + goto out; } #if IS_BIG_ENDIAN @@ -492,7 +493,7 @@ script_freeze(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, /* Swap bytes in Unichars to keep frozen strings machine-independent. */ chars = JS_GetStringChars(str); for (i = 0; i < len; i++) - chars[i] = JSXDR_SWAB16(chars[i]); + chars[i] = JSXDR_SWAB16(chars[i]); } #endif *rval = STRING_TO_JSVAL(str); @@ -504,7 +505,7 @@ out: static JSBool script_thaw(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) + jsval *rval) { JSXDRState *xdr; JSString *str; @@ -514,18 +515,18 @@ script_thaw(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, JSBool ok, hasMagic; if (!JS_InstanceOf(cx, obj, &js_ScriptClass, argv)) - return JS_FALSE; + return JS_FALSE; if (argc == 0) - return JS_TRUE; + return JS_TRUE; str = js_ValueToString(cx, argv[0]); if (!str) - return JS_FALSE; + return JS_FALSE; /* create new XDR */ xdr = JS_XDRNewMem(cx, JSXDR_DECODE); if (!xdr) - return JS_FALSE; + return JS_FALSE; buf = JS_GetStringChars(str); len = JS_GetStringLength(str); @@ -542,7 +543,7 @@ script_thaw(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, return JS_FALSE; } for (i = 0; i < len; i++) - to[i] = JSXDR_SWAB16(from[i]); + to[i] = JSXDR_SWAB16(from[i]); buf = (char *)to; } #endif @@ -552,21 +553,21 @@ script_thaw(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, /* XXXbe should magic mismatch be error, or false return value? */ ok = js_XDRScript(xdr, &script, &hasMagic); if (!ok) - goto out; + goto out; if (!hasMagic) { - *rval = JSVAL_FALSE; - goto out; + *rval = JSVAL_FALSE; + goto out; } /* Swap script for obj's old script, if any. */ oldscript = (JSScript *) JS_GetPrivate(cx, obj); ok = JS_SetPrivate(cx, obj, script); if (!ok) { - JS_free(cx, script); - goto out; + JS_free(cx, script); + goto out; } if (oldscript) - js_DestroyScript(cx, oldscript); + js_DestroyScript(cx, oldscript); script->object = obj; @@ -596,8 +597,8 @@ static JSFunctionSpec script_methods[] = { {"compile", script_compile, 2,0,0}, {"exec", script_exec, 1,0,0}, #if JS_HAS_XDR - {"freeze", script_freeze, 0,0,0}, - {js_thaw_str, script_thaw, 1,0,0}, + {"freeze", script_freeze, 0,0,0}, + {js_thaw_str, script_thaw, 1,0,0}, #endif /* JS_HAS_XDR */ {0,0,0,0,0} }; @@ -611,7 +612,7 @@ script_finalize(JSContext *cx, JSObject *obj) script = (JSScript *) JS_GetPrivate(cx, obj); if (script) - js_DestroyScript(cx, script); + js_DestroyScript(cx, script); } static JSBool @@ -651,9 +652,9 @@ Script(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) { /* If not constructing, replace obj with a new Script object. */ if (!cx->fp->constructing) { - obj = js_NewObject(cx, &js_ScriptClass, NULL, NULL); - if (!obj) - return JS_FALSE; + obj = js_NewObject(cx, &js_ScriptClass, NULL, NULL); + if (!obj) + return JS_FALSE; } return script_compile(cx, obj, argc, argv, rval); } @@ -662,13 +663,13 @@ Script(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) static JSBool script_static_thaw(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) + jsval *rval) { obj = js_NewObject(cx, &js_ScriptClass, NULL, NULL); if (!obj) - return JS_FALSE; + return JS_FALSE; if (!script_thaw(cx, obj, argc, argv, rval)) - return JS_FALSE; + return JS_FALSE; *rval = OBJECT_TO_JSVAL(obj); return JS_TRUE; } @@ -688,7 +689,7 @@ JSObject * js_InitScriptClass(JSContext *cx, JSObject *obj) { return JS_InitClass(cx, obj, NULL, &js_ScriptClass, Script, 1, - NULL, script_methods, NULL, script_static_methods); + NULL, script_methods, NULL, script_static_methods); } #endif /* JS_HAS_SCRIPT_OBJECT */ @@ -701,7 +702,7 @@ js_NewScript(JSContext *cx, uint32 length) script = (JSScript *) JS_malloc(cx, sizeof(JSScript) + length * sizeof(jsbytecode)); if (!script) - return NULL; + return NULL; memset(script, 0, sizeof(JSScript)); script->code = script->main = (jsbytecode *)(script + 1); script->length = length; @@ -711,32 +712,32 @@ js_NewScript(JSContext *cx, uint32 length) JSScript * js_NewScriptFromParams(JSContext *cx, jsbytecode *code, uint32 length, - jsbytecode *prolog, uint32 prologLength, - const char *filename, uintN lineno, uintN depth, - jssrcnote *notes, JSTryNote *trynotes, - JSPrincipals *principals) + jsbytecode *prolog, uint32 prologLength, + const char *filename, uintN lineno, uintN depth, + jssrcnote *notes, JSTryNote *trynotes, + JSPrincipals *principals) { JSScript *script; script = js_NewScript(cx, prologLength + length); if (!script) - return NULL; + return NULL; script->main += prologLength; memcpy(script->code, prolog, prologLength * sizeof(jsbytecode)); memcpy(script->main, code, length * sizeof(jsbytecode)); if (filename) { - script->filename = JS_strdup(cx, filename); - if (!script->filename) { - js_DestroyScript(cx, script); - return NULL; - } + script->filename = JS_strdup(cx, filename); + if (!script->filename) { + js_DestroyScript(cx, script); + return NULL; + } } script->lineno = lineno; script->depth = depth; script->notes = notes; script->trynotes = trynotes; if (principals) - JSPRINCIPALS_HOLD(cx, principals); + JSPRINCIPALS_HOLD(cx, principals); script->principals = principals; return script; } @@ -751,26 +752,26 @@ js_NewScriptFromCG(JSContext *cx, JSCodeGenerator *cg, JSFunction *fun) JSNewScriptHook hook; if (!js_FinishTakingTryNotes(cx, cg, &trynotes)) - return NULL; + return NULL; notes = js_FinishTakingSrcNotes(cx, cg); script = js_NewScriptFromParams(cx, CG_BASE(cg), CG_OFFSET(cg), CG_PROLOG_BASE(cg), CG_PROLOG_OFFSET(cg), - cg->filename, cg->firstLine, - cg->maxStackDepth, notes, trynotes, - cg->principals); + cg->filename, cg->firstLine, + cg->maxStackDepth, notes, trynotes, + cg->principals); if (!script) - return NULL; + return NULL; if (!notes || !js_InitAtomMap(cx, &script->atomMap, &cg->atomList)) { - js_DestroyScript(cx, script); - return NULL; + js_DestroyScript(cx, script); + return NULL; } /* Tell the debugger about this compiled script. */ rt = cx->runtime; hook = rt->newScriptHook; if (hook) { - (*hook)(cx, cg->filename, cg->firstLine, script, fun, - rt->newScriptHookData); + (*hook)(cx, cg->filename, cg->firstLine, script, fun, + rt->newScriptHookData); } return script; } @@ -784,7 +785,7 @@ js_DestroyScript(JSContext *cx, JSScript *script) rt = cx->runtime; hook = rt->destroyScriptHook; if (hook) - (*hook)(cx, script, rt->destroyScriptHookData); + (*hook)(cx, script, rt->destroyScriptHookData); JS_ClearScriptTraps(cx, script); js_FreeAtomMap(cx, &script->atomMap); @@ -792,7 +793,7 @@ js_DestroyScript(JSContext *cx, JSScript *script) JS_free(cx, script->notes); JS_free(cx, script->trynotes); if (script->principals) - JSPRINCIPALS_DROP(cx, script->principals); + JSPRINCIPALS_DROP(cx, script->principals); JS_free(cx, script); } @@ -818,14 +819,14 @@ js_GetSrcNote(JSScript *script, jsbytecode *pc) sn = script->notes; if (!sn) - return NULL; + return NULL; target = PTRDIFF(pc, script->main, jsbytecode); if ((uintN)target >= script->length) - return NULL; + return NULL; for (offset = 0; !SN_IS_TERMINATOR(sn); sn = SN_NEXT(sn)) { - offset += SN_DELTA(sn); - if (offset == target && SN_IS_GETTABLE(sn)) - return sn; + offset += SN_DELTA(sn); + if (offset == target && SN_IS_GETTABLE(sn)) + return sn; } return NULL; } @@ -840,21 +841,21 @@ js_PCToLineNumber(JSScript *script, jsbytecode *pc) sn = script->notes; if (!sn) - return 0; + return 0; target = PTRDIFF(pc, script->main, jsbytecode); lineno = script->lineno; for (offset = 0; !SN_IS_TERMINATOR(sn); sn = SN_NEXT(sn)) { - offset += SN_DELTA(sn); - type = (JSSrcNoteType) SN_TYPE(sn); - if (type == SRC_SETLINE) { - if (offset <= target) - lineno = (uintN) js_GetSrcNoteOffset(sn, 0); - } else if (type == SRC_NEWLINE) { - if (offset <= target) - lineno++; - } - if (offset > target) - break; + offset += SN_DELTA(sn); + type = (JSSrcNoteType) SN_TYPE(sn); + if (type == SRC_SETLINE) { + if (offset <= target) + lineno = (uintN) js_GetSrcNoteOffset(sn, 0); + } else if (type == SRC_NEWLINE) { + if (offset <= target) + lineno++; + } + if (offset > target) + break; } return lineno; } @@ -869,18 +870,18 @@ js_LineNumberToPC(JSScript *script, uintN target) sn = script->notes; if (!sn) - return NULL; + return NULL; lineno = script->lineno; for (offset = 0; !SN_IS_TERMINATOR(sn); sn = SN_NEXT(sn)) { - if (lineno >= target) - break; - offset += SN_DELTA(sn); - type = (JSSrcNoteType) SN_TYPE(sn); - if (type == SRC_SETLINE) { - lineno = (uintN) js_GetSrcNoteOffset(sn, 0); - } else if (type == SRC_NEWLINE) { - lineno++; - } + if (lineno >= target) + break; + offset += SN_DELTA(sn); + type = (JSSrcNoteType) SN_TYPE(sn); + if (type == SRC_SETLINE) { + lineno = (uintN) js_GetSrcNoteOffset(sn, 0); + } else if (type == SRC_NEWLINE) { + lineno++; + } } return script->main + offset; } @@ -894,15 +895,15 @@ js_GetScriptLineExtent(JSScript *script) sn = script->notes; if (!sn) - return 0; + return 0; lineno = script->lineno; for (; !SN_IS_TERMINATOR(sn); sn = SN_NEXT(sn)) { - type = (JSSrcNoteType) SN_TYPE(sn); - if (type == SRC_SETLINE) { - lineno = (uintN) js_GetSrcNoteOffset(sn, 0); - } else if (type == SRC_NEWLINE) { - lineno++; - } + type = (JSSrcNoteType) SN_TYPE(sn); + if (type == SRC_SETLINE) { + lineno = (uintN) js_GetSrcNoteOffset(sn, 0); + } else if (type == SRC_NEWLINE) { + lineno++; + } } return 1 + lineno - script->lineno; } diff --git a/js/src/jsxdrapi.c b/js/src/jsxdrapi.c index 08690d17831f..f8c27ebced60 100644 --- a/js/src/jsxdrapi.c +++ b/js/src/jsxdrapi.c @@ -36,10 +36,11 @@ #include #include "jstypes.h" #include "jsutil.h" /* Added by JSIFY */ +#include "jsdhash.h" #include "jsprf.h" #include "jsapi.h" #include "jscntxt.h" -#include "jsobj.h" /* js_XDRObject */ +#include "jsobj.h" /* js_XDRObject */ #include "jsstr.h" #include "jsxdrapi.h" @@ -64,36 +65,29 @@ typedef struct JSXDRMemState { #define MEM_LEFT(xdr, bytes) \ JS_BEGIN_MACRO \ - if ((xdr)->mode == JSXDR_DECODE && \ - MEM_COUNT(xdr) + bytes > MEM_LIMIT(xdr)) { \ - JS_ReportErrorNumber((xdr)->cx, js_GetErrorMessage, NULL, \ - JSMSG_END_OF_DATA); \ - return 0; \ - } \ + if ((xdr)->mode == JSXDR_DECODE && \ + MEM_COUNT(xdr) + bytes > MEM_LIMIT(xdr)) { \ + JS_ReportErrorNumber((xdr)->cx, js_GetErrorMessage, NULL, \ + JSMSG_END_OF_DATA); \ + return 0; \ + } \ JS_END_MACRO -/* XXXbe why does NEED even allow or cope with non-ENCODE mode? */ #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); \ - if (!_data) \ - return 0; \ - (xdr)->data = _data; \ - MEM_LIMIT(xdr) = _new_limit; \ - } \ - } else { \ - if (MEM_LIMIT(xdr) < MEM_COUNT(xdr) + bytes) { \ - JS_ReportErrorNumber((xdr)->cx, js_GetErrorMessage, NULL, \ - JSMSG_END_OF_DATA); \ - return 0; \ - } \ - } \ + 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_); \ + if (!data_) \ + return 0; \ + (xdr)->data = data_; \ + MEM_LIMIT(xdr) = new_limit_; \ + } \ + } else { \ + MEM_LEFT(xdr, bytes); \ + } \ JS_END_MACRO #define MEM_DATA(xdr) ((void *)((char *)(xdr)->data + MEM_COUNT(xdr))) @@ -140,9 +134,9 @@ mem_raw(JSXDRState *xdr, uint32 len) { void *data; if (xdr->mode == JSXDR_ENCODE) { - MEM_NEED(xdr, len); + MEM_NEED(xdr, len); } else if (xdr->mode == JSXDR_DECODE) { - MEM_LEFT(xdr, len); + MEM_LEFT(xdr, len); } data = MEM_DATA(xdr); MEM_INCR(xdr, len); @@ -154,50 +148,50 @@ mem_seek(JSXDRState *xdr, int32 offset, JSXDRWhence whence) { switch (whence) { case JSXDR_SEEK_CUR: - if ((int32)MEM_COUNT(xdr) + offset < 0) { - JS_ReportErrorNumber(xdr->cx, js_GetErrorMessage, NULL, - JSMSG_SEEK_BEYOND_START); - return JS_FALSE; - } - if (offset > 0) - MEM_NEED(xdr, offset); - MEM_COUNT(xdr) += offset; - return JS_TRUE; + if ((int32)MEM_COUNT(xdr) + offset < 0) { + JS_ReportErrorNumber(xdr->cx, js_GetErrorMessage, NULL, + JSMSG_SEEK_BEYOND_START); + return JS_FALSE; + } + if (offset > 0) + MEM_NEED(xdr, offset); + MEM_COUNT(xdr) += offset; + return JS_TRUE; case JSXDR_SEEK_SET: - if (offset < 0) { - JS_ReportErrorNumber(xdr->cx, js_GetErrorMessage, NULL, - JSMSG_SEEK_BEYOND_START); - return JS_FALSE; - } - if (xdr->mode == JSXDR_ENCODE) { - if ((uint32)offset > MEM_COUNT(xdr)) - MEM_NEED(xdr, offset - MEM_COUNT(xdr)); - MEM_COUNT(xdr) = offset; - } else { - if ((uint32)offset > MEM_LIMIT(xdr)) { - JS_ReportErrorNumber(xdr->cx, js_GetErrorMessage, NULL, - JSMSG_SEEK_BEYOND_END); - return JS_FALSE; - } - MEM_COUNT(xdr) = offset; - } - return JS_TRUE; + if (offset < 0) { + JS_ReportErrorNumber(xdr->cx, js_GetErrorMessage, NULL, + JSMSG_SEEK_BEYOND_START); + return JS_FALSE; + } + if (xdr->mode == JSXDR_ENCODE) { + if ((uint32)offset > MEM_COUNT(xdr)) + MEM_NEED(xdr, offset - MEM_COUNT(xdr)); + MEM_COUNT(xdr) = offset; + } else { + if ((uint32)offset > MEM_LIMIT(xdr)) { + JS_ReportErrorNumber(xdr->cx, js_GetErrorMessage, NULL, + JSMSG_SEEK_BEYOND_END); + return JS_FALSE; + } + MEM_COUNT(xdr) = offset; + } + return JS_TRUE; case JSXDR_SEEK_END: - if (offset >= 0 || - xdr->mode == JSXDR_ENCODE || - (int32)MEM_LIMIT(xdr) + offset < 0) { - JS_ReportErrorNumber(xdr->cx, js_GetErrorMessage, NULL, - JSMSG_END_SEEK); - return JS_FALSE; - } - MEM_COUNT(xdr) = MEM_LIMIT(xdr) + offset; - return JS_TRUE; + if (offset >= 0 || + xdr->mode == JSXDR_ENCODE || + (int32)MEM_LIMIT(xdr) + offset < 0) { + JS_ReportErrorNumber(xdr->cx, js_GetErrorMessage, NULL, + JSMSG_END_SEEK); + return JS_FALSE; + } + MEM_COUNT(xdr) = MEM_LIMIT(xdr) + offset; + return JS_TRUE; default: { - char numBuf[12]; - JS_snprintf(numBuf, sizeof numBuf, "%d", whence); - JS_ReportErrorNumber(xdr->cx, js_GetErrorMessage, NULL, - JSMSG_WHITHER_WHENCE, numBuf); - return JS_FALSE; + char numBuf[12]; + JS_snprintf(numBuf, sizeof numBuf, "%d", whence); + JS_ReportErrorNumber(xdr->cx, js_GetErrorMessage, NULL, + JSMSG_WHITHER_WHENCE, numBuf); + return JS_FALSE; } } } @@ -211,8 +205,7 @@ mem_tell(JSXDRState *xdr) static void mem_finalize(JSXDRState *xdr) { - JSContext *cx = xdr->cx; - JS_free(cx, xdr->data); + JS_free(xdr->cx, xdr->data); } static JSXDROps xdrmem_ops = { @@ -221,12 +214,13 @@ static JSXDROps xdrmem_ops = { }; JS_PUBLIC_API(void) -JS_XDRNewBase(JSContext *cx, JSXDRState *xdr, JSXDRMode mode) +JS_XDRInitBase(JSXDRState *xdr, JSXDRMode mode, JSContext *cx) { - xdr->cx = cx; xdr->mode = mode; + xdr->cx = cx; xdr->registry = NULL; - xdr->nclasses = 0; + xdr->numclasses = xdr->maxclasses = 0; + xdr->reghash = NULL; } JS_PUBLIC_API(JSXDRState *) @@ -234,16 +228,16 @@ JS_XDRNewMem(JSContext *cx, JSXDRMode mode) { JSXDRState *xdr = (JSXDRState *) JS_malloc(cx, sizeof(JSXDRMemState)); if (!xdr) - return NULL; - JS_XDRNewBase(cx, xdr, mode); + return NULL; + JS_XDRInitBase(xdr, mode, cx); if (mode == JSXDR_ENCODE) { - if (!(xdr->data = JS_malloc(cx, MEM_BLOCK))) { - JS_free(cx, xdr); - return NULL; - } + if (!(xdr->data = JS_malloc(cx, MEM_BLOCK))) { + JS_free(cx, xdr); + return NULL; + } } else { - /* XXXbe ok, so better not deref xdr->data if not ENCODE */ - xdr->data = NULL; + /* XXXbe ok, so better not deref xdr->data if not ENCODE */ + xdr->data = NULL; } xdr->ops = &xdrmem_ops; MEM_PRIV(xdr)->count = 0; @@ -255,7 +249,7 @@ JS_PUBLIC_API(void *) JS_XDRMemGetData(JSXDRState *xdr, uint32 *lp) { if (xdr->ops != &xdrmem_ops) - return NULL; + return NULL; *lp = MEM_PRIV(xdr)->count; return xdr->data; } @@ -264,19 +258,32 @@ JS_PUBLIC_API(void) JS_XDRMemSetData(JSXDRState *xdr, void *data, uint32 len) { if (xdr->ops != &xdrmem_ops) - return; + return; MEM_PRIV(xdr)->limit = len; xdr->data = data; MEM_PRIV(xdr)->count = 0; } +JS_PUBLIC_API(void) +JS_XDRDestroy(JSXDRState *xdr) +{ + JSContext *cx = xdr->cx; + xdr->ops->finalize(xdr); + if (xdr->registry) { + JS_free(cx, xdr->registry); + if (xdr->reghash) + JS_DHashTableDestroy(xdr->reghash); + } + JS_free(cx, xdr); +} + JS_PUBLIC_API(JSBool) JS_XDRUint8(JSXDRState *xdr, uint8 *b) { uint32 l = *b; if (!JS_XDRUint32(xdr, &l)) - return JS_FALSE; - *b = (uint8) l & 0xff; + return JS_FALSE; + *b = (uint8) l; return JS_TRUE; } @@ -285,21 +292,21 @@ JS_XDRUint16(JSXDRState *xdr, uint16 *s) { uint32 l = *s; if (!JS_XDRUint32(xdr, &l)) - return JS_FALSE; - *s = (uint16) l & 0xffff; + return JS_FALSE; + *s = (uint16) l; return JS_TRUE; } JS_PUBLIC_API(JSBool) JS_XDRUint32(JSXDRState *xdr, uint32 *lp) { - JSBool ok = JS_FALSE; + JSBool ok = JS_TRUE; if (xdr->mode == JSXDR_ENCODE) { - uint32 xl = JSXDR_SWAB32(*lp); - ok = xdr->ops->set32(xdr, &xl); + uint32 xl = JSXDR_SWAB32(*lp); + ok = xdr->ops->set32(xdr, &xl); } else if (xdr->mode == JSXDR_DECODE) { - ok = xdr->ops->get32(xdr, lp); - *lp = JSXDR_SWAB32(*lp); + ok = xdr->ops->get32(xdr, lp); + *lp = JSXDR_SWAB32(*lp); } return ok; } @@ -307,19 +314,28 @@ JS_XDRUint32(JSXDRState *xdr, uint32 *lp) JS_PUBLIC_API(JSBool) JS_XDRBytes(JSXDRState *xdr, char **bytesp, uint32 len) { + uint32 padlen; + char *padbp; + static char padbuf[JSXDR_ALIGN-1]; + if (xdr->mode == JSXDR_ENCODE) { - if (!xdr->ops->setbytes(xdr, bytesp, len)) - return JS_FALSE; + if (!xdr->ops->setbytes(xdr, bytesp, len)) + return JS_FALSE; } else { - if (!xdr->ops->getbytes(xdr, bytesp, len)) - return JS_FALSE; + if (!xdr->ops->getbytes(xdr, bytesp, len)) + return JS_FALSE; } len = xdr->ops->tell(xdr); if (len % JSXDR_ALIGN) { - if (!xdr->ops->seek(xdr, JSXDR_ALIGN - (len % JSXDR_ALIGN), - JSXDR_SEEK_CUR)) { - return JS_FALSE; - } + padlen = JSXDR_ALIGN - (len % JSXDR_ALIGN); + if (xdr->mode == JSXDR_ENCODE) { + padbp = padbuf; + if (!xdr->ops->setbytes(xdr, &padbp, padlen)) + return JS_FALSE; + } else { + if (!xdr->ops->seek(xdr, padlen, JSXDR_SEEK_CUR)) + return JS_FALSE; + } } return JS_TRUE; } @@ -335,22 +351,22 @@ JS_XDRCString(JSXDRState *xdr, char **sp) uint32 len; if (xdr->mode == JSXDR_ENCODE) - len = strlen(*sp); + len = strlen(*sp); JS_XDRUint32(xdr, &len); if (xdr->mode == JSXDR_DECODE) { - if (!(*sp = (char *) JS_malloc(xdr->cx, len + 1))) - return JS_FALSE; + if (!(*sp = (char *) JS_malloc(xdr->cx, len + 1))) + return JS_FALSE; } if (!JS_XDRBytes(xdr, sp, len)) { - if (xdr->mode == JSXDR_DECODE) - JS_free(xdr->cx, *sp); - return JS_FALSE; + if (xdr->mode == JSXDR_DECODE) + JS_free(xdr->cx, *sp); + return JS_FALSE; } if (xdr->mode == JSXDR_DECODE) { - (*sp)[len] = '\0'; + (*sp)[len] = '\0'; } else if (xdr->mode == JSXDR_FREE) { - JS_free(xdr->cx, *sp); - *sp = NULL; + JS_free(xdr->cx, *sp); + *sp = NULL; } return JS_TRUE; } @@ -360,10 +376,10 @@ JS_XDRCStringOrNull(JSXDRState *xdr, char **sp) { uint32 null = (*sp == NULL); if (!JS_XDRUint32(xdr, &null)) - return JS_FALSE; + return JS_FALSE; if (null) { - *sp = NULL; - return JS_TRUE; + *sp = NULL; + return JS_TRUE; } return JS_XDRCString(xdr, sp); } @@ -374,42 +390,47 @@ JS_XDRCStringOrNull(JSXDRState *xdr, char **sp) JS_PUBLIC_API(JSBool) JS_XDRString(JSXDRState *xdr, JSString **strp) { - uint32 i, len, nbytes; + uint32 i, len, padlen, nbytes; jschar *chars = NULL, *raw; if (xdr->mode == JSXDR_ENCODE) - len = (*strp)->length; + len = (*strp)->length; if (!JS_XDRUint32(xdr, &len)) - return JS_FALSE; + return JS_FALSE; nbytes = len * sizeof(jschar); - if (xdr->mode == JSXDR_ENCODE) { - chars = (*strp)->chars; - } else if (xdr->mode == JSXDR_DECODE) { - if (!(chars = (jschar *) JS_malloc(xdr->cx, nbytes + sizeof(jschar)))) - return JS_FALSE; + if (xdr->mode == JSXDR_DECODE) { + if (!(chars = (jschar *) JS_malloc(xdr->cx, nbytes + sizeof(jschar)))) + return JS_FALSE; + } else { + chars = (*strp)->chars; } - if (nbytes % JSXDR_ALIGN) - nbytes += JSXDR_ALIGN - (nbytes % JSXDR_ALIGN); + padlen = nbytes % JSXDR_ALIGN; + if (padlen) { + padlen = JSXDR_ALIGN - padlen; + nbytes += padlen; + } if (!(raw = (jschar *) xdr->ops->raw(xdr, nbytes))) - goto bad; + goto bad; if (xdr->mode == JSXDR_ENCODE) { - for (i = 0; i < len; i++) - raw[i] = JSXDR_SWAB16(chars[i]); + for (i = 0; i < len; i++) + raw[i] = JSXDR_SWAB16(chars[i]); + if (padlen) + memset((char *)raw + nbytes - padlen, 0, padlen); } else if (xdr->mode == JSXDR_DECODE) { - for (i = 0; i < len; i++) - chars[i] = JSXDR_SWAB16(raw[i]); + for (i = 0; i < len; i++) + chars[i] = JSXDR_SWAB16(raw[i]); chars[len] = 0; - if (!(*strp = JS_NewUCString(xdr->cx, chars, len))) - goto bad; + if (!(*strp = JS_NewUCString(xdr->cx, chars, len))) + goto bad; } return JS_TRUE; bad: if (xdr->mode == JSXDR_DECODE) - JS_free(xdr->cx, chars); + JS_free(xdr->cx, chars); return JS_FALSE; } @@ -418,10 +439,10 @@ JS_XDRStringOrNull(JSXDRState *xdr, JSString **strp) { uint32 null = (*strp == NULL); if (!JS_XDRUint32(xdr, &null)) - return JS_FALSE; + return JS_FALSE; if (null) { - *strp = NULL; - return JS_TRUE; + *strp = NULL; + return JS_TRUE; } return JS_XDRString(xdr, strp); } @@ -431,150 +452,213 @@ JS_XDRDouble(JSXDRState *xdr, jsdouble **dp) { jsdouble d; if (xdr->mode == JSXDR_ENCODE) - d = **dp; + d = **dp; #if IS_BIG_ENDIAN if (!JS_XDRUint32(xdr, (uint32 *)&d + 1) || - !JS_XDRUint32(xdr, (uint32 *)&d)) -#else /* !IS_BIG_ENDIAN */ + !JS_XDRUint32(xdr, (uint32 *)&d)) +#else if (!JS_XDRUint32(xdr, (uint32 *)&d) || - !JS_XDRUint32(xdr, (uint32 *)&d + 1)) -#endif /* IS_BIG_ENDIAN */ - return JS_FALSE; + !JS_XDRUint32(xdr, (uint32 *)&d + 1)) +#endif + return JS_FALSE; if (xdr->mode == JSXDR_DECODE) { - *dp = JS_NewDouble(xdr->cx, d); - if (!*dp) - return JS_FALSE; + *dp = JS_NewDouble(xdr->cx, d); + if (!*dp) + return JS_FALSE; } return JS_TRUE; } +/* These are magic: see jsapi.h, near the top, for the real jsval tags. */ +#define JSVAL_XDRNULL 0x8 +#define JSVAL_XDRVOID 0xA + JS_PUBLIC_API(JSBool) JS_XDRValue(JSXDRState *xdr, jsval *vp) { - uint32 type = JSVAL_TAG(*vp); + uint32 type; + + if (xdr->mode == JSXDR_ENCODE) { + if (JSVAL_IS_NULL(*vp)) + type = JSVAL_XDRNULL; + else if (JSVAL_IS_VOID(*vp)) + type = JSVAL_XDRVOID; + else + type = JSVAL_TAG(*vp); + } if (!JS_XDRUint32(xdr, &type)) - return JS_FALSE; + return JS_FALSE; switch (type) { + case JSVAL_XDRNULL: + *vp = JSVAL_NULL; + break; + case JSVAL_XDRVOID: + *vp = JSVAL_VOID; + break; case JSVAL_STRING: { - JSString *str = JSVAL_TO_STRING(*vp); - if (!JS_XDRString(xdr, &str)) - return JS_FALSE; - if (xdr->mode == JSXDR_DECODE) - *vp = STRING_TO_JSVAL(str); - break; + JSString *str = JSVAL_TO_STRING(*vp); + if (!JS_XDRString(xdr, &str)) + return JS_FALSE; + if (xdr->mode == JSXDR_DECODE) + *vp = STRING_TO_JSVAL(str); + break; } case JSVAL_DOUBLE: { - jsdouble *dp; - if (xdr->mode == JSXDR_ENCODE) - dp = JSVAL_TO_DOUBLE(*vp); - if (!JS_XDRDouble(xdr, &dp)) - return JS_FALSE; - if (xdr->mode == JSXDR_DECODE) - *vp = DOUBLE_TO_JSVAL(dp); - break; + jsdouble *dp; + if (xdr->mode == JSXDR_ENCODE) + dp = JSVAL_TO_DOUBLE(*vp); + if (!JS_XDRDouble(xdr, &dp)) + return JS_FALSE; + if (xdr->mode == JSXDR_DECODE) + *vp = DOUBLE_TO_JSVAL(dp); + break; } case JSVAL_OBJECT: { - JSObject *obj; - if (xdr->mode == JSXDR_ENCODE) - obj = JSVAL_TO_OBJECT(*vp); - if (!js_XDRObject(xdr, &obj)) - return JS_FALSE; - if (xdr->mode == JSXDR_DECODE) - *vp = OBJECT_TO_JSVAL(obj); - break; + JSObject *obj; + if (xdr->mode == JSXDR_ENCODE) + obj = JSVAL_TO_OBJECT(*vp); + if (!js_XDRObject(xdr, &obj)) + return JS_FALSE; + if (xdr->mode == JSXDR_DECODE) + *vp = OBJECT_TO_JSVAL(obj); + break; } case JSVAL_BOOLEAN: { - uint32 b; - if (xdr->mode == JSXDR_ENCODE) - 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); - break; + uint32 b; + if (xdr->mode == JSXDR_ENCODE) + 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); + break; } - case JSVAL_VOID: - if (!JS_XDRUint32(xdr, (uint32 *)vp)) - return JS_FALSE; - break; default: { - char numBuf[12]; - if (type & JSVAL_INT) { - uint32 i; - if (xdr->mode == JSXDR_ENCODE) - i = JSVAL_TO_INT(*vp); - if (!JS_XDRUint32(xdr, &i)) - return JS_FALSE; - if (xdr->mode == JSXDR_DECODE) - *vp = INT_TO_JSVAL(i); - break; - } - JS_snprintf(numBuf, sizeof numBuf, "%#lx", type); - JS_ReportErrorNumber(xdr->cx, js_GetErrorMessage, NULL, - JSMSG_BAD_JVAL_TYPE, type); - return JS_FALSE; + 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; } } return JS_TRUE; } - -JS_PUBLIC_API(void) -JS_XDRDestroy(JSXDRState *xdr) +JS_PUBLIC_API(JSBool) +JS_XDRScript(JSXDRState *xdr, JSScript **scriptp) { - JSContext *cx = xdr->cx; - xdr->ops->finalize(xdr); - if (xdr->registry) - JS_free(cx, xdr->registry); - JS_free(cx, xdr); + JSBool hasMagic; + + return js_XDRScript(xdr, scriptp, &hasMagic); } -#define REGISTRY_CHUNK 4 +#define CLASS_REGISTRY_MIN 8 +#define CLASS_INDEX_TO_ID(i) ((i)+1) +#define CLASS_ID_TO_INDEX(id) ((id)-1) + +typedef struct JSRegHashEntry { + JSDHashEntryHdr hdr; + const char *name; + uint32 index; +} JSRegHashEntry; JS_PUBLIC_API(JSBool) -JS_RegisterClass(JSXDRState *xdr, JSClass *clasp, uint32 *idp) +JS_XDRRegisterClass(JSXDRState *xdr, JSClass *clasp, uint32 *idp) { - uintN nclasses; + uintN numclasses, maxclasses; JSClass **registry; - nclasses = xdr->nclasses; - if (nclasses == 0) { - registry = (JSClass **) - JS_malloc(xdr->cx, REGISTRY_CHUNK * sizeof(JSClass *)); - } else if (nclasses % REGISTRY_CHUNK == 0) { - registry = (JSClass **) - JS_realloc(xdr->cx, - xdr->registry, - (nclasses + REGISTRY_CHUNK) * sizeof(JSClass *)); + numclasses = xdr->numclasses; + maxclasses = xdr->maxclasses; + if (numclasses == maxclasses) { + maxclasses = (maxclasses == 0) ? CLASS_REGISTRY_MIN : maxclasses << 1; + registry = (JSClass **) + JS_realloc(xdr->cx, xdr->registry, maxclasses * sizeof(JSClass *)); + if (!registry) + return JS_FALSE; + xdr->registry = registry; + xdr->maxclasses = maxclasses; } else { + JS_ASSERT(numclasses && numclasses < maxclasses); registry = xdr->registry; } - if (!registry) - return JS_FALSE; - registry[nclasses++] = clasp; - xdr->registry = registry; - xdr->nclasses = nclasses; - *idp = nclasses; + + registry[numclasses] = clasp; + if (xdr->reghash) { + JSRegHashEntry *entry = (JSRegHashEntry *) + JS_DHashTableOperate(xdr->reghash, clasp->name, JS_DHASH_ADD); + if (!entry) { + JS_ReportOutOfMemory(xdr->cx); + return JS_FALSE; + } + entry->name = clasp->name; + entry->index = numclasses; + } + *idp = CLASS_INDEX_TO_ID(numclasses); + xdr->numclasses = ++numclasses; return JS_TRUE; } JS_PUBLIC_API(uint32) -JS_FindClassIdByName(JSXDRState *xdr, const char *name) +JS_XDRFindClassIdByName(JSXDRState *xdr, const char *name) { - uintN i; + uintN i, numclasses; - for (i = 0; i < xdr->nclasses; i++) { - if (!strcmp(name, xdr->registry[i]->name)) - return i+1; + numclasses = xdr->numclasses; + if (numclasses >= 10) { + JSRegHashEntry *entry; + + /* Bootstrap reghash from registry on first overpopulated Find. */ + if (!xdr->reghash) { + xdr->reghash = JS_NewDHashTable(JS_DHashGetStubOps(), NULL, + sizeof(JSRegHashEntry), + numclasses); + if (xdr->reghash) { + for (i = 0; i < numclasses; i++) { + JSClass *clasp = xdr->registry[i]; + entry = (JSRegHashEntry *) + JS_DHashTableOperate(xdr->reghash, clasp->name, + JS_DHASH_ADD); + entry->name = clasp->name; + entry->index = i; + } + } + } + + /* If we managed to create reghash, use it for O(1) Find. */ + if (xdr->reghash) { + entry = (JSRegHashEntry *) + JS_DHashTableOperate(xdr->reghash, name, JS_DHASH_LOOKUP); + if (JS_DHASH_ENTRY_IS_BUSY(&entry->hdr)) + return CLASS_INDEX_TO_ID(entry->index); + } + } + + /* Only a few classes, or we couldn't malloc reghash: use linear search. */ + for (i = 0; i < numclasses; i++) { + if (!strcmp(name, xdr->registry[i]->name)) + return CLASS_INDEX_TO_ID(i); } return 0; } JS_PUBLIC_API(JSClass *) -JS_FindClassById(JSXDRState *xdr, uint32 id) +JS_XDRFindClassById(JSXDRState *xdr, uint32 id) { - if (id > xdr->nclasses) - return NULL; - return xdr->registry[id-1]; + uintN i = CLASS_ID_TO_INDEX(id); + + if (i >= xdr->numclasses) + return NULL; + return xdr->registry[i]; } diff --git a/js/src/jsxdrapi.h b/js/src/jsxdrapi.h index 34eddd1b41cd..22a1f9a45954 100644 --- a/js/src/jsxdrapi.h +++ b/js/src/jsxdrapi.h @@ -66,11 +66,11 @@ JS_BEGIN_EXTERN_C #define JSXDR_SWAB32(x) x #define JSXDR_SWAB16(x) x #elif defined IS_BIG_ENDIAN -#define JSXDR_SWAB32(x) (((x) >> 24) | \ - (((x) >> 8) & 0xff00) | \ - (((x) << 8) & 0xff0000) | \ - ((x) << 24)) -#define JSXDR_SWAB16(x) (((x) >> 8) | ((x) << 8)) +#define JSXDR_SWAB32(x) (((uint32)(x) >> 24) | \ + (((uint32)(x) >> 8) & 0xff00) | \ + (((uint32)(x) << 8) & 0xff0000) | \ + ((uint32)(x) << 24)) +#define JSXDR_SWAB16(x) (((uint16)(x) >> 8) | ((uint16)(x) << 8)) #else #error "unknown byte order" #endif @@ -105,12 +105,14 @@ struct JSXDRState { JSXDROps *ops; JSContext *cx; JSClass **registry; - uintN nclasses; + uintN numclasses; + uintN maxclasses; + void *reghash; void *data; }; extern JS_PUBLIC_API(void) -JS_XDRNewBase(JSContext *cx, JSXDRState *xdr, JSXDRMode mode); +JS_XDRInitBase(JSXDRState *xdr, JSXDRMode mode, JSContext *cx); extern JS_PUBLIC_API(JSXDRState *) JS_XDRNewMem(JSContext *cx, JSXDRMode mode); @@ -155,16 +157,20 @@ extern JS_PUBLIC_API(JSBool) JS_XDRValue(JSXDRState *xdr, jsval *vp); extern JS_PUBLIC_API(JSBool) -JS_RegisterClass(JSXDRState *xdr, JSClass *clasp, uint32 *lp); +JS_XDRScript(JSXDRState *xdr, JSScript **scriptp); + +extern JS_PUBLIC_API(JSBool) +JS_XDRRegisterClass(JSXDRState *xdr, JSClass *clasp, uint32 *lp); extern JS_PUBLIC_API(uint32) -JS_FindClassIdByName(JSXDRState *xdr, const char *name); +JS_XDRFindClassIdByName(JSXDRState *xdr, const char *name); extern JS_PUBLIC_API(JSClass *) -JS_FindClassById(JSXDRState *xdr, uint32 id); - -/* Magic values */ +JS_XDRFindClassById(JSXDRState *xdr, uint32 id); +/* + * Magic numbers. + */ #define JSXDR_MAGIC_SCRIPT_1 0xdead0001 #define JSXDR_MAGIC_SCRIPT_2 0xdead0002 #define JSXDR_MAGIC_SCRIPT_CURRENT JSXDR_MAGIC_SCRIPT_2