📄 jsemit.c
字号:
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_SPAN(sd, pivot); if (span < JUMP_OFFSET_MIN || JUMP_OFFSET_MAX < span) { ptrdiff_t deltaFromTop = 0; 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: ReportStatementTooLarge(cx, cg); return JS_FALSE; } *pc = (jsbytecode) op; for (sd2 = sdtop; sd2 < sdlimit && sd2->top == top; sd2++) { if (sd2 <= sd) { /* * sd2->offset already includes delta as it stood * before we entered this loop, but it must also * include the delta relative to top due to all the * extended jump offset immediates for the opcode * starting at top, which we extend in this loop. * * If there is only one extended jump offset, then * sd2->offset won't change and this for loop will * iterate once only. */ sd2->offset += deltaFromTop; deltaFromTop += JUMPX_OFFSET_LEN - JUMP_OFFSET_LEN; } else { /* * sd2 comes after sd, and won't be revisited by * the outer for loop, so we have to increase its * offset by delta, not merely by deltaFromTop. */ 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_CHUNK); size = BYTECODE_SIZE(PTRDIFF(limit, base, jsbytecode)); incr = BYTECODE_SIZE(length) - size; JS_ARENA_GROW_CAST(base, jsbytecode *, cg->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_SPAN(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. However, we fix only main * notes here, not prolog notes -- we know that prolog opcodes are not * span-dependent, and aren't likely ever to be. */ offset = growth = 0; sd = sdbase; for (sn = cg->main.notes, snlimit = sn + cg->main.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->main.notes + cg->main.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->main.notes; if (!js_SetSrcNoteOffset(cx, cg, noteIndex, i, span)) return JS_FALSE; sn = cg->main.notes + noteIndex; snlimit = cg->main.notes + cg->main.noteCount; } } } cg->main.lastNoteOffset += growth; /* * 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_SPAN(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; cg->spanDepTodo = CG_OFFSET(cg); return JS_TRUE;}static JSBoolEmitJump(JSContext *cx, JSCodeGenerator *cg, JSOp op, ptrdiff_t off){ JSBool extend;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -