📄 jsopcode.c
字号:
} str = js_DecompileValueGenerator(ss->sprinter.context, off, JSVAL_NULL, NULL); if (!str) return 0; off = SprintCString(&ss->sprinter, JS_GetStringBytes(str)); if (off < 0) off = 0; ss->offsets[i] = off; } return off;}static const char *GetStr(SprintStack *ss, uintN i){ ptrdiff_t off; /* * Must call GetOff before using ss->sprinter.base, since it may be null * until bootstrapped by GetOff. */ off = GetOff(ss, i); return OFF2STR(&ss->sprinter, off);}/* Gap between stacked strings to allow for insertion of parens and commas. */#define PAREN_SLOP (2 + 1)/* * These pseudo-ops help js_DecompileValueGenerator decompile JSOP_SETNAME, * JSOP_SETPROP, and JSOP_SETELEM, respectively. They are never stored in * bytecode, so they don't preempt valid opcodes. */#define JSOP_GETPROP2 256#define JSOP_GETELEM2 257static JSBoolPushOff(SprintStack *ss, ptrdiff_t off, JSOp op){ uintN top; if (!SprintAlloc(&ss->sprinter, PAREN_SLOP)) return JS_FALSE; /* ss->top points to the next free slot; be paranoid about overflow. */ top = ss->top; JS_ASSERT(top < ss->printer->script->depth); if (top >= ss->printer->script->depth) { JS_ReportOutOfMemory(ss->sprinter.context); return JS_FALSE; } /* The opcodes stack must contain real bytecodes that index js_CodeSpec. */ ss->offsets[top] = off; ss->opcodes[top] = (op == JSOP_GETPROP2) ? JSOP_GETPROP : (op == JSOP_GETELEM2) ? JSOP_GETELEM : (jsbytecode) op; ss->top = ++top; memset(OFF2STR(&ss->sprinter, ss->sprinter.offset), 0, PAREN_SLOP); ss->sprinter.offset += PAREN_SLOP; return JS_TRUE;}static ptrdiff_tPopOff(SprintStack *ss, JSOp op){ uintN top; const JSCodeSpec *cs, *topcs; ptrdiff_t off; /* ss->top points to the next free slot; be paranoid about underflow. */ top = ss->top; JS_ASSERT(top != 0); if (top == 0) return 0; ss->top = --top; off = GetOff(ss, top); topcs = &js_CodeSpec[ss->opcodes[top]]; cs = &js_CodeSpec[op]; if (topcs->prec != 0 && topcs->prec < cs->prec) { ss->sprinter.offset = ss->offsets[top] = off - 2; off = Sprint(&ss->sprinter, "(%s)", OFF2STR(&ss->sprinter, off)); } else { ss->sprinter.offset = off; } return off;}static const char *PopStr(SprintStack *ss, JSOp op){ ptrdiff_t off; off = PopOff(ss, op); return OFF2STR(&ss->sprinter, off);}typedef struct TableEntry { jsval key; ptrdiff_t offset; JSAtom *label; jsint order; /* source order for stable tableswitch sort */} TableEntry;static JSBoolCompareOffsets(void *arg, const void *v1, const void *v2, int *result){ ptrdiff_t offset_diff; const TableEntry *te1 = (const TableEntry *) v1, *te2 = (const TableEntry *) v2; offset_diff = te1->offset - te2->offset; *result = (offset_diff == 0 ? te1->order - te2->order : offset_diff < 0 ? -1 : 1); return JS_TRUE;}static jsbytecode *Decompile(SprintStack *ss, jsbytecode *pc, intN nb);static JSBoolDecompileSwitch(SprintStack *ss, TableEntry *table, uintN tableLength, jsbytecode *pc, ptrdiff_t switchLength, ptrdiff_t defaultOffset, JSBool isCondSwitch){ JSContext *cx; JSPrinter *jp; ptrdiff_t off, off2, diff, caseExprOff; char *lval, *rval; uintN i; jsval key; JSString *str; cx = ss->sprinter.context; jp = ss->printer; /* JSOP_CONDSWITCH doesn't pop, unlike JSOP_{LOOKUP,TABLE}SWITCH. */ off = isCondSwitch ? GetOff(ss, ss->top-1) : PopOff(ss, JSOP_NOP); lval = OFF2STR(&ss->sprinter, off); js_printf(CLEAR_MAYBE_BRACE(jp), "\tswitch (%s) {\n", lval); if (tableLength) { diff = table[0].offset - defaultOffset; if (diff > 0) { jp->indent += 2; js_printf(jp, "\t%s:\n", js_default_str); jp->indent += 2; if (!Decompile(ss, pc + defaultOffset, diff)) return JS_FALSE; jp->indent -= 4; } caseExprOff = isCondSwitch ? JSOP_CONDSWITCH_LENGTH : 0; for (i = 0; i < tableLength; i++) { off = table[i].offset; off2 = (i + 1 < tableLength) ? table[i + 1].offset : switchLength; key = table[i].key; if (isCondSwitch) { ptrdiff_t nextCaseExprOff; /* * key encodes the JSOP_CASE bytecode's offset from switchtop. * The next case expression follows immediately, unless we are * at the last case. */ nextCaseExprOff = (ptrdiff_t)JSVAL_TO_INT(key); nextCaseExprOff += js_CodeSpec[pc[nextCaseExprOff]].length; jp->indent += 2; if (!Decompile(ss, pc + caseExprOff, nextCaseExprOff - caseExprOff)) { return JS_FALSE; } caseExprOff = nextCaseExprOff; /* Balance the stack as if this JSOP_CASE matched. */ --ss->top; } else { /* * key comes from an atom, not the decompiler, so we need to * quote it if it's a string literal. But if table[i].label * is non-null, key was constant-propagated and label is the * name of the const we should show as the case label. We set * key to undefined so this identifier is escaped, if required * by non-ASCII characters, but not quoted, by QuoteString. */ if (table[i].label) { str = ATOM_TO_STRING(table[i].label); key = JSVAL_VOID; } else { str = js_ValueToString(cx, key); if (!str) return JS_FALSE; } rval = QuoteString(&ss->sprinter, str, (jschar)(JSVAL_IS_STRING(key) ? '"' : 0)); if (!rval) return JS_FALSE; RETRACT(&ss->sprinter, rval); jp->indent += 2; js_printf(jp, "\tcase %s:\n", rval); } jp->indent += 2; if (off <= defaultOffset && defaultOffset < off2) { diff = defaultOffset - off; if (diff != 0) { if (!Decompile(ss, pc + off, diff)) return JS_FALSE; off = defaultOffset; } jp->indent -= 2; js_printf(jp, "\t%s:\n", js_default_str); jp->indent += 2; } if (!Decompile(ss, pc + off, off2 - off)) return JS_FALSE; jp->indent -= 4; /* Re-balance as if last JSOP_CASE or JSOP_DEFAULT mismatched. */ if (isCondSwitch) ++ss->top; } } if (defaultOffset == switchLength) { jp->indent += 2; js_printf(jp, "\t%s:;\n", js_default_str); jp->indent -= 2; } js_printf(jp, "\t}\n"); /* By the end of a JSOP_CONDSWITCH, the discriminant has been popped. */ if (isCondSwitch) --ss->top; return JS_TRUE;}static JSAtom *GetSlotAtom(JSPrinter *jp, JSPropertyOp getter, uintN slot){ JSScope *scope; JSScopeProperty *sprop; JSObject *obj, *proto; scope = jp->scope; while (scope) { for (sprop = SCOPE_LAST_PROP(scope); sprop; sprop = sprop->parent) { if (sprop->getter != getter) continue; JS_ASSERT(sprop->flags & SPROP_HAS_SHORTID); JS_ASSERT(JSID_IS_ATOM(sprop->id)); if ((uintN) sprop->shortid == slot) return JSID_TO_ATOM(sprop->id); } obj = scope->object; if (!obj) break; proto = OBJ_GET_PROTO(jp->sprinter.context, obj); if (!proto) break; scope = OBJ_SCOPE(proto); } return NULL;}/* * NB: Indexed by SRC_DECL_* defines from jsemit.h. */static const char * const var_prefix[] = {"var ", "const ", "let "};static const char *VarPrefix(jssrcnote *sn){ if (sn && (SN_TYPE(sn) == SRC_DECL || SN_TYPE(sn) == SRC_GROUPASSIGN)) { ptrdiff_t type = js_GetSrcNoteOffset(sn, 0); if ((uintN)type <= SRC_DECL_LET) return var_prefix[type]; } return "";}#define LOCAL_ASSERT_RV(expr, rv) \ JS_BEGIN_MACRO \ JS_ASSERT(expr); \ if (!(expr)) return (rv); \ JS_END_MACROconst char *GetLocal(SprintStack *ss, jsint i){ ptrdiff_t off; JSContext *cx; JSScript *script; jsatomid j, n; JSAtom *atom; JSObject *obj; jsint depth, count; JSScopeProperty *sprop; const char *rval;#define LOCAL_ASSERT(expr) LOCAL_ASSERT_RV(expr, "") off = ss->offsets[i]; if (off >= 0) return OFF2STR(&ss->sprinter, off); /* * We must be called from js_DecompileValueGenerator (via Decompile) when * dereferencing a local that's undefined or null. Search script->atomMap * for the block containing this local by its stack index, i. */ cx = ss->sprinter.context; script = ss->printer->script; for (j = 0, n = script->atomMap.length; j < n; j++) { atom = script->atomMap.vector[j]; if (ATOM_IS_OBJECT(atom)) { obj = ATOM_TO_OBJECT(atom); if (OBJ_GET_CLASS(cx, obj) == &js_BlockClass) { depth = OBJ_BLOCK_DEPTH(cx, obj); count = OBJ_BLOCK_COUNT(cx, obj); if ((jsuint)(i - depth) < (jsuint)count) break; } } } LOCAL_ASSERT(j < n); i -= depth; for (sprop = OBJ_SCOPE(obj)->lastProp; sprop; sprop = sprop->parent) { if (sprop->shortid == i) break; } LOCAL_ASSERT(sprop && JSID_IS_ATOM(sprop->id)); atom = JSID_TO_ATOM(sprop->id); rval = QuoteString(&ss->sprinter, ATOM_TO_STRING(atom), 0); if (!rval) return NULL; RETRACT(&ss->sprinter, rval); return rval;#undef LOCAL_ASSERT}#if JS_HAS_DESTRUCTURING#define LOCAL_ASSERT(expr) LOCAL_ASSERT_RV(expr, NULL)#define LOAD_OP_DATA(pc) (oplen = (cs = &js_CodeSpec[op = *pc])->length)static jsbytecode *DecompileDestructuring(SprintStack *ss, jsbytecode *pc, jsbytecode *endpc);static jsbytecode *DecompileDestructuringLHS(SprintStack *ss, jsbytecode *pc, jsbytecode *endpc, JSBool *hole){ JSContext *cx; JSPrinter *jp; JSOp op; const JSCodeSpec *cs; uintN oplen, i; const char *lval, *xval; ptrdiff_t todo; JSAtom *atom; *hole = JS_FALSE; cx = ss->sprinter.context; jp = ss->printer; LOAD_OP_DATA(pc); switch (op) { case JSOP_POP: *hole = JS_TRUE; todo = SprintPut(&ss->sprinter, ", ", 2); break; case JSOP_DUP: pc = DecompileDestructuring(ss, pc, endpc); if (!pc) return NULL; if (pc == endpc) return pc; LOAD_OP_DATA(pc); lval = PopStr(ss, JSOP_NOP); todo = SprintCString(&ss->sprinter, lval); if (op == JSOP_SETSP) return pc; LOCAL_ASSERT(*pc == JSOP_POP); break; case JSOP_SETARG: case JSOP_SETVAR: case JSOP_SETGVAR: case JSOP_SETLOCAL: LOCAL_ASSERT(pc[oplen] == JSOP_POP || pc[oplen] == JSOP_SETSP); /* FALL THROUGH */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -