зеркало из https://github.com/mozilla/gecko-dev.git
js.c jsemit.c jsemit.h jsgc.c jsinterp.c jsopcode.c jsopcode.def
- Switch improvements: - JSOP_CONDSWITCH is a 1 byte nop, not variable length with the same kind of immediate operand as JSOP_LOOKUPSWITCH (which is useless except for decompilation). New scheme uses SRC_COMMA notes on each JSOP_CASE opcode, usually 2 bytes per note, and a typically-1-byte 2nd offset on SRC_SWITCH: 1 + 2 * ncases vs. the previous JSOP_LOOKUPSWITCH immediate, which consumed: 4 * ncases bytes after the switch opcode just for decompilation. - SRC_SWITCH has two offsets, first to end of switch as before, the second to first case if JSOP_CONDSWITCH, for decompilation. - Optimize switches with all-constant cases using JSOP_TABLESWITH, or if that can't be used, JSOP_LOOKUPSWITCH, before falling back on ECMAv2's JSOP_CONDSWITCH. - Use cx->gcDisabled when evaluating case exprs at compile time for old, pre-ECMAv2 switches, to prevent branch-callback-based GC invocations from ripping apart the unrooted temporary script for each case expr. - Fixed up stale SRC_SWITCH comments in jsemit.h. jsemit.c jsemit.h - TREE_CONTEXT_INIT to match ATOM_LIST_INIT, not English word order. - Reorganized JSCodeGenerator to sort of match argument order to js_InitCodeGenerator. - Got rid of confusing CG_RESET* macros and used memset(cg, 0, sizeof *cg) and non-zero-default init in js_InitCodeGenerator. js_ResetCodeGenerator just releases the code and temp arena pools and leaves the cg in a state where it must be re-initialized (as before, but more obvious). - In the same spirit, don't do partial "resets" or src and trynotes in their js_FinishTaking*Notes functions -- those are friends of jsscript.c and are not general, idempotent functions. jsapi.c jsapi.h jsarray.c jsatom.c jsatom.h jscntxt.c jsemit.c jsmsg.def jsnum.c jsobj.c jsopcode.c jsregexp.c jsscan.c jsstr.c jsxdrapi. - Use PR_snprintf rather than sprintf always, so we don't have to worry about systems with 64-bit longs that overflow 12-byte buffers and open Morris-Worm-type security holes. - Trim extra spaces, fix hanging indentation, and similar anal retention. - Renamed JSMSG_BAD_PROTO_SORT to JSMSG_BAD_SORT_ARG cuz that's what it is complaining about. - SRC_CATCHGUARD still lived in comments, but it's SRC_CATCH in code. jscntxt.c jscntxt.h jsinterp.c - Packed nearby JSPackedBools and added a new one: gcDisabled, for use by jsemit.c's pre-ECMAv2 switch case expr eval. - Rip out old js_InterpreterHooks stuff from original liveconnect (moja). - Remove javaData and savedErrors from JSContext. Leaving it to fur or shaver to remove javaData from jsscript.h.
This commit is contained in:
Родитель
cb5493bab6
Коммит
347aaac8d3
|
@ -539,7 +539,7 @@ PCToLine(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
|
|||
static void
|
||||
SrcNotes(JSContext *cx, JSFunction *fun )
|
||||
{
|
||||
uintN offset, delta;
|
||||
uintN offset, delta, caseOff;
|
||||
jssrcnote *notes, *sn;
|
||||
JSSrcNoteType type;
|
||||
jsatomid atomIndex;
|
||||
|
@ -578,6 +578,12 @@ 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_SWITCH:
|
||||
printf(" length %u", (uintN) js_GetSrcNoteOffset(sn, 0));
|
||||
caseOff = (uintN) js_GetSrcNoteOffset(sn, 1);
|
||||
if (caseOff)
|
||||
printf(" first case offset %u", caseOff);
|
||||
break;
|
||||
case SRC_CATCH:
|
||||
delta = (uintN) js_GetSrcNoteOffset(sn, 0);
|
||||
if (delta)
|
||||
|
@ -723,6 +729,7 @@ DisassWithSrc(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval
|
|||
fclose(file);
|
||||
}
|
||||
return JS_TRUE;
|
||||
#undef LINE_BUF_LEN
|
||||
}
|
||||
|
||||
static JSBool
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
#include "prarena.h"
|
||||
#include "prassert.h"
|
||||
#include "prclist.h"
|
||||
#include "prprintf.h"
|
||||
#include "jsapi.h"
|
||||
#include "jsarray.h"
|
||||
#include "jsatom.h"
|
||||
|
@ -115,11 +116,10 @@ JS_ConvertArguments(JSContext *cx, uintN argc, jsval *argv, const char *format,
|
|||
fun = js_ValueToFunction(cx, &argv[-2], JS_FALSE);
|
||||
if (fun) {
|
||||
char numBuf[12];
|
||||
sprintf(numBuf, "%u", argc);
|
||||
PR_snprintf(numBuf, sizeof numBuf, "%u", argc);
|
||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
|
||||
JSMSG_MORE_ARGS_NEEDED,
|
||||
JS_GetFunctionName(fun),
|
||||
numBuf,
|
||||
JS_GetFunctionName(fun), numBuf,
|
||||
(argc == 1) ? "" : "s");
|
||||
}
|
||||
return JS_FALSE;
|
||||
|
@ -191,8 +191,8 @@ JS_ConvertArguments(JSContext *cx, uintN argc, jsval *argv, const char *format,
|
|||
default: {
|
||||
char charBuf[2] = " ";
|
||||
charBuf[0] = *cp;
|
||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
|
||||
JSMSG_BAD_CHAR, charBuf);
|
||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_CHAR,
|
||||
charBuf);
|
||||
return JS_FALSE;
|
||||
}
|
||||
}
|
||||
|
@ -249,13 +249,13 @@ JS_ConvertValue(JSContext *cx, jsval v, JSType type, jsval *vp)
|
|||
break;
|
||||
default: {
|
||||
char numBuf[12];
|
||||
sprintf(numBuf, "%d", (int)type);
|
||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
|
||||
JSMSG_BAD_TYPE, numBuf);
|
||||
PR_snprintf(numBuf, sizeof numBuf, "%d", (int)type);
|
||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_TYPE,
|
||||
numBuf);
|
||||
ok = JS_FALSE;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
|
@ -1704,7 +1704,7 @@ JS_AliasElement(JSContext *cx, JSObject *obj, const char *name, jsint alias)
|
|||
if (obj2 != obj || !OBJ_IS_NATIVE(obj2)) {
|
||||
char numBuf[12];
|
||||
OBJ_DROP_PROPERTY(cx, obj2, prop);
|
||||
sprintf(numBuf, "%ld", (long)alias);
|
||||
PR_snprintf(numBuf, sizeof numBuf, "%ld", (long)alias);
|
||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_ALIAS,
|
||||
numBuf, name, OBJ_GET_CLASS(cx, obj2)->name);
|
||||
return JS_FALSE;
|
||||
|
|
|
@ -949,12 +949,11 @@ JS_ReportOutOfMemory(JSContext *cx);
|
|||
struct JSErrorReport {
|
||||
const char *filename; /* source file name, URL, etc., or null */
|
||||
uintN lineno; /* source line number */
|
||||
const char *linebuf; /* offending source line without final '\n' */
|
||||
const char *linebuf; /* offending source line without final \n */
|
||||
const char *tokenptr; /* pointer to error token in linebuf */
|
||||
const jschar *uclinebuf; /* unicode (original) line buffer */
|
||||
const jschar *uctokenptr;/* unicode (original) token pointer */
|
||||
const jschar *uctokenptr; /* unicode (original) token pointer */
|
||||
uintN flags; /* error/warning, etc. */
|
||||
|
||||
uintN errorNumber; /* the error number, e.g. see jsmsg.def */
|
||||
JSString *ucmessage; /* the (default) error message */
|
||||
JSString **messageArgs; /* arguments for the error message */
|
||||
|
|
|
@ -24,7 +24,6 @@
|
|||
#include <string.h>
|
||||
#include "prtypes.h"
|
||||
#include "prassert.h"
|
||||
#include "prprintf.h"
|
||||
#include "jsapi.h"
|
||||
#include "jsarray.h"
|
||||
#include "jsatom.h"
|
||||
|
@ -699,7 +698,7 @@ array_sort(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
|
|||
if (argc > 0) {
|
||||
if (JSVAL_IS_PRIMITIVE(argv[0])) {
|
||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
|
||||
JSMSG_BAD_PROTO_SORT);
|
||||
JSMSG_BAD_SORT_ARG);
|
||||
return JS_FALSE;
|
||||
}
|
||||
fval = argv[0];
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#include "prtypes.h"
|
||||
#include "prassert.h"
|
||||
#include "prhash.h"
|
||||
#include "prprintf.h"
|
||||
#include "jsapi.h"
|
||||
#include "jsatom.h"
|
||||
#include "jscntxt.h"
|
||||
|
@ -606,7 +607,7 @@ js_GetAtom(JSContext *cx, JSAtomMap *map, jsatomid i)
|
|||
PR_ASSERT(map->vector && i < map->length);
|
||||
if (!map->vector || i >= map->length) {
|
||||
char numBuf[12];
|
||||
sprintf(numBuf, "%s", (long)i);
|
||||
PR_snprintf(numBuf, sizeof numBuf, "%lu", (unsigned long)i);
|
||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
|
||||
JSMSG_BAD_ATOMIC_NUMBER, numBuf);
|
||||
return NULL;
|
||||
|
|
|
@ -40,14 +40,6 @@
|
|||
#include "jsscan.h"
|
||||
#include "jsscript.h"
|
||||
|
||||
JSInterpreterHooks *js_InterpreterHooks = NULL;
|
||||
|
||||
JS_FRIEND_API(void)
|
||||
js_SetInterpreterHooks(JSInterpreterHooks *hooks)
|
||||
{
|
||||
js_InterpreterHooks = hooks;
|
||||
}
|
||||
|
||||
JSContext *
|
||||
js_NewContext(JSRuntime *rt, size_t stacksize)
|
||||
{
|
||||
|
@ -103,11 +95,6 @@ js_DestroyContext(JSContext *cx)
|
|||
rtempty = (rt->contextList.next == (PRCList *)&rt->contextList);
|
||||
JS_UNLOCK_RUNTIME(rt);
|
||||
|
||||
if (js_InterpreterHooks && js_InterpreterHooks->destroyContext) {
|
||||
/* This is a stub, but in case it removes roots, call it now. */
|
||||
js_InterpreterHooks->destroyContext(cx);
|
||||
}
|
||||
|
||||
if (rtempty) {
|
||||
/* Unpin all pinned atoms before final GC. */
|
||||
js_UnpinPinnedAtoms(&rt->atomState);
|
||||
|
@ -209,14 +196,14 @@ js_ReportErrorVA(JSContext *cx, uintN flags, const char *format, va_list ap)
|
|||
*/
|
||||
JSBool
|
||||
js_ExpandErrorArguments(JSContext *cx, JSErrorCallback callback,
|
||||
void *userRef, const uintN errorNumber, char **message,
|
||||
JSErrorReport *reportp, va_list ap)
|
||||
void *userRef, const uintN errorNumber,
|
||||
char **messagep, JSErrorReport *reportp, va_list ap)
|
||||
{
|
||||
const JSErrorFormatString *fmtData;
|
||||
int i;
|
||||
int argCount;
|
||||
|
||||
*message = NULL;
|
||||
*messagep = NULL;
|
||||
if (callback) {
|
||||
fmtData = (*callback)(userRef, "Mountain View", errorNumber);
|
||||
if (fmtData != NULL) {
|
||||
|
@ -250,7 +237,7 @@ js_ExpandErrorArguments(JSContext *cx, JSErrorCallback callback,
|
|||
expandedLength
|
||||
+= strlen((char *)reportp->messageArgs[i]);
|
||||
}
|
||||
*message = out = malloc(expandedLength + 1);
|
||||
*messagep = out = malloc(expandedLength + 1);
|
||||
if (!out) {
|
||||
if (reportp->messageArgs) {
|
||||
free(reportp->messageArgs);
|
||||
|
@ -285,20 +272,21 @@ js_ExpandErrorArguments(JSContext *cx, JSErrorCallback callback,
|
|||
JS_NewStringCopyZ(cx, (char *)reportp->messageArgs[i]);
|
||||
}
|
||||
} else {
|
||||
*message = JS_strdup(cx, fmtData->format);
|
||||
*messagep = JS_strdup(cx, fmtData->format);
|
||||
}
|
||||
/*
|
||||
* And finally convert the message.
|
||||
*/
|
||||
reportp->ucmessage = JS_NewStringCopyZ(cx, *message);
|
||||
reportp->ucmessage = JS_NewStringCopyZ(cx, *messagep);
|
||||
}
|
||||
}
|
||||
if (*message == NULL) {
|
||||
if (*messagep == NULL) {
|
||||
/* where's the right place for this ??? */
|
||||
const char *defaultErrorMessage
|
||||
= "No error message available for error number %d";
|
||||
*message = (char *)malloc(strlen(defaultErrorMessage) + 16);
|
||||
sprintf(*message, defaultErrorMessage, errorNumber);
|
||||
size_t nbytes = strlen(defaultErrorMessage) + 16;
|
||||
*messagep = (char *)malloc(nbytes);
|
||||
PR_snprintf(*messagep, nbytes, defaultErrorMessage, errorNumber);
|
||||
}
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
@ -308,7 +296,7 @@ js_ReportErrorNumberVA(JSContext *cx, uintN flags, JSErrorCallback callback,
|
|||
void *userRef, const uintN errorNumber, va_list ap)
|
||||
{
|
||||
JSStackFrame *fp;
|
||||
JSErrorReport report, *reportp;
|
||||
JSErrorReport report;
|
||||
char *message;
|
||||
|
||||
report.messageArgs = NULL;
|
||||
|
@ -319,22 +307,19 @@ js_ReportErrorNumberVA(JSContext *cx, uintN flags, JSErrorCallback callback,
|
|||
if (fp && fp->script && fp->pc) {
|
||||
report.filename = fp->script->filename;
|
||||
report.lineno = js_PCToLineNumber(fp->script, fp->pc);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
report.filename = NULL;
|
||||
report.lineno = 0;
|
||||
}
|
||||
|
||||
/* XXX should fetch line somehow */
|
||||
report.linebuf = NULL;
|
||||
report.tokenptr = NULL;
|
||||
report.flags = flags;
|
||||
|
||||
report.errorNumber = errorNumber;
|
||||
|
||||
reportp = &report;
|
||||
|
||||
if (!js_ExpandErrorArguments(cx, callback, userRef, errorNumber,
|
||||
&message, reportp, ap))
|
||||
&message, &report, ap))
|
||||
return;
|
||||
|
||||
#if JS_HAS_ERROR_EXCEPTIONS
|
||||
|
@ -344,10 +329,10 @@ js_ReportErrorNumberVA(JSContext *cx, uintN flags, JSErrorCallback callback,
|
|||
* exception is thrown, then the JSREPORT_EXCEPTION flag will be set
|
||||
* on the error report, and exception-aware hosts should ignore it.
|
||||
*/
|
||||
js_ErrorToException(cx, reportp, message);
|
||||
js_ErrorToException(cx, &report, message);
|
||||
#endif
|
||||
|
||||
js_ReportErrorAgain(cx, message, reportp);
|
||||
js_ReportErrorAgain(cx, message, &report);
|
||||
|
||||
if (message)
|
||||
free(message);
|
||||
|
|
|
@ -150,31 +150,20 @@ struct JSContext {
|
|||
/* Client opaque pointer */
|
||||
void *data;
|
||||
|
||||
/* Java environment and JS errors to throw as exceptions. */
|
||||
void *javaEnv;
|
||||
void *savedErrors;
|
||||
|
||||
/* GC and thread-safe state. */
|
||||
JSStackFrame *dormantFrameChain; /* dormant stack frame to scan */
|
||||
uint32 gcDisabled; /* XXX for pre-ECMAv2 switch */
|
||||
#ifdef JS_THREADSAFE
|
||||
prword thread;
|
||||
JSPackedBool gcActive;
|
||||
jsrefcount requestDepth;
|
||||
JSPackedBool gcActive;
|
||||
#endif
|
||||
JSStackFrame *dormantFrameChain; /* dormant frame chains */
|
||||
|
||||
/* Exception state (NB: throwing is packed with gcActive above). */
|
||||
JSPackedBool throwing; /* is there a pending exception? */
|
||||
jsval exception; /* most-recently-thrown exceptin */
|
||||
};
|
||||
|
||||
typedef struct JSInterpreterHooks {
|
||||
void (*destroyContext)(JSContext *cx);
|
||||
void (*destroyScript)(JSContext *cx, JSScript *script);
|
||||
void (*destroyFrame)(JSContext *cx, JSStackFrame *frame);
|
||||
} JSInterpreterHooks;
|
||||
|
||||
extern JSInterpreterHooks *js_InterpreterHooks;
|
||||
|
||||
extern JS_FRIEND_API(void)
|
||||
js_SetInterpreterHooks(JSInterpreterHooks *hooks);
|
||||
|
||||
extern JSContext *
|
||||
js_NewContext(JSRuntime *rt, size_t stacksize);
|
||||
|
||||
|
|
224
js/ref/jsemit.c
224
js/ref/jsemit.c
|
@ -21,12 +21,11 @@
|
|||
*/
|
||||
#include "jsstddef.h"
|
||||
#include <memory.h>
|
||||
|
||||
|
||||
#include <string.h>
|
||||
#include "prtypes.h"
|
||||
#include "prarena.h"
|
||||
#include "prassert.h"
|
||||
#include "prprintf.h"
|
||||
#include "jsapi.h"
|
||||
#include "jscntxt.h"
|
||||
#include "jsconfig.h"
|
||||
|
@ -45,6 +44,7 @@ js_InitCodeGenerator(JSContext *cx, JSCodeGenerator *cg,
|
|||
const char *filename, uintN lineno,
|
||||
JSPrincipals *principals)
|
||||
{
|
||||
memset(cx, 0, sizeof *cg);
|
||||
cg->codeMark = PR_ARENA_MARK(&cx->codePool);
|
||||
cg->tempMark = PR_ARENA_MARK(&cx->tempPool);
|
||||
PR_ARENA_ALLOCATE(cg->base, &cx->codePool, CGINCR);
|
||||
|
@ -52,12 +52,13 @@ js_InitCodeGenerator(JSContext *cx, JSCodeGenerator *cg,
|
|||
JS_ReportOutOfMemory(cx);
|
||||
return JS_FALSE;
|
||||
}
|
||||
cg->next = cg->base;
|
||||
cg->limit = CG_CODE(cg, CGINCR);
|
||||
cg->filename = filename;
|
||||
cg->firstLine = lineno;
|
||||
cg->firstLine = cg->currentLine = lineno;
|
||||
cg->principals = principals;
|
||||
cg->tryBase = cg->tryLimit = NULL;
|
||||
CG_RESET(cg);
|
||||
TREE_CONTEXT_INIT(&cg->treeContext);
|
||||
ATOM_LIST_INIT(&cg->atomList);
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
|
@ -66,7 +67,6 @@ js_ResetCodeGenerator(JSContext *cx, JSCodeGenerator *cg)
|
|||
{
|
||||
PR_ARENA_RELEASE(&cx->codePool, cg->codeMark);
|
||||
PR_ARENA_RELEASE(&cx->tempPool, cg->tempMark);
|
||||
CG_RESET(cg);
|
||||
}
|
||||
|
||||
static ptrdiff_t
|
||||
|
@ -77,8 +77,6 @@ EmitCheck(JSContext *cx, JSCodeGenerator *cg, JSOp op, ptrdiff_t delta)
|
|||
|
||||
PR_ASSERT(delta < CGINCR);
|
||||
offset = CG_OFFSET(cg);
|
||||
if (op != JSOP_NOP)
|
||||
cg->lastCodeOffset = offset;
|
||||
if ((pruword)cg->next + delta >= (pruword)cg->limit) {
|
||||
length = PTRDIFF(cg->limit, cg->base, jsbytecode);
|
||||
cgsize = length * sizeof(jsbytecode);
|
||||
|
@ -108,7 +106,7 @@ UpdateDepth(JSContext *cx, JSCodeGenerator *cg, ptrdiff_t target)
|
|||
cg->stackDepth -= nuses;
|
||||
if (cg->stackDepth < 0) {
|
||||
char numBuf[12];
|
||||
sprintf(numBuf, "%d", target);
|
||||
PR_snprintf(numBuf, sizeof numBuf, "%d", target);
|
||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
|
||||
JSMSG_STACK_UNDERFLOW,
|
||||
cg->filename ? cg->filename : "stdin", numBuf);
|
||||
|
@ -201,8 +199,8 @@ StatementName(JSCodeGenerator *cg)
|
|||
static void
|
||||
ReportStatementTooLarge(JSContext *cx, JSCodeGenerator *cg)
|
||||
{
|
||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
|
||||
JSMSG_NEED_DIET, StatementName(cg));
|
||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_NEED_DIET,
|
||||
StatementName(cg));
|
||||
}
|
||||
|
||||
JSBool
|
||||
|
@ -242,8 +240,9 @@ EmitGoto(JSContext *cx, JSCodeGenerator *cg, JSStmtInfo *toStmt,
|
|||
case STMT_FINALLY:
|
||||
if (js_NewSrcNote(cx, cg, SRC_HIDDEN) < 0 ||
|
||||
js_Emit3(cx, cg, JSOP_GOSUB, JUMP_OFFSET_HI(finallyIndex),
|
||||
JUMP_OFFSET_LO(finallyIndex)) < 0)
|
||||
JUMP_OFFSET_LO(finallyIndex)) < 0) {
|
||||
return -1;
|
||||
}
|
||||
finallyIndex--;
|
||||
break;
|
||||
case STMT_WITH:
|
||||
|
@ -446,6 +445,8 @@ js_EmitFunctionBody(JSContext *cx, JSCodeGenerator *cg, JSParseNode *body,
|
|||
}
|
||||
|
||||
#if JS_HAS_EXCEPTIONS
|
||||
|
||||
/* XXX use PatchGotos-style back-patch chaining, not bytecode-linear search */
|
||||
#define BYTECODE_ITER(pc, max, body) \
|
||||
while (pc < max) { \
|
||||
JSCodeSpec *cs = &js_CodeSpec[(JSOp)*pc]; \
|
||||
|
@ -495,7 +496,7 @@ FixupCatchJumps(JSContext *cx, JSCodeGenerator *cg, ptrdiff_t tryStart,
|
|||
return JS_TRUE;
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif /* JS_HAS_EXCEPTIONS */
|
||||
|
||||
JSBool
|
||||
js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
|
||||
|
@ -664,6 +665,7 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
|
|||
uint32 ncases, tablen;
|
||||
JSScript *script;
|
||||
jsint i, low, high;
|
||||
jsdouble d;
|
||||
size_t switchsize, tablesize;
|
||||
void *mark;
|
||||
JSParseNode **table;
|
||||
|
@ -671,9 +673,10 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
|
|||
JSBool hasDefault = JS_FALSE;
|
||||
JSBool isEcmaSwitch = cx->version == JSVERSION_DEFAULT ||
|
||||
cx->version >= JSVERSION_1_4;
|
||||
ptrdiff_t defaultOpPc = -1;
|
||||
ptrdiff_t defaultOffset = -1;
|
||||
|
||||
switchop = isEcmaSwitch ? JSOP_CONDSWITCH : JSOP_TABLESWITCH;
|
||||
/* Try for most optimal, fall back if not dense ints, and per ECMAv2. */
|
||||
switchop = JSOP_TABLESWITCH;
|
||||
|
||||
/* Emit code for the discriminant first. */
|
||||
if (!js_EmitTree(cx, cg, pn->pn_kid1))
|
||||
|
@ -701,8 +704,41 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
|
|||
continue;
|
||||
}
|
||||
PR_ASSERT(pn3->pn_type == TOK_CASE);
|
||||
pn4 = pn3->pn_left;
|
||||
if (isEcmaSwitch) {
|
||||
if (switchop == JSOP_CONDSWITCH)
|
||||
continue;
|
||||
switch (pn4->pn_type) {
|
||||
case TOK_NUMBER:
|
||||
d = pn4->pn_dval;
|
||||
if (JSDOUBLE_IS_INT(d, i) && INT_FITS_IN_JSVAL(i)) {
|
||||
pn3->pn_val = INT_TO_JSVAL(i);
|
||||
} else {
|
||||
atom = js_AtomizeDouble(cx, d, 0);
|
||||
if (!atom)
|
||||
return JS_FALSE;
|
||||
pn3->pn_val = ATOM_KEY(atom);
|
||||
}
|
||||
break;
|
||||
case TOK_STRING:
|
||||
pn3->pn_val = ATOM_KEY(pn4->pn_atom);
|
||||
break;
|
||||
case TOK_PRIMARY:
|
||||
if (pn4->pn_op == JSOP_TRUE) {
|
||||
pn3->pn_val = JSVAL_TRUE;
|
||||
break;
|
||||
}
|
||||
if (pn4->pn_op == JSOP_FALSE) {
|
||||
pn3->pn_val = JSVAL_FALSE;
|
||||
break;
|
||||
}
|
||||
/* FALL THROUGH */
|
||||
default:
|
||||
switchop = JSOP_CONDSWITCH;
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
/* Pre-ECMAv2 switch evals case exprs at compile time. */
|
||||
if (!cg2.base) {
|
||||
if (!js_InitCodeGenerator(cx, &cg2, cg->filename,
|
||||
pn3->pn_pos.begin.lineno,
|
||||
|
@ -712,7 +748,6 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
|
|||
} else {
|
||||
js_ResetCodeGenerator(cx, &cg2);
|
||||
}
|
||||
pn4 = pn3->pn_left;
|
||||
cg2.currentLine = pn4->pn_pos.begin.lineno;
|
||||
if (!js_EmitTree(cx, &cg2, pn4))
|
||||
return JS_FALSE;
|
||||
|
@ -723,29 +758,31 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
|
|||
return JS_FALSE;
|
||||
|
||||
/*
|
||||
* The GC must not run during this case expression
|
||||
* evaluation. It won't if it runs only from the
|
||||
* branch callback (because the only branches possible
|
||||
* in a case expression come from ?: expressions,
|
||||
* and those generate downward branches, while the
|
||||
* branch callback runs only for upward branches).
|
||||
* XXX - but function calls are possible!
|
||||
* XXX The GC must not run during this case expr eval, so
|
||||
* kludge cx->gcDisabled to keep it at bay. The current GC
|
||||
* rules say that the GC can run only when no requests are
|
||||
* active, or when the only active request explicitly calls
|
||||
* JS_GC or JS_MaybeGC from its branch callback.
|
||||
*/
|
||||
cx->gcDisabled++;
|
||||
ok = js_Execute(cx, cx->fp->scopeChain, script, NULL,
|
||||
cx->fp, JS_FALSE, &pn3->pn_val);
|
||||
cx->gcDisabled--;
|
||||
js_DestroyScript(cx, script);
|
||||
if (!ok)
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
if (!JSVAL_IS_NUMBER(pn3->pn_val) &&
|
||||
!JSVAL_IS_STRING(pn3->pn_val) &&
|
||||
!JSVAL_IS_BOOLEAN(pn3->pn_val)) {
|
||||
char numBuf[12];
|
||||
sprintf(numBuf, "%u", pn4->pn_pos.begin.lineno);
|
||||
PR_snprintf(numBuf, sizeof numBuf, "%u",
|
||||
pn4->pn_pos.begin.lineno);
|
||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
|
||||
JSMSG_BAD_CASE,
|
||||
cg2.filename ? cg2.filename : "stdin",
|
||||
numBuf);
|
||||
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
|
@ -765,7 +802,10 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
|
|||
if (high < i)
|
||||
high = i;
|
||||
}
|
||||
if (switchop != JSOP_CONDSWITCH && cg2.base)
|
||||
if (switchop == JSOP_CONDSWITCH) {
|
||||
PR_ASSERT(!cg2.base);
|
||||
} else {
|
||||
if (cg2.base)
|
||||
js_ResetCodeGenerator(cx, &cg2);
|
||||
if (switchop == JSOP_TABLESWITCH) {
|
||||
tablen = (uint32)(high - low + 1);
|
||||
|
@ -773,19 +813,29 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
|
|||
switchop = JSOP_LOOKUPSWITCH;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Emit a note with an offset telling total switch code length. */
|
||||
noteIndex = js_NewSrcNote2(cx, cg, SRC_SWITCH, 0);
|
||||
/*
|
||||
* Emit a note with two offsets: first tells total switch code length,
|
||||
* second tells offset to first JSOP_CASE if condswitch.
|
||||
*/
|
||||
noteIndex = js_NewSrcNote3(cx, cg, SRC_SWITCH, 0, 0);
|
||||
if (noteIndex < 0)
|
||||
return JS_FALSE;
|
||||
|
||||
if (switchop == JSOP_TABLESWITCH) {
|
||||
if (switchop == JSOP_CONDSWITCH) {
|
||||
/*
|
||||
* 0 bytes of immediate for unoptimized ECMAv2 switch.
|
||||
*/
|
||||
switchsize = 0;
|
||||
} else if (switchop == JSOP_TABLESWITCH) {
|
||||
/*
|
||||
* 3 offsets (len, low, high) before the table, 1 per entry.
|
||||
*/
|
||||
switchsize = (size_t)(6 + 2 * tablen);
|
||||
} else {
|
||||
/*
|
||||
* JSOP_LOOKUPSWITCH:
|
||||
* 1 offset (len) and 1 atom index (npairs) before the table,
|
||||
* 1 atom index and 1 jump offset per entry.
|
||||
*/
|
||||
|
@ -797,24 +847,39 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
|
|||
return JS_FALSE;
|
||||
|
||||
if (switchop == JSOP_CONDSWITCH) {
|
||||
intN caseNoteIndex = -1;
|
||||
|
||||
/* Emit code for evaluating cases and jumping to case statements. */
|
||||
if (!js_SetJumpOffset(cx, cg, CG_CODE(cg, top),
|
||||
CG_OFFSET(cg) - top))
|
||||
return JS_FALSE;
|
||||
for (pn3 = pn2->pn_head; pn3; pn3 = pn3->pn_next) {
|
||||
pn4 = pn3->pn_left;
|
||||
if (pn4 && !js_EmitTree(cx, cg, pn4))
|
||||
return JS_FALSE;
|
||||
if (caseNoteIndex >= 0) {
|
||||
/* off is the previous JSOP_CASE's bytecode offset. */
|
||||
if (!js_SetSrcNoteOffset(cx, cg, caseNoteIndex, 0,
|
||||
CG_OFFSET(cg) - off)) {
|
||||
return JS_FALSE;
|
||||
}
|
||||
}
|
||||
if (pn3->pn_type == TOK_DEFAULT)
|
||||
continue;
|
||||
pn4 = pn3->pn_left;
|
||||
if (!js_EmitTree(cx, cg, pn4))
|
||||
caseNoteIndex = js_NewSrcNote2(cx, cg, SRC_COMMA, 0);
|
||||
if (caseNoteIndex < 0)
|
||||
return JS_FALSE;
|
||||
pn3->pn_offset = js_Emit3(cx, cg, JSOP_CASE, 0, 0);
|
||||
if (pn3->pn_offset < 0)
|
||||
off = js_Emit3(cx, cg, JSOP_CASE, 0, 0);
|
||||
if (off < 0)
|
||||
return JS_FALSE;
|
||||
pn3->pn_offset = off;
|
||||
if (pn3 == pn2->pn_head) {
|
||||
/* Switch note's second offset is to first JSOP_CASE. */
|
||||
if (!js_SetSrcNoteOffset(cx, cg, noteIndex, 1, off - top))
|
||||
return JS_FALSE;
|
||||
pn3->pn_offset;
|
||||
}
|
||||
}
|
||||
|
||||
/* Emit default even if no explicit default statement. */
|
||||
defaultOpPc = js_Emit3(cx, cg, JSOP_DEFAULT, 0, 0);
|
||||
if (defaultOpPc < 0)
|
||||
defaultOffset = js_Emit3(cx, cg, JSOP_DEFAULT, 0, 0);
|
||||
if (defaultOffset < 0)
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
|
@ -833,30 +898,31 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
|
|||
}
|
||||
|
||||
if (!hasDefault) {
|
||||
/* If no default case, offset for default is to end of switch */
|
||||
/* If no default case, offset for default is to end of switch. */
|
||||
off = CG_OFFSET(cg) - top;
|
||||
}
|
||||
|
||||
/* Set the default offset (to end of switch if no default). */
|
||||
if (switchop == JSOP_CONDSWITCH) {
|
||||
PR_ASSERT(defaultOffset != -1);
|
||||
if (!js_SetJumpOffset(cx, cg, CG_CODE(cg, defaultOffset),
|
||||
off - (defaultOffset - top))) {
|
||||
return JS_FALSE;
|
||||
}
|
||||
} else {
|
||||
pc = CG_CODE(cg, top);
|
||||
if (switchop != JSOP_CONDSWITCH) {
|
||||
if (!js_SetJumpOffset(cx, cg, pc, off))
|
||||
return JS_FALSE;
|
||||
}
|
||||
if (defaultOpPc != -1) {
|
||||
if (!js_SetJumpOffset(cx, cg, CG_CODE(cg, defaultOpPc),
|
||||
off - (defaultOpPc - top)))
|
||||
return JS_FALSE;
|
||||
}
|
||||
pc += 2;
|
||||
}
|
||||
|
||||
/* Set the SRC_SWITCH note's offset operand to tell end of switch. */
|
||||
off = CG_OFFSET(cg) - top;
|
||||
if (!js_SetSrcNoteOffset(cx, cg, noteIndex, 0, (ptrdiff_t)off))
|
||||
if (!js_SetSrcNoteOffset(cx, cg, noteIndex, 0, off))
|
||||
return JS_FALSE;
|
||||
|
||||
/* Fill in jump or lookup table. */
|
||||
if (switchop == JSOP_TABLESWITCH) {
|
||||
/* Fill in jump table. */
|
||||
if (!js_SetJumpOffset(cx, cg, pc, low))
|
||||
return JS_FALSE;
|
||||
pc += 2;
|
||||
|
@ -890,7 +956,8 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
|
|||
}
|
||||
PR_ARENA_RELEASE(&cx->tempPool, mark);
|
||||
}
|
||||
} else {
|
||||
} else if (switchop == JSOP_LOOKUPSWITCH) {
|
||||
/* Fill in lookup table. */
|
||||
SET_ATOM_INDEX(pc, ncases);
|
||||
pc += 2;
|
||||
|
||||
|
@ -1193,7 +1260,7 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
|
|||
if (!js_Emit3(cx, cg, JSOP_GOSUB, 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 GOSUB being written into the bytecode
|
||||
|
@ -1213,9 +1280,9 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
|
|||
|
||||
/*
|
||||
* About SETSP:
|
||||
* An exception can be thrown while the stack is in an
|
||||
* unbalanced state, and this causes problems with things like
|
||||
* function invocation later on.
|
||||
* An exception can be thrown while the stack is in an unbalanced
|
||||
* state, and this causes problems with things like function invocation
|
||||
* later on.
|
||||
*
|
||||
* To fix this, we compute the `balanced' stack depth upon try entry,
|
||||
* and then restore the stack to this depth when we hit the first catch
|
||||
|
@ -1256,7 +1323,7 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
|
|||
* pushobj
|
||||
* newinit
|
||||
* exception
|
||||
* initprop <atom> maybe marked SRC_CATCHGUARD
|
||||
* initprop <atom> marked SRC_CATCH
|
||||
* enterwith
|
||||
* [< catchguard code >] if there's a catchguard
|
||||
* ifeq <offset to next catch block>
|
||||
|
@ -1402,9 +1469,10 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
|
|||
return JS_FALSE;
|
||||
}
|
||||
|
||||
/* if we've got a finally, it goes here, and we have to fix up
|
||||
the gosubs that might have been emitted before non-local jumps */
|
||||
|
||||
/*
|
||||
* If we've got a finally, it goes here, and we have to fix up
|
||||
* the gosubs that might have been emitted before non-local jumps.
|
||||
*/
|
||||
if (pn->pn_kid3) {
|
||||
ptrdiff_t finallyIndex;
|
||||
finallyIndex = CG_OFFSET(cg);
|
||||
|
@ -2140,10 +2208,10 @@ uint8 js_SrcNoteArity[] = {
|
|||
0, /* SRC_ENDBRACE */
|
||||
1, /* SRC_BREAK2LABEL */
|
||||
1, /* SRC_CONT2LABEL */
|
||||
1, /* SRC_SWITCH */
|
||||
2, /* SRC_SWITCH */
|
||||
1, /* SRC_FUNCDEF */
|
||||
1, /* SRC_TRYFIN */
|
||||
1, /* SRC_CATCHGUARD */
|
||||
1, /* SRC_CATCH */
|
||||
0, /* SRC_NEWLINE */
|
||||
1, /* SRC_SETLINE */
|
||||
0 /* SRC_XDELTA */
|
||||
|
@ -2181,7 +2249,7 @@ js_NewSrcNote(JSContext *cx, JSCodeGenerator *cg, JSSrcNoteType type)
|
|||
{
|
||||
intN index, n;
|
||||
jssrcnote *sn;
|
||||
ptrdiff_t offset, saveOffset, delta, xdelta;
|
||||
ptrdiff_t offset, delta, xdelta;
|
||||
|
||||
/*
|
||||
* Claim a note slot in cg->notes by growing it if necessary and then
|
||||
|
@ -2195,8 +2263,7 @@ js_NewSrcNote(JSContext *cx, JSCodeGenerator *cg, JSSrcNoteType type)
|
|||
* big to fit in sn, allocate one or more xdelta notes and reset sn.
|
||||
*/
|
||||
offset = CG_OFFSET(cg);
|
||||
saveOffset = cg->lastNoteOffset;
|
||||
delta = offset - saveOffset;
|
||||
delta = offset - cg->lastNoteOffset;
|
||||
cg->lastNoteOffset = offset;
|
||||
if (delta >= SN_DELTA_LIMIT) {
|
||||
do {
|
||||
|
@ -2281,7 +2348,7 @@ js_SrcNoteLength(jssrcnote *sn)
|
|||
return 1;
|
||||
for (base = sn++; --arity >= 0; sn++) {
|
||||
if (*sn & SN_3BYTE_OFFSET_FLAG)
|
||||
sn +=2 ;
|
||||
sn +=2;
|
||||
}
|
||||
return sn - base;
|
||||
}
|
||||
|
@ -2296,8 +2363,10 @@ js_GetSrcNoteOffset(jssrcnote *sn, uintN which)
|
|||
if (*sn & SN_3BYTE_OFFSET_FLAG)
|
||||
sn += 2;
|
||||
}
|
||||
if (*sn & SN_3BYTE_OFFSET_FLAG)
|
||||
return (ptrdiff_t)((((uint32)(*sn & SN_3BYTE_OFFSET_MASK)) << 16) | (sn[1] << 8) | sn[2]);
|
||||
if (*sn & SN_3BYTE_OFFSET_FLAG) {
|
||||
return (ptrdiff_t)((((uint32)(sn[0] & SN_3BYTE_OFFSET_MASK)) << 16)
|
||||
| (sn[1] << 8) | sn[2]);
|
||||
}
|
||||
return (ptrdiff_t)*sn;
|
||||
}
|
||||
|
||||
|
@ -2365,7 +2434,6 @@ js_FinishTakingSrcNotes(JSContext *cx, JSCodeGenerator *cg)
|
|||
return NULL;
|
||||
memcpy(final, tmp, count * sizeof(jssrcnote));
|
||||
SN_MAKE_TERMINATOR(&final[count]);
|
||||
CG_RESET_NOTES(cg);
|
||||
return final;
|
||||
}
|
||||
|
||||
|
@ -2373,32 +2441,16 @@ JSBool
|
|||
js_AllocTryNotes(JSContext *cx, JSCodeGenerator *cg)
|
||||
{
|
||||
size_t size;
|
||||
|
||||
if (!cg->treeContext.tryCount)
|
||||
return JS_TRUE;
|
||||
|
||||
if (!cg->tryBase) {
|
||||
PR_ASSERT(!cg->tryBase);
|
||||
size = (cg->treeContext.tryCount + 1) * sizeof(JSTryNote);
|
||||
PR_ARENA_ALLOCATE(cg->tryBase, &cx->tempPool, size);
|
||||
if (!cg->tryBase)
|
||||
return JS_FALSE;
|
||||
cg->tryNext = cg->tryBase;
|
||||
} else {
|
||||
/* already have some TryNotes here, so extend them. */
|
||||
ptrdiff_t nextOffset = cg->tryNext - cg->tryBase;
|
||||
size_t oldsize = (char *)cg->tryLimit - (char *)cg->tryBase;
|
||||
size = oldsize + cg->treeContext.tryCount * sizeof(JSTryNote);
|
||||
|
||||
PR_ARENA_GROW(cg->tryBase, &cx->tempPool, oldsize, size);
|
||||
if (!cg->tryBase)
|
||||
return JS_FALSE;
|
||||
|
||||
/* need to reset tryNext because GROW may relocate the block */
|
||||
cg->tryNext = (JSTryNote *)((char *)cg->tryBase + nextOffset);
|
||||
}
|
||||
cg->tryLimit = (JSTryNote *)((char *)cg->tryBase + size);
|
||||
|
||||
/* reset tryCount */
|
||||
cg->treeContext.tryCount = 0;
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
|
@ -2408,7 +2460,7 @@ js_NewTryNote(JSContext *cx, JSCodeGenerator *cg, ptrdiff_t start,
|
|||
{
|
||||
JSTryNote *tn;
|
||||
|
||||
PR_ASSERT(cg->tryNext < cg->tryLimit);
|
||||
PR_ASSERT(cg->tryBase <= cg->tryNext && cg->tryNext < cg->tryLimit);
|
||||
tn = cg->tryNext++;
|
||||
tn->start = start;
|
||||
tn->length = end - start;
|
||||
|
|
|
@ -75,7 +75,7 @@ struct JSTreeContext { /* tree context for semantic checks */
|
|||
#define TCF_RETURN_VOID 0x04 /* function has 'return;' */
|
||||
#define TCF_IN_FOR_INIT 0x08 /* parsing init expr of for; exclude 'in' */
|
||||
|
||||
#define INIT_TREE_CONTEXT(tc) \
|
||||
#define TREE_CONTEXT_INIT(tc) \
|
||||
((tc)->flags = 0, (tc)->tryCount = 0, (tc)->topStmt = NULL)
|
||||
|
||||
struct JSCodeGenerator {
|
||||
|
@ -84,37 +84,24 @@ struct JSCodeGenerator {
|
|||
jsbytecode *base; /* base of JS bytecode vector */
|
||||
jsbytecode *limit; /* one byte beyond end of bytecode */
|
||||
jsbytecode *next; /* pointer to next free bytecode */
|
||||
JSAtomList atomList; /* literals indexed for mapping */
|
||||
ptrdiff_t lastCodeOffset; /* offset of last non-nop opcode */
|
||||
intN stackDepth; /* current stack depth in basic block */
|
||||
uintN maxStackDepth; /* maximum stack depth so far */
|
||||
jssrcnote *notes; /* source notes, see below */
|
||||
uintN noteCount; /* number of source notes so far */
|
||||
ptrdiff_t lastNoteOffset; /* code offset for last source note */
|
||||
const char *filename; /* null or weak link to source filename */
|
||||
uintN firstLine; /* first line, for js_NewScriptFromCG */
|
||||
uintN currentLine; /* line number for tree-based srcnote gen */
|
||||
JSPrincipals *principals; /* principals for constant folding eval */
|
||||
JSTreeContext treeContext; /* for break/continue code generation */
|
||||
JSTryNote *tryBase; /* first exception handling block */
|
||||
JSTryNote *tryNext; /* next avail block */
|
||||
JSTryNote *tryLimit; /* pointer to one-past-end block */
|
||||
JSAtomList atomList; /* literals indexed for mapping */
|
||||
intN stackDepth; /* current stack depth in basic block */
|
||||
uintN maxStackDepth; /* maximum stack depth so far */
|
||||
jssrcnote *notes; /* source notes, see below */
|
||||
uintN noteCount; /* number of source notes so far */
|
||||
ptrdiff_t lastNoteOffset; /* code offset for last source note */
|
||||
JSTryNote *tryBase; /* first exception handling note */
|
||||
JSTryNote *tryLimit; /* pointer to one-past-end note */
|
||||
JSTryNote *tryNext; /* next available note */
|
||||
};
|
||||
|
||||
#define CG_CODE(cg,offset) ((cg)->base + (offset))
|
||||
#define CG_OFFSET(cg) PTRDIFF((cg)->next, (cg)->base, jsbytecode)
|
||||
#define CG_RESET(cg) ((cg)->next = (cg)->base, \
|
||||
ATOM_LIST_INIT(&(cg)->atomList), \
|
||||
(cg)->lastCodeOffset = 0, \
|
||||
(cg)->stackDepth = (cg)->maxStackDepth = 0, \
|
||||
(cg)->currentLine = (cg)->firstLine, \
|
||||
INIT_TREE_CONTEXT(&(cg)->treeContext), \
|
||||
(cg)->tryNext = (cg)->tryBase, \
|
||||
CG_RESET_NOTES(cg))
|
||||
#define CG_RESET_NOTES(cg) ((cg)->notes = NULL, (cg)->noteCount = 0, \
|
||||
(cg)->lastNoteOffset = 0)
|
||||
#define CG_PUSH(cg, newcg) ((newcg)->atomList = (cg)->atomList)
|
||||
#define CG_POP(cg, newcg) ((cg)->atomList = (newcg)->atomList)
|
||||
|
||||
/*
|
||||
* Initialize cg to allocate bytecode space from cx->codePool, and srcnote
|
||||
|
@ -228,7 +215,7 @@ js_EmitFunctionBody(JSContext *cx, JSCodeGenerator *cg, JSParseNode *body,
|
|||
* the previous note. If 3 bits of offset aren't enough, extended delta notes
|
||||
* (SRC_XDELTA) consisting of 2 set high order bits followed by 6 offset bits
|
||||
* are emitted before the next note. Some notes have operand offsets encoded
|
||||
* in note bytes or byte-pairs.
|
||||
* immediately after them, in note bytes or byte-triples.
|
||||
*
|
||||
* At most one "gettable" note (i.e., a note of type other than SRC_NEWLINE,
|
||||
* SRC_SETLINE, and SRC_XDELTA) applies to a given bytecode.
|
||||
|
@ -255,9 +242,10 @@ typedef enum JSSrcNoteType {
|
|||
SRC_ENDBRACE = 15, /* JSOP_NOP for label: {...} end brace */
|
||||
SRC_BREAK2LABEL = 16, /* JSOP_GOTO for 'break label' with atomid */
|
||||
SRC_CONT2LABEL = 17, /* JSOP_GOTO for 'continue label' with atomid */
|
||||
SRC_SWITCH = 18, /* JSOP_*SWITCH with offset to end of switch */
|
||||
SRC_SWITCH = 18, /* JSOP_*SWITCH with offset to end of switch,
|
||||
2nd off to first JSOP_CASE if condswitch */
|
||||
SRC_FUNCDEF = 19, /* JSOP_NOP for function f() with atomid */
|
||||
SRC_TRYFIN = 20, /* JSOP_NOP for try{} or finally{} section */
|
||||
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 */
|
||||
|
@ -351,8 +339,7 @@ js_FinishTakingSrcNotes(JSContext *cx, JSCodeGenerator *cg);
|
|||
/*
|
||||
* Allocate cg->treeContext.tryCount notes (plus one for the end sentinel)
|
||||
* from cx->tempPool and set cg->tryBase/tryNext/tryLimit for exactly tryCount
|
||||
* js_NewTryNote calls. The storage is freed in one fell swoop by JS_Compile*
|
||||
* API entry points at the end of compilation.
|
||||
* js_NewTryNote calls. The storage is freed by js_ResetCodeGenerator.
|
||||
*/
|
||||
extern JSBool
|
||||
js_AllocTryNotes(JSContext *cx, JSCodeGenerator *cg);
|
||||
|
|
|
@ -383,7 +383,8 @@ js_InitExceptionClasses(JSContext *cx, JSObject *obj)
|
|||
}
|
||||
|
||||
JSErrorReport *
|
||||
js_GetErrorFromException(JSContext *cx, JSObject *errobj) {
|
||||
js_GetErrorFromException(JSContext *cx, JSObject *errobj)
|
||||
{
|
||||
JSExnPrivate *privateData;
|
||||
#if 0
|
||||
{
|
||||
|
@ -419,7 +420,8 @@ static struct exnname { char *name; char *exception; } errortoexnname[] = {
|
|||
#endif /* DEBUG */
|
||||
|
||||
JSBool
|
||||
js_ErrorToException(JSContext *cx, JSErrorReport *reportp, const char *message) {
|
||||
js_ErrorToException(JSContext *cx, JSErrorReport *reportp, const char *message)
|
||||
{
|
||||
JSErrNum errorNumber;
|
||||
JSObject *errobj;
|
||||
JSExnType exn;
|
||||
|
|
|
@ -891,8 +891,8 @@ fun_setProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
|
|||
_readonly:
|
||||
if (JSVERSION_IS_ECMA(cx->version))
|
||||
return fun_getProperty(cx, obj, id, vp);
|
||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
|
||||
JSMSG_READ_ONLY, js_arguments_str);
|
||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_READ_ONLY,
|
||||
js_arguments_str);
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
|
@ -1482,8 +1482,8 @@ Function(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
|
|||
#ifdef CHECK_ARGUMENT_HIDING
|
||||
PR_ASSERT(sprop->getter == js_GetArgument);
|
||||
OBJ_DROP_PROPERTY(cx, obj2, (JSProperty *)sprop);
|
||||
JS_ReportErrorNumber(cx, JSREPORT_WARNING, JSMSG_SAME_FORMAL,
|
||||
ATOM_BYTES(atom));
|
||||
JS_ReportErrorNumber(cx, JSREPORT_WARNING,
|
||||
JSMSG_SAME_FORMAL, ATOM_BYTES(atom));
|
||||
goto badargs;
|
||||
#else
|
||||
/*
|
||||
|
|
|
@ -624,6 +624,13 @@ js_GC(JSContext *cx)
|
|||
GCFinalizeOp finalizer;
|
||||
JSBool a_all_clear, f_all_clear;
|
||||
|
||||
/*
|
||||
* XXX kludge for pre-ECMAv2 compile-time switch case expr eval, see
|
||||
* jsemit.c:js_EmitTree, under case TOK_SWITCH: (look for XXX).
|
||||
*/
|
||||
if (cx->gcDisabled)
|
||||
return;
|
||||
|
||||
rt = cx->runtime;
|
||||
#ifdef JS_THREADSAFE
|
||||
/* Avoid deadlock. */
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#include "prtypes.h"
|
||||
#include "prarena.h"
|
||||
#include "prassert.h"
|
||||
#include "prprintf.h"
|
||||
#include "jsapi.h"
|
||||
#include "jsarray.h"
|
||||
#include "jsatom.h"
|
||||
|
@ -656,17 +657,6 @@ have_fun:
|
|||
}
|
||||
|
||||
out:
|
||||
/*
|
||||
* Checking frame.annotation limits the use of this hook for uses other
|
||||
* than releasing annotations, but avoids one C function call for every
|
||||
* JS function call.
|
||||
*/
|
||||
if (frame.annotation &&
|
||||
js_InterpreterHooks &&
|
||||
js_InterpreterHooks->destroyFrame) {
|
||||
js_InterpreterHooks->destroyFrame(cx, &frame);
|
||||
}
|
||||
|
||||
#if JS_HAS_CALL_OBJECT
|
||||
/* If frame has a call object, sync values and clear back-pointer. */
|
||||
if (frame.callobj)
|
||||
|
@ -849,7 +839,8 @@ ImportProperty(JSContext *cx, JSObject *obj, jsid id)
|
|||
str = js_DecompileValueGenerator(cx, js_IdToValue(id), NULL);
|
||||
if (str) {
|
||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
|
||||
JSMSG_NOT_EXPORTED, JS_GetStringBytes(str));
|
||||
JSMSG_NOT_EXPORTED,
|
||||
JS_GetStringBytes(str));
|
||||
}
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
@ -1941,7 +1932,8 @@ js_Interpret(JSContext *cx, jsval *result)
|
|||
str = js_ValueToString(cx, rval);
|
||||
if (str) {
|
||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
|
||||
JSMSG_BAD_NEW_RESULT, JS_GetStringBytes(str));
|
||||
JSMSG_BAD_NEW_RESULT,
|
||||
JS_GetStringBytes(str));
|
||||
}
|
||||
ok = JS_FALSE;
|
||||
goto out;
|
||||
|
@ -2253,8 +2245,9 @@ js_Interpret(JSContext *cx, jsval *result)
|
|||
* (This opcode is only emitted for all-integer switches.)
|
||||
*/
|
||||
if (JSVERSION_IS_ECMAv2(cx->version) &&
|
||||
!JSVAL_IS_INT(*sp))
|
||||
!JSVAL_IS_INT(*sp)) {
|
||||
break;
|
||||
}
|
||||
|
||||
SAVE_SP(fp);
|
||||
ok = PopInt(cx, &i);
|
||||
|
@ -2326,8 +2319,7 @@ js_Interpret(JSContext *cx, jsval *result)
|
|||
break;
|
||||
|
||||
case JSOP_CONDSWITCH:
|
||||
len = GET_JUMP_OFFSET(pc);
|
||||
goto advance_pc;
|
||||
break;
|
||||
|
||||
#endif /* JS_HAS_SWITCH_STATEMENT */
|
||||
|
||||
|
@ -2581,7 +2573,7 @@ js_Interpret(JSContext *cx, jsval *result)
|
|||
rval = sp[-1];
|
||||
if (JSVAL_IS_PRIMITIVE(rval)) {
|
||||
char numBuf[12];
|
||||
sprintf(numBuf, "%u", (unsigned) i);
|
||||
PR_snprintf(numBuf, sizeof numBuf, "%u", (unsigned) i);
|
||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
|
||||
JSMSG_BAD_SHARP_DEF, numBuf);
|
||||
ok = JS_FALSE;
|
||||
|
@ -2605,7 +2597,7 @@ js_Interpret(JSContext *cx, jsval *result)
|
|||
}
|
||||
if (!JSVAL_IS_OBJECT(rval)) {
|
||||
char numBuf[12];
|
||||
sprintf(numBuf, "%u", (unsigned) i);
|
||||
PR_snprintf(numBuf, sizeof numBuf, "%u", (unsigned) i);
|
||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
|
||||
JSMSG_BAD_SHARP_USE, numBuf);
|
||||
ok = JS_FALSE;
|
||||
|
@ -2671,8 +2663,8 @@ js_Interpret(JSContext *cx, jsval *result)
|
|||
str = js_DecompileValueGenerator(cx, rval, NULL);
|
||||
if (str) {
|
||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
|
||||
JSMSG_BAD_INSTANCEOF_RHS, JS_GetStringBytes(str));
|
||||
|
||||
JSMSG_BAD_INSTANCEOF_RHS,
|
||||
JS_GetStringBytes(str));
|
||||
}
|
||||
ok = JS_FALSE;
|
||||
goto out;
|
||||
|
@ -2715,7 +2707,7 @@ js_Interpret(JSContext *cx, jsval *result)
|
|||
|
||||
default: {
|
||||
char numBuf[12];
|
||||
sprintf(numBuf, "%d", op);
|
||||
PR_snprintf(numBuf, sizeof numBuf, "%d", op);
|
||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
|
||||
JSMSG_BAD_BYTECODE, numBuf);
|
||||
ok = JS_FALSE;
|
||||
|
|
|
@ -68,7 +68,7 @@ MSG_DEF(JSMSG_INCOMPATIBLE_PROTO, 8, 3, JSEXN_TARGETERR, "{0}.prototype.{1
|
|||
MSG_DEF(JSMSG_NO_CONSTRUCTOR, 9, 1, JSEXN_NONE, "{0} has no constructor")
|
||||
MSG_DEF(JSMSG_CANT_ALIAS, 10, 3, JSEXN_NONE, "can't alias {0} to {1} in class {2}")
|
||||
MSG_DEF(JSMSG_NO_PROTO, 11, 1, JSEXN_INTERNALERR, "sorry, Array.prototype.{0} is not yet implemented")
|
||||
MSG_DEF(JSMSG_BAD_PROTO_SORT, 12, 0, JSEXN_ARRAYERR, "invalid Array.prototype.sort argument")
|
||||
MSG_DEF(JSMSG_BAD_SORT_ARG, 12, 0, JSEXN_ARRAYERR, "invalid Array.prototype.sort argument")
|
||||
MSG_DEF(JSMSG_BAD_ATOMIC_NUMBER, 13, 1, JSEXN_INTERNALERR, "internal error: no index for atom {0}")
|
||||
MSG_DEF(JSMSG_TOO_MANY_LITERALS, 14, 0, JSEXN_INTERNALERR, "too many literals")
|
||||
MSG_DEF(JSMSG_CANT_WATCH, 15, 1, JSEXN_NONE, "can't watch non-native objects of class {0}")
|
||||
|
@ -192,6 +192,3 @@ MSG_DEF(JSMSG_RESERVED_ID, 132, 1, JSEXN_SYNTAXERR, "{0} is a reserve
|
|||
MSG_DEF(JSMSG_SYNTAX_ERROR, 133, 0, JSEXN_SYNTAXERR, "syntax error")
|
||||
MSG_DEF(JSMSG_BAD_SHARP_VAR_DEF, 134, 0, JSEXN_SYNTAXERR, "invalid sharp variable definition")
|
||||
MSG_DEF(JSMSG_BAD_PROTOTYPE, 135, 1, JSEXN_ERR, "'prototype' property of {0} is not an object")
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -213,9 +213,9 @@ num_toString(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
|
|||
return JS_FALSE;
|
||||
if (base < 2 || base > 36) {
|
||||
char numBuf[12];
|
||||
sprintf(numBuf, "%d", base);
|
||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
|
||||
JSMSG_BAD_RADIX, numBuf);
|
||||
PR_snprintf(numBuf, sizeof numBuf, "%ld", (long) base);
|
||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_RADIX,
|
||||
numBuf);
|
||||
return JS_FALSE;
|
||||
}
|
||||
if (base != 10 && JSDOUBLE_IS_FINITE(d)) {
|
||||
|
|
|
@ -1943,9 +1943,10 @@ js_DeleteProperty(JSContext *cx, JSObject *obj, jsid id, jsval *rval)
|
|||
return JS_TRUE;
|
||||
}
|
||||
str = js_DecompileValueGenerator(cx, js_IdToValue(id), NULL);
|
||||
if (str)
|
||||
if (str) {
|
||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
|
||||
JSMSG_PERMANENT, JS_GetStringBytes(str));
|
||||
}
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
|
@ -2393,8 +2394,7 @@ js_ValueToNonNullObject(JSContext *cx, jsval v)
|
|||
str = js_DecompileValueGenerator(cx, v, NULL);
|
||||
if (str) {
|
||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
|
||||
JSMSG_NO_PROPERTIES,
|
||||
JS_GetStringBytes(str));
|
||||
JSMSG_NO_PROPERTIES, JS_GetStringBytes(str));
|
||||
}
|
||||
}
|
||||
return obj;
|
||||
|
@ -2480,7 +2480,7 @@ js_XDRObject(JSXDRState *xdr, JSObject **objp)
|
|||
clasp = JS_FindClassById(xdr, classId);
|
||||
if (!clasp) {
|
||||
char numBuf[12];
|
||||
sprintf(numBuf, "%d", (long)classId);
|
||||
PR_snprintf(numBuf, sizeof numBuf, "%ld", (long)classId);
|
||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
|
||||
JSMSG_CANT_FIND_CLASS, numBuf);
|
||||
ok = JS_FALSE;
|
||||
|
|
|
@ -111,10 +111,9 @@ js_Disassemble1(JSContext *cx, JSScript *script, jsbytecode *pc, uintN loc,
|
|||
|
||||
op = (JSOp)*pc;
|
||||
if (op >= JSOP_LIMIT) {
|
||||
char numBuf1[12];
|
||||
char numBuf2[12];
|
||||
sprintf(numBuf1, "%d", op);
|
||||
sprintf(numBuf2, "%d", JSOP_LIMIT);
|
||||
char numBuf1[12], numBuf2[12];
|
||||
PR_snprintf(numBuf1, sizeof numBuf1, "%d", op);
|
||||
PR_snprintf(numBuf2, sizeof numBuf2, "%d", JSOP_LIMIT);
|
||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
|
||||
JSMSG_BYTECODE_TOO_BIG, numBuf1, numBuf2);
|
||||
return 0;
|
||||
|
@ -228,7 +227,7 @@ js_Disassemble1(JSContext *cx, JSScript *script, jsbytecode *pc, uintN loc,
|
|||
|
||||
default: {
|
||||
char numBuf[12];
|
||||
sprintf(numBuf, "%x", cs->format);
|
||||
PR_snprintf(numBuf, sizeof numBuf, "%lx", (unsigned long) cs->format);
|
||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
|
||||
JSMSG_UNKNOWN_FORMAT, numBuf);
|
||||
return 0;
|
||||
|
@ -594,24 +593,39 @@ DecompileSwitch(SprintStack *ss, TableEntry *table, uintN tableLength,
|
|||
return JS_FALSE;
|
||||
jp->indent -= 4;
|
||||
}
|
||||
caseExprOff = 1 + JUMP_OFFSET_LEN + ATOM_INDEX_LEN +
|
||||
tableLength * (ATOM_INDEX_LEN + JUMP_OFFSET_LEN);
|
||||
|
||||
if (isCondSwitch)
|
||||
caseExprOff = (ptrdiff_t) js_CodeSpec[JSOP_CONDSWITCH].length;
|
||||
|
||||
for (i = 0; i < tableLength; i++) {
|
||||
off = table[i].offset;
|
||||
if (i + 1 < tableLength)
|
||||
off2 = table[i + 1].offset;
|
||||
else
|
||||
off2 = switchLength;
|
||||
|
||||
key = table[i].key;
|
||||
if (isCondSwitch) {
|
||||
uint32 caseLen = js_CodeSpec[JSOP_CASE].length;
|
||||
ptrdiff_t caseOff = JSVAL_TO_INT(key);
|
||||
ptrdiff_t nextCaseExprOff;
|
||||
|
||||
/*
|
||||
* key encodes the JSOP_CASE bytecode's offset from switchtop.
|
||||
* The next case expression follows immediately, unless we are
|
||||
* at the last case.
|
||||
*/
|
||||
nextCaseExprOff = (ptrdiff_t)
|
||||
(JSVAL_TO_INT(key) + js_CodeSpec[JSOP_CASE].length);
|
||||
jp->indent += 2;
|
||||
if (!Decompile(ss, pc + caseExprOff,
|
||||
caseOff - caseExprOff + caseLen))
|
||||
nextCaseExprOff - caseExprOff)) {
|
||||
return JS_FALSE;
|
||||
caseExprOff = caseOff + caseLen;
|
||||
}
|
||||
caseExprOff = nextCaseExprOff;
|
||||
} else {
|
||||
/*
|
||||
* key comes from an atom, not the decompiler, so we need to
|
||||
* quote it if it's a string literal.
|
||||
*/
|
||||
str = js_ValueToString(cx, key);
|
||||
if (!str)
|
||||
return JS_FALSE;
|
||||
|
@ -625,6 +639,7 @@ DecompileSwitch(SprintStack *ss, TableEntry *table, uintN tableLength,
|
|||
}
|
||||
js_printf(jp, "\tcase %s:\n", rval);
|
||||
}
|
||||
|
||||
jp->indent += 2;
|
||||
if (off <= defaultOffset && defaultOffset < off2) {
|
||||
diff = defaultOffset - off;
|
||||
|
@ -642,6 +657,7 @@ DecompileSwitch(SprintStack *ss, TableEntry *table, uintN tableLength,
|
|||
jp->indent -= 4;
|
||||
}
|
||||
}
|
||||
|
||||
if (defaultOffset == switchLength) {
|
||||
jp->indent += 2;
|
||||
js_printf(jp, "\tdefault:\n");
|
||||
|
@ -1603,9 +1619,8 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb)
|
|||
}
|
||||
|
||||
case JSOP_LOOKUPSWITCH:
|
||||
case JSOP_CONDSWITCH:
|
||||
{
|
||||
jsbytecode *pc2 = pc;
|
||||
jsbytecode *pc2;
|
||||
ptrdiff_t off, off2;
|
||||
jsint npairs;
|
||||
TableEntry *table;
|
||||
|
@ -1613,6 +1628,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb)
|
|||
sn = js_GetSrcNote(jp->script, pc);
|
||||
PR_ASSERT(sn && SN_TYPE(sn) == SRC_SWITCH);
|
||||
len = js_GetSrcNoteOffset(sn, 0);
|
||||
pc2 = pc;
|
||||
off = GET_JUMP_OFFSET(pc2);
|
||||
pc2 += JUMP_OFFSET_LEN;
|
||||
npairs = (jsint) GET_ATOM_INDEX(pc2);
|
||||
|
@ -1629,21 +1645,81 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb)
|
|||
table[i].key = ATOM_KEY(atom);
|
||||
table[i].offset = off2;
|
||||
}
|
||||
if (op == JSOP_CONDSWITCH) {
|
||||
/*
|
||||
* Find offset of default code by finding the default
|
||||
* instruction and adding its offset.
|
||||
*/
|
||||
jsbytecode *pc3;
|
||||
|
||||
off = JSVAL_TO_INT(table[npairs-1].key) +
|
||||
js_CodeSpec[JSOP_CASE].length;
|
||||
pc3 = pc + off;
|
||||
off += GET_JUMP_OFFSET(pc3);
|
||||
}
|
||||
|
||||
ok = DecompileSwitch(ss, table, (uintN)npairs, pc, len, off,
|
||||
op == JSOP_CONDSWITCH);
|
||||
JS_FALSE);
|
||||
JS_free(cx, table);
|
||||
if (!ok)
|
||||
return ok;
|
||||
todo = -2;
|
||||
break;
|
||||
}
|
||||
|
||||
case JSOP_CONDSWITCH:
|
||||
{
|
||||
jsbytecode *pc2;
|
||||
ptrdiff_t off, off2, caseOff;
|
||||
jsint ncases;
|
||||
TableEntry *table;
|
||||
|
||||
sn = js_GetSrcNote(jp->script, pc);
|
||||
PR_ASSERT(sn && SN_TYPE(sn) == SRC_SWITCH);
|
||||
len = js_GetSrcNoteOffset(sn, 0);
|
||||
off = js_GetSrcNoteOffset(sn, 1);
|
||||
|
||||
/*
|
||||
* Count the cases using offsets from switch to first case,
|
||||
* and case to case, stored in srcnote immediates.
|
||||
*/
|
||||
pc2 = pc;
|
||||
off2 = off;
|
||||
for (ncases = 0; off2 != 0; ncases++) {
|
||||
pc2 += off2;
|
||||
PR_ASSERT(*pc2 == JSOP_CASE || *pc2 == JSOP_DEFAULT);
|
||||
if (*pc2 == JSOP_DEFAULT) {
|
||||
/* End of cases, but count default as a case. */
|
||||
off2 = 0;
|
||||
} else {
|
||||
sn = js_GetSrcNote(jp->script, pc2);
|
||||
PR_ASSERT(sn && SN_TYPE(sn) == SRC_COMMA);
|
||||
off2 = js_GetSrcNoteOffset(sn, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Allocate table and rescan the cases using their srcnotes,
|
||||
* stashing each case's delta from switch top in table[i].key,
|
||||
* and the distance to its statements in table[i].offset.
|
||||
*/
|
||||
table = JS_malloc(cx, (size_t)ncases * sizeof *table);
|
||||
if (!table)
|
||||
return JS_FALSE;
|
||||
pc2 = pc;
|
||||
off2 = off;
|
||||
for (i = 0; i < ncases; i++) {
|
||||
pc2 += off2;
|
||||
PR_ASSERT(*pc2 == JSOP_CASE || *pc2 == JSOP_DEFAULT);
|
||||
caseOff = pc2 - pc;
|
||||
table[i].key = INT_TO_JSVAL((jsint) caseOff);
|
||||
table[i].offset = caseOff + GET_JUMP_OFFSET(pc2);
|
||||
if (*pc2 == JSOP_CASE) {
|
||||
sn = js_GetSrcNote(jp->script, pc2);
|
||||
PR_ASSERT(sn && SN_TYPE(sn) == SRC_COMMA);
|
||||
off2 = js_GetSrcNoteOffset(sn, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Find offset of default code by fetching the default offset
|
||||
* from the end of table. JSOP_CONDSWITCH always has a default
|
||||
* case at the end.
|
||||
*/
|
||||
off = JSVAL_TO_INT(table[ncases-1].key);
|
||||
pc2 = pc + off;
|
||||
off += GET_JUMP_OFFSET(pc2);
|
||||
|
||||
ok = DecompileSwitch(ss, table, (uintN)ncases, pc, len, off,
|
||||
JS_TRUE);
|
||||
JS_free(cx, table);
|
||||
if (!ok)
|
||||
return ok;
|
||||
|
|
|
@ -204,8 +204,9 @@ OPDEF(JSOP_SETSP, 117,"setsp", NULL, 3, 0, 0, 0, JOF_UINT16
|
|||
|
||||
/*
|
||||
* ECMA-compliant switch statement ops.
|
||||
* "switch" is essentially "nop" and "default" is essentially "pop" + "goto".
|
||||
* CONDSWITCH is a decompilable NOP; CASE is ===, POP, jump if true, re-push
|
||||
* lval if false; and DEFAULT is POP lval and GOTO.
|
||||
*/
|
||||
OPDEF(JSOP_CONDSWITCH,118,"switch", NULL, -1, 0, 0, 0, JOF_LOOKUPSWITCH)
|
||||
OPDEF(JSOP_CONDSWITCH,118,"condswitch", NULL, 1, 0, 0, 0, JOF_BYTE)
|
||||
OPDEF(JSOP_CASE, 119,"case", NULL, 3, 1, 0, 0, JOF_JUMP)
|
||||
OPDEF(JSOP_DEFAULT, 120,"default", NULL, 3, 1, 0, 0, JOF_JUMP)
|
||||
|
|
|
@ -38,7 +38,6 @@
|
|||
#include "prtypes.h"
|
||||
#include "prarena.h"
|
||||
#include "prassert.h"
|
||||
#include "prprintf.h"
|
||||
#include "jsapi.h"
|
||||
#include "jsatom.h"
|
||||
#include "jscntxt.h"
|
||||
|
@ -496,7 +495,7 @@ FunctionDef(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc,
|
|||
ok = JS_FALSE; goto out);
|
||||
pn->pn_pos.begin = ts->token.pos.begin;
|
||||
|
||||
INIT_TREE_CONTEXT(&funtc);
|
||||
TREE_CONTEXT_INIT(&funtc);
|
||||
pn2 = FunctionBody(cx, ts, fun, &funtc);
|
||||
if (!pn2) {
|
||||
ok = JS_FALSE;
|
||||
|
@ -843,7 +842,7 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
|
|||
case TOK_SWITCH:
|
||||
{
|
||||
uintN newlines;
|
||||
JSParseNode *pn5, *pn6;
|
||||
JSParseNode *pn5;
|
||||
JSBool seenDefault = JS_FALSE;
|
||||
|
||||
pn = NewParseNode(cx, &ts->token, PN_BINARY);
|
||||
|
@ -882,17 +881,17 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
|
|||
/* fall through */
|
||||
|
||||
case TOK_CASE:
|
||||
pn4 = NewParseNode(cx, &ts->token, PN_BINARY);
|
||||
if (!pn4)
|
||||
pn3 = NewParseNode(cx, &ts->token, PN_BINARY);
|
||||
if (!pn3)
|
||||
goto bad_switch;
|
||||
if (tt == TOK_DEFAULT) {
|
||||
pn4->pn_left = NULL;
|
||||
pn3->pn_left = NULL;
|
||||
} else {
|
||||
pn4->pn_left = Expr(cx, ts, tc);
|
||||
if (!pn4->pn_left)
|
||||
pn3->pn_left = Expr(cx, ts, tc);
|
||||
if (!pn3->pn_left)
|
||||
goto bad_switch;
|
||||
}
|
||||
PN_APPEND(pn2, pn4);
|
||||
PN_APPEND(pn2, pn3);
|
||||
if (pn2->pn_count == PR_BIT(16)) {
|
||||
js_ReportCompileErrorNumber(cx, ts, JSREPORT_ERROR,
|
||||
JSMSG_TOO_MANY_CASES);
|
||||
|
@ -910,23 +909,23 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
|
|||
}
|
||||
MUST_MATCH_TOKEN(TOK_COLON, JSMSG_COLON_AFTER_CASE);
|
||||
|
||||
pn5 = NewParseNode(cx, &ts->token, PN_LIST);
|
||||
if (!pn5)
|
||||
pn4 = NewParseNode(cx, &ts->token, PN_LIST);
|
||||
if (!pn4)
|
||||
goto bad_switch;
|
||||
pn5->pn_type = TOK_LC;
|
||||
PN_INIT_LIST(pn5);
|
||||
pn4->pn_type = TOK_LC;
|
||||
PN_INIT_LIST(pn4);
|
||||
while ((tt = js_PeekToken(cx, ts)) != TOK_RC &&
|
||||
tt != TOK_CASE && tt != TOK_DEFAULT) {
|
||||
if (tt == TOK_ERROR)
|
||||
goto bad_switch;
|
||||
pn6 = Statement(cx, ts, tc);
|
||||
if (!pn6)
|
||||
pn5 = Statement(cx, ts, tc);
|
||||
if (!pn5)
|
||||
goto bad_switch;
|
||||
pn5->pn_pos.end = pn6->pn_pos.end;
|
||||
PN_APPEND(pn5, pn6);
|
||||
}
|
||||
pn4->pn_pos.end = pn5->pn_pos.end;
|
||||
pn4->pn_right = pn5;
|
||||
PN_APPEND(pn4, pn5);
|
||||
}
|
||||
pn3->pn_pos.end = pn4->pn_pos.end;
|
||||
pn3->pn_right = pn4;
|
||||
}
|
||||
|
||||
if (newlines)
|
||||
|
|
|
@ -649,8 +649,7 @@ loop:
|
|||
case '{':
|
||||
c = *++cp;
|
||||
if (!JS7_ISDEC(c)) {
|
||||
JS_ReportErrorNumber(state->context,
|
||||
js_GetErrorMessage, NULL,
|
||||
JS_ReportErrorNumber(state->context, js_GetErrorMessage, NULL,
|
||||
JSMSG_BAD_QUANTIFIER, state->cp);
|
||||
return NULL;
|
||||
}
|
||||
|
@ -658,8 +657,7 @@ loop:
|
|||
for (c = *++cp; JS7_ISDEC(c); c = *++cp) {
|
||||
min = 10 * min + (uint32)JS7_UNDEC(c);
|
||||
if (min >> 16) {
|
||||
JS_ReportErrorNumber(state->context,
|
||||
js_GetErrorMessage, NULL,
|
||||
JS_ReportErrorNumber(state->context, js_GetErrorMessage, NULL,
|
||||
JSMSG_MIN_TOO_BIG, state->cp);
|
||||
return NULL;
|
||||
}
|
||||
|
@ -693,16 +691,14 @@ loop:
|
|||
/* Exactly n times. */
|
||||
if (min == 0) {
|
||||
zero_quant:
|
||||
JS_ReportErrorNumber(state->context,
|
||||
js_GetErrorMessage, NULL,
|
||||
JS_ReportErrorNumber(state->context, js_GetErrorMessage, NULL,
|
||||
JSMSG_ZERO_QUANTIFIER, state->cp);
|
||||
return NULL;
|
||||
}
|
||||
max = min;
|
||||
}
|
||||
if (*cp != '}') {
|
||||
JS_ReportErrorNumber(state->context,
|
||||
js_GetErrorMessage, NULL,
|
||||
JS_ReportErrorNumber(state->context, js_GetErrorMessage, NULL,
|
||||
JSMSG_UNTERM_QUANTIFIER, state->cp);
|
||||
return NULL;
|
||||
}
|
||||
|
@ -720,8 +716,7 @@ loop:
|
|||
|
||||
case '*':
|
||||
if (!(ren->flags & RENODE_NONEMPTY)) {
|
||||
JS_ReportErrorNumber(state->context,
|
||||
js_GetErrorMessage, NULL,
|
||||
JS_ReportErrorNumber(state->context, js_GetErrorMessage, NULL,
|
||||
JSMSG_EMPTY_BEFORE_STAR);
|
||||
return NULL;
|
||||
}
|
||||
|
@ -731,8 +726,7 @@ loop:
|
|||
|
||||
case '+':
|
||||
if (!(ren->flags & RENODE_NONEMPTY)) {
|
||||
JS_ReportErrorNumber(state->context,
|
||||
js_GetErrorMessage, NULL,
|
||||
JS_ReportErrorNumber(state->context, js_GetErrorMessage, NULL,
|
||||
JSMSG_EMPTY_BEFORE_PLUS);
|
||||
return NULL;
|
||||
}
|
||||
|
@ -815,8 +809,7 @@ ParseAtom(CompilerState *state)
|
|||
return NULL;
|
||||
cp = state->cp;
|
||||
if (*cp != ')') {
|
||||
JS_ReportErrorNumber(state->context,
|
||||
js_GetErrorMessage, NULL,
|
||||
JS_ReportErrorNumber(state->context, js_GetErrorMessage, NULL,
|
||||
JSMSG_MISSING_PAREN, ocp);
|
||||
return NULL;
|
||||
}
|
||||
|
@ -857,8 +850,7 @@ ParseAtom(CompilerState *state)
|
|||
while ((c = *++cp) != ']') {
|
||||
if (c == 0) {
|
||||
bad_cclass:
|
||||
JS_ReportErrorNumber(state->context,
|
||||
js_GetErrorMessage, NULL,
|
||||
JS_ReportErrorNumber(state->context, js_GetErrorMessage, NULL,
|
||||
JSMSG_UNTERM_CLASS, ocp);
|
||||
return NULL;
|
||||
}
|
||||
|
@ -875,8 +867,7 @@ ParseAtom(CompilerState *state)
|
|||
c = *++cp;
|
||||
switch (c) {
|
||||
case 0:
|
||||
JS_ReportErrorNumber(state->context,
|
||||
js_GetErrorMessage, NULL,
|
||||
JS_ReportErrorNumber(state->context, js_GetErrorMessage, NULL,
|
||||
JSMSG_TRAILING_SLASH);
|
||||
return NULL;
|
||||
|
||||
|
|
|
@ -226,8 +226,8 @@ js_NewFileTokenStream(JSContext *cx, const char *filename, FILE *defaultfp)
|
|||
} else {
|
||||
file = fopen(filename, "r");
|
||||
if (!file) {
|
||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
|
||||
JSMSG_CANT_OPEN, filename, strerror(errno));
|
||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_OPEN,
|
||||
filename, strerror(errno));
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
@ -785,8 +785,7 @@ retry:
|
|||
*/
|
||||
if (c > '7' && JSVERSION_IS_ECMA(cx->version)) {
|
||||
js_ReportCompileError(cx, ts, JSREPORT_WARNING,
|
||||
"0%c is not an ECMA-legal numeric constant",
|
||||
c);
|
||||
"0%c is not a legal ECMA-262 numeric constant", c);
|
||||
radix = 10;
|
||||
} else {
|
||||
radix = 8;
|
||||
|
|
|
@ -677,8 +677,6 @@ js_DestroyScript(JSContext *cx, JSScript *script)
|
|||
|
||||
JS_ClearScriptTraps(cx, script);
|
||||
js_FreeAtomMap(cx, &script->atomMap);
|
||||
if (js_InterpreterHooks && js_InterpreterHooks->destroyScript)
|
||||
js_InterpreterHooks->destroyScript(cx, script);
|
||||
JS_free(cx, (void *)script->filename);
|
||||
JS_free(cx, script->notes);
|
||||
JS_free(cx, script->trynotes);
|
||||
|
|
|
@ -53,7 +53,7 @@
|
|||
|
||||
/* Contributions from the String class to the set of methods defined for the
|
||||
* global object. escape and unescape used to be defined in the Mocha library,
|
||||
* but as ECMA decided to spec them. So they've been moved to the core engine
|
||||
* but as ECMA decided to spec them, they've been moved to the core engine
|
||||
* and made ECMA-compliant. (Incomplete escapes are interpreted as literal
|
||||
* characters by unescape.)
|
||||
*/
|
||||
|
@ -110,7 +110,7 @@ str_escape(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
|
|||
mask & ~(URL_XALPHAS | URL_XPALPHAS | URL_PATH))
|
||||
{
|
||||
char numBuf[12];
|
||||
sprintf(numBuf, "%x", mask);
|
||||
PR_snprintf(numBuf, sizeof numBuf, "%lx", (unsigned long) mask);
|
||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
|
||||
JSMSG_BAD_STRING_MASK, numBuf);
|
||||
return JS_FALSE;
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include <string.h>
|
||||
#include "prtypes.h"
|
||||
#include "prassert.h"
|
||||
#include "prprintf.h"
|
||||
#include "jsapi.h"
|
||||
#include "jscntxt.h"
|
||||
#include "jsobj.h" /* js_XDRObject */
|
||||
|
@ -176,12 +177,12 @@ mem_seek(JSXDRState *xdr, int32 offset, JSXDRWhence whence)
|
|||
return JS_TRUE;
|
||||
default: {
|
||||
char numBuf[12];
|
||||
sprintf(numBuf, "%d", whence);
|
||||
PR_snprintf(numBuf, sizeof numBuf, "%d", whence);
|
||||
JS_ReportErrorNumber(xdr->cx, js_GetErrorMessage, NULL,
|
||||
JSMSG_WHITHER_WHENCE, numBuf);
|
||||
}
|
||||
return JS_FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static uint32
|
||||
|
@ -490,12 +491,12 @@ JS_XDRValue(JSXDRState *xdr, jsval *vp)
|
|||
*vp = INT_TO_JSVAL(i);
|
||||
break;
|
||||
}
|
||||
sprintf(numBuf, "%#lx", type);
|
||||
PR_snprintf(numBuf, sizeof numBuf, "%#lx", type);
|
||||
JS_ReportErrorNumber(xdr->cx, js_GetErrorMessage, NULL,
|
||||
JSMSG_BAD_JVAL_TYPE, type);
|
||||
}
|
||||
return JS_FALSE;
|
||||
}
|
||||
}
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче