📄 jsopcode.c
字号:
case JSOP_SETLOCALPOP: i = GET_UINT16(pc); atom = NULL; lval = NULL; if (op == JSOP_SETARG) atom = GetSlotAtom(jp, js_GetArgument, i); else if (op == JSOP_SETVAR) atom = GetSlotAtom(jp, js_GetLocalVariable, i); else if (op == JSOP_SETGVAR) atom = GET_ATOM(cx, jp->script, pc); else lval = GetLocal(ss, i); if (atom) lval = js_AtomToPrintableString(cx, atom); LOCAL_ASSERT(lval); todo = SprintCString(&ss->sprinter, lval); if (op != JSOP_SETLOCALPOP) { pc += oplen; if (pc == endpc) return pc; LOAD_OP_DATA(pc); if (op == JSOP_SETSP) return pc; LOCAL_ASSERT(op == JSOP_POP); } break; default: /* * We may need to auto-parenthesize the left-most value decompiled * here, so add back PAREN_SLOP temporarily. Then decompile until the * opcode that would reduce the stack depth to (ss->top-1), which we * pass to Decompile encoded as -(ss->top-1) - 1 or just -ss->top for * the nb parameter. */ todo = ss->sprinter.offset; ss->sprinter.offset = todo + PAREN_SLOP; pc = Decompile(ss, pc, -ss->top); if (!pc) return NULL; if (pc == endpc) return pc; LOAD_OP_DATA(pc); LOCAL_ASSERT(op == JSOP_ENUMELEM || op == JSOP_ENUMCONSTELEM); xval = PopStr(ss, JSOP_NOP); lval = PopStr(ss, JSOP_GETPROP); ss->sprinter.offset = todo; if (*lval == '\0') { /* lval is from JSOP_BINDNAME, so just print xval. */ todo = SprintCString(&ss->sprinter, xval); } else if (*xval == '\0') { /* xval is from JSOP_SETCALL or JSOP_BINDXMLNAME, print lval. */ todo = SprintCString(&ss->sprinter, lval); } else { todo = Sprint(&ss->sprinter, (js_CodeSpec[ss->opcodes[ss->top+1]].format & JOF_XMLNAME) ? "%s.%s" : "%s[%s]", lval, xval); } break; } if (todo < 0) return NULL; LOCAL_ASSERT(pc < endpc); pc += oplen; return pc;}/* * Starting with a SRC_DESTRUCT-annotated JSOP_DUP, decompile a destructuring * left-hand side object or array initialiser, including nested destructuring * initialisers. On successful return, the decompilation will be pushed on ss * and the return value will point to the POP or GROUP bytecode following the * destructuring expression. * * At any point, if pc is equal to endpc and would otherwise advance, we stop * immediately and return endpc. */static jsbytecode *DecompileDestructuring(SprintStack *ss, jsbytecode *pc, jsbytecode *endpc){ ptrdiff_t head, todo; JSContext *cx; JSPrinter *jp; JSOp op, saveop; const JSCodeSpec *cs; uintN oplen; jsint i, lasti; jsdouble d; const char *lval; jsbytecode *pc2; jsatomid atomIndex; JSAtom *atom; jssrcnote *sn; JSString *str; JSBool hole; LOCAL_ASSERT(*pc == JSOP_DUP); pc += JSOP_DUP_LENGTH; /* * Set head so we can rewrite '[' to '{' as needed. Back up PAREN_SLOP * chars so the destructuring decompilation accumulates contiguously in * ss->sprinter starting with "[". */ head = SprintPut(&ss->sprinter, "[", 1); if (head < 0 || !PushOff(ss, head, JSOP_NOP)) return NULL; ss->sprinter.offset -= PAREN_SLOP; LOCAL_ASSERT(head == ss->sprinter.offset - 1); LOCAL_ASSERT(*OFF2STR(&ss->sprinter, head) == '['); cx = ss->sprinter.context; jp = ss->printer; lasti = -1; while (pc < endpc) { LOAD_OP_DATA(pc); saveop = op; switch (op) { case JSOP_POP: pc += oplen; goto out; /* Handle the optimized number-pushing opcodes. */ case JSOP_ZERO: d = i = 0; goto do_getelem; case JSOP_ONE: d = i = 1; goto do_getelem; case JSOP_UINT16: d = i = GET_UINT16(pc); goto do_getelem; case JSOP_UINT24: d = i = GET_UINT24(pc); goto do_getelem; /* Handle the extended literal form of JSOP_NUMBER. */ case JSOP_LITOPX: atomIndex = GET_LITERAL_INDEX(pc); pc2 = pc + 1 + LITERAL_INDEX_LEN; op = *pc2; LOCAL_ASSERT(op == JSOP_NUMBER); goto do_getatom; case JSOP_NUMBER: atomIndex = GET_ATOM_INDEX(pc); do_getatom: atom = js_GetAtom(cx, &jp->script->atomMap, atomIndex); d = *ATOM_TO_DOUBLE(atom); LOCAL_ASSERT(JSDOUBLE_IS_FINITE(d) && !JSDOUBLE_IS_NEGZERO(d)); i = (jsint)d; do_getelem: sn = js_GetSrcNote(jp->script, pc); pc += oplen; if (pc == endpc) return pc; LOAD_OP_DATA(pc); LOCAL_ASSERT(op == JSOP_GETELEM); /* Distinguish object from array by opcode or source note. */ if (saveop == JSOP_LITERAL || (sn && SN_TYPE(sn) == SRC_INITPROP)) { *OFF2STR(&ss->sprinter, head) = '{'; if (Sprint(&ss->sprinter, "%g: ", d) < 0) return NULL; } else { /* Sanity check for the gnarly control flow above. */ LOCAL_ASSERT(i == d); /* Fill in any holes (holes at the end don't matter). */ while (++lasti < i) { if (SprintPut(&ss->sprinter, ", ", 2) < 0) return NULL; } } break; case JSOP_LITERAL: atomIndex = GET_LITERAL_INDEX(pc); goto do_getatom; case JSOP_GETPROP: *OFF2STR(&ss->sprinter, head) = '{'; atom = GET_ATOM(cx, jp->script, pc); str = ATOM_TO_STRING(atom); if (!QuoteString(&ss->sprinter, str, js_IsIdentifier(str) ? 0 : (jschar)'\'')) { return NULL; } if (SprintPut(&ss->sprinter, ": ", 2) < 0) return NULL; break; default: LOCAL_ASSERT(0); } pc += oplen; if (pc == endpc) return pc; /* * Decompile the left-hand side expression whose bytecode starts at pc * and continues for a bounded number of bytecodes or stack operations * (and which in any event stops before endpc). */ pc = DecompileDestructuringLHS(ss, pc, endpc, &hole); if (!pc) return NULL; if (pc == endpc || *pc != JSOP_DUP) break; /* * Check for SRC_DESTRUCT on this JSOP_DUP, which would mean another * destructuring initialiser abuts this one, and we should stop. This * happens with source of the form '[a] = [b] = c'. */ sn = js_GetSrcNote(jp->script, pc); if (sn && SN_TYPE(sn) == SRC_DESTRUCT) break; if (!hole && SprintPut(&ss->sprinter, ", ", 2) < 0) return NULL; pc += JSOP_DUP_LENGTH; }out: lval = OFF2STR(&ss->sprinter, head); todo = SprintPut(&ss->sprinter, (*lval == '[') ? "]" : "}", 1); if (todo < 0) return NULL; return pc;}static jsbytecode *DecompileGroupAssignment(SprintStack *ss, jsbytecode *pc, jsbytecode *endpc, jssrcnote *sn, ptrdiff_t *todop){ JSOp op; const JSCodeSpec *cs; uintN oplen, start, end, i; ptrdiff_t todo; JSBool hole; const char *rval; LOAD_OP_DATA(pc); LOCAL_ASSERT(op == JSOP_PUSH || op == JSOP_GETLOCAL); todo = Sprint(&ss->sprinter, "%s[", VarPrefix(sn)); if (todo < 0 || !PushOff(ss, todo, JSOP_NOP)) return NULL; ss->sprinter.offset -= PAREN_SLOP; for (;;) { pc += oplen; if (pc == endpc) return pc; pc = DecompileDestructuringLHS(ss, pc, endpc, &hole); if (!pc) return NULL; if (pc == endpc) return pc; LOAD_OP_DATA(pc); if (op != JSOP_PUSH && op != JSOP_GETLOCAL) break; if (!hole && SprintPut(&ss->sprinter, ", ", 2) < 0) return NULL; } LOCAL_ASSERT(op == JSOP_SETSP); if (SprintPut(&ss->sprinter, "] = [", 5) < 0) return NULL; start = GET_UINT16(pc); end = ss->top - 1; for (i = start; i < end; i++) { rval = GetStr(ss, i); if (Sprint(&ss->sprinter, "%s%s", (i == start) ? "" : ", ", (i == end - 1 && *rval == '\0') ? ", " : rval) < 0) { return NULL; } } if (SprintPut(&ss->sprinter, "]", 1) < 0) return NULL; ss->sprinter.offset = ss->offsets[i]; ss->top = start; *todop = todo; return pc;}#undef LOCAL_ASSERT#undef LOAD_OP_DATA#endif /* JS_HAS_DESTRUCTURING *//* * If nb is non-negative, decompile nb bytecodes starting at pc. Otherwise * the decompiler starts at pc and continues until it reaches an opcode for * which decompiling would result in the stack depth equaling -(nb + 1). */static jsbytecode *Decompile(SprintStack *ss, jsbytecode *pc, intN nb){ JSContext *cx; JSPrinter *jp, *jp2; jsbytecode *startpc, *endpc, *pc2, *done, *forelem_tail, *forelem_done; ptrdiff_t tail, todo, len, oplen, cond, next; JSOp op, lastop, saveop; const JSCodeSpec *cs; jssrcnote *sn, *sn2; const char *lval, *rval, *xval, *fmt; jsint i, argc; char **argv; jsatomid atomIndex; JSAtom *atom; JSObject *obj; JSFunction *fun; JSString *str; JSBool ok;#if JS_HAS_XML_SUPPORT JSBool foreach, inXML, quoteAttr;#else#define inXML JS_FALSE#endif jsval val; int stackDummy; static const char exception_cookie[] = "/*EXCEPTION*/"; static const char retsub_pc_cookie[] = "/*RETSUB_PC*/"; static const char forelem_cookie[] = "/*FORELEM*/"; static const char with_cookie[] = "/*WITH*/"; static const char dot_format[] = "%s.%s"; static const char index_format[] = "%s[%s]"; static const char predot_format[] = "%s%s.%s"; static const char postdot_format[] = "%s.%s%s"; static const char preindex_format[] = "%s%s[%s]"; static const char postindex_format[] = "%s[%s]%s"; static const char ss_format[] = "%s%s";/* * Local macros */#define DECOMPILE_CODE(pc,nb) if (!Decompile(ss, pc, nb)) return NULL#define POP_STR() PopStr(ss, op)#define LOCAL_ASSERT(expr) LOCAL_ASSERT_RV(expr, JS_FALSE)/* * Callers know that ATOM_IS_STRING(atom), and we leave it to the optimizer to * common ATOM_TO_STRING(atom) here and near the call sites. */#define ATOM_IS_IDENTIFIER(atom) js_IsIdentifier(ATOM_TO_STRING(atom))#define ATOM_IS_KEYWORD(atom) \ (js_CheckKeyword(JSSTRING_CHARS(ATOM_TO_STRING(atom)), \ JSSTRING_LENGTH(ATOM_TO_STRING(atom))) != TOK_EOF)/* * Given an atom already fetched from jp->script's atom map, quote/escape its * string appropriately into rval, and select fmt from the quoted and unquoted * alternatives. */#define GET_QUOTE_AND_FMT(qfmt, ufmt, rval) \ JS_BEGIN_MACRO \ jschar quote_; \ if (!ATOM_IS_IDENTIFIER(atom)) { \ quote_ = '\''; \ fmt = qfmt; \ } else { \ quote_ = 0; \ fmt = ufmt; \ } \ rval = QuoteString(&ss->sprinter, ATOM_TO_STRING(atom), quote_); \ if (!rval) \ return NULL; \ JS_END_MACRO/* * Get atom from jp->script's atom map, quote/escape its string appropriately * into rval, and select fmt from the quoted and unquoted alternatives. */#define GET_ATOM_QUOTE_AND_FMT(qfmt, ufmt, rval) \ JS_BEGIN_MACRO \ atom = GET_ATOM(cx, jp->script, pc); \ GET_QUOTE_AND_FMT(qfmt, ufmt, rval); \ JS_END_MACRO cx = ss->sprinter.context; if (!JS_CHECK_STACK_SIZE(cx, stackDummy)) { JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_OVER_RECURSED); return NULL; } jp = ss->printer; startpc = pc; endpc = (nb < 0) ? jp->script->code + jp->script->length : pc + nb; forelem_tail = forelem_done = NULL; tail = -1; todo = -2; /* NB: different from Sprint() error return. */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -