if (sd2 > sd)
if (sd2 <= sd) {  sd2->offset += deltaFromTop; deltaFromTop += JUMPX_OFFSET_LEN - JUMP_OFFSET_LEN; } else {
OptimizeSpanDeps(JSContext *cx, JSCodeGenerator *cg){    jsbytecode *pc, *oldpc, *base, *limit, *next;    JSSpanDep *sd, *sd2, *sdbase, *sdlimit, *sdtop, guard;    ptrdiff_t offset, growth, delta, top, pivot, span, length, target;    JSBool done;    JSOp op;    uint32 type;    size_t size, incr;    jssrcnote *sn, *snlimit;    JSSrcNoteSpec *spec;    uintN i, n, noteIndex;    JSTryNote *tn, *tnlimit;#ifdef DEBUG_brendan    int passes = 0;#endif    base = CG_BASE(cg);    sdbase = cg->spanDeps;    sdlimit = sdbase + cg->numSpanDeps;    offset = CG_OFFSET(cg);    growth = 0;    do {        done = JS_TRUE;        delta = 0;        top = pivot = -1;        sdtop = NULL;        pc = NULL;        op = JSOP_NOP;        type = 0;#ifdef DEBUG_brendan        passes++;#endif        for (sd = sdbase; sd < sdlimit; sd++) {            JS_ASSERT(JT_HAS_TAG(sd->target));            sd->offset += delta;            if (sd->top != top) {                sdtop = sd;                top = sd->top;                JS_ASSERT(top == sd->before);                pivot = sd->offset;                pc = base + top;                op = (JSOp) *pc;                type = (js_CodeSpec[op].format & JOF_TYPEMASK);                if (JOF_TYPE_IS_EXTENDED_JUMP(type)) {                    /*                     * We already extended all the jump offset operands for                     * the opcode at sd->top.  Jumps and branches have only                     * one jump offset operand, but switches have many, all                     * of which are adjacent in cg->spanDeps.                     */                    continue;                }                JS_ASSERT(type == JOF_JUMP ||                          type == JOF_TABLESWITCH ||                          type == JOF_LOOKUPSWITCH);            }            if (!JOF_TYPE_IS_EXTENDED_JUMP(type)) {                span = SD_TARGET_OFFSET(sd) - pivot;                if (span < JUMP_OFFSET_MIN || JUMP_OFFSET_MAX < span) {                    done = JS_FALSE;                    switch (op) {                      case JSOP_GOTO:         op = JSOP_GOTOX; break;                      case JSOP_IFEQ:         op = JSOP_IFEQX; break;                      case JSOP_IFNE:         op = JSOP_IFNEX; break;                      case JSOP_OR:           op = JSOP_ORX; break;                      case JSOP_AND:          op = JSOP_ANDX; break;                      case JSOP_GOSUB:        op = JSOP_GOSUBX; break;                      case JSOP_CASE:         op = JSOP_CASEX; break;                      case JSOP_DEFAULT:      op = JSOP_DEFAULTX; break;                      case JSOP_TABLESWITCH:  op = JSOP_TABLESWITCHX; break;                      case JSOP_LOOKUPSWITCH: op = JSOP_LOOKUPSWITCHX; break;                      default:                JS_ASSERT(0);                    }                    *pc = (jsbytecode) op;                    for (sd2 = sdtop; sd2 < sdlimit && sd2->top == top; sd2++) {                        if (sd2 > sd)                            sd2->offset += delta;                        delta += JUMPX_OFFSET_LEN - JUMP_OFFSET_LEN;                        UpdateJumpTargets(cg->jumpTargets, sd2->offset,                                          JUMPX_OFFSET_LEN - JUMP_OFFSET_LEN);                    }                    sd = sd2 - 1;                }            }        }        growth += delta;    } while (!done);    if (growth) {#ifdef DEBUG_brendan        printf("%s:%u: %u/%u jumps extended in %d passes (%d=%d+%d)\n",               cg->filename ? cg->filename : "stdin", cg->firstLine,               growth / (JUMPX_OFFSET_LEN - JUMP_OFFSET_LEN), cg->numSpanDeps,               passes, offset + growth, offset, growth);#endif        /*         * Ensure that we have room for the extended jumps, but don't round up         * to a power of two -- we're done generating code, so we cut to fit.         */        limit = CG_LIMIT(cg);        length = offset + growth;        next = base + length;        if (next > limit) {            JS_ASSERT(length > BYTECODE_GRAIN);            size = BYTECODE_SIZE(PTRDIFF(limit, base, jsbytecode));            incr = BYTECODE_SIZE(length) - size;            JS_ARENA_GROW_CAST(base, jsbytecode *, &cx->codePool, size, incr);            if (!base) {                JS_ReportOutOfMemory(cx);                return JS_FALSE;            }            CG_BASE(cg) = base;            CG_LIMIT(cg) = next = base + length;        }        CG_NEXT(cg) = next;        /*         * Set up a fake span dependency record to guard the end of the code         * being generated.  This guard record is returned as a fencepost by         * FindNearestSpanDep if there is no real spandep at or above a given         * unextended code offset.         */        guard.top = -1;        guard.offset = offset + growth;        guard.before = offset;        guard.target = NULL;    }    /*     * Now work backwards through the span dependencies, copying chunks of     * bytecode between each extended jump toward the end of the grown code     * space, and restoring immediate offset operands for all jump bytecodes.     * The first chunk of bytecodes, starting at base and ending at the first     * extended jump offset (NB: this chunk includes the operation bytecode     * just before that immediate jump offset), doesn't need to be copied.     */    JS_ASSERT(sd == sdlimit);    top = -1;    while (--sd >= sdbase) {        if (sd->top != top) {            top = sd->top;            op = (JSOp) base[top];            type = (js_CodeSpec[op].format & JOF_TYPEMASK);            for (sd2 = sd - 1; sd2 >= sdbase && sd2->top == top; sd2--)                continue;            sd2++;            pivot = sd2->offset;            JS_ASSERT(top == sd2->before);        }        oldpc = base + sd->before;        span = SD_TARGET_OFFSET(sd) - pivot;        /*         * If this jump didn't need to be extended, restore its span immediate         * offset operand now, overwriting the index of sd within cg->spanDeps         * that was stored temporarily after *pc when BuildSpanDepTable ran.         *         * Note that span might fit in 16 bits even for an extended jump op,         * if the op has multiple span operands, not all of which overflowed         * (e.g. JSOP_LOOKUPSWITCH or JSOP_TABLESWITCH where some cases are in         * range for a short jump, but others are not).         */        if (!JOF_TYPE_IS_EXTENDED_JUMP(type)) {            JS_ASSERT(JUMP_OFFSET_MIN <= span && span <= JUMP_OFFSET_MAX);            SET_JUMP_OFFSET(oldpc, span);            continue;        }        /*         * Set up parameters needed to copy the next run of bytecode starting         * at offset (which is a cursor into the unextended, original bytecode         * vector), down to sd->before (a cursor of the same scale as offset,         * it's the index of the original jump pc).  Reuse delta to count the         * nominal number of bytes to copy.         */        pc = base + sd->offset;        delta = offset - sd->before;        JS_ASSERT(delta >= 1 + JUMP_OFFSET_LEN);        /*         * Don't bother copying the jump offset we're about to reset, but do         * copy the bytecode at oldpc (which comes just before its immediate         * jump offset operand), on the next iteration through the loop, by         * including it in offset's new value.         */        offset = sd->before + 1;        size = BYTECODE_SIZE(delta - (1 + JUMP_OFFSET_LEN));        if (size) {            memmove(pc + 1 + JUMPX_OFFSET_LEN,                    oldpc + 1 + JUMP_OFFSET_LEN,                    size);        }        SET_JUMPX_OFFSET(pc, span);    }    if (growth) {        /*         * Fix source note deltas.  Don't hardwire the delta fixup adjustment,         * even though currently it must be JUMPX_OFFSET_LEN - JUMP_OFFSET_LEN         * at each sd that moved.  The future may bring different offset sizes         * for span-dependent instruction operands.         */        offset = growth = 0;        sd = sdbase;        for (sn = cg->notes, snlimit = sn + cg->noteCount;             sn < snlimit;             sn = SN_NEXT(sn)) {            /*             * Recall that the offset of a given note includes its delta, and             * tells the offset of the annotated bytecode from the main entry             * point of the script.             */            offset += SN_DELTA(sn);            while (sd < sdlimit && sd->before < offset) {                /*                 * To compute the delta to add to sn, we need to look at the                 * spandep after sd, whose offset - (before + growth) tells by                 * how many bytes sd's instruction grew.                 */                sd2 = sd + 1;                if (sd2 == sdlimit)                    sd2 = &guard;                delta = sd2->offset - (sd2->before + growth);                if (delta > 0) {                    JS_ASSERT(delta == JUMPX_OFFSET_LEN - JUMP_OFFSET_LEN);                    sn = js_AddToSrcNoteDelta(cx, cg, sn, delta);                    if (!sn)                        return JS_FALSE;                    snlimit = cg->notes + cg->noteCount;                    growth += delta;                }                sd++;            }            /*             * If sn has span-dependent offset operands, check whether each             * covers further span-dependencies, and increase those operands             * accordingly.  Some source notes measure offset not from the             * annotated pc, but from that pc plus some small bias.  NB: we             * assume that spec->offsetBias can't itself span span-dependent             * instructions!             */            spec = &js_SrcNoteSpec[SN_TYPE(sn)];            if (spec->isSpanDep) {                pivot = offset + spec->offsetBias;                n = spec->arity;                for (i = 0; i < n; i++) {                    span = js_GetSrcNoteOffset(sn, i);                    if (span == 0)                        continue;                    target = pivot + span * spec->isSpanDep;                    sd2 = FindNearestSpanDep(cg, target,                                             (target >= pivot)                                             ? sd - sdbase                                             : 0,                                             &guard);                    /*                     * Increase target by sd2's before-vs-after offset delta,                     * which is absolute (i.e., relative to start of script,                     * as is target).  Recompute the span by subtracting its                     * adjusted pivot from target.                     */                    target += sd2->offset - sd2->before;                    span = target - (pivot + growth);                    span *= spec->isSpanDep;                    noteIndex = sn - cg->notes;                    if (!js_SetSrcNoteOffset(cx, cg, noteIndex, i, span))                        return JS_FALSE;                    sn = cg->notes + noteIndex;                    snlimit = cg->notes + cg->noteCount;                }            }        }        /*         * Fix try/catch notes (O(numTryNotes * log2(numSpanDeps)), but it's         * not clear how we can beat that).         */        for (tn = cg->tryBase, tnlimit = cg->tryNext; tn < tnlimit; tn++) {            /*             * First, look for the nearest span dependency at/above tn->start.             * There may not be any such spandep, in which case the guard will             * be returned.             */            offset = tn->start;            sd = FindNearestSpanDep(cg, offset, 0, &guard);            delta = sd->offset - sd->before;            tn->start = offset + delta;            /*             * Next, find the nearest spandep at/above tn->start + tn->length.             * Use its delta minus tn->start's delta to increase tn->length.             */            length = tn->length;            sd2 = FindNearestSpanDep(cg, offset + length, sd - sdbase, &guard);            if (sd2 != sd)                tn->length = length + sd2->offset - sd2->before - delta;            /*             * Finally, adjust tn->catchStart upward only if it is non-zero,             * and provided there are spandeps below it that grew.             */            offset = tn->catchStart;            if (offset != 0) {                sd = FindNearestSpanDep(cg, offset, sd2 - sdbase, &guard);                tn->catchStart = offset + sd->offset - sd->before;            }        }    }#ifdef DEBUG_brendan  {    uintN bigspans = 0;    top = -1;    for (sd = sdbase; sd < sdlimit; sd++) {        offset = sd->offset;        /* NB: sd->top cursors into the original, unextended bytecode vector. */        if (sd->top != top) {            JS_ASSERT(top == -1 ||                      !JOF_TYPE_IS_EXTENDED_JUMP(type) ||                      bigspans != 0);            bigspans = 0;            top = sd->top;            JS_ASSERT(top == sd->before);            op = (JSOp) base[offset];            type = (js_CodeSpec[op].format & JOF_TYPEMASK);            JS_ASSERT(type == JOF_JUMP ||                      type == JOF_JUMPX ||                      type == JOF_TABLESWITCH ||                      type == JOF_TABLESWITCHX ||                      type == JOF_LOOKUPSWITCH ||                      type == JOF_LOOKUPSWITCHX);            pivot = offset;        }        pc = base + offset;        if (JOF_TYPE_IS_EXTENDED_JUMP(type)) {            span = GET_JUMPX_OFFSET(pc);            if (span < JUMP_OFFSET_MIN || JUMP_OFFSET_MAX < span) {                bigspans++;            } else {                JS_ASSERT(type == JOF_TABLESWITCHX ||                          type == JOF_LOOKUPSWITCHX);            }        } else {            span = GET_JUMP_OFFSET(pc);        }        JS_ASSERT(SD_TARGET_OFFSET(sd) == pivot + span);    }    JS_ASSERT(!JOF_TYPE_IS_EXTENDED_JUMP(type) || bigspans != 0);  }#endif    /*     * Reset so we optimize at most once -- cg may be used for further code     * generation of successive, independent, top-level statements.  No jump     * can span top-level statements, because JS lacks goto.     */    size = SPANDEPS_SIZE(JS_BIT(JS_CeilingLog2(cg->numSpanDeps)));    JS_ArenaFreeAllocation(&cx->tempPool, cg->spanDeps,                           JS_MAX(size, SPANDEPS_SIZE_MIN));    cg->spanDeps = NULL;    FreeJumpTargets(cg, cg->jumpTargets);    cg->jumpTargets = NULL;    cg->numSpanDeps = cg->numJumpTargets = 0;    return JS_TRUE;}