Igor's patch for bug 433382, r=me.

This commit is contained in:
Brendan Eich 2008-05-23 23:44:08 -07:00
Родитель f70689f2fd
Коммит 58024bbded
13 изменённых файлов: 281 добавлений и 247 удалений

Просмотреть файл

@ -238,6 +238,9 @@ HOST_SIMPLE_PROGRAMS += host_jskwgen$(HOST_BIN_SUFFIX)
GARBAGE += jsautokw.h host_jskwgen$(HOST_BIN_SUFFIX) GARBAGE += jsautokw.h host_jskwgen$(HOST_BIN_SUFFIX)
USE_HOST_CXX = 1 USE_HOST_CXX = 1
HOST_SIMPLE_PROGRAMS += host_jsoplengen$(HOST_BIN_SUFFIX)
GARBAGE += jsautooplen.h host_jsoplengen$(HOST_BIN_SUFFIX)
ifdef HAVE_DTRACE ifdef HAVE_DTRACE
ifneq ($(OS_ARCH),Darwin) ifneq ($(OS_ARCH),Darwin)
DTRACE_PROBE_OBJ = $(LIBRARY_NAME)-dtrace.$(OBJ_SUFFIX) DTRACE_PROBE_OBJ = $(LIBRARY_NAME)-dtrace.$(OBJ_SUFFIX)
@ -439,14 +442,20 @@ jscpucfg$(HOST_BIN_SUFFIX): jscpucfg.cpp Makefile.in
endif endif
endif endif
# Extra dependancies and rules for keyword switch code # Extra dependancies and rules for auto-generated headers
jsscan.$(OBJ_SUFFIX): jsautokw.h jskeyword.tbl
host_jskwgen.$(OBJ_SUFFIX): jsconfig.h jskeyword.tbl host_jskwgen.$(OBJ_SUFFIX): jsconfig.h jskeyword.tbl
jsautokw.h: host_jskwgen$(HOST_BIN_SUFFIX) jsautokw.h: host_jskwgen$(HOST_BIN_SUFFIX)
./host_jskwgen$(HOST_BIN_SUFFIX) $@ ./host_jskwgen$(HOST_BIN_SUFFIX) $@
host_jsoplengen.$(OBJ_SUFFIX): jsopcode.tbl
jsautooplen.h: host_jsoplengen$(HOST_BIN_SUFFIX)
./host_jsoplengen$(HOST_BIN_SUFFIX) $@
# Force auto-header generation before compiling any source that may use them
$(CPPSRCS:%.cpp=%.$(OBJ_SUFFIX)): jsautokw.h jsautooplen.h
ifdef HAVE_DTRACE ifdef HAVE_DTRACE
javascript-trace.h: $(srcdir)/javascript-trace.d javascript-trace.h: $(srcdir)/javascript-trace.d
dtrace -h -s $(srcdir)/javascript-trace.d -o javascript-trace.h.in dtrace -h -s $(srcdir)/javascript-trace.d -o javascript-trace.h.in

Просмотреть файл

@ -276,39 +276,39 @@ nsinstall-target:
cd ../../config; $(MAKE) OBJDIR=$(OBJDIR) OBJDIR_NAME=$(OBJDIR) cd ../../config; $(MAKE) OBJDIR=$(OBJDIR) OBJDIR_NAME=$(OBJDIR)
# #
# Rules for keyword switch generation # Automatic header generation
# #
GARBAGE += $(OBJDIR)/jsautokw.h $(OBJDIR)/jskwgen$(HOST_BIN_SUFFIX) AUTO_HEADERS = $(OBJDIR)/jsautokw.h $(OBJDIR)/jsautooplen.h
GARBAGE += $(OBJDIR)/jskwgen.$(OBJ_SUFFIX)
$(OBJDIR)/jsscan.$(OBJ_SUFFIX): $(OBJDIR)/jsautokw.h jskeyword.tbl $(OBJDIR)/jsautokw.h: jskeyword.tbl
$(OBJDIR)/jskwgen.$(OBJ_SUFFIX): jskwgen.cpp jskeyword.tbl $(OBJDIR)/jsautooplen.h: jsopcode.tbl
$(OBJDIR)/jsautokw.h: $(OBJDIR)/jskwgen$(HOST_BIN_SUFFIX) jskeyword.tbl GARBAGE += $(AUTO_HEADERS)
$(OBJDIR)/jskwgen$(HOST_BIN_SUFFIX) $@ GARBAGE += $(AUTO_HEADERS:$(OBJDIR)/jsauto%.h=$(OBJDIR)/js%gen$(HOST_BIN_SUFFIX))
ifdef USE_MSVC ifdef USE_MSVC
$(OBJDIR)/jskwgen.obj: jskwgen.cpp jskeyword.tbl GARBAGE += $(AUTO_HEADERS:$(OBJDIR)/jsauto%.h=$(OBJDIR)/js%gen.obj)
$(AUTO_HEADERS): $(OBJDIR)/jsauto%.h: js%gen.cpp
@$(MAKE_OBJDIR) @$(MAKE_OBJDIR)
$(CXX) -Fo$(OBJDIR)/ -c $(CFLAGS) $< $(CXX) -Fo$(OBJDIR)/ -c $(CFLAGS) $<
link.exe -out:"$(OBJDIR)/js$*gen$(HOST_BIN_SUFFIX)" $(EXE_LINK_FLAGS) $(OBJDIR)/js$*gen.obj
$(OBJDIR)/jskwgen$(HOST_BIN_SUFFIX): $(OBJDIR)/jskwgen.$(OBJ_SUFFIX) $(OBJDIR)/js$*gen$(HOST_BIN_SUFFIX) $@
link.exe -out:"$@" $(EXE_LINK_FLAGS) $^
else else
$(OBJDIR)/jskwgen.o: jskwgen.cpp jskeyword.tbl $(AUTO_HEADERS): $(OBJDIR)/jsauto%.h: js%gen.cpp
@$(MAKE_OBJDIR) @$(MAKE_OBJDIR)
$(CXX) -o $@ -c $(CFLAGS) $< $(CXX) -o $(OBJDIR)/js$*gen$(HOST_BIN_SUFFIX) $(CFLAGS) $(LDFLAGS) $<
$(OBJDIR)/js$*gen$(HOST_BIN_SUFFIX) $@
$(OBJDIR)/jskwgen$(HOST_BIN_SUFFIX): $(OBJDIR)/jskwgen.$(OBJ_SUFFIX)
$(CXX) -o $@ $(CFLAGS) $(LDFLAGS) $^
endif endif
# force creation of autoheaders before compiling any source that may use them
$(LIB_OBJS) : $(AUTO_HEADERS)
# #
# JS shell executable # JS shell executable
# #

Просмотреть файл

@ -62,6 +62,8 @@
#include "jsscript.h" #include "jsscript.h"
#include "jsstr.h" #include "jsstr.h"
#include "jsautooplen.h"
typedef struct JSTrap { typedef struct JSTrap {
JSCList links; JSCList links;
JSScript *script; JSScript *script;

Просмотреть файл

@ -66,6 +66,8 @@
#include "jsscope.h" #include "jsscope.h"
#include "jsscript.h" #include "jsscript.h"
#include "jsautooplen.h"
/* Allocation chunk counts, must be powers of two in general. */ /* Allocation chunk counts, must be powers of two in general. */
#define BYTECODE_CHUNK 256 /* code allocation increment */ #define BYTECODE_CHUNK 256 /* code allocation increment */
#define SRCNOTE_CHUNK 64 /* initial srcnote allocation increment */ #define SRCNOTE_CHUNK 64 /* initial srcnote allocation increment */

Просмотреть файл

@ -77,6 +77,8 @@
#include "jsxml.h" #include "jsxml.h"
#endif #endif
#include "jsautooplen.h"
#ifdef js_invoke_c__ #ifdef js_invoke_c__
uint32 uint32
@ -2073,6 +2075,77 @@ js_DoIncDec(JSContext *cx, const JSCodeSpec *cs, jsval *vp, jsval *vp2)
return JS_TRUE; return JS_TRUE;
} }
#ifdef DEBUG
void
js_TraceOpcode(JSContext *cx, jsint len)
{
FILE *tracefp;
JSStackFrame *fp;
JSFrameRegs *regs;
JSOp prevop;
intN ndefs, n, nuses;
jsval *siter;
JSString *str;
JSOp op;
tracefp = (FILE *) cx->tracefp;
JS_ASSERT(tracefp);
fp = cx->fp;
regs = fp->regs;
if (len != 0) {
prevop = (JSOp) regs->pc[-len];
ndefs = js_CodeSpec[prevop].ndefs;
if (ndefs != 0) {
if (prevop == JSOP_FORELEM && regs->sp[-1] == JSVAL_FALSE)
--ndefs;
for (n = -ndefs; n < 0; n++) {
char *bytes = js_DecompileValueGenerator(cx, n, regs->sp[n],
NULL);
if (bytes) {
fprintf(tracefp, "%s %s",
(n == -ndefs) ? " output:" : ",",
bytes);
JS_free(cx, bytes);
}
}
fprintf(tracefp, " @ %d\n", regs->sp - fp->spbase);
}
fprintf(tracefp, " stack: ");
for (siter = fp->spbase; siter < regs->sp; siter++) {
str = js_ValueToString(cx, *siter);
if (!str)
fputs("<null>", tracefp);
else
js_FileEscapedString(tracefp, str, 0);
fputc(' ', tracefp);
}
fputc('\n', tracefp);
}
fprintf(tracefp, "%4u: ", js_PCToLineNumber(cx, fp->script, regs->pc));
js_Disassemble1(cx, fp->script, regs->pc,
PTRDIFF(regs->pc, fp->script->code, jsbytecode),
JS_FALSE, tracefp);
op = (JSOp) *regs->pc;
nuses = js_CodeSpec[op].nuses;
if (nuses != 0) {
for (n = -nuses; n < 0; n++) {
char *bytes = js_DecompileValueGenerator(cx, n, regs->sp[n],
NULL);
if (bytes) {
fprintf(tracefp, "%s %s",
(n == -nuses) ? " inputs:" : ",",
bytes);
JS_free(cx, bytes);
}
}
fprintf(tracefp, " @ %d\n", regs->sp - fp->spbase);
}
}
#endif /* DEBUG */
#ifdef JS_OPMETER #ifdef JS_OPMETER
# include <stdlib.h> # include <stdlib.h>
@ -2421,6 +2494,13 @@ JS_STATIC_ASSERT(!CAN_DO_FAST_INC_DEC(INT_TO_JSVAL(JSVAL_INT_MAX)));
# endif # endif
#endif #endif
/*
* Interpreter assumes the following to implement condition-free interrupt
* implementation when !JS_THREADED_INTERP.
*/
JS_STATIC_ASSERT(JSOP_INTERRUPT == 0);
/* /*
* Ensure that the intrepreter switch can close call-bytecode cases in the * Ensure that the intrepreter switch can close call-bytecode cases in the
* same way as non-call bytecodes. * same way as non-call bytecodes.
@ -2454,7 +2534,6 @@ js_Interpret(JSContext *cx)
JSFrameRegs regs; JSFrameRegs regs;
JSObject *obj, *obj2, *parent; JSObject *obj, *obj2, *parent;
JSBool ok, cond; JSBool ok, cond;
JSTrapHandler interruptHandler;
jsint len; jsint len;
jsbytecode *endpc, *pc2; jsbytecode *endpc, *pc2;
JSOp op, op2; JSOp op, op2;
@ -2473,8 +2552,11 @@ js_Interpret(JSContext *cx)
JSClass *clasp; JSClass *clasp;
JSFunction *fun; JSFunction *fun;
JSType type; JSType type;
#if !JS_THREADED_INTERP && defined DEBUG #if JS_THREADED_INTERP
FILE *tracefp = NULL; register const void * const *jumpTable;
#else
register uint32 switchMask;
uintN switchOp;
#endif #endif
#if JS_HAS_EXPORT_IMPORT #if JS_HAS_EXPORT_IMPORT
JSIdArray *ida; JSIdArray *ida;
@ -2494,42 +2576,68 @@ js_Interpret(JSContext *cx)
#endif #endif
#if JS_THREADED_INTERP #if JS_THREADED_INTERP
static void *normalJumpTable[] = { static const void *const normalJumpTable[] = {
# define OPDEF(op,val,name,token,length,nuses,ndefs,prec,format) \ # define OPDEF(op,val,name,token,length,nuses,ndefs,prec,format) \
JS_EXTENSION &&L_##op, JS_EXTENSION &&L_##op,
# include "jsopcode.tbl" # include "jsopcode.tbl"
# undef OPDEF # undef OPDEF
}; };
static void *interruptJumpTable[] = { static const void *const interruptJumpTable[] = {
# define OPDEF(op,val,name,token,length,nuses,ndefs,prec,format) \ # define OPDEF(op,val,name,token,length,nuses,ndefs,prec,format) \
JS_EXTENSION &&interrupt, JS_EXTENSION &&L_JSOP_INTERRUPT,
# include "jsopcode.tbl" # include "jsopcode.tbl"
# undef OPDEF # undef OPDEF
}; };
register void **jumpTable = normalJumpTable;
METER_OP_INIT(op); /* to nullify first METER_OP_PAIR */ METER_OP_INIT(op); /* to nullify first METER_OP_PAIR */
# define DO_OP() JS_EXTENSION_(goto *jumpTable[op]) # define DO_OP() JS_EXTENSION_(goto *jumpTable[op])
# define DO_NEXT_OP(n) do { METER_OP_PAIR(op, regs.pc[n]); \ # define DO_NEXT_OP(n) JS_BEGIN_MACRO \
METER_OP_PAIR(op, regs.pc[n]); \
op = (JSOp) *(regs.pc += (n)); \ op = (JSOp) *(regs.pc += (n)); \
DO_OP(); } while (0) DO_OP(); \
JS_END_MACRO
# define BEGIN_CASE(OP) L_##OP: # define BEGIN_CASE(OP) L_##OP:
# define END_CASE(OP) DO_NEXT_OP(OP##_LENGTH); # define END_CASE(OP) DO_NEXT_OP(OP##_LENGTH);
# define END_VARLEN_CASE DO_NEXT_OP(len); # define END_VARLEN_CASE DO_NEXT_OP(len);
# define EMPTY_CASE(OP) BEGIN_CASE(OP) op = (JSOp) *++regs.pc; DO_OP(); # define ADD_EMPTY_CASE(OP) BEGIN_CASE(OP) \
#else JS_ASSERT(js_CodeSpec[OP].length == 1); \
op = (JSOp) *++regs.pc; \
DO_OP();
# define END_EMPTY_CASES
#else /* !JS_THREADED_INTERP */
# define DO_OP() goto do_op # define DO_OP() goto do_op
# define DO_NEXT_OP(n) goto advance_pc # define DO_NEXT_OP(n) JS_BEGIN_MACRO \
JS_ASSERT((n) == len); \
goto advance_pc; \
JS_END_MACRO
# define BEGIN_CASE(OP) case OP: # define BEGIN_CASE(OP) case OP:
# define END_CASE(OP) break; # define END_CASE(OP) END_CASE_LEN(OP##_LENGTH)
# define END_VARLEN_CASE break; # define END_CASE_LEN(n) END_CASE_LENX(n)
# define EMPTY_CASE(OP) BEGIN_CASE(OP) END_CASE(OP) # define END_CASE_LENX(n) END_CASE_LEN##n
/*
* To share the code for all len == 1 cases we use the specialized label with
* code that falls through to advance_pc: .
*/
# define END_CASE_LEN1 goto advance_pc_by_one;
# define END_CASE_LEN2 len = 2; goto advance_pc;
# define END_CASE_LEN3 len = 3; goto advance_pc;
# define END_CASE_LEN4 len = 4; goto advance_pc;
# define END_CASE_LEN5 len = 5; goto advance_pc;
# define END_VARLEN_CASE goto advance_pc;
# define ADD_EMPTY_CASE(OP) BEGIN_CASE(OP)
# define END_EMPTY_CASES goto advance_pc_by_one;
#endif #endif
/* Check for too deep a C stack. */ /* Check for too deep of a native thread stack. */
JS_CHECK_RECURSION(cx, return JS_FALSE); JS_CHECK_RECURSION(cx, return JS_FALSE);
rt = cx->runtime; rt = cx->runtime;
@ -2608,18 +2716,15 @@ js_Interpret(JSContext *cx)
* the compiler can keep it in a register when it is non-null. * the compiler can keep it in a register when it is non-null.
*/ */
#if JS_THREADED_INTERP #if JS_THREADED_INTERP
# define LOAD_JUMP_TABLE() \ # define LOAD_INTERRUPT_HANDLER(cx) \
(jumpTable = interruptHandler ? interruptJumpTable : normalJumpTable) ((void) (jumpTable = (cx)->debugHooks->interruptHandler \
? interruptJumpTable \
: normalJumpTable))
#else #else
# define LOAD_JUMP_TABLE() ((void) 0) # define LOAD_INTERRUPT_HANDLER(cx) \
((void) (switchMask = (cx)->debugHooks->interruptHandler ? 0 : 255))
#endif #endif
#define LOAD_INTERRUPT_HANDLER(cx) \
JS_BEGIN_MACRO \
interruptHandler = (cx)->debugHooks->interruptHandler; \
LOAD_JUMP_TABLE(); \
JS_END_MACRO
LOAD_INTERRUPT_HANDLER(cx); LOAD_INTERRUPT_HANDLER(cx);
/* /*
@ -2667,107 +2772,89 @@ js_Interpret(JSContext *cx)
} }
} }
#if JS_THREADED_INTERP /*
* It is important that "op" be initialized before calling DO_OP because
* it is possible for "op" to be specially assigned during the normal
* processing of an opcode while looping. We rely on DO_NEXT_OP to manage
* "op" correctly in all other cases.
*/
len = 0;
DO_NEXT_OP(len);
#if JS_THREADED_INTERP
/* /*
* This is a loop, but it does not look like a loop. The loop-closing * This is a loop, but it does not look like a loop. The loop-closing
* jump is distributed throughout interruptJumpTable, and comes back to * jump is distributed throughout goto *jumpTable[op] inside of DO_OP.
* the interrupt label. The dispatch on op is through normalJumpTable. * When interrupts are enabled, jumpTable is set to interruptJumpTable
* The trick is LOAD_INTERRUPT_HANDLER setting jumpTable appropriately. * where all jumps point to the JSOP_INTERRUPT case. The latter, after
* * calling the interrupt handler, dispatches through normalJumpTable to
* It is important that "op" be initialized before the interrupt label * continue the normal bytecode processing.
* because it is possible for "op" to be specially assigned during the
* normally processing of an opcode while looping (in particular, this
* happens in JSOP_TRAP while debugging). We rely on DO_NEXT_OP to
* correctly manage "op" in all other cases.
*/ */
op = (JSOp) *regs.pc; #else
if (interruptHandler) {
interrupt:
switch (interruptHandler(cx, script, regs.pc, &rval,
cx->debugHooks->interruptHandlerData)) {
case JSTRAP_ERROR:
goto error;
case JSTRAP_CONTINUE:
break;
case JSTRAP_RETURN:
fp->rval = rval;
ok = JS_TRUE;
goto forced_return;
case JSTRAP_THROW:
cx->throwing = JS_TRUE;
cx->exception = rval;
goto error;
default:;
}
LOAD_INTERRUPT_HANDLER(cx);
}
JS_ASSERT((uintN)op < (uintN)JSOP_LIMIT);
JS_EXTENSION_(goto *normalJumpTable[op]);
#else /* !JS_THREADED_INTERP */
for (;;) { for (;;) {
advance_pc_by_one:
JS_ASSERT(js_CodeSpec[op].length == 1);
len = 1;
advance_pc:
regs.pc += len;
op = (JSOp) *regs.pc; op = (JSOp) *regs.pc;
do_op:
len = js_CodeSpec[op].length;
#ifdef DEBUG #ifdef DEBUG
tracefp = (FILE *) cx->tracefp; if (cx->tracefp)
if (tracefp) { js_TraceOpcode(cx, len);
intN nuses, n; #endif
fprintf(tracefp, "%4u: ", js_PCToLineNumber(cx, script, regs.pc));
js_Disassemble1(cx, script, regs.pc,
PTRDIFF(regs.pc, script->code, jsbytecode),
JS_FALSE, tracefp);
nuses = js_CodeSpec[op].nuses;
if (nuses) {
for (n = -nuses; n < 0; n++) {
char *bytes = js_DecompileValueGenerator(cx, n, regs.sp[n],
NULL);
if (bytes) {
fprintf(tracefp, "%s %s",
(n == -nuses) ? " inputs:" : ",",
bytes);
JS_free(cx, bytes);
}
}
fprintf(tracefp, " @ %d\n", regs.sp - fp->spbase);
}
}
#endif /* DEBUG */
if (interruptHandler) {
switch (interruptHandler(cx, script, regs.pc, &rval,
cx->debugHooks->interruptHandlerData)) {
case JSTRAP_ERROR:
goto error;
case JSTRAP_CONTINUE:
break;
case JSTRAP_RETURN:
fp->rval = rval;
ok = JS_TRUE;
goto forced_return;
case JSTRAP_THROW:
cx->throwing = JS_TRUE;
cx->exception = rval;
goto error;
default:;
}
LOAD_INTERRUPT_HANDLER(cx);
}
switch (op) {
do_op:
switchOp = op & switchMask;
do_switch:
switch (switchOp) {
#endif /* !JS_THREADED_INTERP */ #endif /* !JS_THREADED_INTERP */
EMPTY_CASE(JSOP_NOP) BEGIN_CASE(JSOP_INTERRUPT)
{
JSTrapHandler handler;
EMPTY_CASE(JSOP_GROUP) handler = cx->debugHooks->interruptHandler;
if (handler) {
switch (handler(cx, script, regs.pc, &rval,
cx->debugHooks->interruptHandlerData)) {
case JSTRAP_ERROR:
goto error;
case JSTRAP_CONTINUE:
break;
case JSTRAP_RETURN:
fp->rval = rval;
ok = JS_TRUE;
goto forced_return;
case JSTRAP_THROW:
cx->throwing = JS_TRUE;
cx->exception = rval;
goto error;
default:;
}
}
LOAD_INTERRUPT_HANDLER(cx);
/* EMPTY_CASE is not used here as JSOP_LINENO_LENGTH == 3. */ #if JS_THREADED_INTERP
JS_EXTENSION_(goto *normalJumpTable[op]);
#else
switchOp = op;
goto do_switch;
#endif
}
/* No-ops for ease of decompilation. */
ADD_EMPTY_CASE(JSOP_NOP)
ADD_EMPTY_CASE(JSOP_GROUP)
ADD_EMPTY_CASE(JSOP_CONDSWITCH)
ADD_EMPTY_CASE(JSOP_TRY)
ADD_EMPTY_CASE(JSOP_FINALLY)
#if JS_HAS_XML_SUPPORT
ADD_EMPTY_CASE(JSOP_STARTXML)
ADD_EMPTY_CASE(JSOP_STARTXMLEXPR)
#endif
END_EMPTY_CASES
/* ADD_EMPTY_CASE is not used here as JSOP_LINENO_LENGTH == 3. */
BEGIN_CASE(JSOP_LINENO) BEGIN_CASE(JSOP_LINENO)
END_CASE(JSOP_LINENO) END_CASE(JSOP_LINENO)
@ -2802,12 +2889,6 @@ interrupt:
#endif #endif
END_CASE(JSOP_POPN) END_CASE(JSOP_POPN)
BEGIN_CASE(JSOP_SWAP)
rtmp = regs.sp[-1];
regs.sp[-1] = regs.sp[-2];
regs.sp[-2] = rtmp;
END_CASE(JSOP_SWAP)
BEGIN_CASE(JSOP_SETRVAL) BEGIN_CASE(JSOP_SETRVAL)
BEGIN_CASE(JSOP_POPV) BEGIN_CASE(JSOP_POPV)
ASSERT_NOT_THROWING(cx); ASSERT_NOT_THROWING(cx);
@ -4076,7 +4157,6 @@ interrupt:
i = 0; i = 0;
COMPUTE_THIS(cx, fp, obj); COMPUTE_THIS(cx, fp, obj);
PUSH_STACK(JSVAL_NULL); PUSH_STACK(JSVAL_NULL);
len = JSOP_GETTHISPROP_LENGTH;
goto do_getprop_with_obj; goto do_getprop_with_obj;
#undef COMPUTE_THIS #undef COMPUTE_THIS
@ -4086,7 +4166,6 @@ interrupt:
slot = GET_ARGNO(regs.pc); slot = GET_ARGNO(regs.pc);
JS_ASSERT(slot < fp->fun->nargs); JS_ASSERT(slot < fp->fun->nargs);
PUSH_STACK(fp->argv[slot]); PUSH_STACK(fp->argv[slot]);
len = JSOP_GETARGPROP_LENGTH;
goto do_getprop_body; goto do_getprop_body;
BEGIN_CASE(JSOP_GETVARPROP) BEGIN_CASE(JSOP_GETVARPROP)
@ -4094,7 +4173,6 @@ interrupt:
slot = GET_VARNO(regs.pc); slot = GET_VARNO(regs.pc);
JS_ASSERT(slot < fp->fun->u.i.nvars); JS_ASSERT(slot < fp->fun->u.i.nvars);
PUSH_STACK(fp->vars[slot]); PUSH_STACK(fp->vars[slot]);
len = JSOP_GETVARPROP_LENGTH;
goto do_getprop_body; goto do_getprop_body;
BEGIN_CASE(JSOP_GETLOCALPROP) BEGIN_CASE(JSOP_GETLOCALPROP)
@ -4102,13 +4180,11 @@ interrupt:
slot = GET_UINT16(regs.pc); slot = GET_UINT16(regs.pc);
JS_ASSERT(slot < script->depth); JS_ASSERT(slot < script->depth);
PUSH_STACK(fp->spbase[slot]); PUSH_STACK(fp->spbase[slot]);
len = JSOP_GETLOCALPROP_LENGTH;
goto do_getprop_body; goto do_getprop_body;
BEGIN_CASE(JSOP_GETPROP) BEGIN_CASE(JSOP_GETPROP)
BEGIN_CASE(JSOP_GETXPROP) BEGIN_CASE(JSOP_GETXPROP)
i = 0; i = 0;
len = JSOP_GETPROP_LENGTH;
do_getprop_body: do_getprop_body:
FETCH_STACK(-1, lval); FETCH_STACK(-1, lval);
@ -4178,8 +4254,9 @@ interrupt:
goto error; goto error;
} }
} else { } else {
i = -1; JS_ASSERT(JSOP_GETPROP_LENGTH + i == js_CodeSpec[op].length);
len = JSOP_LENGTH_LENGTH; len = JSOP_GETPROP_LENGTH + i;
i = -2;
goto do_getprop_with_lval; goto do_getprop_with_lval;
} }
END_CASE(JSOP_LENGTH) END_CASE(JSOP_LENGTH)
@ -4938,12 +5015,12 @@ interrupt:
goto error; goto error;
if (!prop) { if (!prop) {
/* Kludge to allow (typeof foo == "undefined") tests. */ /* Kludge to allow (typeof foo == "undefined") tests. */
len = JSOP_NAME_LENGTH;
endpc = script->code + script->length; endpc = script->code + script->length;
for (pc2 = regs.pc + len; pc2 < endpc; pc2++) { for (pc2 = regs.pc + JSOP_NAME_LENGTH; pc2 < endpc; pc2++) {
op2 = (JSOp)*pc2; op2 = (JSOp)*pc2;
if (op2 == JSOP_TYPEOF) { if (op2 == JSOP_TYPEOF) {
PUSH_STACK(JSVAL_VOID); PUSH_STACK(JSVAL_VOID);
len = JSOP_NAME_LENGTH;
DO_NEXT_OP(len); DO_NEXT_OP(len);
} }
if (op2 != JSOP_GROUP) if (op2 != JSOP_GROUP)
@ -5280,8 +5357,6 @@ interrupt:
: GET_JUMPX_OFFSET(pc2); : GET_JUMPX_OFFSET(pc2);
END_VARLEN_CASE END_VARLEN_CASE
EMPTY_CASE(JSOP_CONDSWITCH)
#if JS_HAS_EXPORT_IMPORT #if JS_HAS_EXPORT_IMPORT
BEGIN_CASE(JSOP_EXPORTALL) BEGIN_CASE(JSOP_EXPORTALL)
obj = fp->varobj; obj = fp->varobj;
@ -5356,15 +5431,13 @@ interrupt:
#endif /* JS_HAS_EXPORT_IMPORT */ #endif /* JS_HAS_EXPORT_IMPORT */
BEGIN_CASE(JSOP_TRAP) BEGIN_CASE(JSOP_TRAP)
switch (JS_HandleTrap(cx, script, regs.pc, &rval)) { {
JSTrapStatus status;
status = JS_HandleTrap(cx, script, regs.pc, &rval);
switch (status) {
case JSTRAP_ERROR: case JSTRAP_ERROR:
goto error; goto error;
case JSTRAP_CONTINUE:
JS_ASSERT(JSVAL_IS_INT(rval));
op = (JSOp) JSVAL_TO_INT(rval);
JS_ASSERT((uintN)op < (uintN)JSOP_LIMIT);
LOAD_INTERRUPT_HANDLER(cx);
DO_OP();
case JSTRAP_RETURN: case JSTRAP_RETURN:
fp->rval = rval; fp->rval = rval;
ok = JS_TRUE; ok = JS_TRUE;
@ -5374,9 +5447,15 @@ interrupt:
cx->exception = rval; cx->exception = rval;
goto error; goto error;
default:; default:;
break;
} }
JS_ASSERT(status == JSTRAP_CONTINUE);
LOAD_INTERRUPT_HANDLER(cx); LOAD_INTERRUPT_HANDLER(cx);
END_CASE(JSOP_TRAP) JS_ASSERT(JSVAL_IS_INT(rval));
op = (JSOp) JSVAL_TO_INT(rval);
JS_ASSERT((uintN)op < (uintN)JSOP_LIMIT);
DO_OP();
}
BEGIN_CASE(JSOP_ARGUMENTS) BEGIN_CASE(JSOP_ARGUMENTS)
if (!js_GetArgsValue(cx, fp, &rval)) if (!js_GetArgsValue(cx, fp, &rval))
@ -6079,7 +6158,7 @@ interrupt:
if (!OBJ_SET_PROPERTY(cx, obj, id, &rval)) if (!OBJ_SET_PROPERTY(cx, obj, id, &rval))
goto error; goto error;
ADJUST_STACK(-2); ADJUST_STACK(-2);
END_CASE(JSOP_INITELEM); END_CASE(JSOP_INITELEM)
#if JS_HAS_SHARP_VARS #if JS_HAS_SHARP_VARS
BEGIN_CASE(JSOP_DEFSHARP) BEGIN_CASE(JSOP_DEFSHARP)
@ -6126,15 +6205,11 @@ interrupt:
END_CASE(JSOP_USESHARP) END_CASE(JSOP_USESHARP)
#endif /* JS_HAS_SHARP_VARS */ #endif /* JS_HAS_SHARP_VARS */
/* No-ops for ease of decompilation and jit'ing. */
EMPTY_CASE(JSOP_TRY)
EMPTY_CASE(JSOP_FINALLY)
BEGIN_CASE(JSOP_GOSUB) BEGIN_CASE(JSOP_GOSUB)
PUSH_STACK(JSVAL_FALSE); PUSH_STACK(JSVAL_FALSE);
i = PTRDIFF(regs.pc, script->main, jsbytecode) + JSOP_GOSUB_LENGTH; i = PTRDIFF(regs.pc, script->main, jsbytecode) + JSOP_GOSUB_LENGTH;
len = GET_JUMP_OFFSET(regs.pc);
PUSH_STACK(INT_TO_JSVAL(i)); PUSH_STACK(INT_TO_JSVAL(i));
len = GET_JUMP_OFFSET(regs.pc);
END_VARLEN_CASE END_VARLEN_CASE
BEGIN_CASE(JSOP_GOSUBX) BEGIN_CASE(JSOP_GOSUBX)
@ -6389,9 +6464,6 @@ interrupt:
ADJUST_STACK(-1); ADJUST_STACK(-1);
END_CASE(JSOP_ENDFILTER); END_CASE(JSOP_ENDFILTER);
EMPTY_CASE(JSOP_STARTXML)
EMPTY_CASE(JSOP_STARTXMLEXPR)
BEGIN_CASE(JSOP_TOXML) BEGIN_CASE(JSOP_TOXML)
FETCH_STACK(-1, rval); FETCH_STACK(-1, rval);
obj = js_ValueToXMLObject(cx, rval); obj = js_ValueToXMLObject(cx, rval);
@ -6691,48 +6763,6 @@ interrupt:
#if !JS_THREADED_INTERP #if !JS_THREADED_INTERP
} /* switch (op) */ } /* switch (op) */
advance_pc:
regs.pc += len;
#ifdef DEBUG
if (tracefp) {
intN ndefs, n;
jsval *siter;
/*
* op may be invalid here when a catch or finally handler jumps to
* advance_pc.
*/
op = (JSOp) regs.pc[-len];
ndefs = js_CodeSpec[op].ndefs;
if (ndefs) {
if (op == JSOP_FORELEM && regs.sp[-1] == JSVAL_FALSE)
--ndefs;
for (n = -ndefs; n < 0; n++) {
char *bytes = js_DecompileValueGenerator(cx, n, regs.sp[n],
NULL);
if (bytes) {
fprintf(tracefp, "%s %s",
(n == -ndefs) ? " output:" : ",",
bytes);
JS_free(cx, bytes);
}
}
fprintf(tracefp, " @ %d\n", regs.sp - fp->spbase);
}
fprintf(tracefp, " stack: ");
for (siter = fp->spbase; siter < regs.sp; siter++) {
str = js_ValueToString(cx, *siter);
if (!str)
fputs("<null>", tracefp);
else
js_FileEscapedString(tracefp, str, 0);
fputc(' ', tracefp);
}
fputc('\n', tracefp);
}
#endif /* DEBUG */
} }
#endif /* !JS_THREADED_INTERP */ #endif /* !JS_THREADED_INTERP */

Просмотреть файл

@ -507,6 +507,13 @@ js_OnUnknownMethod(JSContext *cx, jsval *vp);
extern JSBool extern JSBool
js_DoIncDec(JSContext *cx, const JSCodeSpec *cs, jsval *vp, jsval *vp2); js_DoIncDec(JSContext *cx, const JSCodeSpec *cs, jsval *vp, jsval *vp2);
/*
* Opcode tracing helper. When len is not 0, cx->fp->regs->pc[-len] gives the
* previous opcode.
*/
extern void
js_TraceOpcode(JSContext *cx, jsint len);
/* /*
* JS_OPMETER helper functions. * JS_OPMETER helper functions.
*/ */

Просмотреть файл

@ -88,6 +88,8 @@
#include "jsdtracef.h" #include "jsdtracef.h"
#endif #endif
#include "jsautooplen.h"
#ifdef JS_THREADSAFE #ifdef JS_THREADSAFE
#define NATIVE_DROP_PROPERTY js_DropProperty #define NATIVE_DROP_PROPERTY js_DropProperty

Просмотреть файл

@ -75,6 +75,14 @@
# include "jsnum.h" # include "jsnum.h"
#endif #endif
#include "jsautooplen.h"
/* Verify JSOP_XXX_LENGTH constant definitions. */
#define OPDEF(op,val,name,token,length,nuses,ndefs,prec,format) \
JS_STATIC_ASSERT(op##_LENGTH == length);
#include "jsopcode.tbl"
#undef OPDEF
static const char js_incop_strs[][3] = {"++", "--"}; static const char js_incop_strs[][3] = {"++", "--"};
const JSCodeSpec js_CodeSpec[] = { const JSCodeSpec js_CodeSpec[] = {
@ -2148,14 +2156,6 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
todo = -2; todo = -2;
break; 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_GOSUB:
case JSOP_GOSUBX: case JSOP_GOSUBX:
/* /*
@ -4936,8 +4936,7 @@ DecompileExpression(JSContext *cx, JSScript *script, JSFunction *fun,
/* None of these stack-writing ops generates novel values. */ /* None of these stack-writing ops generates novel values. */
JS_ASSERT(op != JSOP_CASE && op != JSOP_CASEX && JS_ASSERT(op != JSOP_CASE && op != JSOP_CASEX &&
op != JSOP_DUP && op != JSOP_DUP2 && op != JSOP_DUP && op != JSOP_DUP2);
op != JSOP_SWAP);
/* /*
* |this| could convert to a very long object initialiser, so cite it by * |this| could convert to a very long object initialiser, so cite it by
@ -5209,13 +5208,6 @@ ReconstructPCStack(JSContext *cx, JSScript *script, jsbytecode *pc,
pcstack[pcdepth + 3] = pcstack[pcdepth + 1]; pcstack[pcdepth + 3] = pcstack[pcdepth + 1];
break; break;
case JSOP_SWAP:
JS_ASSERT(ndefs == 2);
pc2 = pcstack[pcdepth];
pcstack[pcdepth] = pcstack[pcdepth + 1];
pcstack[pcdepth + 1] = pc2;
break;
case JSOP_LEAVEBLOCKEXPR: case JSOP_LEAVEBLOCKEXPR:
/* /*
* The decompiler wants to see [leaveblockexpr] on pcstack, not * The decompiler wants to see [leaveblockexpr] on pcstack, not

Просмотреть файл

@ -60,14 +60,6 @@ typedef enum JSOp {
JSOP_LIMIT JSOP_LIMIT
} JSOp; } JSOp;
typedef enum JSOpLength {
#define OPDEF(op,val,name,token,length,nuses,ndefs,prec,format) \
op##_LENGTH = length,
#include "jsopcode.tbl"
#undef OPDEF
JSOP_LIMIT_LENGTH
} JSOpLength;
/* /*
* JS bytecode formats. * JS bytecode formats.
*/ */

Просмотреть файл

@ -97,7 +97,7 @@
/* legend: op val name image len use def prec format */ /* legend: op val name image len use def prec format */
/* Longstanding JavaScript bytecodes. */ /* Longstanding JavaScript bytecodes. */
OPDEF(JSOP_NOP, 0, "nop", NULL, 1, 0, 0, 0, JOF_BYTE) OPDEF(JSOP_INTERRUPT, 0, "interrupt", NULL, 1, 0, 0, 0, JOF_BYTE)
OPDEF(JSOP_PUSH, 1, "push", NULL, 1, 0, 1, 0, JOF_BYTE) OPDEF(JSOP_PUSH, 1, "push", NULL, 1, 0, 1, 0, JOF_BYTE)
OPDEF(JSOP_POPV, 2, "popv", NULL, 1, 1, 0, 2, JOF_BYTE) OPDEF(JSOP_POPV, 2, "popv", NULL, 1, 1, 0, 2, JOF_BYTE)
OPDEF(JSOP_ENTERWITH, 3, "enterwith", NULL, 1, 1, 1, 0, JOF_BYTE|JOF_PARENHEAD) OPDEF(JSOP_ENTERWITH, 3, "enterwith", NULL, 1, 1, 1, 0, JOF_BYTE|JOF_PARENHEAD)
@ -331,9 +331,9 @@ OPDEF(JSOP_TRY, 133,"try", NULL, 1, 0, 0, 0, JOF_BYTE)
OPDEF(JSOP_FINALLY, 134,"finally", NULL, 1, 0, 0, 0, JOF_BYTE) OPDEF(JSOP_FINALLY, 134,"finally", NULL, 1, 0, 0, 0, JOF_BYTE)
/* /*
* Swap the top two stack elements. * Generic nop for the decompiler.
*/ */
OPDEF(JSOP_SWAP, 135,"swap", NULL, 1, 2, 2, 0, JOF_BYTE) OPDEF(JSOP_NOP, 135,"nop", NULL, 1, 0, 0, 0, JOF_BYTE)
/* /*
* Bytecodes that avoid making an arguments object in most cases: * Bytecodes that avoid making an arguments object in most cases:

Просмотреть файл

@ -202,7 +202,7 @@ JS_XDRFindClassById(JSXDRState *xdr, uint32 id);
* before deserialization of bytecode. If the saved version does not match * before deserialization of bytecode. If the saved version does not match
* the current version, abort deserialization and invalidate the file. * the current version, abort deserialization and invalidate the file.
*/ */
#define JSXDR_BYTECODE_VERSION (0xb973c0de - 24) #define JSXDR_BYTECODE_VERSION (0xb973c0de - 25)
/* /*
* Library-private functions. * Library-private functions.

Просмотреть файл

@ -192,8 +192,8 @@ AutoPushJSContext::AutoPushJSContext(nsISupports* aSecuritySupports,
mFrame.callee = JS_GetFunctionObject(fun); mFrame.callee = JS_GetFunctionObject(fun);
mFrame.scopeChain = JS_GetParent(cx, mFrame.callee); mFrame.scopeChain = JS_GetParent(cx, mFrame.callee);
mFrame.down = cx->fp; mFrame.down = cx->fp;
mRegs.pc = script->code + script->length mRegs.pc = script->code + script->length - 1;
- JSOP_STOP_LENGTH; JS_ASSERT(static_cast<JSOp>(*mRegs.pc) == JSOP_STOP);
mRegs.sp = NULL; mRegs.sp = NULL;
mFrame.regs = &mRegs; mFrame.regs = &mRegs;
cx->fp = &mFrame; cx->fp = &mFrame;

Просмотреть файл

@ -185,11 +185,9 @@ endif
clean: clean:
rm -rf $(OBJS) $(GARBAGE) rm -rf $(OBJS) $(GARBAGE)
@cd fdlibm; $(MAKE) -f Makefile.ref clean
clobber: clobber:
rm -rf $(OBJS) $(TARGETS) $(DEPENDENCIES) rm -rf $(OBJS) $(TARGETS) $(DEPENDENCIES)
@cd fdlibm; $(MAKE) -f Makefile.ref clobber
tar: tar:
tar cvf $(TARNAME) $(TARFILES) tar cvf $(TARNAME) $(TARFILES)