mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-30 00:01:50 +00:00
Propagating work and bug fixes from
development branch: - Preliminary exception handling per ECMA proposal; try, multiple catchblocks, and finally. Catchblocks are of the form catch (v) or catch(v:<guard>), where guard is an optional boolean expression that is evaluated to determine whether the exception is to be caught by that block. - ECMA-proposed 'in' operator; "'foo' in o" or "4 in o" asks if o has property foo or element 4. - Added a new set of defines in jsconfig.h for js 1.4 features-in-progress. (in, instanceof, exception handling.) Default build version is now 1.4. Fixed a few conditional features that had become broken. - Progress towards porting to FreeBSD and Alpha; casts of NaN and friends to int are a little more localized. Not there yet... - New config files to compile on more OSes; various fixes to improve portability.
This commit is contained in:
parent
f0d7459661
commit
7596bde975
68
js/ref/js.c
68
js/ref/js.c
@ -42,6 +42,10 @@
|
||||
#include "jsscope.h"
|
||||
#include "jsscript.h"
|
||||
|
||||
#ifdef PERLCONNECT
|
||||
#include "jsperl.h"
|
||||
#endif
|
||||
|
||||
#ifdef LIVECONNECT
|
||||
#include "jsjava.h"
|
||||
#endif
|
||||
@ -51,6 +55,9 @@
|
||||
#ifdef JSDEBUGGER_JAVA_UI
|
||||
#include "jsdjava.h"
|
||||
#endif /* JSDEBUGGER_JAVA_UI */
|
||||
#ifdef JSDEBUGGER_C_UI
|
||||
#include "jsdb.h"
|
||||
#endif /* JSDEBUGGER_C_UI */
|
||||
#endif /* JSDEBUGGER */
|
||||
|
||||
#ifdef XP_UNIX
|
||||
@ -64,7 +71,7 @@
|
||||
#define isatty(f) 1
|
||||
|
||||
#include <SIOUX.h>
|
||||
#include <Types.h>
|
||||
#include <MacTypes.h>
|
||||
|
||||
static char* mac_argv[] = { "js", NULL };
|
||||
|
||||
@ -72,12 +79,12 @@ static void initConsole(StringPtr consoleName, const char* startupMessage, int *
|
||||
{
|
||||
SIOUXSettings.autocloseonquit = true;
|
||||
SIOUXSettings.asktosaveonclose = false;
|
||||
// SIOUXSettings.initializeTB = false;
|
||||
// SIOUXSettings.showstatusline = true;
|
||||
/* SIOUXSettings.initializeTB = false;
|
||||
SIOUXSettings.showstatusline = true;*/
|
||||
puts(startupMessage);
|
||||
SIOUXSetTitle(consoleName);
|
||||
|
||||
// set up a buffer for stderr (otherwise it's a pig).
|
||||
/* set up a buffer for stderr (otherwise it's a pig). */
|
||||
setvbuf(stderr, malloc(BUFSIZ), _IOLBF, BUFSIZ);
|
||||
|
||||
*argc = 1;
|
||||
@ -261,8 +268,6 @@ my_ErrorReporter(JSContext *cx, const char *message, JSErrorReport *report);
|
||||
static JSBool
|
||||
Load(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
|
||||
{
|
||||
JSContext *cx2;
|
||||
JSVersion version;
|
||||
uintN i;
|
||||
JSString *str;
|
||||
const char *filename;
|
||||
@ -270,39 +275,22 @@ Load(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
|
||||
JSBool ok;
|
||||
jsval result;
|
||||
|
||||
/*
|
||||
* Create new context to execute in so that gc will still find
|
||||
* roots for the script that called load().
|
||||
*/
|
||||
cx2 = JS_NewContext(cx->runtime, 8192);
|
||||
if (!cx2)
|
||||
return JS_FALSE;
|
||||
JS_SetErrorReporter(cx2, my_ErrorReporter);
|
||||
JS_SetGlobalObject(cx2, JS_GetGlobalObject(cx));
|
||||
version = JS_GetVersion(cx);
|
||||
if (version != JSVERSION_DEFAULT)
|
||||
JS_SetVersion(cx2, version);
|
||||
|
||||
ok = JS_TRUE;
|
||||
for (i = 0; i < argc; i++) {
|
||||
str = JS_ValueToString(cx, argv[i]);
|
||||
if (!str) {
|
||||
ok = JS_FALSE;
|
||||
break;
|
||||
}
|
||||
if (!str)
|
||||
return JS_FALSE;
|
||||
argv[i] = STRING_TO_JSVAL(str);
|
||||
filename = JS_GetStringBytes(str);
|
||||
errno = 0;
|
||||
script = JS_CompileFile(cx, obj, filename);
|
||||
if (!script)
|
||||
continue;
|
||||
ok = JS_ExecuteScript(cx2, obj, script, &result);
|
||||
ok = JS_ExecuteScript(cx, obj, script, &result);
|
||||
JS_DestroyScript(cx, script);
|
||||
if (!ok)
|
||||
break;
|
||||
return JS_FALSE;
|
||||
}
|
||||
JS_DestroyContext(cx2);
|
||||
return ok;
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
static JSBool
|
||||
@ -543,6 +531,11 @@ SrcNotes(JSContext *cx, JSFunction *fun )
|
||||
atom = js_GetAtom(cx, &fun->script->atomMap, atomIndex);
|
||||
printf(" atom %u (%s)", (uintN)atomIndex, ATOM_BYTES(atom));
|
||||
break;
|
||||
case SRC_CATCH:
|
||||
delta = (uintN) js_GetSrcNoteOffset(sn, 0);
|
||||
if (delta)
|
||||
printf(" guard size %u", delta);
|
||||
break;
|
||||
default:;
|
||||
}
|
||||
putchar('\n');
|
||||
@ -573,10 +566,10 @@ TryNotes(JSContext *cx, JSFunction *fun)
|
||||
|
||||
if (!tn)
|
||||
return JS_TRUE;
|
||||
printf("\nException table:\nstart\tend\tcatch\tfinally\n");
|
||||
while (tn->catchStart || tn->finallyStart) {
|
||||
printf(" %d\t%d\t%d\t%d\n",
|
||||
tn->start, tn->length, tn->catchStart, tn->finallyStart);
|
||||
printf("\nException table:\nstart\tend\tcatch\n");
|
||||
while (tn->start && tn->catchStart) {
|
||||
printf(" %d\t%d\t%d\n",
|
||||
tn->start, tn->length, tn->catchStart);
|
||||
tn++;
|
||||
}
|
||||
return JS_TRUE;
|
||||
@ -1285,9 +1278,10 @@ main(int argc, char **argv)
|
||||
#endif
|
||||
|
||||
version = JSVERSION_DEFAULT;
|
||||
#ifndef LIVECONNECT
|
||||
argc--;
|
||||
argv++;
|
||||
|
||||
#endif
|
||||
rt = JS_NewRuntime(8L * 1024L * 1024L);
|
||||
if (!rt)
|
||||
return 1;
|
||||
@ -1314,6 +1308,11 @@ main(int argc, char **argv)
|
||||
if (!JS_DefineProperties(cx, it, its_props))
|
||||
return 1;
|
||||
|
||||
#ifdef PERLCONNECT
|
||||
if (!js_InitPerlClass(cx, glob))
|
||||
return 1;
|
||||
#endif
|
||||
|
||||
#ifdef LIVECONNECT
|
||||
if (!JSJ_SimpleInit(cx, glob, NULL, getenv("CLASSPATH")))
|
||||
return 1;
|
||||
@ -1340,6 +1339,9 @@ main(int argc, char **argv)
|
||||
* is passed on the cmd line.
|
||||
*/
|
||||
#endif /* JSDEBUGGER_JAVA_UI */
|
||||
#ifdef JSDEBUGGER_C_UI
|
||||
JSDB_InitDebugger(rt, _jsdc, 0);
|
||||
#endif /* JSDEBUGGER_C_UI */
|
||||
#endif /* JSDEBUGGER */
|
||||
|
||||
result = ProcessArgs(cx, glob, argv, argc);
|
||||
|
@ -2541,7 +2541,7 @@ JS_GetPendingException(JSContext *cx, jsval *vp)
|
||||
#if JS_HAS_EXCEPTIONS
|
||||
if (!cx->fp->throwing)
|
||||
return JS_FALSE;
|
||||
*vp = cx->fp->rval;
|
||||
*vp = cx->fp->exception;
|
||||
return JS_TRUE;
|
||||
#else
|
||||
return JS_FALSE;
|
||||
@ -2554,7 +2554,7 @@ JS_SetPendingException(JSContext *cx, jsval v)
|
||||
CHECK_REQUEST(cx);
|
||||
#if JS_HAS_EXCEPTIONS
|
||||
cx->fp->throwing = JS_TRUE;
|
||||
cx->fp->rval = v;
|
||||
cx->fp->exception = v;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -80,6 +80,8 @@ struct JSRuntime {
|
||||
void *newScriptHookData;
|
||||
JSDestroyScriptHook destroyScriptHook;
|
||||
void *destroyScriptHookData;
|
||||
JSTrapHandler debuggerHandler;
|
||||
void *debuggerHandlerData;
|
||||
|
||||
/* More debugging state, see jsdbgapi.c. */
|
||||
PRCList trapList;
|
||||
@ -147,7 +149,7 @@ struct JSContext {
|
||||
|
||||
/* Client opaque pointer */
|
||||
void *data;
|
||||
|
||||
|
||||
/* Java environment and JS errors to throw as exceptions. */
|
||||
void *javaEnv;
|
||||
void *savedErrors;
|
||||
@ -157,6 +159,7 @@ struct JSContext {
|
||||
JSPackedBool gcActive;
|
||||
jsrefcount requestDepth;
|
||||
#endif
|
||||
JSStackFrame *dormantFrameChain; /* dormant frame chains */
|
||||
};
|
||||
|
||||
typedef struct JSInterpreterHooks {
|
||||
|
@ -20,7 +20,7 @@
|
||||
* JS configuration macros.
|
||||
*/
|
||||
#ifndef JS_VERSION
|
||||
#define JS_VERSION 130
|
||||
#define JS_VERSION 140
|
||||
#endif
|
||||
|
||||
#if JS_VERSION == 100
|
||||
|
@ -757,3 +757,13 @@ JS_PutPropertyDescArray(JSContext *cx, JSPropertyDescArray *pda)
|
||||
}
|
||||
JS_free(cx, pd);
|
||||
}
|
||||
|
||||
/************************************************************************/
|
||||
|
||||
JS_PUBLIC_API(JSBool)
|
||||
JS_SetDebuggerHandler(JSRuntime *rt, JSTrapHandler handler, void *closure)
|
||||
{
|
||||
rt->debuggerHandler = handler;
|
||||
rt->debuggerHandlerData = closure;
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
@ -211,6 +211,11 @@ JS_GetPropertyDescArray(JSContext *cx, JSObject *obj, JSPropertyDescArray *pda);
|
||||
extern JS_PUBLIC_API(void)
|
||||
JS_PutPropertyDescArray(JSContext *cx, JSPropertyDescArray *pda);
|
||||
|
||||
/************************************************************************/
|
||||
|
||||
extern JS_PUBLIC_API(JSBool)
|
||||
JS_SetDebuggerHandler(JSRuntime *rt, JSTrapHandler handler, void *closure);
|
||||
|
||||
PR_END_EXTERN_C
|
||||
|
||||
#endif /* jsdbgapi_h___ */
|
||||
|
324
js/ref/jsemit.c
324
js/ref/jsemit.c
@ -231,10 +231,18 @@ EmitGoto(JSContext *cx, JSCodeGenerator *cg, JSStmtInfo *toStmt,
|
||||
{
|
||||
JSStmtInfo *stmt;
|
||||
intN index;
|
||||
uint16 finallyIndex = 0;
|
||||
ptrdiff_t offset, delta;
|
||||
|
||||
for (stmt = cg->treeContext.topStmt; stmt != toStmt; stmt = stmt->down) {
|
||||
switch (stmt->type) {
|
||||
case STMT_FINALLY:
|
||||
if (js_NewSrcNote(cx, cg, SRC_HIDDEN) < 0 ||
|
||||
js_Emit3(cx, cg, JSOP_JSR, JUMP_OFFSET_HI(finallyIndex),
|
||||
JUMP_OFFSET_LO(finallyIndex)) < 0)
|
||||
return -1;
|
||||
finallyIndex--;
|
||||
break;
|
||||
case STMT_WITH:
|
||||
if (js_NewSrcNote(cx, cg, SRC_HIDDEN) < 0)
|
||||
return -1;
|
||||
@ -434,6 +442,57 @@ js_EmitFunctionBody(JSContext *cx, JSCodeGenerator *cg, JSParseNode *body,
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
#if JS_HAS_EXCEPTIONS
|
||||
#define BYTECODE_ITER(pc, max, body) \
|
||||
while (pc < max) { \
|
||||
JSCodeSpec *cs = &js_CodeSpec[(JSOp)*pc]; \
|
||||
body; \
|
||||
if ((cs->format & JOF_TYPEMASK) == JOF_TABLESWITCH || \
|
||||
(cs->format & JOF_TYPEMASK) == JOF_LOOKUPSWITCH) { \
|
||||
pc += GET_JUMP_OFFSET(pc); \
|
||||
} else { \
|
||||
pc += cs->length; \
|
||||
} \
|
||||
}
|
||||
|
||||
static JSBool
|
||||
FixupFinallyJumps(JSContext *cx, JSCodeGenerator *cg, ptrdiff_t tryStart,
|
||||
ptrdiff_t finallyIndex)
|
||||
{
|
||||
jsbytecode *pc;
|
||||
pc = cg->base + tryStart;
|
||||
BYTECODE_ITER(pc, cg->next, \
|
||||
if (*pc == JSOP_JSR) { \
|
||||
ptrdiff_t index = GET_JUMP_OFFSET(pc); \
|
||||
if (index <= 0) { \
|
||||
if (index == 0) { \
|
||||
index = finallyIndex - (pc - cg->base); \
|
||||
} else { \
|
||||
index++; \
|
||||
} \
|
||||
CHECK_AND_SET_JUMP_OFFSET(cx, cg, pc, index); \
|
||||
} \
|
||||
} \
|
||||
);
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
static JSBool
|
||||
FixupCatchJumps(JSContext *cx, JSCodeGenerator *cg, ptrdiff_t tryStart,
|
||||
ptrdiff_t postCatch)
|
||||
{
|
||||
jsbytecode *pc;
|
||||
pc = cg->base + tryStart;
|
||||
BYTECODE_ITER(pc, cg->next, \
|
||||
if (*pc == JSOP_GOTO && !GET_JUMP_OFFSET(pc)) { \
|
||||
CHECK_AND_SET_JUMP_OFFSET(cx, cg, pc, postCatch - (pc - cg->base)); \
|
||||
} \
|
||||
);
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
JSBool
|
||||
js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
|
||||
{
|
||||
@ -1069,24 +1128,46 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
|
||||
|
||||
#if JS_HAS_EXCEPTIONS
|
||||
case TOK_TRY: {
|
||||
ptrdiff_t start, end, catchStart;
|
||||
ptrdiff_t start, end, catchStart, finallyCatch, catchjmp = -1;
|
||||
JSParseNode *iter = pn;
|
||||
|
||||
#if shaver_finally
|
||||
/* if this try has a finally, push marker onto treeContext */
|
||||
/* XXX use -(CG_OFFSET + 1) */
|
||||
#define EMIT_FINALLY_JSR(cx, cg) \
|
||||
PR_BEGIN_MACRO \
|
||||
if (!js_Emit3(cx, cg, JSOP_JSR, 0, 0)) \
|
||||
return JS_FALSE; \
|
||||
PR_END_MACRO
|
||||
;
|
||||
/*
|
||||
* When a finally block is `active' (STMT_FINALLY on the treeContext),
|
||||
* non-local jumps result in a JSR being written into the bytecode
|
||||
* stream for later fixup. The jsr is written with offset 0 for the
|
||||
* innermost finally, -1 for the next, etc. As the finally fixup code
|
||||
* runs for each finished try/finally, it will fix the JSRs with
|
||||
* offset 0 to match the appropriate finally code for its block
|
||||
* and decrement all others by one.
|
||||
*
|
||||
* NOTE: This will cause problems if we use JSRs for something other
|
||||
* than finally handling in the future. Caveat hacker!
|
||||
*/
|
||||
|
||||
if (pn->pn_kid3)
|
||||
js_PushStatement(&cg->treeContext, &stmtInto, STMT_FINALLY,
|
||||
js_PushStatement(&cg->treeContext, &stmtInfo, STMT_FINALLY,
|
||||
CG_OFFSET(cg));
|
||||
#endif
|
||||
|
||||
/* mark try location for decompilation, then emit try block */
|
||||
if (js_NewSrcNote(cx, cg, SRC_TRY) < 0 ||
|
||||
if (js_NewSrcNote2(cx, cg, SRC_TRYFIN, 0) < 0 ||
|
||||
js_Emit1(cx, cg, JSOP_NOP) < 0)
|
||||
return JS_FALSE;
|
||||
start = CG_OFFSET(cg);
|
||||
if(!js_EmitTree(cx, cg, pn->pn_kid1))
|
||||
return JS_FALSE;
|
||||
|
||||
/* emit (hidden) jump over try and/or finally */
|
||||
/* emit (hidden) jump over catch and/or finally */
|
||||
if (js_NewSrcNote(cx, cg, SRC_HIDDEN) < 0)
|
||||
return JS_FALSE;
|
||||
if (pn->pn_kid3)
|
||||
EMIT_FINALLY_JSR(cx, cg);
|
||||
if (js_NewSrcNote(cx, cg, SRC_HIDDEN) < 0)
|
||||
return JS_FALSE;
|
||||
jmp = js_Emit3(cx, cg, JSOP_GOTO, 0, 0);
|
||||
@ -1094,68 +1175,198 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
|
||||
return JS_FALSE;
|
||||
end = CG_OFFSET(cg);
|
||||
|
||||
|
||||
/* if this try has a catch block, emit it */
|
||||
if (pn->pn_kid2) {
|
||||
catchStart = end;
|
||||
if (!js_EmitTree(cx, cg, pn->pn_kid2))
|
||||
return JS_FALSE;
|
||||
} else {
|
||||
catchStart = 0;
|
||||
/*
|
||||
* The emitted code for a catch block looks like:
|
||||
*
|
||||
* [ popscope ] only if 2nd+ catch block
|
||||
* name Object
|
||||
* pushobj
|
||||
* newinit
|
||||
* exception
|
||||
* initprop <atom> maybe marked SRC_CATCHGUARD
|
||||
* enterwith
|
||||
* [< catchguard code >] if there's a catchguard
|
||||
* ifeq <offset to next catch block>
|
||||
* < catch block contents >
|
||||
* leavewith
|
||||
* goto <end of catch blocks> non-local; finally applies
|
||||
*
|
||||
* If there's no catch block without a catchguard, the last
|
||||
* <offset to next catch block> points to rethrow code. This
|
||||
* code will jsr to the finally code if appropriate, and is
|
||||
* also used for the catch-all trynote for capturing exceptions
|
||||
* thrown from catch{} blocks.
|
||||
*/
|
||||
do {
|
||||
JSStmtInfo stmtInfo2;
|
||||
JSParseNode *disc;
|
||||
ptrdiff_t guardnote;
|
||||
|
||||
iter = iter->pn_kid2;
|
||||
disc = iter->pn_kid1;
|
||||
|
||||
if (catchjmp != -1) {
|
||||
/* fix up and clean up previous catch block */
|
||||
CHECK_AND_SET_JUMP_OFFSET_AT(cx, cg, catchjmp);
|
||||
if ((uintN)++cg->stackDepth > cg->maxStackDepth)
|
||||
cg->maxStackDepth = cg->stackDepth;
|
||||
if (js_NewSrcNote(cx, cg, SRC_HIDDEN) < 0 ||
|
||||
js_Emit1(cx, cg, JSOP_LEAVEWITH) < 0)
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
/* non-zero guardnote is length of catchguard */
|
||||
guardnote = js_NewSrcNote2(cx, cg, SRC_CATCH, 0);
|
||||
if (guardnote < 0 ||
|
||||
js_Emit1(cx, cg, JSOP_NOP) < 0)
|
||||
return JS_FALSE;
|
||||
|
||||
/* construct the scope holder and push it on */
|
||||
ale = js_IndexAtom(cx, cx->runtime->atomState.ObjectAtom,
|
||||
&cg->atomList);
|
||||
if (!ale)
|
||||
return JS_FALSE;
|
||||
EMIT_ATOM_INDEX_OP(JSOP_NAME, ale->index);
|
||||
|
||||
if (js_Emit1(cx, cg, JSOP_PUSHOBJ) < 0 ||
|
||||
js_Emit1(cx, cg, JSOP_NEWINIT) < 0 ||
|
||||
js_Emit1(cx, cg, JSOP_EXCEPTION) < 0)
|
||||
return JS_FALSE;
|
||||
|
||||
/* setprop <atomIndex> */
|
||||
ale = js_IndexAtom(cx, disc->pn_atom, &cg->atomList);
|
||||
if (!ale)
|
||||
return JS_FALSE;
|
||||
|
||||
EMIT_ATOM_INDEX_OP(JSOP_INITPROP, ale->index);
|
||||
if (js_NewSrcNote(cx, cg, SRC_HIDDEN) < 0 ||
|
||||
js_Emit1(cx, cg, JSOP_ENTERWITH) < 0)
|
||||
return JS_FALSE;
|
||||
|
||||
/* boolean_expr */
|
||||
if (disc->pn_expr) {
|
||||
ptrdiff_t guardstart = CG_OFFSET(cg);
|
||||
if (!js_EmitTree(cx, cg, disc->pn_expr))
|
||||
return JS_FALSE;
|
||||
/* ifeq <next block> */
|
||||
catchjmp = js_Emit3(cx, cg, JSOP_IFEQ, 0, 0);
|
||||
if (catchjmp < 0)
|
||||
return JS_FALSE;
|
||||
if (!js_SetSrcNoteOffset(cx, cg, guardnote, 0,
|
||||
(ptrdiff_t)CG_OFFSET(cg) -
|
||||
guardstart))
|
||||
return JS_FALSE;
|
||||
}
|
||||
/* emit catch block */
|
||||
js_PushStatement(&cg->treeContext, &stmtInfo2, STMT_WITH,
|
||||
CG_OFFSET(cg));
|
||||
if (!js_EmitTree(cx, cg, iter->pn_kid3))
|
||||
return JS_FALSE;
|
||||
js_PopStatementCG(cx, cg);
|
||||
|
||||
/*
|
||||
* jump over the remaining catch blocks
|
||||
* this counts as a non-local jump, so do the finally thing
|
||||
*/
|
||||
|
||||
/* popscope */
|
||||
if (js_NewSrcNote(cx, cg, SRC_HIDDEN) < 0 ||
|
||||
js_Emit1(cx, cg, JSOP_LEAVEWITH) < 0)
|
||||
return JS_FALSE;
|
||||
|
||||
/* jsr <finally>, if required */
|
||||
if (pn->pn_kid3)
|
||||
EMIT_FINALLY_JSR(cx, cg);
|
||||
|
||||
/* this will get fixed up to jump to after catch/finally */
|
||||
if (js_NewSrcNote(cx, cg, SRC_HIDDEN) < 0 ||
|
||||
js_Emit3(cx, cg, JSOP_GOTO, 0, 0) < 0)
|
||||
return JS_FALSE;
|
||||
if (!iter->pn_kid2)
|
||||
break;
|
||||
} while (iter);
|
||||
|
||||
}
|
||||
|
||||
#if shaver_finally
|
||||
/* if we've got a finally, it goes here, and we have to fix up
|
||||
the jsrs that might have been emitted before non-local jumps */
|
||||
if (pn->pn_kid3) {
|
||||
ptrdiff_t finallyIndex = CG_OFFSET(CG);
|
||||
js_PopStatement(tc);
|
||||
if (!FixupFinallyJumps(cx, cg, tryStart, finallyIndex))
|
||||
/*
|
||||
* we use a [leavewith],[jsr],rethrow block for rethrowing
|
||||
* when there's no unguarded catch, and also for
|
||||
* running finally code while letting an uncaught exception
|
||||
* pass through
|
||||
*/
|
||||
if (pn->pn_kid3 ||
|
||||
(catchjmp != -1 && iter->pn_kid1->pn_expr)) {
|
||||
if (catchjmp != -1) {
|
||||
CHECK_AND_SET_JUMP_OFFSET_AT(cx, cg, catchjmp);
|
||||
}
|
||||
/* last discriminant jumps to rethrow if none match */
|
||||
if ((uintN)++cg->stackDepth > cg->maxStackDepth)
|
||||
cg->maxStackDepth = cg->stackDepth;
|
||||
if (pn->pn_kid2 &&
|
||||
(js_NewSrcNote(cx, cg, SRC_HIDDEN) < 0 ||
|
||||
js_Emit1(cx, cg, JSOP_LEAVEWITH) < 0))
|
||||
return JS_FALSE;
|
||||
if (!js_EmitTree(cx, cg, pn->pn_kid3))
|
||||
|
||||
if (pn->pn_kid3) {
|
||||
finallyCatch = CG_OFFSET(cg);
|
||||
EMIT_FINALLY_JSR(cx, cg);
|
||||
}
|
||||
if (js_NewSrcNote(cx, cg, SRC_HIDDEN) < 0 ||
|
||||
js_Emit1(cx, cg, JSOP_EXCEPTION) < 0 ||
|
||||
js_NewSrcNote(cx, cg, SRC_HIDDEN) < 0 ||
|
||||
js_Emit1(cx, cg, JSOP_THROW) < 0)
|
||||
return JS_FALSE;
|
||||
}
|
||||
#endif
|
||||
/* come from post-try */
|
||||
CHECK_AND_SET_JUMP_OFFSET_AT(cx, cg, jmp);
|
||||
|
||||
/* if we've got a finally, it goes here, and we have to fix up
|
||||
the jsrs that might have been emitted before non-local jumps */
|
||||
|
||||
if (pn->pn_kid3) {
|
||||
ptrdiff_t finallyIndex;
|
||||
finallyIndex = CG_OFFSET(cg);
|
||||
if (!FixupFinallyJumps(cx, cg, start, finallyIndex))
|
||||
return JS_FALSE;
|
||||
js_PopStatementCG(cx, cg);
|
||||
if (js_NewSrcNote2(cx, cg, SRC_TRYFIN, 1) < 0 ||
|
||||
js_Emit1(cx, cg, JSOP_NOP) < 0 ||
|
||||
!js_EmitTree(cx, cg, pn->pn_kid3) ||
|
||||
js_Emit1(cx, cg, JSOP_RETSUB) < 0)
|
||||
return JS_FALSE;
|
||||
|
||||
}
|
||||
|
||||
if (js_NewSrcNote(cx, cg, SRC_ENDBRACE) < 0 ||
|
||||
js_Emit1(cx, cg, JSOP_NOP) < 0)
|
||||
return JS_FALSE;
|
||||
|
||||
/* fix up the end-of-try/catch jumps to come here */
|
||||
if (!FixupCatchJumps(cx, cg, start, CG_OFFSET(cg)))
|
||||
return JS_FALSE;
|
||||
|
||||
CHECK_AND_SET_JUMP_OFFSET_AT(cx, cg, jmp);
|
||||
|
||||
/*
|
||||
* Add the try note last, to let post-order give us the right ordering
|
||||
* (first to last, inner to outer).
|
||||
*/
|
||||
if (!js_NewTryNote(cx, cg, start, end, catchStart, 0))
|
||||
if (pn->pn_kid2 &&
|
||||
!js_NewTryNote(cx, cg, start, end, catchStart))
|
||||
return JS_FALSE;
|
||||
|
||||
/*
|
||||
* If we've got a finally, mark try+catch region with additional
|
||||
* trynote to catch exceptions (re)thrown from a catch block or
|
||||
* for the try{}finally{} case.
|
||||
*/
|
||||
if (pn->pn_kid3 &&
|
||||
!js_NewTryNote(cx, cg, start, finallyCatch-1, finallyCatch))
|
||||
return JS_FALSE;
|
||||
break;
|
||||
}
|
||||
|
||||
case TOK_CATCH:
|
||||
/*
|
||||
* Catch blocks are very magical. Mainly, the magic involves
|
||||
* special generation for the declaration/conditional, and
|
||||
* mucking with the stack depth counter so that the implicit
|
||||
* push of the exception that happens at runtime doesn't make
|
||||
* the code generator very confused.
|
||||
*
|
||||
* If a catch block has a finally associated with it, the try
|
||||
* block will already have pushed the appropriate statement info
|
||||
* onto the tree context, so we don't need to worry about it.
|
||||
*/
|
||||
noteIndex = js_NewSrcNote(cx, cg, SRC_CATCH);
|
||||
if (noteIndex < 0 ||
|
||||
!js_Emit1(cx, cg, JSOP_NOP))
|
||||
return JS_FALSE;
|
||||
|
||||
/* need to adjust stack depth */
|
||||
if ((uintN)++cg->stackDepth > cg->maxStackDepth)
|
||||
cg->maxStackDepth = cg->stackDepth;
|
||||
if (!js_EmitTree(cx, cg, pn->pn_left) ||
|
||||
!js_EmitTree(cx, cg, pn->pn_right))
|
||||
return JS_FALSE;
|
||||
break;
|
||||
#endif /* JS_HAS_EXCEPTIONS */
|
||||
|
||||
case TOK_VAR:
|
||||
@ -1790,6 +2001,11 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
|
||||
case TOK_PRIMARY:
|
||||
return js_Emit1(cx, cg, pn->pn_op) >= 0;
|
||||
|
||||
#if JS_HAS_DEBUGGER_KEYWORD
|
||||
case TOK_DEBUGGER:
|
||||
return js_Emit1(cx, cg, JSOP_DEBUGGER) >= 0;
|
||||
#endif /* JS_HAS_DEBUGGER_KEYWORD */
|
||||
|
||||
default:
|
||||
PR_ASSERT(0);
|
||||
}
|
||||
@ -1818,7 +2034,7 @@ JS_FRIEND_DATA(const char *) js_SrcNoteName[] = {
|
||||
"cont2label",
|
||||
"switch",
|
||||
"funcdef",
|
||||
"try",
|
||||
"tryfin",
|
||||
"catch",
|
||||
"newline",
|
||||
"setline",
|
||||
@ -1846,8 +2062,8 @@ uint8 js_SrcNoteArity[] = {
|
||||
1, /* SRC_CONT2LABEL */
|
||||
1, /* SRC_SWITCH */
|
||||
1, /* SRC_FUNCDEF */
|
||||
0, /* SRC_TRY */
|
||||
0, /* SRC_CATCH */
|
||||
1, /* SRC_TRYFIN */
|
||||
1, /* SRC_CATCHGUARD */
|
||||
0, /* SRC_NEWLINE */
|
||||
1, /* SRC_SETLINE */
|
||||
0 /* SRC_XDELTA */
|
||||
@ -2001,7 +2217,7 @@ js_GetSrcNoteOffset(jssrcnote *sn, uintN which)
|
||||
sn += 2;
|
||||
}
|
||||
if (*sn & SN_3BYTE_OFFSET_FLAG)
|
||||
return (ptrdiff_t)((((uint32)(*sn & SN_3BYTE_OFFSET_MASK)) << 16) | (sn[1] << 8) | sn[0]);
|
||||
return (ptrdiff_t)((((uint32)(*sn & SN_3BYTE_OFFSET_MASK)) << 16) | (sn[1] << 8) | sn[2]);
|
||||
return (ptrdiff_t)*sn;
|
||||
}
|
||||
|
||||
@ -2089,7 +2305,7 @@ js_AllocTryNotes(JSContext *cx, JSCodeGenerator *cg)
|
||||
|
||||
JS_FRIEND_API(JSTryNote *)
|
||||
js_NewTryNote(JSContext *cx, JSCodeGenerator *cg, ptrdiff_t start,
|
||||
ptrdiff_t end, ptrdiff_t catchStart, ptrdiff_t finallyStart)
|
||||
ptrdiff_t end, ptrdiff_t catchStart)
|
||||
{
|
||||
JSTryNote *tn;
|
||||
|
||||
@ -2098,7 +2314,6 @@ js_NewTryNote(JSContext *cx, JSCodeGenerator *cg, ptrdiff_t start,
|
||||
tn->start = start;
|
||||
tn->length = end - start;
|
||||
tn->catchStart = catchStart;
|
||||
tn->finallyStart = finallyStart;
|
||||
return tn;
|
||||
}
|
||||
|
||||
@ -2124,7 +2339,6 @@ js_FinishTakingTryNotes(JSContext *cx, JSCodeGenerator *cg, JSTryNote **tryp)
|
||||
final[count].start = 0;
|
||||
final[count].length = CG_OFFSET(cg);
|
||||
final[count].catchStart = 0;
|
||||
final[count].finallyStart = 0;
|
||||
*tryp = final;
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
@ -248,7 +248,7 @@ typedef enum JSSrcNoteType {
|
||||
SRC_ASSIGNOP = 8, /* += or another assign-op follows */
|
||||
SRC_COND = 9, /* JSOP_IFEQ is from conditional ?: operator */
|
||||
SRC_PAREN = 10, /* JSOP_NOP generated to mark user parens */
|
||||
SRC_HIDDEN = 11, /* JSOP_LEAVEWITH for break/continue in with */
|
||||
SRC_HIDDEN = 11, /* opcode shouldn't be decompiled */
|
||||
SRC_PCBASE = 12, /* offset of first obj.prop.subprop bytecode */
|
||||
SRC_LABEL = 13, /* JSOP_NOP for label: with atomid immediate */
|
||||
SRC_LABELBRACE = 14, /* JSOP_NOP for label: {...} begin brace */
|
||||
@ -257,8 +257,8 @@ typedef enum JSSrcNoteType {
|
||||
SRC_CONT2LABEL = 17, /* JSOP_GOTO for 'continue label' with atomid */
|
||||
SRC_SWITCH = 18, /* JSOP_*SWITCH with offset to end of switch */
|
||||
SRC_FUNCDEF = 19, /* JSOP_NOP for function f() with atomid */
|
||||
SRC_TRY = 20, /* JSOP_NOP for beginning of try{} section */
|
||||
SRC_CATCH = 21, /* beginning of catch block (at conditional) */
|
||||
SRC_TRYFIN = 20, /* JSOP_NOP for try{} or finally{} section */
|
||||
SRC_CATCH = 21, /* catch block has guard */
|
||||
SRC_NEWLINE = 22, /* bytecode follows a source newline */
|
||||
SRC_SETLINE = 23, /* a file-absolute source line number note */
|
||||
SRC_XDELTA = 24 /* 24-31 are for extended delta notes */
|
||||
@ -362,7 +362,7 @@ js_AllocTryNotes(JSContext *cx, JSCodeGenerator *cg);
|
||||
*/
|
||||
extern JS_FRIEND_API(JSTryNote *)
|
||||
js_NewTryNote(JSContext *cx, JSCodeGenerator *cg, ptrdiff_t start,
|
||||
ptrdiff_t end, ptrdiff_t catchStart, ptrdiff_t finallyStart);
|
||||
ptrdiff_t end, ptrdiff_t catchStart);
|
||||
|
||||
/*
|
||||
* Finish generating exception information, and copy it to JS_malloc
|
||||
|
@ -607,7 +607,7 @@ js_GC(JSContext *cx)
|
||||
PRArena *a, *ma, *fa, **ap, **fap;
|
||||
jsval v, *vp, *sp;
|
||||
pruword begin, end;
|
||||
JSStackFrame *fp;
|
||||
JSStackFrame *fp, *chain;
|
||||
void *mark;
|
||||
uint8 flags, *flagp;
|
||||
JSGCThing *thing, *final, **flp, **oflp;
|
||||
@ -695,8 +695,19 @@ restart:
|
||||
js_MarkAtomState(&rt->atomState, gc_mark);
|
||||
iter = NULL;
|
||||
while ((acx = js_ContextIterator(rt, &iter)) != NULL) {
|
||||
fp = acx->fp;
|
||||
if (fp) {
|
||||
/* Iterate frame chain and dormant chains. Temporarily tack current
|
||||
* frame onto the head of the dormant list to ease iteration.
|
||||
*
|
||||
* (NOTE: see comment on this whole 'dormant' thing in js_Execute)
|
||||
*/
|
||||
chain = acx->fp;
|
||||
if (chain) {
|
||||
PR_ASSERT(!chain->dormantNext);
|
||||
chain->dormantNext = acx->dormantFrameChain;
|
||||
} else {
|
||||
chain = acx->dormantFrameChain;
|
||||
}
|
||||
for (fp=chain; fp; fp = chain = chain->dormantNext) {
|
||||
sp = fp->sp;
|
||||
if (sp) {
|
||||
for (a = acx->stackPool.first.next; a; a = a->next) {
|
||||
@ -728,6 +739,9 @@ restart:
|
||||
GC_MARK(rt, fp->sharpArray, "sharp array", NULL);
|
||||
} while ((fp = fp->down) != NULL);
|
||||
}
|
||||
/* cleanup temporary link */
|
||||
if (acx->fp)
|
||||
acx->fp->dormantNext = NULL;
|
||||
GC_MARK(rt, acx->globalObject, "global object", NULL);
|
||||
GC_MARK(rt, acx->newborn[GCX_OBJECT], "newborn object", NULL);
|
||||
GC_MARK(rt, acx->newborn[GCX_STRING], "newborn string", NULL);
|
||||
|
@ -390,6 +390,7 @@ js_SetLocalVariable(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Find a function reference and its 'this' object implicit first parameter
|
||||
* under argc arguments on cx's stack, and call the function. Push missing
|
||||
@ -506,6 +507,7 @@ have_fun:
|
||||
frame.overrides = 0;
|
||||
frame.debugging = JS_FALSE;
|
||||
frame.throwing = JS_FALSE;
|
||||
frame.dormantNext = NULL;
|
||||
|
||||
/* Compute the 'this' parameter and store it in frame. */
|
||||
if (thisp && OBJ_GET_CLASS(cx, thisp) != &js_CallClass) {
|
||||
@ -652,7 +654,7 @@ have_fun:
|
||||
/* Native or script returns JS_FALSE on error or uncaught exception */
|
||||
if (!ok && frame.throwing) {
|
||||
fp->throwing = JS_TRUE;
|
||||
fp->rval = frame.rval;
|
||||
fp->exception = frame.exception;
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -774,9 +776,37 @@ js_Execute(JSContext *cx, JSObject *chain, JSScript *script, JSFunction *fun,
|
||||
frame.overrides = 0;
|
||||
frame.debugging = debugging;
|
||||
frame.throwing = JS_FALSE;
|
||||
frame.dormantNext = NULL;
|
||||
|
||||
|
||||
/* Here we wrap the call to js_Interpret with code to (conditionally)
|
||||
* save and restore the old stack frame chain into a chain of 'dormant'
|
||||
* frame chains. Since we are replacing cx->fp we were running into the
|
||||
* problem that if gc was called, then some of the objects associated
|
||||
* with the old frame chain (stored here in the C stack as 'oldfp') were
|
||||
* not rooted and were being collected. This was bad. So, now we
|
||||
* preserve the links to these 'dormant' frame chains in cx before
|
||||
* calling js_Interpret and cleanup afterwards. gc walks these dormant
|
||||
* chains and marks objects in the same way that it marks object in the
|
||||
* primary cx->fp chain.
|
||||
*/
|
||||
|
||||
if (oldfp && oldfp != down) {
|
||||
PR_ASSERT(!oldfp->dormantNext);
|
||||
oldfp->dormantNext = cx->dormantFrameChain;
|
||||
cx->dormantFrameChain = oldfp;
|
||||
}
|
||||
|
||||
cx->fp = &frame;
|
||||
ok = js_Interpret(cx, result);
|
||||
cx->fp = oldfp;
|
||||
|
||||
if (oldfp && oldfp != down) {
|
||||
PR_ASSERT(cx->dormantFrameChain == oldfp);
|
||||
cx->dormantFrameChain = oldfp->dormantNext;
|
||||
oldfp->dormantNext = NULL;
|
||||
}
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
@ -1034,19 +1064,21 @@ js_Interpret(JSContext *cx, jsval *result)
|
||||
|
||||
if (rt->interruptHandler) {
|
||||
JSTrapHandler handler = (JSTrapHandler) rt->interruptHandler;
|
||||
|
||||
switch (handler(cx, script, pc, &rval,
|
||||
rt->interruptHandlerData)) {
|
||||
case JSTRAP_ERROR:
|
||||
ok = JS_FALSE;
|
||||
goto out;
|
||||
case JSTRAP_CONTINUE:
|
||||
break;
|
||||
case JSTRAP_RETURN:
|
||||
fp->rval = rval;
|
||||
goto out;
|
||||
default:;
|
||||
}
|
||||
/* check copy of pointer for safety in multithreaded situation */
|
||||
if (handler) {
|
||||
switch (handler(cx, script, pc, &rval,
|
||||
rt->interruptHandlerData)) {
|
||||
case JSTRAP_ERROR:
|
||||
ok = JS_FALSE;
|
||||
goto out;
|
||||
case JSTRAP_CONTINUE:
|
||||
break;
|
||||
case JSTRAP_RETURN:
|
||||
fp->rval = rval;
|
||||
goto out;
|
||||
default:;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
switch (op) {
|
||||
@ -1869,8 +1901,7 @@ js_Interpret(JSContext *cx, jsval *result)
|
||||
cx->newborn[GCX_OBJECT] = NULL;
|
||||
#if JS_HAS_EXCEPTIONS
|
||||
if (fp->throwing) {
|
||||
/* do_throw expects to have the exception on the stack */
|
||||
PR_ASSERT(vp == sp - 1 && *vp == fp->rval);
|
||||
sp[-1] = fp->exception;
|
||||
goto do_throw;
|
||||
}
|
||||
#endif
|
||||
@ -2091,7 +2122,7 @@ js_Interpret(JSContext *cx, jsval *result)
|
||||
#if JS_HAS_EXCEPTIONS
|
||||
if (fp->throwing) {
|
||||
/* do_throw expects to have the exception on the stack */
|
||||
PR_ASSERT(sp[-1] == fp->rval);
|
||||
sp[-1] = fp->exception;
|
||||
goto do_throw;
|
||||
}
|
||||
#endif
|
||||
@ -2549,18 +2580,31 @@ js_Interpret(JSContext *cx, jsval *result)
|
||||
#endif /* JS_HAS_INITIALIZERS */
|
||||
|
||||
#if JS_HAS_EXCEPTIONS
|
||||
case JSOP_JSR:
|
||||
len = GET_JUMP_OFFSET(pc);
|
||||
PUSH(INT_TO_JSVAL(pc - script->code));
|
||||
CHECK_BRANCH(len);
|
||||
break;
|
||||
|
||||
case JSOP_RETSUB:
|
||||
rval = POP();
|
||||
PR_ASSERT(JSVAL_IS_INT(rval));
|
||||
pc = script->code + JSVAL_TO_INT(rval) + 3 /* JSR */;
|
||||
len = 0;
|
||||
CHECK_BRANCH(-1);
|
||||
break;
|
||||
|
||||
case JSOP_EXCEPTION:
|
||||
PUSH(fp->exception);
|
||||
break;
|
||||
|
||||
case JSOP_THROW:
|
||||
/*
|
||||
* We enter here with an exception on the stack already, so we
|
||||
* need to pop it off if we're leaving this frame, but we leave
|
||||
* it on if we're jumping to a catch block.
|
||||
*/
|
||||
PR_ASSERT(!fp->throwing);
|
||||
do_throw:
|
||||
fp->exception = POP();
|
||||
tn = script->trynotes;
|
||||
offset = PTRDIFF(pc, script->code, jsbytecode);
|
||||
if (tn) {
|
||||
while (PR_UPTRDIFF(offset, tn->start) >= tn->length)
|
||||
while (PR_UPTRDIFF(offset, tn->start) >= (pruword)tn->length)
|
||||
tn++;
|
||||
if (tn->catchStart) {
|
||||
pc = script->code + tn->catchStart;
|
||||
@ -2571,7 +2615,6 @@ js_Interpret(JSContext *cx, jsval *result)
|
||||
|
||||
/* Not in a catch block, so propagate the exception. */
|
||||
fp->throwing = JS_TRUE;
|
||||
fp->rval = POP();
|
||||
ok = JS_FALSE;
|
||||
goto out;
|
||||
#endif /* JS_HAS_EXCEPTIONS */
|
||||
@ -2601,6 +2644,29 @@ js_Interpret(JSContext *cx, jsval *result)
|
||||
break;
|
||||
#endif /* JS_HAS_INSTANCEOF */
|
||||
|
||||
#if JS_HAS_DEBUGGER_KEYWORD
|
||||
case JSOP_DEBUGGER:
|
||||
if (rt->debuggerHandler) {
|
||||
JSTrapHandler handler = (JSTrapHandler) rt->debuggerHandler;
|
||||
/* check copy of pointer for safety in multithread situation */
|
||||
if (handler) {
|
||||
switch (handler(cx, script, pc, &rval,
|
||||
rt->debuggerHandlerData)) {
|
||||
case JSTRAP_ERROR:
|
||||
ok = JS_FALSE;
|
||||
goto out;
|
||||
case JSTRAP_CONTINUE:
|
||||
break;
|
||||
case JSTRAP_RETURN:
|
||||
fp->rval = rval;
|
||||
goto out;
|
||||
default:;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
#endif /* JS_HAS_DEBUGGER_KEYWORD */
|
||||
|
||||
default:
|
||||
JS_ReportError(cx, "unimplemented JavaScript bytecode %d", op);
|
||||
ok = JS_FALSE;
|
||||
@ -2631,7 +2697,6 @@ js_Interpret(JSContext *cx, jsval *result)
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
out:
|
||||
/*
|
||||
* Restore the previous frame's execution state.
|
||||
@ -2640,4 +2705,3 @@ out:
|
||||
cx->interpLevel--;
|
||||
return ok;
|
||||
}
|
||||
|
||||
|
@ -49,6 +49,8 @@ struct JSStackFrame {
|
||||
uint8 overrides; /* bit-set of overridden Call properties */
|
||||
JSPackedBool debugging; /* true if for JS_EvaluateInStackFrame */
|
||||
JSPackedBool throwing; /* is there a pending exception? */
|
||||
jsval exception; /* most-recently-thrown exceptin */
|
||||
JSStackFrame *dormantNext; /* next dormant frame chain */
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -815,37 +815,35 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb)
|
||||
js_printf(jp, "\t}\n");
|
||||
break;
|
||||
|
||||
case SRC_TRY:
|
||||
js_printf(jp, "\ttry {\n");
|
||||
case SRC_TRYFIN:
|
||||
if (js_GetSrcNoteOffset(sn, 0) == 0) {
|
||||
js_printf(jp, "\ttry {\n");
|
||||
} else {
|
||||
jp->indent -= 4;
|
||||
js_printf(jp, "\t} finally {\n");
|
||||
}
|
||||
jp->indent += 4;
|
||||
break;
|
||||
|
||||
case SRC_CATCH:
|
||||
jp->indent -= 4;
|
||||
sn = js_GetSrcNote(jp->script, pc);
|
||||
pc += oplen;
|
||||
js_printf(jp, "\t} catch ("); /* balance) */
|
||||
sn = js_GetSrcNote(jp->script, pc);
|
||||
len = js_CodeSpec[*pc].length;
|
||||
switch (*pc) {
|
||||
case JSOP_SETVAR:
|
||||
lval = ATOM_BYTES(GetSlotAtom(jp->scope, js_GetLocalVariable,
|
||||
GET_VARNO(pc)));
|
||||
goto do_catchvar;
|
||||
case JSOP_SETARG:
|
||||
lval = ATOM_BYTES(GetSlotAtom(jp->scope, js_GetArgument,
|
||||
GET_ARGNO(pc)));
|
||||
goto do_catchvar;
|
||||
case JSOP_SETNAME:
|
||||
lval = ATOM_BYTES(GET_ATOM(cx, jp->script, pc));
|
||||
do_catchvar:
|
||||
js_printf(jp, "%s%s",
|
||||
(sn && SN_TYPE(sn) == SRC_VAR ? "var " : ""), lval);
|
||||
break;
|
||||
default:
|
||||
PR_ASSERT(0);
|
||||
pc += 6; /* name Object, pushobj, exception */
|
||||
js_printf(jp, "%s", ATOM_BYTES(GET_ATOM(cx,
|
||||
jp->script, pc)));
|
||||
len = js_GetSrcNoteOffset(sn, 0);
|
||||
pc += 4; /* initprop, enterwith */
|
||||
if (len) {
|
||||
js_printf(jp, " if ");
|
||||
DECOMPILE_CODE(pc, len - 3); /* don't decompile ifeq */
|
||||
js_printf(jp, "%s", POP_STR());
|
||||
pc += len;
|
||||
}
|
||||
js_printf(jp, ") {\n"); /* balance} */
|
||||
jp->indent += 4;
|
||||
len = 0;
|
||||
break;
|
||||
|
||||
case SRC_FUNCDEF: {
|
||||
@ -881,6 +879,17 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb)
|
||||
todo = Sprint(&ss->sprinter, "");
|
||||
break;
|
||||
|
||||
case JSOP_JSR:
|
||||
case JSOP_RETSUB:
|
||||
todo = -2;
|
||||
break;
|
||||
|
||||
case JSOP_EXCEPTION:
|
||||
sn = js_GetSrcNote(jp->script, pc);
|
||||
if (sn && SN_TYPE(sn) == SRC_HIDDEN)
|
||||
todo = -2;
|
||||
break;
|
||||
|
||||
case JSOP_POP:
|
||||
case JSOP_POPV:
|
||||
sn = js_GetSrcNote(jp->script, pc);
|
||||
@ -934,10 +943,13 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb)
|
||||
break;
|
||||
|
||||
case JSOP_ENTERWITH:
|
||||
sn = js_GetSrcNote(jp->script, pc);
|
||||
todo = -2;
|
||||
if (sn && SN_TYPE(sn) == SRC_HIDDEN)
|
||||
break;
|
||||
rval = POP_STR();
|
||||
js_printf(jp, "\twith (%s) {\n", rval);
|
||||
jp->indent += 4;
|
||||
todo = -2;
|
||||
break;
|
||||
|
||||
case JSOP_LEAVEWITH:
|
||||
@ -959,9 +971,12 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb)
|
||||
break;
|
||||
|
||||
case JSOP_THROW:
|
||||
sn = js_GetSrcNote(jp->script, pc);
|
||||
todo = -2;
|
||||
if (sn && SN_TYPE(sn) == SRC_HIDDEN)
|
||||
break;
|
||||
rval = POP_STR();
|
||||
js_printf(jp, "\t%s %s;\n", cs->name, rval);
|
||||
todo = -2;
|
||||
break;
|
||||
|
||||
case JSOP_GOTO:
|
||||
@ -1763,6 +1778,13 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb)
|
||||
#endif /* JS_HAS_SHARP_VARS */
|
||||
#endif /* JS_HAS_INITIALIZERS */
|
||||
|
||||
#if JS_HAS_DEBUGGER_KEYWORD
|
||||
case JSOP_DEBUGGER:
|
||||
js_printf(jp, "\tdebugger;\n");
|
||||
todo = -2;
|
||||
break;
|
||||
#endif /* JS_HAS_DEBUGGER_KEYWORD */
|
||||
|
||||
default:
|
||||
todo = -2;
|
||||
break;
|
||||
@ -1889,7 +1911,7 @@ js_DecompileFunction(JSPrinter *jp, JSFunction *fun, JSBool newlines)
|
||||
}
|
||||
if (atom == NULL)
|
||||
break;
|
||||
js_printf(jp, (i > 0 ? ", %s" : "%s"), ATOM_BYTES(atom));
|
||||
js_printf(jp, (i > 0 ? ", %s" : "%s"), ATOM_BYTES(atom));
|
||||
}
|
||||
}
|
||||
js_puts(jp, ") {\n");
|
||||
|
@ -190,3 +190,13 @@ OPDEF(JSOP_THROW, 110,"throw", NULL, 1, 1, 0, 0, JOF_BYTE)
|
||||
/* 'in' and 'instanceof' ops. */
|
||||
OPDEF(JSOP_IN, 111,js_in_str, js_in_str, 1, 2, 1, 6, JOF_BYTE)
|
||||
OPDEF(JSOP_INSTANCEOF,112,js_instanceof_str,js_instanceof_str,1,2,1,6,JOF_BYTE)
|
||||
|
||||
/* debugger op */
|
||||
OPDEF(JSOP_DEBUGGER, 113,"debugger", NULL, 1, 0, 0, 0, JOF_BYTE)
|
||||
|
||||
/* jsr/return for finally handling */
|
||||
OPDEF(JSOP_JSR, 114,"jsr", NULL, 3, 0, 1, 0, JOF_JUMP)
|
||||
OPDEF(JSOP_RETSUB, 115,"retsub", NULL, 1, 1, 0, 0, JOF_BYTE)
|
||||
|
||||
/* more exception handling ops */
|
||||
OPDEF(JSOP_EXCEPTION, 116,"exception", NULL, 1, 0, 1, 0, JOF_BYTE)
|
||||
|
177
js/ref/jsparse.c
177
js/ref/jsparse.c
@ -1081,114 +1081,108 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
|
||||
return pn;
|
||||
|
||||
#if JS_HAS_EXCEPTIONS
|
||||
case TOK_TRY:
|
||||
case TOK_TRY: {
|
||||
JSParseNode *catchtail = NULL;
|
||||
/*
|
||||
* try nodes are ternary.
|
||||
* kid1 is the try Statement
|
||||
* kid2 is the catch node
|
||||
* kid3 is the finally Statement
|
||||
*
|
||||
* catch nodes are ternary.
|
||||
* kid1 is the discriminant
|
||||
* kid2 is the next catch node, or NULL
|
||||
* kid3 is the catch block (on kid3 so that we can always append a
|
||||
* new catch pn on catchtail->kid2)
|
||||
*
|
||||
* catch discriminant nodes are binary
|
||||
* atom is the receptacle
|
||||
* expr is the discriminant code
|
||||
*
|
||||
* finally nodes are unary (just the finally expression)
|
||||
*/
|
||||
pn = NewParseNode(cx, &ts->token, PN_TERNARY);
|
||||
pn1 = Statement(cx, ts, tc);
|
||||
if (!pn1)
|
||||
pn->pn_op = JSOP_NOP;
|
||||
|
||||
MUST_MATCH_TOKEN(TOK_LC, "missing { after before try block");
|
||||
/* } balance */
|
||||
pn->pn_kid1 = Statements(cx, ts, tc);
|
||||
if (!pn->pn_kid1)
|
||||
return NULL;
|
||||
if (js_PeekToken(cx, ts) == TOK_CATCH) {
|
||||
pn2 = NewParseNode(cx, &ts->token, PN_BINARY);
|
||||
if (!pn2)
|
||||
/* { balance */
|
||||
MUST_MATCH_TOKEN(TOK_RC, "missing } after try block");
|
||||
|
||||
pn->pn_kid2 = NULL;
|
||||
catchtail = pn;
|
||||
while(js_PeekToken(cx, ts) == TOK_CATCH) {
|
||||
/*
|
||||
* legal catch forms are:
|
||||
* catch (v)
|
||||
* catch (v if <boolean_expression>)
|
||||
*/
|
||||
|
||||
if (!catchtail->pn_kid1->pn_expr) {
|
||||
js_ReportCompileError(cx, ts,
|
||||
"catch clause after general catch");
|
||||
return NULL;
|
||||
(void)js_GetToken(cx, ts);
|
||||
}
|
||||
|
||||
/* catch node */
|
||||
pn2 = NewParseNode(cx, &ts->token, PN_TERNARY);
|
||||
pn2->pn_op = JSOP_NOP;
|
||||
/*
|
||||
* We use a PN_NAME for the discriminant (catchguard) node
|
||||
* with the actual discriminant code in the initializer spot
|
||||
*/
|
||||
pn3 = NewParseNode(cx, &ts->token, PN_NAME);
|
||||
if (!pn2 || !pn3)
|
||||
return NULL;
|
||||
|
||||
(void)js_GetToken(cx, ts); /* eat `catch' */
|
||||
|
||||
MUST_MATCH_TOKEN(TOK_LP, "missing ( after catch"); /* balance) */
|
||||
tt = js_PeekToken(cx, ts);
|
||||
if (tt == TOK_VAR) {
|
||||
(void)js_GetToken(cx, ts);
|
||||
pn4 = Variables(cx, ts, tc);
|
||||
if (!pn4)
|
||||
MUST_MATCH_TOKEN(TOK_NAME, "missing identifier in catch");
|
||||
pn3->pn_atom = ts->token.t_atom;
|
||||
if (js_PeekToken(cx, ts) == TOK_COLON) {
|
||||
(void)js_GetToken(cx, ts); /* eat `:' */
|
||||
pn3->pn_expr = Expr(cx, ts, tc);
|
||||
if (!pn3->pn_expr)
|
||||
return NULL;
|
||||
if (pn4->pn_count != 1) {
|
||||
js_ReportCompileError(cx, ts,
|
||||
"only one variable declaration permitted in catch declaration");
|
||||
return NULL;
|
||||
}
|
||||
} else {
|
||||
pn4 = Expr(cx, ts, tc);
|
||||
if (!pn4)
|
||||
return NULL;
|
||||
/* restrict the expression to instanceof */
|
||||
if (pn4->pn_op != JSOP_INSTANCEOF &&
|
||||
pn4->pn_op != JSOP_NAME &&
|
||||
pn4->pn_op != JSOP_GETARG &&
|
||||
pn4->pn_op != JSOP_GETVAR) {
|
||||
js_ReportCompileError(cx, ts,
|
||||
"catch conditional must be instanceof or variable declaration");
|
||||
PR_ASSERT(0);
|
||||
return NULL;
|
||||
}
|
||||
pn3->pn_expr = NULL;
|
||||
}
|
||||
pn2->pn_kid1 = pn3;
|
||||
|
||||
/* rewrite the declaration/conditional expr as appropriate */
|
||||
switch(pn4->pn_type) {
|
||||
case TOK_NAME:
|
||||
switch(pn4->pn_op) {
|
||||
case JSOP_NAME:
|
||||
pn4->pn_op = JSOP_SETNAME;
|
||||
break;
|
||||
case JSOP_GETARG:
|
||||
pn4->pn_op = JSOP_SETARG;
|
||||
break;
|
||||
default:
|
||||
PR_ASSERT(0);
|
||||
}
|
||||
break;
|
||||
case TOK_VAR:
|
||||
PR_ASSERT(pn4->pn_head->pn_type == TOK_NAME);
|
||||
switch(pn4->pn_head->pn_op) {
|
||||
case JSOP_GETVAR:
|
||||
pn4->pn_head->pn_op = JSOP_SETVAR;
|
||||
break;
|
||||
case JSOP_GETARG:
|
||||
pn4->pn_head->pn_op = JSOP_SETARG;
|
||||
break;
|
||||
case JSOP_NAME:
|
||||
pn4->pn_head->pn_op = JSOP_SETNAME;
|
||||
case JSOP_NOP:
|
||||
break;
|
||||
default:
|
||||
PR_ASSERT(0);
|
||||
}
|
||||
break;
|
||||
case TOK_INSTANCEOF:
|
||||
PR_ASSERT(0);
|
||||
default:
|
||||
PR_ASSERT(0);
|
||||
}
|
||||
pn2->pn_left = pn4;
|
||||
/* ( balance: */
|
||||
MUST_MATCH_TOKEN(TOK_RP, "missing ) after catch");
|
||||
|
||||
/* (balance: */
|
||||
MUST_MATCH_TOKEN(TOK_RP, "missing ) after catch declaration");
|
||||
pn2->pn_right = Statement(cx, ts, tc);
|
||||
if (!pn2->pn_right)
|
||||
MUST_MATCH_TOKEN(TOK_LC, "missing { before catch block");
|
||||
pn2->pn_kid3 = Statements(cx, ts, tc);
|
||||
if (!pn2->pn_kid3)
|
||||
return NULL;
|
||||
} else {
|
||||
pn2 = NULL;
|
||||
MUST_MATCH_TOKEN(TOK_RC, "missing } after catch block");
|
||||
|
||||
catchtail = catchtail->pn_kid2 = pn2;
|
||||
}
|
||||
catchtail->pn_kid2 = NULL;
|
||||
|
||||
if (js_MatchToken(cx, ts, TOK_FINALLY)) {
|
||||
pn3 = Statement(cx, ts, tc);
|
||||
if (!pn3)
|
||||
MUST_MATCH_TOKEN(TOK_LC, "missing { before finally block");
|
||||
pn->pn_kid3 = Statements(cx, ts, tc);
|
||||
if (!pn->pn_kid3)
|
||||
return NULL;
|
||||
MUST_MATCH_TOKEN(TOK_RC, "missing } after finally block");
|
||||
} else {
|
||||
pn3 = NULL;
|
||||
pn->pn_kid3 = NULL;
|
||||
}
|
||||
if (!pn2 && !pn3) {
|
||||
if (!pn->pn_kid2 && !pn->pn_kid3) {
|
||||
js_ReportCompileError(cx, ts,
|
||||
"missing catch or finally after try");
|
||||
return NULL;
|
||||
}
|
||||
tc->tryCount++;
|
||||
pn->pn_kid1 = pn1;
|
||||
pn->pn_kid2 = pn2;
|
||||
pn->pn_kid3 = pn3;
|
||||
return pn;
|
||||
|
||||
}
|
||||
case TOK_THROW:
|
||||
pn = NewParseNode(cx, &ts->token, PN_UNARY);
|
||||
if (!pn)
|
||||
@ -1204,6 +1198,16 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
|
||||
pn->pn_op = JSOP_THROW;
|
||||
pn->pn_kid = pn2;
|
||||
break;
|
||||
|
||||
/* TOK_CATCH and TOK_FINALLY are both handled in the TOK_TRY case */
|
||||
case TOK_CATCH:
|
||||
js_ReportCompileError(cx, ts, "catch without try");
|
||||
return NULL;
|
||||
|
||||
case TOK_FINALLY:
|
||||
js_ReportCompileError(cx, ts, "finally without try");
|
||||
return NULL;
|
||||
|
||||
#endif /* JS_HAS_EXCEPTIONS */
|
||||
|
||||
case TOK_BREAK:
|
||||
@ -1373,6 +1377,17 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
|
||||
pn->pn_kid = NULL;
|
||||
return pn;
|
||||
|
||||
#if JS_HAS_DEBUGGER_KEYWORD
|
||||
case TOK_DEBUGGER:
|
||||
if(!WellTerminated(cx, ts, TOK_ERROR))
|
||||
return NULL;
|
||||
pn = NewParseNode(cx, &ts->token, PN_NULLARY);
|
||||
if (!pn)
|
||||
return NULL;
|
||||
pn->pn_type = TOK_DEBUGGER;
|
||||
return pn;
|
||||
#endif /* JS_HAS_DEBUGGER_KEYWORD */
|
||||
|
||||
case TOK_ERROR:
|
||||
return NULL;
|
||||
|
||||
|
@ -127,10 +127,14 @@ static struct keyword {
|
||||
#endif
|
||||
|
||||
#ifdef RESERVE_ECMA_KEYWORDS
|
||||
{"debugger", TOK_RESERVED, JSOP_NOP, JSVERSION_1_3},
|
||||
{"enum", TOK_RESERVED, JSOP_NOP, JSVERSION_1_3},
|
||||
#endif
|
||||
|
||||
#if JS_HAS_DEBUGGER_KEYWORD
|
||||
{"debugger", TOK_DEBUGGER, JSOP_NOP}, /* XXX version? */
|
||||
#elif defined(RESERVE_ECMA_KEYWORDS)
|
||||
{"debugger", TOK_RESERVED, JSOP_NOP, JSVERSION_1_3},
|
||||
#endif
|
||||
{0}
|
||||
};
|
||||
|
||||
@ -249,8 +253,17 @@ static void
|
||||
SendSourceToJSDebugger(JSTokenStream *ts, jschar *str, size_t length)
|
||||
{
|
||||
if (!ts->jsdsrc) {
|
||||
ts->jsdsrc = JSD_NewSourceText(ts->jsdc,
|
||||
ts->filename ? ts->filename : "typein");
|
||||
const char* filename = ts->filename ? ts->filename : "typein";
|
||||
|
||||
if (1 == ts->lineno) {
|
||||
ts->jsdsrc = JSD_NewSourceText(ts->jsdc, filename);
|
||||
} else {
|
||||
ts->jsdsrc = JSD_FindSourceForURL(ts->jsdc, filename);
|
||||
if (ts->jsdsrc && JSD_SOURCE_PARTIAL !=
|
||||
JSD_GetSourceStatus(ts->jsdc, ts->jsdsrc)) {
|
||||
ts->jsdsrc = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (ts->jsdsrc) {
|
||||
/* here we convert our Unicode into a C string to pass to JSD */
|
||||
@ -283,11 +296,11 @@ GetChar(JSTokenStream *ts)
|
||||
int32 c;
|
||||
ptrdiff_t len, olen;
|
||||
jschar *nl;
|
||||
|
||||
|
||||
if (ts->ungetpos != 0) {
|
||||
c = ts->ungetbuf[--ts->ungetpos];
|
||||
} else {
|
||||
if (ts->linebuf.ptr == ts->linebuf.limit) {
|
||||
if (ts->linebuf.ptr == ts->linebuf.limit) {
|
||||
len = PTRDIFF(ts->userbuf.limit, ts->userbuf.ptr, jschar);
|
||||
if (len <= 0) {
|
||||
#ifdef JSFILE
|
||||
@ -518,6 +531,7 @@ js_ReportCompileError(JSContext *cx, JSTokenStream *ts, const char *format,
|
||||
fprintf(stderr, "%s:\n%s\n",message,
|
||||
js_DeflateString(cx, ts->linebuf.base,
|
||||
ts->linebuf.limit - ts->linebuf.base));
|
||||
|
||||
#endif
|
||||
}
|
||||
if (lastc == '\n')
|
||||
|
@ -91,6 +91,7 @@ typedef enum JSTokenType {
|
||||
TOK_FINALLY = 57, /* finally keyword */
|
||||
TOK_THROW = 58, /* throw keyword */
|
||||
TOK_INSTANCEOF = 59, /* instanceof keyword */
|
||||
TOK_DEBUGGER = 60, /* debugger keyword */
|
||||
TOK_RESERVED, /* reserved keywords */
|
||||
TOK_LIMIT /* domain size */
|
||||
} JSTokenType;
|
||||
|
@ -304,60 +304,6 @@ XDRAtomMap(JSXDRState *xdr, JSAtomMap *map)
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
#ifdef JS_XDR_SCRIPT_VERIFIER
|
||||
/*
|
||||
* Make sure that the script is "safe".
|
||||
* We currently only check for a balanced stack budget.
|
||||
*/
|
||||
static JSBool
|
||||
VerifyScript(JSContext *cx, JSScript *scr) {
|
||||
int depth = 0;
|
||||
jsbytecode *pc, *endpc;
|
||||
|
||||
pc = script->code;
|
||||
endpc = pc + script->length; /* XXX attack based on falsified length? */
|
||||
|
||||
while (pc < endpc) {
|
||||
JSCodeSpec *cs = &js_CodeSpec[(JSOp)*pc];
|
||||
intN nuses = cs->nuses;
|
||||
if (nuses < 0)
|
||||
nuses = 2 + GET_ARGC(pc);
|
||||
depth -= nuses;
|
||||
if (depth < 0) { /* underflow */
|
||||
JS_ReportError(cx,
|
||||
"script verification failed: stack underflow\n");
|
||||
return JS_FALSE;
|
||||
}
|
||||
depth += cs->ndefs;
|
||||
if (depth > maxdepth) {
|
||||
maxdepth = depth;
|
||||
if (depth > script->depth) { /* overflow */
|
||||
JS_ReportError(cx,
|
||||
"script verification failed: stack overflow\n");
|
||||
return JS_FALSE;
|
||||
}
|
||||
}
|
||||
if (cs->format & JOF_TYPEMASK == JOF_TABLESWITCH ||
|
||||
cs->format & JOF_TYPEMASK == JOF_LOOKUPSWITCH) {
|
||||
/*
|
||||
* the immediate operand is the length of the switch/lookup table
|
||||
* (also the default offset)
|
||||
*/
|
||||
pc += GET_JUMP_OFFSET(pc);
|
||||
} else {
|
||||
pc += cs->length;
|
||||
}
|
||||
}
|
||||
if (maxdepth != script->depth) { /* perhaps not attack, but malformed */
|
||||
JS_ReportError(cx,
|
||||
"script stack budget mismatch (max %d, declared %d)\n",
|
||||
maxdepth, script->depth);
|
||||
return JS_FALSE;
|
||||
}
|
||||
return JS_TRUE;
|
||||
}
|
||||
#endif
|
||||
|
||||
JSBool
|
||||
js_XDRScript(JSXDRState *xdr, JSScript **scriptp, JSBool *magic)
|
||||
{
|
||||
@ -402,13 +348,6 @@ js_XDRScript(JSXDRState *xdr, JSScript **scriptp, JSBool *magic)
|
||||
if (xdr->mode == JSXDR_DECODE) {
|
||||
script->lineno = (uintN)lineno;
|
||||
script->depth = (uintN)depth;
|
||||
#ifdef JS_XDR_SCRIPT_VERIFIER
|
||||
if (!VerifyScript(xdr->cx, script)) {
|
||||
js_DestroyScript(xdr->cx, script);
|
||||
*scriptp = NULL;
|
||||
return JS_FALSE;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
@ -38,8 +38,6 @@ struct JSTryNote {
|
||||
ptrdiff_t start; /* start of try statement */
|
||||
ptrdiff_t length; /* count of try statement bytecodes */
|
||||
ptrdiff_t catchStart; /* start of catch block (0 if none) */
|
||||
ptrdiff_t finallyStart; /* XXX unneeded except for end-of-vector mark:
|
||||
if (!catchStart && !finallyStart) break */
|
||||
};
|
||||
|
||||
struct JSScript {
|
||||
|
@ -1,20 +1,19 @@
|
||||
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* Version 1.0 (the "License"); you may not use this file except in
|
||||
* compliance with the License. You may obtain a copy of the License at
|
||||
* Version 1.0 (the "NPL"); you may not use this file except in
|
||||
* compliance with the NPL. You may obtain a copy of the NPL at
|
||||
* http://www.mozilla.org/NPL/
|
||||
*
|
||||
* 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.
|
||||
* Software distributed under the NPL is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
|
||||
* for the specific language governing rights and limitations under the
|
||||
* NPL.
|
||||
*
|
||||
* The Original Code is Mozilla Communicator client code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications
|
||||
* Corporation. Portions created by Netscape are Copyright (C) 1998
|
||||
* Netscape Communications Corporation. All Rights Reserved.
|
||||
* The Initial Developer of this code under the NPL is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
|
||||
* Reserved.
|
||||
*/
|
||||
|
||||
/*
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* -*- Mode: C; tab-width: 8; c-basic-offset: 4 -*-
|
||||
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* Version 1.0 (the "NPL"); you may not use this file except in
|
||||
@ -455,30 +455,30 @@ JS_XDRValue(JSXDRState *xdr, jsval *vp)
|
||||
break;
|
||||
}
|
||||
case JSVAL_BOOLEAN: {
|
||||
uint32 bool;
|
||||
uint32 b;
|
||||
if (xdr->mode == JSXDR_ENCODE)
|
||||
bool = (uint32)JSVAL_TO_BOOLEAN(*vp);
|
||||
if (!JS_XDRUint32(xdr, &bool))
|
||||
b = (uint32)JSVAL_TO_BOOLEAN(*vp);
|
||||
if (!JS_XDRUint32(xdr, &b))
|
||||
return JS_FALSE;
|
||||
if (xdr->mode == JSXDR_DECODE)
|
||||
*vp = BOOLEAN_TO_JSVAL((JSBool)bool);
|
||||
*vp = BOOLEAN_TO_JSVAL((JSBool)b);
|
||||
break;
|
||||
}
|
||||
case JSVAL_VOID:
|
||||
if (!JS_XDRUint32(xdr, (uint32 *)vp))
|
||||
return JS_FALSE;
|
||||
break;
|
||||
case JSVAL_INT: {
|
||||
uint32 i;
|
||||
if (xdr->mode == JSXDR_ENCODE)
|
||||
i = JSVAL_TO_INT(*vp);
|
||||
if (!JS_XDRUint32(xdr, &i))
|
||||
return JS_FALSE;
|
||||
if (xdr->mode == JSXDR_DECODE)
|
||||
*vp = INT_TO_JSVAL(i);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
if (type & JSVAL_INT) {
|
||||
uint32 i;
|
||||
if (xdr->mode == JSXDR_ENCODE)
|
||||
i = JSVAL_TO_INT(*vp);
|
||||
if (!JS_XDRUint32(xdr, &i))
|
||||
return JS_FALSE;
|
||||
if (xdr->mode == JSXDR_DECODE)
|
||||
*vp = INT_TO_JSVAL(i);
|
||||
break;
|
||||
}
|
||||
JS_ReportError(xdr->cx, "unknown jsval type %#lx for XDR", type);
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* -*- Mode: C; tab-width: 8; c-basic-offset: 4 -*-
|
||||
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* Version 1.0 (the "NPL"); you may not use this file except in
|
||||
|
@ -44,7 +44,7 @@ static PRArenaStats *arena_stats_list;
|
||||
#define PR_ARENA_DEFAULT_ALIGN sizeof(double)
|
||||
|
||||
PR_PUBLIC_API(void)
|
||||
PR_InitArenaPool(PRArenaPool *pool, const char *name, size_t size, size_t align)
|
||||
PR_InitArenaPool(PRArenaPool *pool, const char *name, PRUint32 size, PRUint32 align)
|
||||
{
|
||||
if (align == 0)
|
||||
align = PR_ARENA_DEFAULT_ALIGN;
|
||||
@ -63,13 +63,13 @@ PR_InitArenaPool(PRArenaPool *pool, const char *name, size_t size, size_t align)
|
||||
}
|
||||
|
||||
PR_PUBLIC_API(void *)
|
||||
PR_ArenaAllocate(PRArenaPool *pool, size_t nb)
|
||||
PR_ArenaAllocate(PRArenaPool *pool, PRUint32 nb)
|
||||
{
|
||||
PRArena **ap, *a, *b;
|
||||
#ifdef JS_THREADSAFE
|
||||
PRArena *c;
|
||||
#endif
|
||||
size_t sz;
|
||||
PRUint32 sz;
|
||||
void *p;
|
||||
|
||||
PR_ASSERT((nb & pool->mask) == 0);
|
||||
@ -118,7 +118,7 @@ PR_ArenaAllocate(PRArenaPool *pool, size_t nb)
|
||||
}
|
||||
|
||||
PR_PUBLIC_API(void *)
|
||||
PR_ArenaGrow(PRArenaPool *pool, void *p, size_t size, size_t incr)
|
||||
PR_ArenaGrow(PRArenaPool *pool, void *p, PRUint32 size, PRUint32 incr)
|
||||
{
|
||||
void *newp;
|
||||
|
||||
@ -258,7 +258,7 @@ PR_ArenaFinish()
|
||||
|
||||
#ifdef PR_ARENAMETER
|
||||
PR_PUBLIC_API(void)
|
||||
PR_ArenaCountAllocation(PRArenaPool *pool, size_t nb)
|
||||
PR_ArenaCountAllocation(PRArenaPool *pool, PRUint32 nb)
|
||||
{
|
||||
pool->stats.nallocs++;
|
||||
pool->stats.nbytes += nb;
|
||||
@ -268,13 +268,13 @@ PR_ArenaCountAllocation(PRArenaPool *pool, size_t nb)
|
||||
}
|
||||
|
||||
PR_PUBLIC_API(void)
|
||||
PR_ArenaCountInplaceGrowth(PRArenaPool *pool, size_t size, size_t incr)
|
||||
PR_ArenaCountInplaceGrowth(PRArenaPool *pool, PRUint32 size, PRUint32 incr)
|
||||
{
|
||||
pool->stats.ninplace++;
|
||||
}
|
||||
|
||||
PR_PUBLIC_API(void)
|
||||
PR_ArenaCountGrowth(PRArenaPool *pool, size_t size, size_t incr)
|
||||
PR_ArenaCountGrowth(PRArenaPool *pool, PRUint32 size, PRUint32 incr)
|
||||
{
|
||||
pool->stats.ngrows++;
|
||||
pool->stats.nbytes += incr;
|
||||
|
@ -164,8 +164,8 @@ struct PRArenaPool {
|
||||
* with a minimum size per arena of size bytes.
|
||||
*/
|
||||
extern PR_PUBLIC_API(void)
|
||||
PR_InitArenaPool(PRArenaPool *pool, const char *name, size_t size,
|
||||
size_t align);
|
||||
PR_InitArenaPool(PRArenaPool *pool, const char *name, PRUint32 size,
|
||||
PRUint32 align);
|
||||
|
||||
/*
|
||||
* Free the arenas in pool. The user may continue to allocate from pool
|
||||
@ -197,10 +197,10 @@ PR_ArenaFinish(void);
|
||||
* Friend functions used by the PR_ARENA_*() macros.
|
||||
*/
|
||||
extern PR_PUBLIC_API(void *)
|
||||
PR_ArenaAllocate(PRArenaPool *pool, size_t nb);
|
||||
PR_ArenaAllocate(PRArenaPool *pool, PRUint32 nb);
|
||||
|
||||
extern PR_PUBLIC_API(void *)
|
||||
PR_ArenaGrow(PRArenaPool *pool, void *p, size_t size, size_t incr);
|
||||
PR_ArenaGrow(PRArenaPool *pool, void *p, PRUint32 size, PRUint32 incr);
|
||||
|
||||
extern PR_PUBLIC_API(void)
|
||||
PR_ArenaRelease(PRArenaPool *pool, char *mark);
|
||||
@ -210,13 +210,13 @@ PR_ArenaRelease(PRArenaPool *pool, char *mark);
|
||||
#include <stdio.h>
|
||||
|
||||
extern PR_PUBLIC_API(void)
|
||||
PR_ArenaCountAllocation(PRArenaPool *pool, size_t nb);
|
||||
PR_ArenaCountAllocation(PRArenaPool *pool, PRUint32 nb);
|
||||
|
||||
extern PR_PUBLIC_API(void)
|
||||
PR_ArenaCountInplaceGrowth(PRArenaPool *pool, size_t size, size_t incr);
|
||||
PR_ArenaCountInplaceGrowth(PRArenaPool *pool, PRUint32 size, PRUint32 incr);
|
||||
|
||||
extern PR_PUBLIC_API(void)
|
||||
PR_ArenaCountGrowth(PRArenaPool *pool, size_t size, size_t incr);
|
||||
PR_ArenaCountGrowth(PRArenaPool *pool, PRUint32 size, PRUint32incr);
|
||||
|
||||
extern PR_PUBLIC_API(void)
|
||||
PR_ArenaCountRelease(PRArenaPool *pool, char *mark);
|
||||
|
@ -126,7 +126,7 @@ typedef struct PRTime PRTime;
|
||||
#endif /* _WIN16 */
|
||||
|
||||
#else /* Mac or Unix */
|
||||
|
||||
#define PR_IMPLEMENT(__type) __type
|
||||
#define PR_PUBLIC_API(__x) __x
|
||||
#define PR_IMPORT_API(__x) __x
|
||||
#define PR_PUBLIC_DATA(__x) __x
|
||||
@ -134,8 +134,6 @@ typedef struct PRTime PRTime;
|
||||
#define PR_CALLBACK
|
||||
#define PR_STATIC_CALLBACK(__x) static __x
|
||||
#define PR_EXTERN(__type) extern __type
|
||||
#define PR_IMPLEMENT(__type) __type
|
||||
|
||||
#endif /* Mac or Unix */
|
||||
|
||||
/************************************************************************/
|
||||
|
Loading…
Reference in New Issue
Block a user