📄 jsopcode.c
字号:
saveop = JSOP_NOP; sn = NULL; rval = NULL;#if JS_HAS_XML_SUPPORT foreach = inXML = quoteAttr = JS_FALSE;#endif while (nb < 0 || pc < endpc) { /* * Move saveop to lastop so prefixed bytecodes can take special action * while sharing maximal code. Set op and saveop to the new bytecode, * use op in POP_STR to trigger automatic parenthesization, but push * saveop at the bottom of the loop if this op pushes. Thus op may be * set to nop or otherwise mutated to suppress auto-parens. */ lastop = saveop; op = saveop = (JSOp) *pc; cs = &js_CodeSpec[saveop]; len = oplen = cs->length; if (nb < 0 && -(nb + 1) == (intN)ss->top - cs->nuses + cs->ndefs) return pc; if (pc + oplen == jp->dvgfence) { JSStackFrame *fp; uint32 format, mode, type; /* * Rewrite non-get ops to their "get" format if the error is in * the bytecode at pc, so we don't decompile more than the error * expression. */ for (fp = cx->fp; fp && !fp->script; fp = fp->down) continue; format = cs->format; if (((fp && pc == fp->pc) || (pc == startpc && cs->nuses != 0)) && format & (JOF_SET|JOF_DEL|JOF_INCDEC|JOF_IMPORT|JOF_FOR)) { mode = (format & JOF_MODEMASK); if (mode == JOF_NAME) { /* * JOF_NAME does not imply JOF_CONST, so we must check for * the QARG and QVAR format types, and translate those to * JSOP_GETARG or JSOP_GETVAR appropriately, instead of to * JSOP_NAME. */ type = format & JOF_TYPEMASK; op = (type == JOF_QARG) ? JSOP_GETARG : (type == JOF_QVAR) ? JSOP_GETVAR : (type == JOF_LOCAL) ? JSOP_GETLOCAL : JSOP_NAME; i = cs->nuses - js_CodeSpec[op].nuses; while (--i >= 0) PopOff(ss, JSOP_NOP); } else { /* * We must replace the faulting pc's bytecode with a * corresponding JSOP_GET* code. For JSOP_SET{PROP,ELEM}, * we must use the "2nd" form of JSOP_GET{PROP,ELEM}, to * throw away the assignment op's right-hand operand and * decompile it as if it were a GET of its left-hand * operand. */ if (mode == JOF_PROP) { op = (format & JOF_SET) ? JSOP_GETPROP2 : JSOP_GETPROP; } else if (mode == JOF_ELEM) { op = (format & JOF_SET) ? JSOP_GETELEM2 : JSOP_GETELEM; } else { /* * Zero mode means precisely that op is uncategorized * for our purposes, so we must write per-op special * case code here. */ switch (op) { case JSOP_ENUMELEM: case JSOP_ENUMCONSTELEM: op = JSOP_GETELEM; break;#if JS_HAS_LVALUE_RETURN case JSOP_SETCALL: op = JSOP_CALL; break;#endif default: LOCAL_ASSERT(0); } } } } saveop = op; if (op >= JSOP_LIMIT) { switch (op) { case JSOP_GETPROP2: saveop = JSOP_GETPROP; break; case JSOP_GETELEM2: saveop = JSOP_GETELEM; break; default:; } } LOCAL_ASSERT(js_CodeSpec[saveop].length == oplen); jp->dvgfence = NULL; } if (cs->token) { switch (cs->nuses) { case 2: sn = js_GetSrcNote(jp->script, pc); if (sn && SN_TYPE(sn) == SRC_ASSIGNOP) { /* * Avoid over-parenthesizing y in x op= y based on its * expansion: x = x op y (replace y by z = w to see the * problem). */ op = pc[oplen]; LOCAL_ASSERT(op != saveop); } rval = POP_STR(); lval = POP_STR(); if (op != saveop) { /* Print only the right operand of the assignment-op. */ todo = SprintCString(&ss->sprinter, rval); op = saveop; } else if (!inXML) { todo = Sprint(&ss->sprinter, "%s %s %s", lval, cs->token, rval); } else { /* In XML, just concatenate the two operands. */ LOCAL_ASSERT(op == JSOP_ADD); todo = Sprint(&ss->sprinter, ss_format, lval, rval); } break; case 1: rval = POP_STR(); todo = Sprint(&ss->sprinter, ss_format, cs->token, rval); break; case 0: todo = SprintCString(&ss->sprinter, cs->token); break; default: todo = -2; break; } } else { switch (op) {#define BEGIN_LITOPX_CASE(OP) \ case OP: \ atomIndex = GET_ATOM_INDEX(pc); \ do_##OP: \ atom = js_GetAtom(cx, &jp->script->atomMap, atomIndex);#define END_LITOPX_CASE \ break; case JSOP_NOP: /* * Check for a do-while loop, a for-loop with an empty * initializer part, a labeled statement, a function * definition, or try/finally. */ sn = js_GetSrcNote(jp->script, pc); todo = -2; switch (sn ? SN_TYPE(sn) : SRC_NULL) { case SRC_WHILE: js_printf(SET_MAYBE_BRACE(jp), "\tdo {\n"); jp->indent += 4; break; case SRC_FOR: rval = ""; do_forloop: /* Skip the JSOP_NOP or JSOP_POP bytecode. */ pc++; /* Get the cond, next, and loop-closing tail offsets. */ cond = js_GetSrcNoteOffset(sn, 0); next = js_GetSrcNoteOffset(sn, 1); tail = js_GetSrcNoteOffset(sn, 2); LOCAL_ASSERT(tail + GetJumpOffset(pc+tail, pc+tail) == 0); /* Print the keyword and the possibly empty init-part. */ js_printf(jp, "\tfor (%s;", rval); if (pc[cond] == JSOP_IFEQ || pc[cond] == JSOP_IFEQX) { /* Decompile the loop condition. */ DECOMPILE_CODE(pc, cond); js_printf(jp, " %s", POP_STR()); } /* Need a semicolon whether or not there was a cond. */ js_puts(jp, ";"); if (pc[next] != JSOP_GOTO && pc[next] != JSOP_GOTOX) { /* Decompile the loop updater. */ DECOMPILE_CODE(pc + next, tail - next - 1); js_printf(jp, " %s", POP_STR()); } /* Do the loop body. */ js_printf(SET_MAYBE_BRACE(jp), ") {\n"); jp->indent += 4; oplen = (cond) ? js_CodeSpec[pc[cond]].length : 0; DECOMPILE_CODE(pc + cond + oplen, next - cond - oplen); jp->indent -= 4; js_printf(jp, "\t}\n"); /* Set len so pc skips over the entire loop. */ len = tail + js_CodeSpec[pc[tail]].length; break; case SRC_LABEL: atom = js_GetAtom(cx, &jp->script->atomMap, (jsatomid) js_GetSrcNoteOffset(sn, 0)); jp->indent -= 4; rval = QuoteString(&ss->sprinter, ATOM_TO_STRING(atom), 0); if (!rval) return NULL; RETRACT(&ss->sprinter, rval); js_printf(CLEAR_MAYBE_BRACE(jp), "\t%s:\n", rval); jp->indent += 4; break; case SRC_LABELBRACE: atom = js_GetAtom(cx, &jp->script->atomMap, (jsatomid) js_GetSrcNoteOffset(sn, 0)); rval = QuoteString(&ss->sprinter, ATOM_TO_STRING(atom), 0); if (!rval) return NULL; RETRACT(&ss->sprinter, rval); js_printf(CLEAR_MAYBE_BRACE(jp), "\t%s: {\n", rval); jp->indent += 4; break; case SRC_ENDBRACE: jp->indent -= 4; js_printf(jp, "\t}\n"); break; case SRC_FUNCDEF: atom = js_GetAtom(cx, &jp->script->atomMap, (jsatomid) js_GetSrcNoteOffset(sn, 0)); LOCAL_ASSERT(ATOM_IS_OBJECT(atom)); do_function: obj = ATOM_TO_OBJECT(atom); fun = (JSFunction *) JS_GetPrivate(cx, obj); jp2 = js_NewPrinter(cx, JS_GetFunctionName(fun), jp->indent, jp->pretty); if (!jp2) return NULL; jp2->scope = jp->scope; js_puts(jp2, "\n"); ok = js_DecompileFunction(jp2, fun); if (ok) { js_puts(jp2, "\n"); str = js_GetPrinterOutput(jp2); if (str) js_printf(jp, "%s\n", JS_GetStringBytes(str)); else ok = JS_FALSE; } js_DestroyPrinter(jp2); if (!ok) return NULL; break; case SRC_BRACE: js_printf(CLEAR_MAYBE_BRACE(jp), "\t{\n"); jp->indent += 4; len = js_GetSrcNoteOffset(sn, 0); DECOMPILE_CODE(pc + oplen, len - oplen); jp->indent -= 4; js_printf(jp, "\t}\n"); break; default:; } break; case JSOP_GROUP: cs = &js_CodeSpec[lastop]; if ((cs->prec != 0 && cs->prec == js_CodeSpec[pc[JSOP_GROUP_LENGTH]].prec) || pc[JSOP_GROUP_LENGTH] == JSOP_PUSHOBJ || pc[JSOP_GROUP_LENGTH] == JSOP_DUP) { /* * Force parens if this JSOP_GROUP forced re-association * against precedence, or if this is a call or constructor * expression, or if it is destructured (JSOP_DUP). * * This is necessary to handle the operator new grammar, * by which new x(y).z means (new x(y))).z. For example * new (x(y).z) must decompile with the constructor * parenthesized, but normal precedence has JSOP_GETPROP * (for the final .z) higher than JSOP_NEW. In general, * if the call or constructor expression is parenthesized, * we preserve parens. */ op = JSOP_NAME; rval = POP_STR(); todo = SprintCString(&ss->sprinter, rval); } else { /* * Don't explicitly parenthesize -- just fix the top * opcode so that the auto-parens magic in PopOff can do * its thing. */ LOCAL_ASSERT(ss->top != 0); ss->opcodes[ss->top-1] = saveop = lastop; todo = -2; } break; case JSOP_STARTITER: todo = -2; break; case JSOP_PUSH:#if JS_HAS_DESTRUCTURING sn = js_GetSrcNote(jp->script, pc); if (sn && SN_TYPE(sn) == SRC_GROUPASSIGN) { pc = DecompileGroupAssignment(ss, pc, endpc, sn, &todo); if (!pc) return NULL; LOCAL_ASSERT(*pc == JSOP_SETSP); len = oplen = JSOP_SETSP_LENGTH; goto end_groupassignment; }#endif /* FALL THROUGH */ case JSOP_PUSHOBJ: case JSOP_BINDNAME: do_JSOP_BINDNAME: todo = Sprint(&ss->sprinter, ""); break; case JSOP_TRY: js_printf(CLEAR_MAYBE_BRACE(jp), "\ttry {\n"); jp->indent += 4; todo = -2; break; case JSOP_FINALLY: jp->indent -= 4; js_printf(CLEAR_MAYBE_BRACE(jp), "\t} finally {\n"); jp->indent += 4; /* * We must push an empty string placeholder for gosub's return * address, popped by JSOP_RETSUB and counted by script->depth * but not by ss->top (see JSOP_SETSP, below). */ todo = Sprint(&ss->sprinter, exception_cookie); if (todo < 0 || !PushOff(ss, todo, op)) return NULL; todo = Sprint(&ss->sprinter, retsub_pc_cookie); break; case JSOP_RETSUB: rval = POP_STR(); LOCAL_ASSERT(strcmp(rval, retsub_pc_cookie) == 0); lval = POP_STR(); LOCAL_ASSERT(strcmp(lval, exception_cookie) == 0); todo = -2; break; case JSOP_SWAP: /* * We don't generate this opcode currently, and previously we * did not need to decompile it. If old, serialized bytecode * uses it still, we should fall through and set todo = -2. */ /* FALL THROUGH */ case JSOP_GOSUB: case JSOP_GOSUBX: /* * JSOP_GOSUB and GOSUBX have no effect on the decompiler's * string stack because the next op in bytecode order finds * the stack balanced by a JSOP_RETSUB executed elsewhere. */ todo = -2; break; case JSOP_SETSP:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -