📄 jsopcode.c
字号:
if (nb > 0 && !SprintAlloc(sp, nb)) return -1; /* Advance offset and copy s into sp's buffer. */ offset = sp->offset; sp->offset += len; bp = sp->base + offset; memmove(bp, s, len); bp[len] = 0; return offset;}static ptrdiff_tSprintCString(Sprinter *sp, const char *s){ return SprintPut(sp, s, strlen(s));}static ptrdiff_tSprint(Sprinter *sp, const char *format, ...){ va_list ap; char *bp; ptrdiff_t offset; va_start(ap, format); bp = JS_vsmprintf(format, ap); /* XXX vsaprintf */ va_end(ap); if (!bp) { JS_ReportOutOfMemory(sp->context); return -1; } offset = SprintCString(sp, bp); free(bp); return offset;}const jschar js_EscapeMap[] = { '\b', 'b', '\f', 'f', '\n', 'n', '\r', 'r', '\t', 't', '\v', 'v', '"', '"', '\'', '\'', '\\', '\\', 0};#define DONT_ESCAPE 0x10000static char *QuoteString(Sprinter *sp, JSString *str, uint32 quote){ JSBool dontEscape, ok; jschar qc, c; ptrdiff_t off, len, nb; const jschar *s, *t, *u, *z; char *bp; /* Sample off first for later return value pointer computation. */ dontEscape = (quote & DONT_ESCAPE) != 0; qc = (jschar) quote; off = sp->offset; if (qc && Sprint(sp, "%c", (char)qc) < 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 != qc && 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 = dontEscape ? Sprint(sp, "%c", (char)c) >= 0 : Sprint(sp, "\\%c", (char)u[1]) >= 0; } else {#ifdef JS_C_STRINGS_ARE_UTF8 /* If this is a surrogate pair, make sure to print the pair. */ if (c >= 0xD800 && c <= 0xDBFF) { jschar buffer[3]; buffer[0] = c; buffer[1] = *++t; buffer[2] = 0; if (t == z) { char numbuf[10]; JS_snprintf(numbuf, sizeof numbuf, "0x%x", c); JS_ReportErrorFlagsAndNumber(sp->context, JSREPORT_ERROR, js_GetErrorMessage, NULL, JSMSG_BAD_SURROGATE_CHAR, numbuf); ok = JS_FALSE; break; } ok = Sprint(sp, "%hs", buffer) >= 0; } else { /* Print as UTF-8 string. */ ok = Sprint(sp, "%hc", c) >= 0; }#else /* Use \uXXXX or \xXX if the string can't be displayed as UTF-8. */ ok = Sprint(sp, (c >> 8) ? "\\u%04X" : "\\x%02X", c) >= 0;#endif } if (!ok) return NULL; } /* Sprint the closing quote and return the quoted string. */ if (qc && Sprint(sp, "%c", (char)qc) < 0) return NULL; /* * If we haven't Sprint'd anything yet, Sprint an empty string so that * the OFF2STR below gives a valid result. */ if (off == sp->offset && Sprint(sp, "") < 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;}/************************************************************************/#if JS_HAS_BLOCK_SCOPEtypedef enum JSBraceState { ALWAYS_BRACE, MAYBE_BRACE, DONT_BRACE} JSBraceState;#endifstruct 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 */ jsbytecode *dvgfence; /* js_DecompileValueGenerator fencepost */ JSScope *scope; /* script function scope */#if JS_HAS_BLOCK_SCOPE JSBraceState braceState; /* remove braces around let declaration */ ptrdiff_t spaceOffset; /* -1 or offset of space before maybe-{ */#endif};/* * 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; 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->dvgfence = NULL; jp->scope = NULL;#if JS_HAS_BLOCK_SCOPE jp->braceState = ALWAYS_BRACE; jp->spaceOffset = -1;#endif 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;}#if !JS_HAS_BLOCK_SCOPE# define SET_MAYBE_BRACE(jp) jp# define CLEAR_MAYBE_BRACE(jp) jp#else# define SET_MAYBE_BRACE(jp) ((jp)->braceState = MAYBE_BRACE, (jp))# define CLEAR_MAYBE_BRACE(jp) ((jp)->braceState = ALWAYS_BRACE, (jp))static voidSetDontBrace(JSPrinter *jp){ ptrdiff_t offset; const char *bp; /* When not pretty-printing, newline after brace is chopped. */ JS_ASSERT(jp->spaceOffset < 0); offset = jp->sprinter.offset - (jp->pretty ? 3 : 2); /* The shortest case is "if (x) {". */ JS_ASSERT(offset >= 6); bp = jp->sprinter.base; if (bp[offset+0] == ' ' && bp[offset+1] == '{') { JS_ASSERT(!jp->pretty || bp[offset+2] == '\n'); jp->spaceOffset = offset; jp->braceState = DONT_BRACE; }}#endifintjs_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') { format++;#if JS_HAS_BLOCK_SCOPE if (*format == '}' && jp->braceState != ALWAYS_BRACE) { JSBraceState braceState; braceState = jp->braceState; jp->braceState = ALWAYS_BRACE; if (braceState == DONT_BRACE) { ptrdiff_t offset, delta, from; JS_ASSERT(format[1] == '\n' || format[1] == ' '); offset = jp->spaceOffset; JS_ASSERT(offset >= 6); /* Replace " {\n" at the end of jp->sprinter with "\n". */ bp = jp->sprinter.base; if (bp[offset+0] == ' ' && bp[offset+1] == '{') { delta = 2; if (jp->pretty) { /* If pretty, we don't have to worry about 'else'. */ JS_ASSERT(bp[offset+2] == '\n'); } else if (bp[offset-1] != ')') { /* Must keep ' ' to avoid 'dolet' or 'elselet'. */ ++offset; delta = 1; } from = offset + delta; memmove(bp + offset, bp + from, jp->sprinter.offset - from); jp->sprinter.offset -= delta; jp->spaceOffset = -1; format += 2; if (*format == '\0') return 0; } } }#endif if (jp->pretty && Sprint(&jp->sprinter, "%*s", jp->indent, "") < 0) return -1; } /* 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 SprintCString(&jp->sprinter, 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 */ uintN inArrayInit; /* array initialiser/comprehension level */ JSPrinter *printer; /* permanent output goes here */} SprintStack;/* * Get a stacked offset from ss->sprinter.base, or if the stacked value |off| * is negative, lazily fetch the generating pc at |spindex = 1 + off| and try * to decompile the code that generated the missing value. This is used when * reporting errors, where the model stack will lack |pcdepth| non-negative * offsets (see js_DecompileValueGenerator and js_DecompileCode). * * If the stacked offset is -1, return 0 to index the NUL padding at the start * of ss->sprinter.base. If this happens, it means there is a decompiler bug * to fix, but it won't violate memory safety. */static ptrdiff_tGetOff(SprintStack *ss, uintN i){ ptrdiff_t off; JSString *str; off = ss->offsets[i]; if (off < 0) {#if defined DEBUG_brendan || defined DEBUG_mrbkap || defined DEBUG_crowder JS_ASSERT(off < -1);#endif if (++off == 0) { if (!ss->sprinter.base && SprintPut(&ss->sprinter, "", 0) >= 0) memset(ss->sprinter.base, 0, ss->sprinter.offset); return 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -