📄 jsopcode.c
字号:
'\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 */
JSBool pretty; /* pretty-print: indent, use newlines */
JSScript *script; /* script being printed */
JSScope *scope; /* script function scope */
};
JSPrinter *
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;
jp->pretty = pretty;
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;
}
void
js_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;
}
int
js_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;
}
JSBool
js_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 255
static JSBool
PushOff(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_t
PopOff(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_STATEMENT
typedef struct TableEntry {
jsval key;
ptrdiff_t offset;
} TableEntry;
static int
CompareOffsets(const void *v1, const void *v2, void *arg)
{
const TableEntry *te1 = (const TableEntry *) v1,
*te2 = (const TableEntry *) v2;
return te1->offset - te2->offset;
}
static JSBool
Decompile(SprintStack *ss, jsbytecode *pc, intN nb);
static JSBool
DecompileSwitch(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;
if (i + 1 < tableLength)
off2 = table[i + 1].offset;
else
off2 = 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.
*/
str = js_ValueToString(cx, key);
if (!str)
return JS_FALSE;
jp->indent += 2;
if (JSVAL_IS_STRING(key)) {
rval = QuoteString(&ss->sprinter, str, (jschar)'"');
if (!rval)
return JS_FALSE;
RETRACT(&ss->sprinter, rval);
} else {
rval = JS_GetStringBytes(str);
}
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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -