📄 jsemit.c
字号:
ptrdiff_t jmp; jsbytecode *pc; extend = off < JUMP_OFFSET_MIN || JUMP_OFFSET_MAX < off; if (extend && !cg->spanDeps && !BuildSpanDepTable(cx, cg)) return JS_FALSE; jmp = js_Emit3(cx, cg, op, JUMP_OFFSET_HI(off), JUMP_OFFSET_LO(off)); if (jmp >= 0 && (extend || cg->spanDeps)) { pc = CG_CODE(cg, jmp); if (!AddSpanDep(cx, cg, pc, pc, off)) return JS_FALSE; } return jmp;}static ptrdiff_tGetJumpOffset(JSCodeGenerator *cg, jsbytecode *pc){ JSSpanDep *sd; JSJumpTarget *jt; ptrdiff_t top; if (!cg->spanDeps) return GET_JUMP_OFFSET(pc); sd = GetSpanDep(cg, pc); jt = sd->target; if (!JT_HAS_TAG(jt)) return JT_TO_BPDELTA(jt); top = sd->top; while (--sd >= cg->spanDeps && sd->top == top) continue; sd++; return JT_CLR_TAG(jt)->offset - sd->offset;}JSBooljs_SetJumpOffset(JSContext *cx, JSCodeGenerator *cg, jsbytecode *pc, ptrdiff_t off){ if (!cg->spanDeps) { if (JUMP_OFFSET_MIN <= off && off <= JUMP_OFFSET_MAX) { SET_JUMP_OFFSET(pc, off); return JS_TRUE; } if (!BuildSpanDepTable(cx, cg)) return JS_FALSE; } return SetSpanDepTarget(cx, cg, GetSpanDep(cg, pc), off);}JSBooljs_InStatement(JSTreeContext *tc, JSStmtType type){ JSStmtInfo *stmt; for (stmt = tc->topStmt; stmt; stmt = stmt->down) { if (stmt->type == type) return JS_TRUE; } return JS_FALSE;}JSBooljs_IsGlobalReference(JSTreeContext *tc, JSAtom *atom, JSBool *loopyp){ JSStmtInfo *stmt; JSObject *obj; JSScope *scope; *loopyp = JS_FALSE; for (stmt = tc->topStmt; stmt; stmt = stmt->down) { if (stmt->type == STMT_WITH) return JS_FALSE; if (STMT_IS_LOOP(stmt)) { *loopyp = JS_TRUE; continue; } if (stmt->flags & SIF_SCOPE) { obj = ATOM_TO_OBJECT(stmt->atom); JS_ASSERT(LOCKED_OBJ_GET_CLASS(obj) == &js_BlockClass); scope = OBJ_SCOPE(obj); if (SCOPE_GET_PROPERTY(scope, ATOM_TO_JSID(atom))) return JS_FALSE; } } return JS_TRUE;}voidjs_PushStatement(JSTreeContext *tc, JSStmtInfo *stmt, JSStmtType type, ptrdiff_t top){ stmt->type = type; stmt->flags = 0; SET_STATEMENT_TOP(stmt, top); stmt->atom = NULL; stmt->down = tc->topStmt; tc->topStmt = stmt; if (STMT_LINKS_SCOPE(stmt)) { stmt->downScope = tc->topScopeStmt; tc->topScopeStmt = stmt; } else { stmt->downScope = NULL; }}voidjs_PushBlockScope(JSTreeContext *tc, JSStmtInfo *stmt, JSAtom *blockAtom, ptrdiff_t top){ JSObject *blockObj; js_PushStatement(tc, stmt, STMT_BLOCK, top); stmt->flags |= SIF_SCOPE; blockObj = ATOM_TO_OBJECT(blockAtom); blockObj->slots[JSSLOT_PARENT] = OBJECT_TO_JSVAL(tc->blockChain); stmt->downScope = tc->topScopeStmt; tc->topScopeStmt = stmt; tc->blockChain = blockObj; stmt->atom = blockAtom;}/* * Emit a backpatch op with offset pointing to the previous jump of this type, * so that we can walk back up the chain fixing up the op and jump offset. */static ptrdiff_tEmitBackPatchOp(JSContext *cx, JSCodeGenerator *cg, JSOp op, ptrdiff_t *lastp){ ptrdiff_t offset, delta; offset = CG_OFFSET(cg); delta = offset - *lastp; *lastp = offset; JS_ASSERT(delta > 0); return EmitJump(cx, cg, op, delta);}/* * Macro to emit a bytecode followed by a uint16 immediate operand stored in * big-endian order, used for arg and var numbers as well as for atomIndexes. * NB: We use cx and cg from our caller's lexical environment, and return * false on error. */#define EMIT_UINT16_IMM_OP(op, i) \ JS_BEGIN_MACRO \ if (js_Emit3(cx, cg, op, UINT16_HI(i), UINT16_LO(i)) < 0) \ return JS_FALSE; \ JS_END_MACRO/* Emit additional bytecode(s) for non-local jumps. */static JSBoolEmitNonLocalJumpFixup(JSContext *cx, JSCodeGenerator *cg, JSStmtInfo *toStmt, JSOp *returnop){ intN depth; JSStmtInfo *stmt; ptrdiff_t jmp; /* * Return from within a try block that has a finally clause must be split * into two ops: JSOP_SETRVAL, to pop the r.v. and store it in fp->rval; * and JSOP_RETRVAL, which makes control flow go back to the caller, who * picks up fp->rval as usual. Otherwise, the stack will be unbalanced * when executing the finally clause. * * We mutate *returnop once only if we find an enclosing try-block (viz, * STMT_FINALLY) to ensure that we emit just one JSOP_SETRVAL before one * or more JSOP_GOSUBs and other fixup opcodes emitted by this function. * Our caller (the TOK_RETURN case of js_EmitTree) then emits *returnop. * The fixup opcodes and gosubs must interleave in the proper order, from * inner statement to outer, so that finally clauses run at the correct * stack depth. */ if (returnop) { JS_ASSERT(*returnop == JSOP_RETURN); for (stmt = cg->treeContext.topStmt; stmt != toStmt; stmt = stmt->down) { if (stmt->type == STMT_FINALLY || ((cg->treeContext.flags & TCF_FUN_HEAVYWEIGHT) && STMT_MAYBE_SCOPE(stmt))) { if (js_Emit1(cx, cg, JSOP_SETRVAL) < 0) return JS_FALSE; *returnop = JSOP_RETRVAL; break; } } /* * If there are no try-with-finally blocks open around this return * statement, we can generate a return forthwith and skip generating * any fixup code. */ if (*returnop == JSOP_RETURN) return JS_TRUE; } /* * The non-local jump fixup we emit will unbalance cg->stackDepth, because * the fixup replicates balanced code such as JSOP_LEAVEWITH emitted at the * end of a with statement, so we save cg->stackDepth here and restore it * just before a successful return. */ depth = cg->stackDepth; for (stmt = cg->treeContext.topStmt; stmt != toStmt; stmt = stmt->down) { switch (stmt->type) { case STMT_FINALLY: if (js_NewSrcNote(cx, cg, SRC_HIDDEN) < 0) return JS_FALSE; jmp = EmitBackPatchOp(cx, cg, JSOP_BACKPATCH, &GOSUBS(*stmt)); if (jmp < 0) return JS_FALSE; break; case STMT_WITH: /* There's a With object on the stack that we need to pop. */ if (js_NewSrcNote(cx, cg, SRC_HIDDEN) < 0) return JS_FALSE; if (js_Emit1(cx, cg, JSOP_LEAVEWITH) < 0) return JS_FALSE; break; case STMT_FOR_IN_LOOP: /* * The iterator and the object being iterated need to be popped. */ if (js_NewSrcNote(cx, cg, SRC_HIDDEN) < 0) return JS_FALSE; if (js_Emit1(cx, cg, JSOP_ENDITER) < 0) return JS_FALSE; break; case STMT_SUBROUTINE: /* * There's a [exception or hole, retsub pc-index] pair on the * stack that we need to pop. */ if (js_NewSrcNote(cx, cg, SRC_HIDDEN) < 0) return JS_FALSE; if (js_Emit1(cx, cg, JSOP_POP2) < 0) return JS_FALSE; break; default:; } if (stmt->flags & SIF_SCOPE) { uintN i; /* There is a Block object with locals on the stack to pop. */ if (js_NewSrcNote(cx, cg, SRC_HIDDEN) < 0) return JS_FALSE; i = OBJ_BLOCK_COUNT(cx, ATOM_TO_OBJECT(stmt->atom)); EMIT_UINT16_IMM_OP(JSOP_LEAVEBLOCK, i); } } cg->stackDepth = depth; return JS_TRUE;}static ptrdiff_tEmitGoto(JSContext *cx, JSCodeGenerator *cg, JSStmtInfo *toStmt, ptrdiff_t *lastp, JSAtomListElement *label, JSSrcNoteType noteType){ intN index; if (!EmitNonLocalJumpFixup(cx, cg, toStmt, NULL)) return -1; if (label) index = js_NewSrcNote2(cx, cg, noteType, (ptrdiff_t) ALE_INDEX(label)); else if (noteType != SRC_NULL) index = js_NewSrcNote(cx, cg, noteType); else index = 0; if (index < 0) return -1; return EmitBackPatchOp(cx, cg, JSOP_BACKPATCH, lastp);}static JSBoolBackPatch(JSContext *cx, JSCodeGenerator *cg, ptrdiff_t last, jsbytecode *target, jsbytecode op){ jsbytecode *pc, *stop; ptrdiff_t delta, span; pc = CG_CODE(cg, last); stop = CG_CODE(cg, -1); while (pc != stop) { delta = GetJumpOffset(cg, pc); span = PTRDIFF(target, pc, jsbytecode); CHECK_AND_SET_JUMP_OFFSET(cx, cg, pc, span); /* * Set *pc after jump offset in case bpdelta didn't overflow, but span * does (if so, CHECK_AND_SET_JUMP_OFFSET might call BuildSpanDepTable * and need to see the JSOP_BACKPATCH* op at *pc). */ *pc = op; pc -= delta; } return JS_TRUE;}voidjs_PopStatement(JSTreeContext *tc){ JSStmtInfo *stmt; JSObject *blockObj; stmt = tc->topStmt; tc->topStmt = stmt->down; if (STMT_LINKS_SCOPE(stmt)) { tc->topScopeStmt = stmt->downScope; if (stmt->flags & SIF_SCOPE) { blockObj = ATOM_TO_OBJECT(stmt->atom); tc->blockChain = JSVAL_TO_OBJECT(blockObj->slots[JSSLOT_PARENT]); } }}JSBooljs_PopStatementCG(JSContext *cx, JSCodeGenerator *cg){ JSStmtInfo *stmt; stmt = cg->treeContext.topStmt; if (!STMT_IS_TRYING(stmt) && (!BackPatch(cx, cg, stmt->breaks, CG_NEXT(cg), JSOP_GOTO) || !BackPatch(cx, cg, stmt->continues, CG_CODE(cg, stmt->update), JSOP_GOTO))) { return JS_FALSE; } js_PopStatement(&cg->treeContext); return JS_TRUE;}JSBooljs_DefineCompileTimeConstant(JSContext *cx, JSCodeGenerator *cg, JSAtom *atom, JSParseNode *pn){ jsdouble dval; jsint ival; JSAtom *valueAtom; JSAtomListElement *ale; /* XXX just do numbers for now */ if (pn->pn_type == TOK_NUMBER) { dval = pn->pn_dval; valueAtom = (JSDOUBLE_IS_INT(dval, ival) && INT_FITS_IN_JSVAL(ival)) ? js_AtomizeInt(cx, ival, 0) : js_AtomizeDouble(cx, dval, 0); if (!valueAtom) return JS_FALSE; ale = js_IndexAtom(cx, atom, &cg->constList); if (!ale) return JS_FALSE; ALE_SET_VALUE(ale, ATOM_KEY(valueAtom)); } return JS_TRUE;}JSStmtInfo *js_LexicalLookup(JSTreeContext *tc, JSAtom *atom, jsint *slotp, JSBool letdecl){ JSStmtInfo *stmt; JSObject *obj; JSScope *scope; JSScopeProperty *sprop; jsval v; for (stmt = tc->topScopeStmt; stmt; stmt = stmt->downScope) { if (stmt->type == STMT_WITH) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -