Prep patch for 'plan A' (346642, r=mrbkap).

This commit is contained in:
brendan@mozilla.org
2006-09-18 11:04:30 +00:00
parent 67f8af50b6
commit 8f85f9080b
13 changed files with 731 additions and 309 deletions

View File

@@ -1584,7 +1584,7 @@ array_extra(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval,
* First, get or compute our callee, so that we error out consistently * First, get or compute our callee, so that we error out consistently
* when passed a non-callable object. * when passed a non-callable object.
*/ */
callable = js_ValueToCallableObject(cx, &argv[0], 0); callable = js_ValueToCallableObject(cx, &argv[0], JSV2F_SEARCH_STACK);
if (!callable) if (!callable)
return JS_FALSE; return JS_FALSE;

View File

@@ -1412,18 +1412,14 @@ EmitGoto(JSContext *cx, JSCodeGenerator *cg, JSStmtInfo *toStmt,
if (!EmitNonLocalJumpFixup(cx, cg, toStmt, NULL)) if (!EmitNonLocalJumpFixup(cx, cg, toStmt, NULL))
return -1; return -1;
if (label) { if (label)
index = js_NewSrcNote2(cx, cg, noteType, (ptrdiff_t) ALE_INDEX(label));
else if (noteType != SRC_NULL)
index = js_NewSrcNote(cx, cg, noteType); index = js_NewSrcNote(cx, cg, noteType);
else
index = 0;
if (index < 0) if (index < 0)
return -1; return -1;
if (!js_SetSrcNoteOffset(cx, cg, (uintN)index, 0,
(ptrdiff_t) ALE_INDEX(label))) {
return -1;
}
} else if (noteType != SRC_NULL) {
if (js_NewSrcNote(cx, cg, noteType) < 0)
return -1;
}
return EmitBackPatchOp(cx, cg, JSOP_BACKPATCH, lastp); return EmitBackPatchOp(cx, cg, JSOP_BACKPATCH, lastp);
} }
@@ -2269,10 +2265,10 @@ CheckSideEffects(JSContext *cx, JSTreeContext *tc, JSParseNode *pn,
/* /*
* Secret handshake with js_EmitTree's TOK_LP/TOK_NEW case logic, to flag all * Secret handshake with js_EmitTree's TOK_LP/TOK_NEW case logic, to flag all
* uses of JSOP_GETMETHOD that implicitly qualify the method-property name with * uses of JSOP_GETMETHOD that implicitly qualify the method property's name
* a function:: prefix. All other JSOP_GETMETHOD and JSOP_SETMETHOD uses must * with a function:: prefix. All other JSOP_GETMETHOD and JSOP_SETMETHOD uses
* be explicit, so need a distinct source note (SRC_PCDELTA rather than PCBASE) * must be explicit, so we need a distinct source note (SRC_METHODBASE rather
* for round-tripping through the beloved decompiler. * than SRC_PCBASE) for round-tripping through the beloved decompiler.
*/ */
#define JSPROP_IMPLICIT_FUNCTION_NAMESPACE 0x100 #define JSPROP_IMPLICIT_FUNCTION_NAMESPACE 0x100
@@ -2282,7 +2278,7 @@ SrcNoteForPropOp(JSParseNode *pn, JSOp op)
return ((op == JSOP_GETMETHOD && return ((op == JSOP_GETMETHOD &&
!(pn->pn_attrs & JSPROP_IMPLICIT_FUNCTION_NAMESPACE)) || !(pn->pn_attrs & JSPROP_IMPLICIT_FUNCTION_NAMESPACE)) ||
op == JSOP_SETMETHOD) op == JSOP_SETMETHOD)
? SRC_PCDELTA ? SRC_METHODBASE
: SRC_PCBASE; : SRC_PCBASE;
} }
@@ -2843,11 +2839,17 @@ EmitSwitch(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn,
return JS_FALSE; return JS_FALSE;
pn3->pn_offset = off; pn3->pn_offset = off;
if (beforeCases) { if (beforeCases) {
uintN noteCount, noteCountDelta;
/* Switch note's second offset is to first JSOP_CASE. */ /* Switch note's second offset is to first JSOP_CASE. */
noteCount = CG_NOTE_COUNT(cg);
if (!js_SetSrcNoteOffset(cx, cg, (uintN)noteIndex, 1, if (!js_SetSrcNoteOffset(cx, cg, (uintN)noteIndex, 1,
off - top)) { off - top)) {
return JS_FALSE; return JS_FALSE;
} }
noteCountDelta = CG_NOTE_COUNT(cg) - noteCount;
if (noteCountDelta != 0)
caseNoteIndex += noteCountDelta;
beforeCases = JS_FALSE; beforeCases = JS_FALSE;
} }
} }
@@ -3330,7 +3332,8 @@ EmitDestructuringOpsHelper(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
index = 0; index = 0;
for (pn2 = pn->pn_head; pn2; pn2 = pn2->pn_next) { for (pn2 = pn->pn_head; pn2; pn2 = pn2->pn_next) {
if (pn2->pn_type == TOK_COMMA) { /* Nullary comma node makes a hole in the array destructurer. */
if (pn2->pn_type == TOK_COMMA && pn2->pn_arity == PN_NULLARY) {
JS_ASSERT(pn->pn_type == TOK_RB); JS_ASSERT(pn->pn_type == TOK_RB);
++index; ++index;
continue; continue;
@@ -4207,6 +4210,7 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
/* Compile a JSOP_FOR* bytecode based on the left hand side. */ /* Compile a JSOP_FOR* bytecode based on the left hand side. */
emitIFEQ = JS_TRUE; emitIFEQ = JS_TRUE;
op = JSOP_NOP;
switch (type) { switch (type) {
#if JS_HAS_BLOCK_SCOPE #if JS_HAS_BLOCK_SCOPE
case TOK_LET: case TOK_LET:
@@ -4218,8 +4222,6 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
if (pn3->pn_type == TOK_ASSIGN) { if (pn3->pn_type == TOK_ASSIGN) {
pn3 = pn3->pn_left; pn3 = pn3->pn_left;
JS_ASSERT(pn3->pn_type == TOK_RB || pn3->pn_type == TOK_RC); JS_ASSERT(pn3->pn_type == TOK_RB || pn3->pn_type == TOK_RC);
op = JSOP_NOP;
goto destructuring_for;
} }
if (pn3->pn_type == TOK_RB || pn3->pn_type == TOK_RC) { if (pn3->pn_type == TOK_RB || pn3->pn_type == TOK_RC) {
op = pn2->pn_left->pn_op; op = pn2->pn_left->pn_op;
@@ -5284,6 +5286,10 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
/* Left parts such as a.b.c and a[b].c need a decompiler note. */ /* Left parts such as a.b.c and a[b].c need a decompiler note. */
if (pn2->pn_type != TOK_NAME && if (pn2->pn_type != TOK_NAME &&
#if JS_HAS_DESTRUCTURING
pn2->pn_type != TOK_RB &&
pn2->pn_type != TOK_RC &&
#endif
js_NewSrcNote2(cx, cg, SrcNoteForPropOp(pn2, pn2->pn_op), js_NewSrcNote2(cx, cg, SrcNoteForPropOp(pn2, pn2->pn_op),
CG_OFFSET(cg) - top) < 0) { CG_OFFSET(cg) - top) < 0) {
return JS_FALSE; return JS_FALSE;
@@ -5311,7 +5317,7 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
#if JS_HAS_DESTRUCTURING #if JS_HAS_DESTRUCTURING
case TOK_RB: case TOK_RB:
case TOK_RC: case TOK_RC:
if (!EmitDestructuringOps(cx, cg, op, pn2)) if (!EmitDestructuringOps(cx, cg, JSOP_NOP, pn2))
return JS_FALSE; return JS_FALSE;
break; break;
#endif #endif
@@ -5787,7 +5793,6 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
* statements get braces by default from the decompiler. * statements get braces by default from the decompiler.
*/ */
noteIndex = -1; noteIndex = -1;
tmp = CG_OFFSET(cg);
type = pn->pn_expr->pn_type; type = pn->pn_expr->pn_type;
if (type != TOK_CATCH && type != TOK_LET && type != TOK_FOR && if (type != TOK_CATCH && type != TOK_LET && type != TOK_FOR &&
(!(stmt = stmtInfo.down) (!(stmt = stmtInfo.down)
@@ -5807,19 +5812,26 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
ale = js_IndexAtom(cx, atom, &cg->atomList); ale = js_IndexAtom(cx, atom, &cg->atomList);
if (!ale) if (!ale)
return JS_FALSE; return JS_FALSE;
JS_ASSERT(CG_OFFSET(cg) == top);
EMIT_ATOM_INDEX_OP(JSOP_ENTERBLOCK, ALE_INDEX(ale)); EMIT_ATOM_INDEX_OP(JSOP_ENTERBLOCK, ALE_INDEX(ale));
if (!js_EmitTree(cx, cg, pn->pn_expr)) if (!js_EmitTree(cx, cg, pn->pn_expr))
return JS_FALSE; return JS_FALSE;
op = pn->pn_op;
if (op == JSOP_LEAVEBLOCKEXPR) {
if (js_NewSrcNote2(cx, cg, SRC_PCBASE, CG_OFFSET(cg) - top) < 0)
return JS_FALSE;
} else {
if (noteIndex >= 0 && if (noteIndex >= 0 &&
!js_SetSrcNoteOffset(cx, cg, (uintN)noteIndex, 0, !js_SetSrcNoteOffset(cx, cg, (uintN)noteIndex, 0,
CG_OFFSET(cg) - tmp)) { CG_OFFSET(cg) - top)) {
return JS_FALSE; return JS_FALSE;
} }
}
/* Emit the JSOP_LEAVEBLOCK or JSOP_LEAVEBLOCKEXPR opcode. */ /* Emit the JSOP_LEAVEBLOCK or JSOP_LEAVEBLOCKEXPR opcode. */
EMIT_UINT16_IMM_OP(pn->pn_op, count); EMIT_UINT16_IMM_OP(op, count);
cg->stackDepth -= count; cg->stackDepth -= count;
ok = js_PopStatementCG(cx, cg); ok = js_PopStatementCG(cx, cg);
@@ -6279,7 +6291,7 @@ JS_FRIEND_DATA(JSSrcNoteSpec) js_SrcNoteSpec[] = {
{"switch", 2, 0, 1}, {"switch", 2, 0, 1},
{"funcdef", 1, 0, 0}, {"funcdef", 1, 0, 0},
{"catch", 1, 0, 1}, {"catch", 1, 0, 1},
{"unused21", 0, 0, 0}, {"extended", -1, 0, 0},
{"newline", 0, 0, 0}, {"newline", 0, 0, 0},
{"setline", 1, 0, 0}, {"setline", 1, 0, 0},
{"xdelta", 0, 0, 0}, {"xdelta", 0, 0, 0},

View File

@@ -80,11 +80,28 @@ typedef enum JSStmtType {
#define STMT_TYPE_IN_RANGE(t,b,e) ((uint)((t) - (b)) <= (uintN)((e) - (b))) #define STMT_TYPE_IN_RANGE(t,b,e) ((uint)((t) - (b)) <= (uintN)((e) - (b)))
/*
* STMT_TYPE_MAYBE_SCOPE tells whether a statement type is always, or may
* become, a lexical scope. It therefore includes block and switch (the two
* "maybe" scopes) and excludes with (which has dynamic scope, pending the
* "reformed with" in ES4/JS2). It includes all try-catch-finally types.
*
* STMT_TYPE_LINKS_SCOPE tells whether a JSStmtInfo of the given type eagerly
* links to other scoping statement info records. It excludes the two "maybe"
* types, block and switch, as well as the try and both finally types, since
* try, etc., don't need block scope unless they contain let declarations.
*
* We treat with as a static scope because it prevents lexical binding from
* continuing further up the static scope chain. With the "reformed with"
* proposal for JS2, we'll be able to model it statically, too.
*/
#define STMT_TYPE_MAYBE_SCOPE(type) \ #define STMT_TYPE_MAYBE_SCOPE(type) \
(type != STMT_WITH && \ (type != STMT_WITH && \
STMT_TYPE_IN_RANGE(type, STMT_BLOCK, STMT_SUBROUTINE)) STMT_TYPE_IN_RANGE(type, STMT_BLOCK, STMT_SUBROUTINE))
#define STMT_TYPE_LINKS_SCOPE(type) \ #define STMT_TYPE_LINKS_SCOPE(type) \
STMT_TYPE_IN_RANGE(type, STMT_WITH, STMT_CATCH) STMT_TYPE_IN_RANGE(type, STMT_WITH, STMT_CATCH)
#define STMT_TYPE_IS_TRYING(type) \ #define STMT_TYPE_IS_TRYING(type) \
STMT_TYPE_IN_RANGE(type, STMT_TRY, STMT_SUBROUTINE) STMT_TYPE_IN_RANGE(type, STMT_TRY, STMT_SUBROUTINE)
@@ -481,6 +498,17 @@ js_EmitFunctionBody(JSContext *cx, JSCodeGenerator *cg, JSParseNode *body,
* *
* NB: the js_SrcNoteSpec array in jsemit.c is indexed by this enum, so its * NB: the js_SrcNoteSpec array in jsemit.c is indexed by this enum, so its
* initializers need to match the order here. * initializers need to match the order here.
*
* Note on adding new source notes: every pair of bytecodes (A, B) where A and
* B have disjoint sets of source notes that could apply to each bytecode may
* reuse the same note type value for two notes (snA, snB) that have the same
* arity, offsetBias, and isSpanDep initializers in js_SrcNoteSpec. This is
* why SRC_IF and SRC_INITPROP have the same value below. For bad historical
* reasons, some bytecodes below that could be overlayed have not been, but
* before using SRC_EXTENDED, consider compressing the existing note types.
*
* Don't forget to update JSXDR_BYTECODE_VERSION in jsxdrapi.h for all such
* incompatible source note or other bytecode changes.
*/ */
typedef enum JSSrcNoteType { typedef enum JSSrcNoteType {
SRC_NULL = 0, /* terminates a note vector */ SRC_NULL = 0, /* terminates a note vector */
@@ -495,17 +523,20 @@ typedef enum JSSrcNoteType {
also used on JSOP_ENDINIT if extra comma also used on JSOP_ENDINIT if extra comma
at end of array literal: [1,2,,] */ at end of array literal: [1,2,,] */
SRC_DECL = 6, /* type of a declaration (var, const, let*) */ SRC_DECL = 6, /* type of a declaration (var, const, let*) */
SRC_PCDELTA = 7, /* distance from comma-operator to next POP, SRC_PCDELTA = 7, /* distance forward from comma-operator to
or from CONDSWITCH to first CASE opcode -- next POP, or from CONDSWITCH to first CASE
or SRC_PCBASE variant for obj.function::foo opcode, etc. -- always a forward delta */
gets and sets */
SRC_ASSIGNOP = 8, /* += or another assign-op follows */ SRC_ASSIGNOP = 8, /* += or another assign-op follows */
SRC_COND = 9, /* JSOP_IFEQ is from conditional ?: operator */ SRC_COND = 9, /* JSOP_IFEQ is from conditional ?: operator */
SRC_BRACE = 10, /* mandatory brace, for scope or to avoid SRC_BRACE = 10, /* mandatory brace, for scope or to avoid
dangling else */ dangling else */
SRC_HIDDEN = 11, /* opcode shouldn't be decompiled */ SRC_HIDDEN = 11, /* opcode shouldn't be decompiled */
SRC_PCBASE = 12, /* distance back from annotated get- or setprop SRC_PCBASE = 12, /* distance back from annotated getprop or
op to first obj.prop.subprop bytecode */ setprop op to left-most obj.prop.subprop
bytecode -- always a backward delta */
SRC_METHODBASE = 13, /* SRC_PCBASE variant for obj.function::foo
gets and sets; disjoint from SRC_LABEL by
bytecode to which it applies */
SRC_LABEL = 13, /* JSOP_NOP for label: with atomid immediate */ SRC_LABEL = 13, /* JSOP_NOP for label: with atomid immediate */
SRC_LABELBRACE = 14, /* JSOP_NOP for label: {...} begin brace */ SRC_LABELBRACE = 14, /* JSOP_NOP for label: {...} begin brace */
SRC_ENDBRACE = 15, /* JSOP_NOP for label: {...} end brace */ SRC_ENDBRACE = 15, /* JSOP_NOP for label: {...} end brace */
@@ -515,7 +546,7 @@ typedef enum JSSrcNoteType {
2nd off to first JSOP_CASE if condswitch */ 2nd off to first JSOP_CASE if condswitch */
SRC_FUNCDEF = 19, /* JSOP_NOP for function f() with atomid */ SRC_FUNCDEF = 19, /* JSOP_NOP for function f() with atomid */
SRC_CATCH = 20, /* catch block has guard */ SRC_CATCH = 20, /* catch block has guard */
SRC_UNUSED21 = 21, /* unused */ SRC_EXTENDED = 21, /* extended source note, 32-159, in next byte */
SRC_NEWLINE = 22, /* bytecode follows a source newline */ SRC_NEWLINE = 22, /* bytecode follows a source newline */
SRC_SETLINE = 23, /* a file-absolute source line number note */ SRC_SETLINE = 23, /* a file-absolute source line number note */
SRC_XDELTA = 24 /* 24-31 are for extended delta notes */ SRC_XDELTA = 24 /* 24-31 are for extended delta notes */

View File

@@ -2234,28 +2234,21 @@ js_ValueToCallableObject(JSContext *cx, jsval *vp, uintN flags)
void void
js_ReportIsNotFunction(JSContext *cx, jsval *vp, uintN flags) js_ReportIsNotFunction(JSContext *cx, jsval *vp, uintN flags)
{ {
JSType type; JSStackFrame *fp;
JSString *fallback;
JSString *str; JSString *str;
JSTempValueRooter tvr; JSTempValueRooter tvr;
const char *bytes, *source; const char *bytes, *source;
/* for (fp = cx->fp; fp && !fp->spbase; fp = fp->down)
* We provide the typename as the fallback to handle the case when continue;
* valueOf is not a function, which prevents ValueToString from being
* called as the default case inside js_DecompileValueGenerator (and
* so recursing back to here).
*/
type = JS_TypeOfValue(cx, *vp);
fallback = ATOM_TO_STRING(cx->runtime->atomState.typeAtoms[type]);
str = js_DecompileValueGenerator(cx, str = js_DecompileValueGenerator(cx,
(flags & JSV2F_SEARCH_STACK) (fp && fp->spbase <= vp && vp < fp->sp)
? vp - fp->sp
: (flags & JSV2F_SEARCH_STACK)
? JSDVG_SEARCH_STACK ? JSDVG_SEARCH_STACK
: cx->fp
? vp - cx->fp->sp
: JSDVG_IGNORE_STACK, : JSDVG_IGNORE_STACK,
*vp, *vp,
fallback); NULL);
if (str) { if (str) {
JS_PUSH_SINGLE_TEMP_ROOT(cx, str, &tvr); JS_PUSH_SINGLE_TEMP_ROOT(cx, str, &tvr);
bytes = JS_GetStringBytes(str); bytes = JS_GetStringBytes(str);

View File

@@ -2333,13 +2333,13 @@ interrupt:
END_CASE(JSOP_POP2) END_CASE(JSOP_POP2)
BEGIN_CASE(JSOP_SWAP) BEGIN_CASE(JSOP_SWAP)
/* vp = sp - depth; /* swap generating pc's for the decompiler */
* N.B. JSOP_SWAP doesn't swap the corresponding generating pcs ltmp = vp[-1];
* for the operands it swaps. vp[-1] = vp[-2];
*/
ltmp = sp[-1];
sp[-1] = sp[-2];
sp[-2] = ltmp; sp[-2] = ltmp;
rtmp = sp[-1];
sp[-1] = sp[-2];
sp[-2] = rtmp;
END_CASE(JSOP_SWAP) END_CASE(JSOP_SWAP)
BEGIN_CASE(JSOP_POPV) BEGIN_CASE(JSOP_POPV)
@@ -2941,16 +2941,22 @@ interrupt:
BEGIN_CASE(JSOP_DUP) BEGIN_CASE(JSOP_DUP)
JS_ASSERT(sp > fp->spbase); JS_ASSERT(sp > fp->spbase);
rval = sp[-1]; vp = sp - 1; /* address top of stack */
PUSH_OPND(rval); rval = *vp;
vp -= depth; /* address generating pc */
vp[1] = *vp;
PUSH(rval);
END_CASE(JSOP_DUP) END_CASE(JSOP_DUP)
BEGIN_CASE(JSOP_DUP2) BEGIN_CASE(JSOP_DUP2)
JS_ASSERT(sp - 1 > fp->spbase); JS_ASSERT(sp - 2 >= fp->spbase);
lval = FETCH_OPND(-2); vp = sp - 1; /* address top of stack */
rval = FETCH_OPND(-1); lval = vp[-1];
PUSH_OPND(lval); rval = *vp;
PUSH_OPND(rval); vp -= depth; /* address generating pc */
vp[1] = vp[2] = *vp;
PUSH(lval);
PUSH(rval);
END_CASE(JSOP_DUP2) END_CASE(JSOP_DUP2)
#define PROPERTY_OP(n, call) \ #define PROPERTY_OP(n, call) \
@@ -3290,6 +3296,7 @@ interrupt:
END_CASE(JSOP_NEW_NE) END_CASE(JSOP_NEW_NE)
BEGIN_CASE(JSOP_CASE) BEGIN_CASE(JSOP_CASE)
pc2 = (jsbytecode *) sp[-2-depth];
NEW_EQUALITY_OP(==); NEW_EQUALITY_OP(==);
(void) POP(); (void) POP();
if (cond) { if (cond) {
@@ -3297,10 +3304,12 @@ interrupt:
CHECK_BRANCH(len); CHECK_BRANCH(len);
DO_NEXT_OP(len); DO_NEXT_OP(len);
} }
sp[-depth] = (jsval)pc2;
PUSH(lval); PUSH(lval);
END_CASE(JSOP_CASE) END_CASE(JSOP_CASE)
BEGIN_CASE(JSOP_CASEX) BEGIN_CASE(JSOP_CASEX)
pc2 = (jsbytecode *) sp[-2-depth];
NEW_EQUALITY_OP(==); NEW_EQUALITY_OP(==);
(void) POP(); (void) POP();
if (cond) { if (cond) {
@@ -3308,6 +3317,7 @@ interrupt:
CHECK_BRANCH(len); CHECK_BRANCH(len);
DO_NEXT_OP(len); DO_NEXT_OP(len);
} }
sp[-depth] = (jsval)pc2;
PUSH(lval); PUSH(lval);
END_CASE(JSOP_CASEX) END_CASE(JSOP_CASEX)

View File

@@ -3799,10 +3799,10 @@ js_DeleteProperty(JSContext *cx, JSObject *obj, jsid id, jsval *rval)
JSBool JSBool
js_DefaultValue(JSContext *cx, JSObject *obj, JSType hint, jsval *vp) js_DefaultValue(JSContext *cx, JSObject *obj, JSType hint, jsval *vp)
{ {
jsval v; jsval v, save;
JSString *str; JSString *str;
v = OBJECT_TO_JSVAL(obj); v = save = OBJECT_TO_JSVAL(obj);
switch (hint) { switch (hint) {
case JSTYPE_STRING: case JSTYPE_STRING:
/* /*
@@ -3846,7 +3846,7 @@ js_DefaultValue(JSContext *cx, JSObject *obj, JSType hint, jsval *vp)
str = NULL; str = NULL;
} }
*vp = OBJECT_TO_JSVAL(obj); *vp = OBJECT_TO_JSVAL(obj);
str = js_DecompileValueGenerator(cx, JSDVG_SEARCH_STACK, v, str); str = js_DecompileValueGenerator(cx, JSDVG_SEARCH_STACK, save, str);
if (str) { if (str) {
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
JSMSG_CANT_CONVERT_TO, JSMSG_CANT_CONVERT_TO,

File diff suppressed because it is too large Load Diff

View File

@@ -284,7 +284,8 @@ js_Disassemble1(JSContext *cx, JSScript *script, jsbytecode *pc, uintN loc,
* Decompilers, for script, function, and expression pretty-printing. * Decompilers, for script, function, and expression pretty-printing.
*/ */
extern JSBool extern JSBool
js_DecompileCode(JSPrinter *jp, JSScript *script, jsbytecode *pc, uintN len); js_DecompileCode(JSPrinter *jp, JSScript *script, jsbytecode *pc, uintN len,
uintN pcdepth);
extern JSBool extern JSBool
js_DecompileScript(JSPrinter *jp, JSScript *script); js_DecompileScript(JSPrinter *jp, JSScript *script);

View File

@@ -321,7 +321,6 @@ OPDEF(JSOP_FINALLY, 134,"finally", NULL, 1, 0, 0, 0, JOF_BYTE)
/* /*
* Swap the top two stack elements. * Swap the top two stack elements.
* XXX JSOP_SWAP doesn't swap the corresponding pc stack generating pcs.
*/ */
OPDEF(JSOP_SWAP, 135,"swap", NULL, 1, 2, 2, 0, JOF_BYTE) OPDEF(JSOP_SWAP, 135,"swap", NULL, 1, 2, 2, 0, JOF_BYTE)

View File

@@ -245,9 +245,8 @@ NewParseNode(JSContext *cx, JSTokenStream *ts, JSParseNodeArity arity,
pn->pn_op = JSOP_NOP; pn->pn_op = JSOP_NOP;
pn->pn_arity = arity; pn->pn_arity = arity;
pn->pn_next = NULL; pn->pn_next = NULL;
#if JS_HAS_XML_SUPPORT
pn->pn_ts = ts; pn->pn_ts = ts;
#endif pn->pn_source = NULL;
return pn; return pn;
} }
@@ -322,9 +321,8 @@ NewBinary(JSContext *cx, JSTokenType tt,
pn->pn_left = left; pn->pn_left = left;
pn->pn_right = right; pn->pn_right = right;
pn->pn_next = NULL; pn->pn_next = NULL;
#if JS_HAS_XML_SUPPORT
pn->pn_ts = NULL; pn->pn_ts = NULL;
#endif pn->pn_source = NULL;
return pn; return pn;
} }
@@ -852,7 +850,7 @@ js_CompileFunctionBody(JSContext *cx, JSTokenStream *ts, JSFunction *fun)
* helper function signature in order to share code among destructuring and * helper function signature in order to share code among destructuring and
* simple variable declaration parsers. In the destructuring case, the binder * simple variable declaration parsers. In the destructuring case, the binder
* function is called indirectly from the variable declaration parser by way * function is called indirectly from the variable declaration parser by way
* of CheckDestructuring and its subroutines. * of CheckDestructuring and its friends.
*/ */
typedef struct BindData BindData; typedef struct BindData BindData;
@@ -984,10 +982,9 @@ BindLocalVariable(JSContext *cx, BindData *data, JSAtom *atom)
/* /*
* Forward declaration to maintain top-down presentation. * Forward declaration to maintain top-down presentation.
*/ */
static JSBool static JSParseNode *
CheckDestructuring(JSContext *cx, BindData *data, DestructuringExpr(JSContext *cx, BindData *data, JSTreeContext *tc,
JSParseNode *left, JSParseNode *right, JSTokenType tt);
JSTreeContext *tc);
static JSBool static JSBool
BindDestructuringArg(JSContext *cx, BindData *data, JSAtom *atom, BindDestructuringArg(JSContext *cx, BindData *data, JSAtom *atom,
@@ -1197,7 +1194,7 @@ FunctionDef(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc,
if (!objAtom) if (!objAtom)
return NULL; return NULL;
/* Initialize early for possible flags mutation via CheckDestructuring. */ /* Initialize early for possible flags mutation via DestructuringExpr. */
TREE_CONTEXT_INIT(&funtc); TREE_CONTEXT_INIT(&funtc);
/* Now parse formal argument list and compute fun->nargs. */ /* Now parse formal argument list and compute fun->nargs. */
@@ -1222,10 +1219,6 @@ FunctionDef(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc,
JSParseNode *lhs, *rhs; JSParseNode *lhs, *rhs;
jsint slot; jsint slot;
lhs = PrimaryExpr(cx, ts, tc, tt, JS_FALSE);
if (!lhs)
return NULL;
/* /*
* A destructuring formal parameter turns into one or more * A destructuring formal parameter turns into one or more
* local variables initialized from properties of a single * local variables initialized from properties of a single
@@ -1239,7 +1232,8 @@ FunctionDef(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc,
data.u.var.setter = js_SetLocalVariable; data.u.var.setter = js_SetLocalVariable;
data.u.var.attrs = JSPROP_PERMANENT; data.u.var.attrs = JSPROP_PERMANENT;
if (!CheckDestructuring(cx, &data, lhs, NULL, &funtc)) lhs = DestructuringExpr(cx, &data, &funtc, tt);
if (!lhs)
return NULL; return NULL;
/* /*
@@ -2141,7 +2135,8 @@ CheckDestructuring(JSContext *cx, BindData *data,
} }
} }
if (pn->pn_type != TOK_COMMA) { /* Nullary comma is an elision; binary comma is an expression.*/
if (pn->pn_type != TOK_COMMA || pn->pn_arity != PN_NULLARY) {
if (pn->pn_type == TOK_RB || pn->pn_type == TOK_RC) { if (pn->pn_type == TOK_RB || pn->pn_type == TOK_RC) {
ok = CheckDestructuring(cx, data, pn, pn2, tc); ok = CheckDestructuring(cx, data, pn, pn2, tc);
} else { } else {
@@ -2220,6 +2215,20 @@ no_var_name:
goto out; goto out;
} }
static JSParseNode *
DestructuringExpr(JSContext *cx, BindData *data, JSTreeContext *tc,
JSTokenType tt)
{
JSParseNode *pn;
pn = PrimaryExpr(cx, data->ts, tc, tt, JS_FALSE);
if (!pn)
return NULL;
if (!CheckDestructuring(cx, data, pn, NULL, tc))
return NULL;
return pn;
}
#endif /* JS_HAS_DESTRUCTURING */ #endif /* JS_HAS_DESTRUCTURING */
extern const char js_with_statement_str[]; extern const char js_with_statement_str[];
@@ -2344,22 +2353,6 @@ ReturnOrYield(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc,
return pn; return pn;
} }
#if JS_HAS_BLOCK_SCOPE
static JSStmtInfo *
FindMaybeScopeStatement(JSTreeContext *tc)
{
JSStmtInfo *stmt;
stmt = tc->topStmt;
while (stmt) {
if (STMT_MAYBE_SCOPE(stmt))
return stmt;
stmt = stmt->down;
}
return NULL;
}
#endif
static JSParseNode * static JSParseNode *
PushLexicalScope(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc, PushLexicalScope(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc,
JSStmtInfo *stmtInfo) JSStmtInfo *stmtInfo)
@@ -2551,13 +2544,16 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
pn2 = Statement(cx, ts, tc); pn2 = Statement(cx, ts, tc);
if (!pn2) if (!pn2)
return NULL; return NULL;
ts->flags |= TSF_OPERAND;
if (js_MatchToken(cx, ts, TOK_ELSE)) { if (js_MatchToken(cx, ts, TOK_ELSE)) {
ts->flags &= ~TSF_OPERAND;
stmtInfo.type = STMT_ELSE; stmtInfo.type = STMT_ELSE;
pn3 = Statement(cx, ts, tc); pn3 = Statement(cx, ts, tc);
if (!pn3) if (!pn3)
return NULL; return NULL;
pn->pn_pos.end = pn3->pn_pos.end; pn->pn_pos.end = pn3->pn_pos.end;
} else { } else {
ts->flags &= ~TSF_OPERAND;
pn3 = NULL; pn3 = NULL;
pn->pn_pos.end = pn2->pn_pos.end; pn->pn_pos.end = pn2->pn_pos.end;
} }
@@ -3056,12 +3052,9 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
#if JS_HAS_DESTRUCTURING #if JS_HAS_DESTRUCTURING
case TOK_LB: case TOK_LB:
case TOK_LC: case TOK_LC:
pn3 = PrimaryExpr(cx, ts, tc, tt, JS_FALSE); pn3 = DestructuringExpr(cx, &data, tc, tt);
if (!pn3) if (!pn3)
return NULL; return NULL;
if (!CheckDestructuring(cx, &data, pn3, NULL, tc))
return NULL;
break; break;
#endif #endif
@@ -3111,7 +3104,10 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
PN_APPEND(catchList, pnblock); PN_APPEND(catchList, pnblock);
lastCatch = pn2; lastCatch = pn2;
} while ((tt = js_GetToken(cx, ts)) == TOK_CATCH); ts->flags |= TSF_OPERAND;
tt = js_GetToken(cx, ts);
ts->flags &= ~TSF_OPERAND;
} while (tt == TOK_CATCH);
} }
pn->pn_kid2 = catchList; pn->pn_kid2 = catchList;
@@ -3289,6 +3285,7 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
#if JS_HAS_BLOCK_SCOPE #if JS_HAS_BLOCK_SCOPE
case TOK_LET: case TOK_LET:
{ {
JSStmtInfo **sip;
JSObject *obj; JSObject *obj;
JSAtom *atom; JSAtom *atom;
@@ -3306,13 +3303,21 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
/* /*
* This is a let declaration. We must convert the nearest JSStmtInfo * This is a let declaration. We must convert the nearest JSStmtInfo
* to be our scope statement. Further let declarations in this block * that is a block or a switch body to be our scope statement. Further
* will find this scope statement and use the same block object. If we * let declarations in this block will find this scope statement and
* are the first let declaration in this block (i.e., when the nearest * use the same block object. If we are the first let declaration in
* maybe-scope JSStmtInfo isn't a scope statement) then we also need * this block (i.e., when the nearest maybe-scope JSStmtInfo isn't a
* to set tc->blockNode to be our TOK_LEXICALSCOPE. * scope statement) then we also need to set tc->blockNode to be our
* TOK_LEXICALSCOPE.
*/ */
stmt = FindMaybeScopeStatement(tc); sip = &tc->topScopeStmt;
for (stmt = tc->topStmt; stmt; stmt = stmt->down) {
if (STMT_MAYBE_SCOPE(stmt))
break;
if (stmt == *sip)
sip = &stmt->downScope;
}
if (stmt && (stmt->flags & SIF_SCOPE)) { if (stmt && (stmt->flags & SIF_SCOPE)) {
JS_ASSERT(tc->blockChain == ATOM_TO_OBJECT(stmt->atom)); JS_ASSERT(tc->blockChain == ATOM_TO_OBJECT(stmt->atom));
obj = tc->blockChain; obj = tc->blockChain;
@@ -3346,14 +3351,27 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
if (!atom) if (!atom)
return NULL; return NULL;
/*
* Insert stmt on the tc->topScopeStmt/stmtInfo.downScope linked
* list stack, if it isn't already there. If it is there, but it
* lacks the SIF_SCOPE flag, it must be a try, catch, or finally
* block.
*/
JS_ASSERT(!(stmt->flags & SIF_SCOPE)); JS_ASSERT(!(stmt->flags & SIF_SCOPE));
stmt->flags |= SIF_SCOPE; stmt->flags |= SIF_SCOPE;
if (!stmt->downScope) { if (stmt != *sip) {
stmt->downScope = tc->topScopeStmt; JS_ASSERT(!stmt->downScope);
tc->topScopeStmt = stmt; JS_ASSERT(stmt->type == STMT_BLOCK ||
stmt->type == STMT_SWITCH ||
stmt->type == STMT_TRY ||
stmt->type == STMT_FINALLY);
stmt->downScope = *sip;
*sip = stmt;
} else { } else {
JS_ASSERT(stmt == tc->topScopeStmt); JS_ASSERT(stmt->type == STMT_CATCH);
JS_ASSERT(stmt->downScope);
} }
obj->slots[JSSLOT_PARENT] = OBJECT_TO_JSVAL(tc->blockChain); obj->slots[JSSLOT_PARENT] = OBJECT_TO_JSVAL(tc->blockChain);
tc->blockChain = obj; tc->blockChain = obj;
stmt->atom = atom; stmt->atom = atom;
@@ -3525,7 +3543,9 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
/* Check termination of this primitive statement. */ /* Check termination of this primitive statement. */
if (ON_CURRENT_LINE(ts, pn->pn_pos)) { if (ON_CURRENT_LINE(ts, pn->pn_pos)) {
ts->flags |= TSF_OPERAND;
tt = js_PeekTokenSameLine(cx, ts); tt = js_PeekTokenSameLine(cx, ts);
ts->flags &= ~TSF_OPERAND;
if (tt == TOK_ERROR) if (tt == TOK_ERROR)
return NULL; return NULL;
if (tt != TOK_EOF && tt != TOK_EOL && tt != TOK_SEMI && tt != TOK_RC) { if (tt != TOK_EOF && tt != TOK_EOL && tt != TOK_SEMI && tt != TOK_RC) {
@@ -3572,12 +3592,12 @@ Variables(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
data.pn = NULL; data.pn = NULL;
data.ts = ts; data.ts = ts;
data.op = CURRENT_TOKEN(ts).t_op; data.op = let ? JSOP_NOP : CURRENT_TOKEN(ts).t_op;
data.binder = let ? BindLet : BindVarOrConst; data.binder = let ? BindLet : BindVarOrConst;
pn = NewParseNode(cx, ts, PN_LIST, tc); pn = NewParseNode(cx, ts, PN_LIST, tc);
if (!pn) if (!pn)
return NULL; return NULL;
pn->pn_op = let ? JSOP_NOP : data.op; pn->pn_op = data.op;
PN_INIT_LIST(pn); PN_INIT_LIST(pn);
/* /*
@@ -4160,7 +4180,9 @@ UnaryExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
/* Don't look across a newline boundary for a postfix incop. */ /* Don't look across a newline boundary for a postfix incop. */
if (ON_CURRENT_LINE(ts, pn->pn_pos)) { if (ON_CURRENT_LINE(ts, pn->pn_pos)) {
ts->flags |= TSF_OPERAND;
tt = js_PeekTokenSameLine(cx, ts); tt = js_PeekTokenSameLine(cx, ts);
ts->flags &= ~TSF_OPERAND;
if (tt == TOK_INC || tt == TOK_DEC) { if (tt == TOK_INC || tt == TOK_DEC) {
(void) js_GetToken(cx, ts); (void) js_GetToken(cx, ts);
pn2 = NewParseNode(cx, ts, PN_UNARY, tc); pn2 = NewParseNode(cx, ts, PN_UNARY, tc);
@@ -4260,9 +4282,8 @@ MemberExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc,
pn2->pn_arity = PN_UNARY; pn2->pn_arity = PN_UNARY;
pn2->pn_kid = pn; pn2->pn_kid = pn;
pn2->pn_next = NULL; pn2->pn_next = NULL;
#if JS_HAS_XML_SUPPORT
pn2->pn_ts = ts; pn2->pn_ts = ts;
#endif pn2->pn_source = NULL;
pn = pn2; pn = pn2;
} }
} }
@@ -5098,7 +5119,6 @@ PrimaryExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc,
JSTokenType tt, JSBool afterDot) JSTokenType tt, JSBool afterDot)
{ {
JSParseNode *pn, *pn2, *pn3; JSParseNode *pn, *pn2, *pn3;
JSBool afterComma;
JSOp op; JSOp op;
#if JS_HAS_SHARP_VARS #if JS_HAS_SHARP_VARS
@@ -5313,13 +5333,10 @@ PrimaryExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc,
#if JS_HAS_DESTRUCTURING #if JS_HAS_DESTRUCTURING
case TOK_LB: case TOK_LB:
case TOK_LC: case TOK_LC:
pnlet = PrimaryExpr(cx, ts, tc, tt, JS_FALSE); pnlet = DestructuringExpr(cx, &data, tc, tt);
if (!pnlet) if (!pnlet)
return NULL; return NULL;
if (!CheckDestructuring(cx, &data, pnlet, NULL, tc))
return NULL;
/* Destructuring requires [key, value] enumeration. */ /* Destructuring requires [key, value] enumeration. */
if (pn2->pn_op != JSOP_FOREACH) if (pn2->pn_op != JSOP_FOREACH)
pn2->pn_op = JSOP_FOREACHKEYVAL; pn2->pn_op = JSOP_FOREACHKEYVAL;
@@ -5408,6 +5425,9 @@ PrimaryExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc,
#endif #endif
case TOK_LC: case TOK_LC:
{
JSBool afterComma;
pn = NewParseNode(cx, ts, PN_LIST, tc); pn = NewParseNode(cx, ts, PN_LIST, tc);
if (!pn) if (!pn)
return NULL; return NULL;
@@ -5524,6 +5544,7 @@ PrimaryExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc,
end_obj_init: end_obj_init:
pn->pn_pos.end = CURRENT_TOKEN(ts).pos.end; pn->pn_pos.end = CURRENT_TOKEN(ts).pos.end;
return pn; return pn;
}
#if JS_HAS_SHARP_VARS #if JS_HAS_SHARP_VARS
case TOK_DEFSHARP: case TOK_DEFSHARP:

View File

@@ -315,9 +315,8 @@ struct JSParseNode {
jsdouble dval; /* aligned numeric literal value */ jsdouble dval; /* aligned numeric literal value */
} pn_u; } pn_u;
JSParseNode *pn_next; /* to align dval and pn_u on RISCs */ JSParseNode *pn_next; /* to align dval and pn_u on RISCs */
#if JS_HAS_XML_SUPPORT JSTokenStream *pn_ts; /* token stream for error reports */
JSTokenStream *pn_ts; /* token stream for XML error reports */ JSAtom *pn_source; /* saved source for decompilation */
#endif
}; };
#define pn_funAtom pn_u.func.funAtom #define pn_funAtom pn_u.func.funAtom

View File

@@ -190,10 +190,14 @@ GrowTokenBuf(JSStringBuffer *sb, size_t newlength)
JS_ARENA_ALLOCATE_CAST(base, jschar *, pool, tbsize); JS_ARENA_ALLOCATE_CAST(base, jschar *, pool, tbsize);
} else { } else {
length = PTRDIFF(sb->limit, base, jschar); length = PTRDIFF(sb->limit, base, jschar);
if ((size_t)length >= ~(size_t)0 / sizeof(jschar)) {
base = NULL;
} else {
tbsize = (length + 1) * sizeof(jschar); tbsize = (length + 1) * sizeof(jschar);
length += length + 1; length += length + 1;
JS_ARENA_GROW_CAST(base, jschar *, pool, tbsize, tbsize); JS_ARENA_GROW_CAST(base, jschar *, pool, tbsize, tbsize);
} }
}
if (!base) { if (!base) {
JS_ReportOutOfMemory(cx); JS_ReportOutOfMemory(cx);
sb->base = STRING_BUFFER_ERROR_BASE; sb->base = STRING_BUFFER_ERROR_BASE;
@@ -530,9 +534,7 @@ ReportCompileErrorNumber(JSContext *cx, void *handle, uintN flags,
JSString *linestr = NULL; JSString *linestr = NULL;
JSTokenStream *ts = NULL; JSTokenStream *ts = NULL;
JSCodeGenerator *cg = NULL; JSCodeGenerator *cg = NULL;
#if JS_HAS_XML_SUPPORT
JSParseNode *pn = NULL; JSParseNode *pn = NULL;
#endif
JSErrorReporter onError; JSErrorReporter onError;
JSTokenPos *tp; JSTokenPos *tp;
JSStackFrame *fp; JSStackFrame *fp;
@@ -560,12 +562,10 @@ ReportCompileErrorNumber(JSContext *cx, void *handle, uintN flags,
case JSREPORT_CG: case JSREPORT_CG:
cg = handle; cg = handle;
break; break;
#if JS_HAS_XML_SUPPORT
case JSREPORT_PN: case JSREPORT_PN:
pn = handle; pn = handle;
ts = pn->pn_ts; ts = pn->pn_ts;
break; break;
#endif
} }
JS_ASSERT(!ts || ts->linebuf.limit < ts->linebuf.base + JS_LINE_LIMIT); JS_ASSERT(!ts || ts->linebuf.limit < ts->linebuf.base + JS_LINE_LIMIT);
@@ -579,13 +579,11 @@ ReportCompileErrorNumber(JSContext *cx, void *handle, uintN flags,
do { do {
if (ts) { if (ts) {
report->filename = ts->filename; report->filename = ts->filename;
#if JS_HAS_XML_SUPPORT
if (pn) { if (pn) {
report->lineno = pn->pn_pos.begin.lineno; report->lineno = pn->pn_pos.begin.lineno;
if (report->lineno != ts->lineno) if (report->lineno != ts->lineno)
break; break;
} }
#endif
report->lineno = ts->lineno; report->lineno = ts->lineno;
linestr = js_NewStringCopyN(cx, ts->linebuf.base, linestr = js_NewStringCopyN(cx, ts->linebuf.base,
PTRDIFF(ts->linebuf.limit, PTRDIFF(ts->linebuf.limit,
@@ -596,10 +594,9 @@ ReportCompileErrorNumber(JSContext *cx, void *handle, uintN flags,
? JS_GetStringBytes(linestr) ? JS_GetStringBytes(linestr)
: NULL; : NULL;
tp = &ts->tokens[(ts->cursor+ts->lookahead) & NTOKENS_MASK].pos; tp = &ts->tokens[(ts->cursor+ts->lookahead) & NTOKENS_MASK].pos;
#if JS_HAS_XML_SUPPORT
if (pn) if (pn)
tp = &pn->pn_pos; tp = &pn->pn_pos;
#endif
/* /*
* FIXME: What should instead happen here is that we should * FIXME: What should instead happen here is that we should
* find error-tokens in userbuf, if !ts->file. That will * find error-tokens in userbuf, if !ts->file. That will
@@ -629,8 +626,8 @@ ReportCompileErrorNumber(JSContext *cx, void *handle, uintN flags,
} }
/* /*
* If we can't find out where the error was based on the current frame, * If we can't find out where the error was based on the current
* see if the next frame has a script/pc combo we can use. * frame, see if the next frame has a script/pc combo we can use.
*/ */
for (fp = cx->fp; fp; fp = fp->down) { for (fp = cx->fp; fp; fp = fp->down) {
if (fp->script && fp->pc) { if (fp->script && fp->pc) {

View File

@@ -1427,8 +1427,12 @@ js_PCToLineNumber(JSContext *cx, JSScript *script, jsbytecode *pc)
* Special case: function definition needs no line number note because * Special case: function definition needs no line number note because
* the function's script contains its starting line number. * the function's script contains its starting line number.
*/ */
if (*pc == JSOP_DEFFUN) { if (*pc == JSOP_DEFFUN ||
atom = GET_ATOM(cx, script, pc); (*pc == JSOP_LITOPX && pc[1 + LITERAL_INDEX_LEN] == JSOP_DEFFUN)) {
atom = js_GetAtom(cx, &script->atomMap,
(*pc == JSOP_DEFFUN)
? GET_ATOM_INDEX(pc)
: GET_LITERAL_INDEX(pc));
fun = (JSFunction *) JS_GetPrivate(cx, ATOM_TO_OBJECT(atom)); fun = (JSFunction *) JS_GetPrivate(cx, ATOM_TO_OBJECT(atom));
JS_ASSERT(FUN_INTERPRETED(fun)); JS_ASSERT(FUN_INTERPRETED(fun));
return fun->u.i.script->lineno; return fun->u.i.script->lineno;