if (magic < JSXDR_MAGIC_SCRIPT_5) {
if (magic < JSXDR_MAGIC_SCRIPT_4) { if (!JS_XDRUint32(xdr, &nsrcnotes)) goto error;
js_XDRScript(JSXDRState *xdr, JSScript **scriptp, JSBool *hasMagic){    JSContext *cx;    JSScript *script, *newscript;    uint32 length, lineno, depth, magic, nsrcnotes, ntrynotes;    uint32 prologLength, version;    JSBool filenameWasSaved;    jssrcnote *notes, *sn;    cx = xdr->cx;    script = *scriptp;    nsrcnotes = ntrynotes = 0;    filenameWasSaved = JS_FALSE;    notes = NULL;    /*     * Encode prologLength and version after script->length (_2 or greater),     * but decode both new (>= _2) and old, prolog&version-free (_1) scripts.     * Version _3 supports principals serialization.  Version _4 reorders the     * nsrcnotes and ntrynotes fields to come before everything except magic,     * length, prologLength, and version, so that srcnote and trynote storage     * can be allocated as part of the JSScript (along with bytecode storage).     *     * So far, the magic number has not changed for every jsopcode.tbl change.     * We stipulate forward compatibility by requiring old bytecodes never to     * change or go away (modulo a few exceptions before the XDR interfaces     * evolved, and a few exceptions during active trunk development).  With     * the addition of JSOP_STOP to support JS_THREADED_INTERP, we make a new     * magic number (_5) so that we know to append JSOP_STOP to old scripts     * when deserializing.     */    if (xdr->mode == JSXDR_ENCODE)        magic = JSXDR_MAGIC_SCRIPT_CURRENT;    if (!JS_XDRUint32(xdr, &magic))        return JS_FALSE;    JS_ASSERT((uint32)JSXDR_MAGIC_SCRIPT_5 - (uint32)JSXDR_MAGIC_SCRIPT_1 == 4);    if (magic - (uint32)JSXDR_MAGIC_SCRIPT_1 > 4) {        if (!hasMagic) {            JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,                                 JSMSG_BAD_SCRIPT_MAGIC);            return JS_FALSE;        }        *hasMagic = JS_FALSE;        return JS_TRUE;    }    if (hasMagic)        *hasMagic = JS_TRUE;    if (xdr->mode == JSXDR_ENCODE) {        length = script->length;        prologLength = PTRDIFF(script->main, script->code, jsbytecode);        JS_ASSERT((int16)script->version != JSVERSION_UNKNOWN);        version = (uint32)script->version | (script->numGlobalVars << 16);        lineno = (uint32)script->lineno;        depth = (uint32)script->depth;        /* Count the srcnotes, keeping notes pointing at the first one. */        notes = SCRIPT_NOTES(script);        for (sn = notes; !SN_IS_TERMINATOR(sn); sn = SN_NEXT(sn))            continue;        nsrcnotes = PTRDIFF(sn, notes, jssrcnote);        nsrcnotes++;            /* room for the terminator */        /* Count the trynotes. */        if (script->trynotes) {            while (script->trynotes[ntrynotes].catchStart)                ntrynotes++;            ntrynotes++;        /* room for the end marker */        }    }    if (!JS_XDRUint32(xdr, &length))        return JS_FALSE;    if (magic >= JSXDR_MAGIC_SCRIPT_2) {        if (!JS_XDRUint32(xdr, &prologLength))            return JS_FALSE;        if (!JS_XDRUint32(xdr, &version))            return JS_FALSE;        /* To fuse allocations, we need srcnote and trynote counts early. */        if (magic >= JSXDR_MAGIC_SCRIPT_4) {            if (!JS_XDRUint32(xdr, &nsrcnotes))                return JS_FALSE;            if (!JS_XDRUint32(xdr, &ntrynotes))                return JS_FALSE;        }    }    if (xdr->mode == JSXDR_DECODE) {        size_t alloclength = length;        if (magic < JSXDR_MAGIC_SCRIPT_5)            ++alloclength;      /* add a byte for JSOP_STOP */        script = js_NewScript(cx, alloclength, nsrcnotes, ntrynotes);        if (!script)            return JS_FALSE;        if (magic >= JSXDR_MAGIC_SCRIPT_2) {            script->main += prologLength;            script->version = (JSVersion) (version & 0xffff);            script->numGlobalVars = (uint16) (version >> 16);            /* If we know nsrcnotes, we allocated space for notes in script. */            if (magic >= JSXDR_MAGIC_SCRIPT_4)                notes = SCRIPT_NOTES(script);        }        *scriptp = script;    }    /*     * Control hereafter must goto error on failure, in order for the DECODE     * case to destroy script and conditionally free notes, which if non-null     * in the (DECODE and magic < _4) case must point at a temporary vector     * allocated just below.     */    if (!JS_XDRBytes(xdr, (char *)script->code, length * sizeof(jsbytecode)) ||        !XDRAtomMap(xdr, &script->atomMap)) {        goto error;    }    if (magic < JSXDR_MAGIC_SCRIPT_5) {        if (xdr->mode == JSXDR_DECODE) {            /*             * Append JSOP_STOP to old scripts, to relieve the interpreter             * from having to bounds-check pc.  Also take care to increment             * length, as it is used below and must count all bytecode.             */            script->code[length++] = JSOP_STOP;        }        if (magic < JSXDR_MAGIC_SCRIPT_4) {            if (!JS_XDRUint32(xdr, &nsrcnotes))                goto error;            if (xdr->mode == JSXDR_DECODE) {                notes = (jssrcnote *)                        JS_malloc(cx, nsrcnotes * sizeof(jssrcnote));                if (!notes)                    goto error;            }        }    }    if (!JS_XDRBytes(xdr, (char *)notes, nsrcnotes * sizeof(jssrcnote)) ||        !JS_XDRCStringOrNull(xdr, (char **)&script->filename) ||        !JS_XDRUint32(xdr, &lineno) ||        !JS_XDRUint32(xdr, &depth) ||        (magic < JSXDR_MAGIC_SCRIPT_4 && !JS_XDRUint32(xdr, &ntrynotes))) {        goto error;    }    /* Script principals transcoding support comes with versions >= _3. */    if (magic >= JSXDR_MAGIC_SCRIPT_3) {        JSPrincipals *principals;        uint32 encodeable;        if (xdr->mode == JSXDR_ENCODE) {            principals = script->principals;            encodeable = (cx->runtime->principalsTranscoder != NULL);            if (!JS_XDRUint32(xdr, &encodeable))                goto error;            if (encodeable &&                !cx->runtime->principalsTranscoder(xdr, &principals)) {                goto error;            }        } else {            if (!JS_XDRUint32(xdr, &encodeable))                goto error;            if (encodeable) {                if (!cx->runtime->principalsTranscoder) {                    JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,                                         JSMSG_CANT_DECODE_PRINCIPALS);                    goto error;                }                if (!cx->runtime->principalsTranscoder(xdr, &principals))                    goto error;                script->principals = principals;            }        }    }    if (xdr->mode == JSXDR_DECODE) {        const char *filename = script->filename;        if (filename) {            filename = js_SaveScriptFilename(cx, filename);            if (!filename)                goto error;            JS_free(cx, (void *) script->filename);            script->filename = filename;            filenameWasSaved = JS_TRUE;        }        script->lineno = (uintN)lineno;        script->depth = (uintN)depth;        if (magic < JSXDR_MAGIC_SCRIPT_4) {            /*             * Argh, we have to reallocate script, copy notes into the extra             * space after the bytecodes, and free the temporary notes vector.             * First, add enough slop to nsrcnotes so we can align the address             * after the srcnotes of the first trynote.             */            uint32 osrcnotes = nsrcnotes;            if (ntrynotes)                nsrcnotes += JSTRYNOTE_ALIGNMASK;            newscript = (JSScript *) JS_realloc(cx, script,                                                sizeof(JSScript) +                                                length * sizeof(jsbytecode) +                                                nsrcnotes * sizeof(jssrcnote) +                                                ntrynotes * sizeof(JSTryNote));            if (!newscript)                goto error;            *scriptp = script = newscript;            script->code = (jsbytecode *)(script + 1);            script->main = script->code + prologLength;            memcpy(script->code + length, notes, osrcnotes * sizeof(jssrcnote));            JS_free(cx, (void *) notes);            notes = NULL;            if (ntrynotes) {                script->trynotes = (JSTryNote *)                                   ((jsword)(SCRIPT_NOTES(script) + nsrcnotes) &                                    ~(jsword)JSTRYNOTE_ALIGNMASK);                memset(script->trynotes, 0, ntrynotes * sizeof(JSTryNote));            }        }    }    while (ntrynotes) {        JSTryNote *tn = &script->trynotes[--ntrynotes];        uint32 start = (uint32) tn->start,               catchLength = (uint32) tn->length,               catchStart = (uint32) tn->catchStart;        if (!JS_XDRUint32(xdr, &start) ||            !JS_XDRUint32(xdr, &catchLength) ||            !JS_XDRUint32(xdr, &catchStart)) {            goto error;        }        tn->start = (ptrdiff_t) start;        tn->length = (ptrdiff_t) catchLength;        tn->catchStart = (ptrdiff_t) catchStart;    }    return JS_TRUE;  error:    if (xdr->mode == JSXDR_DECODE) {        if (script->filename && !filenameWasSaved) {            JS_free(cx, (void *) script->filename);            script->filename = NULL;        }        if (notes && magic < JSXDR_MAGIC_SCRIPT_4)            JS_free(cx, (void *) notes);        js_DestroyScript(cx, script);        *scriptp = NULL;    }    return JS_FALSE;}