📄 jsopcode.c
字号:
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* ***** 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 "jsscope.h"
#include "jsscript.h"
#include "jsstr.h"
const char js_const_str[] = "const";
const char js_var_str[] = "var";
const char js_function_str[] = "function";
const char js_in_str[] = "in";
const char js_instanceof_str[] = "instanceof";
const char js_new_str[] = "new";
const char js_delete_str[] = "delete";
const char js_typeof_str[] = "typeof";
const char js_void_str[] = "void";
const char js_null_str[] = "null";
const char js_this_str[] = "this";
const char js_false_str[] = "false";
const char js_true_str[] = "true";
const char *js_incop_str[] = {"++", "--"};
/* 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_t
GetJumpOffset(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 DEBUG
JS_FRIEND_API(void)
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;
pc += len;
}
}
JS_FRIEND_API(uintN)
js_Disassemble1(JSContext *cx, JSScript *script, jsbytecode *pc, uintN loc,
JSBool lines, FILE *fp)
{
JSOp op;
const JSCodeSpec *cs;
intN len, off;
JSAtom *atom;
JSString *str;
char *cstr;
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 = (intN)cs->length;
fprintf(fp, "%05u:", loc);
if (lines)
fprintf(fp, "%4u", JS_PCToLineNumber(cx, script, pc));
fprintf(fp, " %s", cs->name);
switch (cs->format & JOF_TYPEMASK) {
case JOF_BYTE:
if (op == JSOP_TRAP) {
op = JS_GetTrapOpcode(cx, script, pc);
if (op == JSOP_LIMIT)
return 0;
len = (intN)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);
str = js_ValueToSource(cx, ATOM_KEY(atom));
if (!str)
return 0;
cstr = js_DeflateString(cx, JSSTRING_CHARS(str), JSSTRING_LENGTH(str));
if (!cstr)
return 0;
fprintf(fp, " %s", cstr);
JS_free(cx, cstr);
break;
case JOF_UINT16:
fprintf(fp, " %u", GET_ARGC(pc));
break;
#if JS_HAS_SWITCH_STATEMENT
case JOF_TABLESWITCH:
{
jsbytecode *pc2;
jsint i, low, high;
pc2 = pc;
off = GetJumpOffset(pc, pc2);
pc2 += JUMP_OFFSET_LEN;
low = GetJumpOffset(pc, pc2);
pc2 += JUMP_OFFSET_LEN;
high = GetJumpOffset(pc, 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 += JUMP_OFFSET_LEN;
}
len = 1 + pc2 - pc;
break;
}
case JOF_LOOKUPSWITCH:
{
jsbytecode *pc2;
jsint npairs;
pc2 = pc;
off = GetJumpOffset(pc, pc2);
pc2 += JUMP_OFFSET_LEN;
npairs = (jsint) 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 += JUMP_OFFSET_LEN;
str = js_ValueToSource(cx, ATOM_KEY(atom));
if (!str)
return 0;
cstr = js_DeflateString(cx, JSSTRING_CHARS(str),
JSSTRING_LENGTH(str));
if (!cstr)
return 0;
fprintf(fp, "\n\t%s: %d", cstr, off);
JS_free(cx, cstr);
npairs--;
}
len = 1 + pc2 - pc;
break;
}
#endif /* JS_HAS_SWITCH_STATEMENT */
case JOF_QARG:
fprintf(fp, " %u", GET_ARGNO(pc));
break;
case JOF_QVAR:
fprintf(fp, " %u", GET_VARNO(pc));
break;
#if JS_HAS_LEXICAL_CLOSURE
case JOF_DEFLOCALVAR:
fprintf(fp, " %u", GET_VARNO(pc));
pc += VARNO_LEN;
atom = GET_ATOM(cx, script, pc);
str = js_ValueToSource(cx, ATOM_KEY(atom));
if (!str)
return 0;
cstr = js_DeflateString(cx, JSSTRING_CHARS(str), JSSTRING_LENGTH(str));
if (!cstr)
return 0;
fprintf(fp, " %s", cstr);
JS_free(cx, cstr);
break;
#endif
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 JSBool
SprintAlloc(Sprinter *sp, size_t nb)
{
if (!sp->base) {
JS_ARENA_ALLOCATE_CAST(sp->base, char *, sp->pool, nb);
} else {
JS_ARENA_GROW_CAST(sp->base, char *, sp->pool, sp->size, nb);
}
if (!sp->base) {
JS_ReportOutOfMemory(sp->context);
return JS_FALSE;
}
sp->size += nb;
return JS_TRUE;
}
static ptrdiff_t
SprintPut(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;
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_t
Sprint(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 = SprintPut(sp, bp, strlen(bp));
free(bp);
return offset;
}
const jschar js_EscapeMap[] = {
'\b', 'b',
'\f', 'f',
'\n', 'n',
'\r', 'r',
'\t', 't',
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -