📄 jsopcode.c
字号:
'\r', 'r', '\t', 't', '\v', 'v', '"', '"', '\'', '\'', '\\', '\\', 0};static char *QuoteString(Sprinter *sp, JSString *str, jschar quote){ ptrdiff_t off, len, nb; const jschar *s, *t, *u, *z; char *bp; jschar c; JSBool ok; /* Sample off first for later return value pointer computation. */ off = sp->offset; if (quote && Sprint(sp, "%c", (char)quote) < 0) return NULL; /* Loop control variables: z points at end of string sentinel. */ s = JSSTRING_CHARS(str); z = s + JSSTRING_LENGTH(str); for (t = s; t < z; s = ++t) { /* Move t forward from s past un-quote-worthy characters. */ c = *t; while (JS_ISPRINT(c) && c != quote && c != '\\' && !(c >> 8)) { c = *++t; if (t == z) break; } len = PTRDIFF(t, s, jschar); /* Allocate space for s, including the '\0' at the end. */ nb = (sp->offset + len + 1) - sp->size; if (nb > 0 && !SprintAlloc(sp, nb)) return NULL; /* Advance sp->offset and copy s into sp's buffer. */ bp = sp->base + sp->offset; sp->offset += len; while (--len >= 0) *bp++ = (char) *s++; *bp = '\0'; if (t == z) break; /* Use js_EscapeMap, \u, or \x only if necessary. */ if ((u = js_strchr(js_EscapeMap, c)) != NULL) ok = Sprint(sp, "\\%c", (char)u[1]) >= 0; else ok = Sprint(sp, (c >> 8) ? "\\u%04X" : "\\x%02X", c) >= 0; if (!ok) return NULL; } /* Sprint the closing quote and return the quoted string. */ if (quote && Sprint(sp, "%c", (char)quote) < 0) return NULL; return OFF2STR(sp, off);}JSString *js_QuoteString(JSContext *cx, JSString *str, jschar quote){ void *mark; Sprinter sprinter; char *bytes; JSString *escstr; mark = JS_ARENA_MARK(&cx->tempPool); INIT_SPRINTER(cx, &sprinter, &cx->tempPool, 0); bytes = QuoteString(&sprinter, str, quote); escstr = bytes ? JS_NewStringCopyZ(cx, bytes) : NULL; JS_ARENA_RELEASE(&cx->tempPool, mark); return escstr;}/************************************************************************/struct JSPrinter { Sprinter sprinter; /* base class state */ JSArenaPool pool; /* string allocation pool */ uintN indent; /* indentation in spaces */ JSPackedBool pretty; /* pretty-print: indent, use newlines */ JSPackedBool grouped; /* in parenthesized expression context */ JSScript *script; /* script being printed */ JSScope *scope; /* script function scope */};/* * Hack another flag, a la JS_DONT_PRETTY_PRINT, into uintN indent parameters * to functions such as js_DecompileFunction and js_NewPrinter. This time, as * opposed to JS_DONT_PRETTY_PRINT back in the dark ages, we can assume that a * uintN is at least 32 bits. */#define JS_IN_GROUP_CONTEXT 0x10000JSPrinter *js_NewPrinter(JSContext *cx, const char *name, uintN indent, JSBool pretty){ JSPrinter *jp; JSStackFrame *fp; JSObjectMap *map; jp = (JSPrinter *) JS_malloc(cx, sizeof(JSPrinter)); if (!jp) return NULL; INIT_SPRINTER(cx, &jp->sprinter, &jp->pool, 0); JS_InitArenaPool(&jp->pool, name, 256, 1); jp->indent = indent & ~JS_IN_GROUP_CONTEXT; jp->pretty = pretty; jp->grouped = (indent & JS_IN_GROUP_CONTEXT) != 0; jp->script = NULL; jp->scope = NULL; fp = cx->fp; if (fp && fp->fun && fp->fun->object) { map = fp->fun->object->map; if (MAP_IS_NATIVE(map)) jp->scope = (JSScope *)map; } return jp;}voidjs_DestroyPrinter(JSPrinter *jp){ JS_FinishArenaPool(&jp->pool); JS_free(jp->sprinter.context, jp);}JSString *js_GetPrinterOutput(JSPrinter *jp){ JSContext *cx; JSString *str; cx = jp->sprinter.context; if (!jp->sprinter.base) return cx->runtime->emptyString; str = JS_NewStringCopyZ(cx, jp->sprinter.base); if (!str) return NULL; JS_FreeArenaPool(&jp->pool); INIT_SPRINTER(cx, &jp->sprinter, &jp->pool, 0); return str;}intjs_printf(JSPrinter *jp, const char *format, ...){ va_list ap; char *bp, *fp; int cc; if (*format == '\0') return 0; va_start(ap, format); /* If pretty-printing, expand magic tab into a run of jp->indent spaces. */ if (*format == '\t') { if (jp->pretty && Sprint(&jp->sprinter, "%*s", jp->indent, "") < 0) return -1; format++; } /* Suppress newlines (must be once per format, at the end) if not pretty. */ fp = NULL; if (!jp->pretty && format[cc = strlen(format)-1] == '\n') { fp = JS_strdup(jp->sprinter.context, format); if (!fp) return -1; fp[cc] = '\0'; format = fp; } /* Allocate temp space, convert format, and put. */ bp = JS_vsmprintf(format, ap); /* XXX vsaprintf */ if (fp) { JS_free(jp->sprinter.context, fp); format = NULL; } if (!bp) { JS_ReportOutOfMemory(jp->sprinter.context); return -1; } cc = strlen(bp); if (SprintPut(&jp->sprinter, bp, (size_t)cc) < 0) cc = -1; free(bp); va_end(ap); return cc;}JSBooljs_puts(JSPrinter *jp, const char *s){ return SprintPut(&jp->sprinter, s, strlen(s)) >= 0;}/************************************************************************/typedef struct SprintStack { Sprinter sprinter; /* sprinter for postfix to infix buffering */ ptrdiff_t *offsets; /* stack of postfix string offsets */ jsbytecode *opcodes; /* parallel stack of JS opcodes */ uintN top; /* top of stack index */ JSPrinter *printer; /* permanent output goes here */} SprintStack;/* 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. See the first assertion in * PushOff. */#define JSOP_GETPROP2 254#define JSOP_GETELEM2 255static JSBoolPushOff(SprintStack *ss, ptrdiff_t off, JSOp op){ uintN top;#if JSOP_LIMIT > JSOP_GETPROP2#error JSOP_LIMIT must be <= JSOP_GETPROP2#endif 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; 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; topcs = &js_CodeSpec[ss->opcodes[top]]; cs = &js_CodeSpec[op]; if (topcs->prec != 0 && topcs->prec < cs->prec) { ss->offsets[top] -= 2; ss->sprinter.offset = ss->offsets[top]; off = Sprint(&ss->sprinter, "(%s)", OFF2STR(&ss->sprinter, ss->sprinter.offset + 2)); } else { off = ss->sprinter.offset = ss->offsets[top]; } return off;}#if JS_HAS_SWITCH_STATEMENTtypedef struct TableEntry { jsval key; ptrdiff_t offset; JSAtom *label; jsint order; /* source order for stable tableswitch sort */} TableEntry;static intCompareOffsets(const void *v1, const void *v2, void *arg){ const TableEntry *te1 = (const TableEntry *) v1, *te2 = (const TableEntry *) v2; if (te1->offset == te2->offset) return (int) (te1->order - te2->order); return (int) (te1->offset - te2->offset);}static JSBoolDecompile(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; char *lval, *rval; uintN i; ptrdiff_t diff, off, off2, caseExprOff; jsval key; JSString *str; cx = ss->sprinter.context; jp = ss->printer; lval = OFF2STR(&ss->sprinter, PopOff(ss, JSOP_NOP)); js_printf(jp, "\tswitch (%s) {\n", lval); if (tableLength) { diff = table[0].offset - defaultOffset; if (diff > 0) { jp->indent += 2; js_printf(jp, "\tdefault:\n"); jp->indent += 2; if (!Decompile(ss, pc + defaultOffset, diff)) return JS_FALSE; jp->indent -= 4; } caseExprOff = isCondSwitch ? (ptrdiff_t) js_CodeSpec[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; } 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, JSVAL_IS_STRING(key) ? (jschar)'"' : 0); if (!rval)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -