📄 jsopcode.c
字号:
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- * vim: set sw=4 ts=8 et tw=78: * * ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is Mozilla Communicator client code, released * March 31, 1998. * * The Initial Developer of the Original Code is * Netscape Communications Corporation. * Portions created by the Initial Developer are Copyright (C) 1998 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * Alternatively, the contents of this file may be used under the terms of * either of the GNU General Public License Version 2 or later (the "GPL"), * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** *//* * JS bytecode descriptors, disassemblers, and decompilers. */#include "jsstddef.h"#ifdef HAVE_MEMORY_H#include <memory.h>#endif#include <stdarg.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include "jstypes.h"#include "jsarena.h" /* Added by JSIFY */#include "jsutil.h" /* Added by JSIFY */#include "jsdtoa.h"#include "jsprf.h"#include "jsapi.h"#include "jsarray.h"#include "jsatom.h"#include "jscntxt.h"#include "jsconfig.h"#include "jsdbgapi.h"#include "jsemit.h"#include "jsfun.h"#include "jslock.h"#include "jsobj.h"#include "jsopcode.h"#include "jsregexp.h"#include "jsscan.h"#include "jsscope.h"#include "jsscript.h"#include "jsstr.h"#if JS_HAS_DESTRUCTURING# include "jsnum.h"#endifstatic const char js_incop_strs[][3] = {"++", "--"};/* Pollute the namespace locally for MSVC Win16, but not for WatCom. */#ifdef __WINDOWS_386__ #ifdef FAR #undef FAR #endif#else /* !__WINDOWS_386__ */#ifndef FAR#define FAR#endif#endif /* !__WINDOWS_386__ */const JSCodeSpec FAR js_CodeSpec[] = {#define OPDEF(op,val,name,token,length,nuses,ndefs,prec,format) \ {name,token,length,nuses,ndefs,prec,format},#include "jsopcode.tbl"#undef OPDEF};uintN js_NumCodeSpecs = sizeof (js_CodeSpec) / sizeof js_CodeSpec[0];/************************************************************************/static ptrdiff_tGetJumpOffset(jsbytecode *pc, jsbytecode *pc2){ uint32 type; type = (js_CodeSpec[*pc].format & JOF_TYPEMASK); if (JOF_TYPE_IS_EXTENDED_JUMP(type)) return GET_JUMPX_OFFSET(pc2); return GET_JUMP_OFFSET(pc2);}#ifdef DEBUGJS_FRIEND_API(JSBool)js_Disassemble(JSContext *cx, JSScript *script, JSBool lines, FILE *fp){ jsbytecode *pc, *end; uintN len; pc = script->code; end = pc + script->length; while (pc < end) { if (pc == script->main) fputs("main:\n", fp); len = js_Disassemble1(cx, script, pc, PTRDIFF(pc, script->code, jsbytecode), lines, fp); if (!len) return JS_FALSE; pc += len; } return JS_TRUE;}const char *ToDisassemblySource(JSContext *cx, jsval v){ JSObject *obj; JSScopeProperty *sprop; char *source; const char *bytes; JSString *str; if (!JSVAL_IS_PRIMITIVE(v)) { obj = JSVAL_TO_OBJECT(v); if (OBJ_GET_CLASS(cx, obj) == &js_BlockClass) { source = JS_sprintf_append(NULL, "depth %d {", OBJ_BLOCK_DEPTH(cx, obj)); for (sprop = OBJ_SCOPE(obj)->lastProp; sprop; sprop = sprop->parent) { bytes = js_AtomToPrintableString(cx, JSID_TO_ATOM(sprop->id)); if (!bytes) return NULL; source = JS_sprintf_append(source, "%s: %d%s", bytes, sprop->shortid, sprop->parent ? ", " : ""); } source = JS_sprintf_append(source, "}"); if (!source) return NULL; str = JS_NewString(cx, source, strlen(source)); if (!str) return NULL; return JS_GetStringBytes(str); } } return js_ValueToPrintableSource(cx, v);}JS_FRIEND_API(uintN)js_Disassemble1(JSContext *cx, JSScript *script, jsbytecode *pc, uintN loc, JSBool lines, FILE *fp){ JSOp op; const JSCodeSpec *cs; ptrdiff_t len, off, jmplen; uint32 type; JSAtom *atom; const char *bytes; op = (JSOp)*pc; if (op >= JSOP_LIMIT) { char numBuf1[12], numBuf2[12]; JS_snprintf(numBuf1, sizeof numBuf1, "%d", op); JS_snprintf(numBuf2, sizeof numBuf2, "%d", JSOP_LIMIT); JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BYTECODE_TOO_BIG, numBuf1, numBuf2); return 0; } cs = &js_CodeSpec[op]; len = (ptrdiff_t) cs->length; fprintf(fp, "%05u:", loc); if (lines) fprintf(fp, "%4u", JS_PCToLineNumber(cx, script, pc)); fprintf(fp, " %s", cs->name); type = cs->format & JOF_TYPEMASK; switch (type) { case JOF_BYTE: if (op == JSOP_TRAP) { op = JS_GetTrapOpcode(cx, script, pc); if (op == JSOP_LIMIT) return 0; len = (ptrdiff_t) js_CodeSpec[op].length; } break; case JOF_JUMP: case JOF_JUMPX: off = GetJumpOffset(pc, pc); fprintf(fp, " %u (%d)", loc + off, off); break; case JOF_CONST: atom = GET_ATOM(cx, script, pc); bytes = ToDisassemblySource(cx, ATOM_KEY(atom)); if (!bytes) return 0; fprintf(fp, " %s", bytes); break; case JOF_UINT16: case JOF_LOCAL: fprintf(fp, " %u", GET_UINT16(pc)); break; case JOF_TABLESWITCH: case JOF_TABLESWITCHX: { jsbytecode *pc2; jsint i, low, high; jmplen = (type == JOF_TABLESWITCH) ? JUMP_OFFSET_LEN : JUMPX_OFFSET_LEN; pc2 = pc; off = GetJumpOffset(pc, pc2); pc2 += jmplen; low = GET_JUMP_OFFSET(pc2); pc2 += JUMP_OFFSET_LEN; high = GET_JUMP_OFFSET(pc2); pc2 += JUMP_OFFSET_LEN; fprintf(fp, " defaultOffset %d low %d high %d", off, low, high); for (i = low; i <= high; i++) { off = GetJumpOffset(pc, pc2); fprintf(fp, "\n\t%d: %d", i, off); pc2 += jmplen; } len = 1 + pc2 - pc; break; } case JOF_LOOKUPSWITCH: case JOF_LOOKUPSWITCHX: { jsbytecode *pc2; jsatomid npairs; jmplen = (type == JOF_LOOKUPSWITCH) ? JUMP_OFFSET_LEN : JUMPX_OFFSET_LEN; pc2 = pc; off = GetJumpOffset(pc, pc2); pc2 += jmplen; npairs = GET_ATOM_INDEX(pc2); pc2 += ATOM_INDEX_LEN; fprintf(fp, " offset %d npairs %u", off, (uintN) npairs); while (npairs) { atom = GET_ATOM(cx, script, pc2); pc2 += ATOM_INDEX_LEN; off = GetJumpOffset(pc, pc2); pc2 += jmplen; bytes = ToDisassemblySource(cx, ATOM_KEY(atom)); if (!bytes) return 0; fprintf(fp, "\n\t%s: %d", bytes, off); npairs--; } len = 1 + pc2 - pc; break; } case JOF_QARG: fprintf(fp, " %u", GET_ARGNO(pc)); break; case JOF_QVAR: fprintf(fp, " %u", GET_VARNO(pc)); break; case JOF_INDEXCONST: fprintf(fp, " %u", GET_VARNO(pc)); pc += VARNO_LEN; atom = GET_ATOM(cx, script, pc); bytes = ToDisassemblySource(cx, ATOM_KEY(atom)); if (!bytes) return 0; fprintf(fp, " %s", bytes); break; case JOF_UINT24: if (op == JSOP_FINDNAME) { /* Special case to avoid a JOF_FINDNAME just for this op. */ atom = js_GetAtom(cx, &script->atomMap, GET_UINT24(pc)); bytes = ToDisassemblySource(cx, ATOM_KEY(atom)); if (!bytes) return 0; fprintf(fp, " %s", bytes); break; } JS_ASSERT(op == JSOP_UINT24 || op == JSOP_LITERAL); fprintf(fp, " %u", GET_UINT24(pc)); break; case JOF_LITOPX: atom = js_GetAtom(cx, &script->atomMap, GET_LITERAL_INDEX(pc)); bytes = ToDisassemblySource(cx, ATOM_KEY(atom)); if (!bytes) return 0; /* * Bytecode: JSOP_LITOPX <uint24> op [<varno> if JSOP_DEFLOCALFUN]. * Advance pc to point at op. */ pc += 1 + LITERAL_INDEX_LEN; op = *pc; cs = &js_CodeSpec[op]; fprintf(fp, " %s op %s", bytes, cs->name); if ((cs->format & JOF_TYPEMASK) == JOF_INDEXCONST) fprintf(fp, " %u", GET_VARNO(pc)); /* * Set len to advance pc to skip op and any other immediates (namely, * <varno> if JSOP_DEFLOCALFUN). */ JS_ASSERT(cs->length > ATOM_INDEX_LEN); len = cs->length - ATOM_INDEX_LEN; break; default: { char numBuf[12]; JS_snprintf(numBuf, sizeof numBuf, "%lx", (unsigned long) cs->format); JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_UNKNOWN_FORMAT, numBuf); return 0; } } fputs("\n", fp); return len;}#endif /* DEBUG *//************************************************************************//* * Sprintf, but with unlimited and automatically allocated buffering. */typedef struct Sprinter { JSContext *context; /* context executing the decompiler */ JSArenaPool *pool; /* string allocation pool */ char *base; /* base address of buffer in pool */ size_t size; /* size of buffer allocated at base */ ptrdiff_t offset; /* offset of next free char in buffer */} Sprinter;#define INIT_SPRINTER(cx, sp, ap, off) \ ((sp)->context = cx, (sp)->pool = ap, (sp)->base = NULL, (sp)->size = 0, \ (sp)->offset = off)#define OFF2STR(sp,off) ((sp)->base + (off))#define STR2OFF(sp,str) ((str) - (sp)->base)#define RETRACT(sp,str) ((sp)->offset = STR2OFF(sp, str))static JSBoolSprintAlloc(Sprinter *sp, size_t nb){ char *base; base = sp->base; if (!base) { JS_ARENA_ALLOCATE_CAST(base, char *, sp->pool, nb); } else { JS_ARENA_GROW_CAST(base, char *, sp->pool, sp->size, nb); } if (!base) { JS_ReportOutOfMemory(sp->context); return JS_FALSE; } sp->base = base; sp->size += nb; return JS_TRUE;}static ptrdiff_tSprintPut(Sprinter *sp, const char *s, size_t len){ ptrdiff_t nb, offset; char *bp; /* Allocate space for s, including the '\0' at the end. */ nb = (sp->offset + len + 1) - sp->size;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -