diff --git a/js/src/jscntxt.cpp b/js/src/jscntxt.cpp index 1d5b25709c2c..42f72b3ceb64 100644 --- a/js/src/jscntxt.cpp +++ b/js/src/jscntxt.cpp @@ -1607,7 +1607,7 @@ js_ReportValueErrorFlags(JSContext *cx, uintN flags, const uintN errorNumber, #if defined DEBUG && defined XP_UNIX /* For gdb usage. */ -void js_traceon(JSContext *cx) { cx->tracefp = stderr; cx->tracePrevOp = JSOP_LIMIT; } +void js_traceon(JSContext *cx) { cx->tracefp = stderr; cx->tracePrevPc = NULL; } void js_traceoff(JSContext *cx) { cx->tracefp = NULL; } #endif diff --git a/js/src/jscntxt.h b/js/src/jscntxt.h index 5d324e0e8e57..60757fea5355 100644 --- a/js/src/jscntxt.h +++ b/js/src/jscntxt.h @@ -932,7 +932,7 @@ struct JSContext { char *lastMessage; #ifdef DEBUG void *tracefp; - JSOp tracePrevOp; + jsbytecode *tracePrevPc; #endif /* Per-context optional error reporter. */ diff --git a/js/src/jsemit.cpp b/js/src/jsemit.cpp index 7fbe30bbb335..9ae23f619e74 100644 --- a/js/src/jsemit.cpp +++ b/js/src/jsemit.cpp @@ -6274,32 +6274,40 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) case TOK_ARRAYCOMP: #endif /* - * Emit code for [a, b, c] of the form: + * Emit code for [a, b, c] that is equivalent to constructing a new + * array and in source order evaluating each element value and adding + * it to the array, without invoking latent setters. We use the + * JSOP_NEWINIT and JSOP_INITELEM bytecodes to ignore setters and to + * avoid dup'ing and popping the array as each element is added, as + * JSOP_SETELEM/JSOP_SETPROP would do. * - * t = new Array; t[0] = a; t[1] = b; t[2] = c; t; - * - * but use a stack slot for t and avoid dup'ing and popping it using - * the JSOP_NEWINIT and JSOP_INITELEM bytecodes. - * - * If no sharp variable is defined and the initialiser is not for an - * array comprehension, use JSOP_NEWARRAY. + * If no sharp variable is defined, the initializer is not for an array + * comprehension, the initializer is not overlarge, and the initializer + * is not in global code (whose stack growth cannot be precisely modeled + * due to the need to reserve space for global variables and regular + * expressions), use JSOP_NEWARRAY to minimize opcodes and to create the + * array using a fast, all-at-once process rather than a slow, element- + * by-element process. */ #if JS_HAS_SHARP_VARS sharpnum = -1; do_emit_array: #endif -#if JS_HAS_GENERATORS || JS_HAS_SHARP_VARS - op = JSOP_NEWARRAY; -# if JS_HAS_GENERATORS + op = (JS_LIKELY(pn->pn_count < JS_BIT(16)) && (cg->flags & TCF_IN_FUNCTION)) + ? JSOP_NEWARRAY + : JSOP_NEWINIT; + +#if JS_HAS_GENERATORS if (pn->pn_type == TOK_ARRAYCOMP) op = JSOP_NEWINIT; -# endif -# if JS_HAS_SHARP_VARS +#endif +#if JS_HAS_SHARP_VARS JS_ASSERT_IF(sharpnum >= 0, cg->flags & TCF_HAS_SHARPS); if (cg->flags & TCF_HAS_SHARPS) op = JSOP_NEWINIT; -# endif +#endif + if (op == JSOP_NEWINIT) { if (js_Emit2(cx, cg, op, (jsbytecode) JSProto_Array) < 0) return JS_FALSE; @@ -6308,7 +6316,6 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) EMIT_UINT16_IMM_OP(JSOP_DEFSHARP, (jsatomid) sharpnum); # endif } -#endif #if JS_HAS_GENERATORS if (pn->pn_type == TOK_ARRAYCOMP) { @@ -6335,10 +6342,8 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) pn2 = pn->pn_head; for (atomIndex = 0; pn2; atomIndex++, pn2 = pn2->pn_next) { -#if JS_HAS_SHARP_VARS if (op == JSOP_NEWINIT && !EmitNumberOp(cx, atomIndex, cg)) return JS_FALSE; -#endif if (pn2->pn_type == TOK_COMMA) { if (js_Emit1(cx, cg, JSOP_HOLE) < 0) return JS_FALSE; @@ -6346,10 +6351,8 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) if (!js_EmitTree(cx, cg, pn2)) return JS_FALSE; } -#if JS_HAS_SHARP_VARS if (op == JSOP_NEWINIT && js_Emit1(cx, cg, JSOP_INITELEM) < 0) return JS_FALSE; -#endif } JS_ASSERT(atomIndex == pn->pn_count); @@ -6359,20 +6362,18 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) return JS_FALSE; } -#if JS_HAS_SHARP_VARS if (op == JSOP_NEWINIT) { - /* Emit an op for sharp array cleanup and decompilation. */ + /* + * Emit an op to finish the array and, secondarily, to aid in sharp + * array cleanup (if JS_HAS_SHARP_VARS) and decompilation. + */ if (js_Emit1(cx, cg, JSOP_ENDINIT) < 0) return JS_FALSE; break; } -#endif - off = js_EmitN(cx, cg, JSOP_NEWARRAY, 3); - if (off < 0) - return JS_FALSE; - pc = CG_CODE(cg, off); - SET_UINT24(pc, atomIndex); - UpdateDepth(cx, cg, off); + + JS_ASSERT(atomIndex < JS_BIT(16)); + EMIT_UINT16_IMM_OP(JSOP_NEWARRAY, atomIndex); break; case TOK_RC: @@ -6388,12 +6389,12 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) } #endif /* - * Emit code for {p:a, '%q':b, 2:c} of the form: - * - * t = new Object; t.p = a; t['%q'] = b; t[2] = c; t; - * - * but use a stack slot for t and avoid dup'ing and popping it via - * the JSOP_NEWINIT and JSOP_INITELEM/JSOP_INITPROP bytecodes. + * Emit code for {p:a, '%q':b, 2:c} that is equivalent to constructing + * a new object and in source order evaluating each property value and + * adding the property to the object, without invoking latent setters. + * We use the JSOP_NEWINIT and JSOP_INITELEM/JSOP_INITPROP bytecodes to + * ignore setters and to avoid dup'ing and popping the object as each + * property is added, as JSOP_SETELEM/JSOP_SETPROP would do. */ if (js_Emit2(cx, cg, JSOP_NEWINIT, (jsbytecode) JSProto_Object) < 0) return JS_FALSE; diff --git a/js/src/jsemit.h b/js/src/jsemit.h index 10333ca21427..fda43ebae16b 100644 --- a/js/src/jsemit.h +++ b/js/src/jsemit.h @@ -261,7 +261,7 @@ struct JSTreeContext { /* tree context for semantic checks */ #define TCF_HAS_SHARPS 0x8000 /* source contains sharp defs or uses */ /* - * Flags to propagate from FunctionBody. + * Sticky deoptimization flags to propagate from FunctionBody. */ #define TCF_FUN_FLAGS (TCF_FUN_SETS_OUTER_NAME | \ TCF_FUN_USES_ARGUMENTS | \ diff --git a/js/src/jsinterp.cpp b/js/src/jsinterp.cpp index f6f2e8ac321a..404f5dba4c42 100644 --- a/js/src/jsinterp.cpp +++ b/js/src/jsinterp.cpp @@ -2104,9 +2104,10 @@ js_TraceOpcode(JSContext *cx) * Operations in prologues don't produce interesting values, and * js_DecompileValueGenerator isn't set up to handle them anyway. */ - if (cx->tracePrevOp != JSOP_LIMIT && regs->pc >= fp->script->main) { - ndefs = js_GetStackDefs(cx, &js_CodeSpec[cx->tracePrevOp], - cx->tracePrevOp, fp->script, regs->pc); + if (cx->tracePrevPc && regs->pc >= fp->script->main) { + JSOp tracePrevOp = JSOp(*cx->tracePrevPc); + ndefs = js_GetStackDefs(cx, &js_CodeSpec[tracePrevOp], tracePrevOp, + fp->script, cx->tracePrevPc); /* * If there aren't that many elements on the stack, then @@ -2159,7 +2160,7 @@ js_TraceOpcode(JSContext *cx) } fprintf(tracefp, " @ %u\n", (uintN) (regs->sp - StackBase(fp))); } - cx->tracePrevOp = op; + cx->tracePrevPc = regs->pc; /* It's nice to have complete traces when debugging a crash. */ fflush(tracefp); @@ -3638,7 +3639,25 @@ js_Interpret(JSContext *cx) do { JSPropCacheEntry *entry; + /* + * We can skip the property lookup for the global object. If + * the property does not exist anywhere on the scope chain, + * JSOP_SETNAME adds the property to the global. + * + * As a consequence of this optimization for the global object + * we run its JSRESOLVE_ASSIGNING-tolerant resolve hooks only + * in JSOP_SETNAME, after the interpreter evaluates the right- + * hand-side of the assignment, and not here. + * + * This should be transparent to the hooks because the script, + * instead of name = rhs, could have used global.name = rhs + * given a global object reference, which also calls the hooks + * only after evaluating the rhs. We desire such resolve hook + * equivalence between the two forms. + */ obj = fp->scopeChain; + if (!OBJ_GET_PARENT(cx, obj)) + break; if (JS_LIKELY(OBJ_IS_NATIVE(obj))) { PROPERTY_CACHE_TEST(cx, regs.pc, obj, obj2, entry, atom); if (!atom) { @@ -3651,7 +3670,7 @@ js_Interpret(JSContext *cx) LOAD_ATOM(0); } id = ATOM_TO_JSID(atom); - obj = js_FindIdentifierBase(cx, id, entry); + obj = js_FindIdentifierBase(cx, fp->scopeChain, id, entry); if (!obj) goto error; } while (0); @@ -4757,8 +4776,10 @@ js_Interpret(JSContext *cx) LOAD_ATOM(0); id = ATOM_TO_JSID(atom); if (entry) { - if (!js_SetPropertyHelper(cx, obj, id, &rval, &entry)) + if (!js_SetPropertyHelper(cx, obj, id, op == JSOP_SETNAME, + &rval, &entry)) { goto error; + } #ifdef JS_TRACER if (entry) TRACE_1(SetPropMiss, entry); @@ -6252,8 +6273,8 @@ js_Interpret(JSContext *cx) END_CASE(JSOP_HOLE) BEGIN_CASE(JSOP_NEWARRAY) - len = GET_UINT24(regs.pc); - JS_ASSERT(len <= regs.sp - StackBase(fp)); + len = GET_UINT16(regs.pc); + cx->fp->assertValidStackDepth(len); obj = js_NewArrayObject(cx, len, regs.sp - len, JS_TRUE); if (!obj) goto error; @@ -6412,7 +6433,7 @@ js_Interpret(JSContext *cx) goto error; } if (JS_UNLIKELY(atom == cx->runtime->atomState.protoAtom) - ? !js_SetPropertyHelper(cx, obj, id, &rval, &entry) + ? !js_SetPropertyHelper(cx, obj, id, false, &rval, &entry) : !js_DefineNativeProperty(cx, obj, id, rval, NULL, NULL, JSPROP_ENUMERATE, 0, 0, NULL, &entry)) { @@ -7288,6 +7309,10 @@ js_Interpret(JSContext *cx) ok &= js_UnwindScope(cx, fp, 0, ok || cx->throwing); JS_ASSERT(regs.sp == StackBase(fp)); +#ifdef DEBUG + cx->tracePrevPc = NULL; +#endif + if (inlineCallCount) goto inline_return; diff --git a/js/src/jsinterp.h b/js/src/jsinterp.h index 1a8790aa22b1..6bd0db85ad91 100644 --- a/js/src/jsinterp.h +++ b/js/src/jsinterp.h @@ -132,6 +132,14 @@ struct JSStackFrame { #ifdef DEBUG jsrefcount pcDisabledSave; /* for balanced property cache control */ #endif + +#ifdef __cplusplus /* Aargh, LiveConnect, bug 442399. */ + void assertValidStackDepth(uintN depth) { + extern jsval *StackBase(JSStackFrame *fp); + JS_ASSERT(0 <= regs->sp - StackBase(this)); + JS_ASSERT(depth <= uintptr_t(regs->sp - StackBase(this))); + } +#endif }; #ifdef __cplusplus diff --git a/js/src/jsobj.cpp b/js/src/jsobj.cpp index 5bd0d324f142..c636451f557b 100644 --- a/js/src/jsobj.cpp +++ b/js/src/jsobj.cpp @@ -4070,45 +4070,68 @@ js_FindProperty(JSContext *cx, jsid id, JSObject **objp, JSObject **pobjp, } JS_REQUIRES_STACK JSObject * -js_FindIdentifierBase(JSContext *cx, jsid id, JSPropCacheEntry *entry) +js_FindIdentifierBase(JSContext *cx, JSObject *scopeChain, jsid id, + JSPropCacheEntry *entry) { - JSObject *obj, *pobj; - JSProperty *prop; + /* + * This function should not be called for a global object or from the + * trace and should have a valid cache entry for native scopeChain. + */ + JSObject *parent = OBJ_GET_PARENT(cx, scopeChain); + JS_ASSERT(parent); + JS_ASSERT(!JS_ON_TRACE(cx)); + JS_ASSERT_IF(OBJ_IS_NATIVE(scopeChain), entry); /* - * Look for id's property along the "with" statement chain and the - * statically-linked scope chain. + * Optimize and cache only for classes that do not have resolve hooks and + * where the prototype is used only to implement a shared scope, bug 462734 + * and bug 487039. */ - if (js_FindPropertyHelper(cx, id, &obj, &pobj, &prop, &entry) < 0) - return NULL; - if (prop) { - OBJ_DROP_PROPERTY(cx, pobj, prop); - return obj; - } + JSObject *obj = scopeChain; + for (int scopeIndex = 0; ; scopeIndex++) { + JSClass *clasp = OBJ_GET_CLASS(cx, obj); + if (clasp != &js_CallClass && clasp != &js_BlockClass) + break; - /* - * Use the top-level scope from the scope chain, which won't end in the - * same scope as cx->globalObject for cross-context function calls. - */ - JS_ASSERT(obj); - - /* - * Property not found. Give a strict warning if binding an undeclared - * top-level variable. - */ - if (JS_HAS_STRICT_OPTION(cx)) { - JSString *str = JSVAL_TO_STRING(ID_TO_VALUE(id)); - const char *bytes = js_GetStringBytes(cx, str); - - if (!bytes || - !JS_ReportErrorFlagsAndNumber(cx, - JSREPORT_WARNING | JSREPORT_STRICT, - js_GetErrorMessage, NULL, - JSMSG_UNDECLARED_VAR, bytes)) { + JSObject *pobj; + JSProperty *prop; + int protoIndex = js_LookupPropertyWithFlags(cx, obj, id, 0, + &pobj, &prop); + if (protoIndex < 0) return NULL; + if (prop) { + JS_ASSERT(OBJ_IS_NATIVE(pobj)); + JS_ASSERT(OBJ_GET_CLASS(cx, pobj) == clasp); + js_FillPropertyCache(cx, scopeChain, OBJ_SHAPE(scopeChain), + scopeIndex, protoIndex, pobj, + (JSScopeProperty *) prop, &entry); + JS_UNLOCK_OBJ(cx, pobj); + return obj; + } + + obj = parent; + parent = OBJ_GET_PARENT(cx, parent); + if (!parent) { + /* + * Here obj is the global one and we can skip any checks for it, + * see comments in the JSOP_BINDNAME case of js_Interpret. + */ + return obj; } } + do { + JSObject *pobj; + JSProperty *prop; + if (!OBJ_LOOKUP_PROPERTY(cx, obj, id, &pobj, &prop)) + return NULL; + if (prop) { + OBJ_DROP_PROPERTY(cx, pobj, prop); + break; + } + obj = parent; + parent = OBJ_GET_PARENT(cx, parent); + } while (parent); return obj; } @@ -4337,8 +4360,8 @@ js_GetMethod(JSContext *cx, JSObject *obj, jsid id, jsval *vp, } JSBool -js_SetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, jsval *vp, - JSPropCacheEntry **entryp) +js_SetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, + JSBool unqualified, jsval *vp, JSPropCacheEntry **entryp) { uint32 shape; int protoIndex; @@ -4368,10 +4391,28 @@ js_SetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, jsval *vp, &pobj, &prop); if (protoIndex < 0) return JS_FALSE; + if (prop) { + if (!OBJ_IS_NATIVE(pobj)) { + OBJ_DROP_PROPERTY(cx, pobj, prop); + prop = NULL; + } + } else { + /* We should never add properties to lexical blocks. */ + JS_ASSERT(OBJ_GET_CLASS(cx, obj) != &js_BlockClass); - if (prop && !OBJ_IS_NATIVE(pobj)) { - OBJ_DROP_PROPERTY(cx, pobj, prop); - prop = NULL; + if (unqualified && !OBJ_GET_PARENT(cx, obj) && + JS_HAS_STRICT_OPTION(cx)) { + JSString *str = JSVAL_TO_STRING(ID_TO_VALUE(id)); + const char *bytes = js_GetStringBytes(cx, str); + if (!bytes || + !JS_ReportErrorFlagsAndNumber(cx, + JSREPORT_WARNING | + JSREPORT_STRICT, + js_GetErrorMessage, NULL, + JSMSG_UNDECLARED_VAR, bytes)) { + return NULL; + } + } } sprop = (JSScopeProperty *) prop; @@ -4487,9 +4528,6 @@ js_SetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, jsval *vp, } if (!sprop) { - /* We should never add properties to lexical blocks. */ - JS_ASSERT(OBJ_GET_CLASS(cx, obj) != &js_BlockClass); - /* * Purge the property cache of now-shadowed id in obj's scope chain. * Do this early, before locking obj to avoid nesting locks. @@ -4549,7 +4587,7 @@ js_SetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, jsval *vp, JSBool js_SetProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp) { - return js_SetPropertyHelper(cx, obj, id, vp, NULL); + return js_SetPropertyHelper(cx, obj, id, false, vp, NULL); } JSBool diff --git a/js/src/jsobj.h b/js/src/jsobj.h index fd7b2512d895..2d2219153834 100644 --- a/js/src/jsobj.h +++ b/js/src/jsobj.h @@ -681,7 +681,8 @@ js_FindProperty(JSContext *cx, jsid id, JSObject **objp, JSObject **pobjp, JSProperty **propp); extern JS_REQUIRES_STACK JSObject * -js_FindIdentifierBase(JSContext *cx, jsid id, JSPropCacheEntry *entry); +js_FindIdentifierBase(JSContext *cx, JSObject *scopeChain, jsid id, + JSPropCacheEntry *entry); extern JSObject * js_FindVariableScope(JSContext *cx, JSFunction **funp); @@ -711,8 +712,8 @@ js_GetMethod(JSContext *cx, JSObject *obj, jsid id, jsval *vp, JSPropCacheEntry **entryp); extern JSBool -js_SetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, jsval *vp, - JSPropCacheEntry **entryp); +js_SetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, + JSBool unqualified, jsval *vp, JSPropCacheEntry **entryp); extern JSBool js_SetProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp); diff --git a/js/src/jsopcode.cpp b/js/src/jsopcode.cpp index 91ebc71468c1..9cfe0caf5b4c 100644 --- a/js/src/jsopcode.cpp +++ b/js/src/jsopcode.cpp @@ -214,7 +214,7 @@ js_GetVariableStackUses(JSOp op, jsbytecode *pc) case JSOP_LEAVEBLOCKEXPR: return GET_UINT16(pc) + 1; case JSOP_NEWARRAY: - return GET_UINT24(pc); + return GET_UINT16(pc); default: /* stack: fun, this, [argc arguments] */ JS_ASSERT(op == JSOP_NEW || op == JSOP_CALL || @@ -4357,7 +4357,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop) break; case JSOP_NEWARRAY: - argc = GET_UINT24(pc); + argc = GET_UINT16(pc); LOCAL_ASSERT(ss->top >= (uintN) argc); if (argc == 0) { todo = SprintCString(&ss->sprinter, "[]"); diff --git a/js/src/jsopcode.tbl b/js/src/jsopcode.tbl index 749b877d1664..93cd0258e84f 100644 --- a/js/src/jsopcode.tbl +++ b/js/src/jsopcode.tbl @@ -554,9 +554,9 @@ OPDEF(JSOP_LENGTH, 221, "length", NULL, 1, 1, 1, 18, JOF_BYTE|J * stack, consuming those values and replacing them with the newly-constructed * array. The topmost value is the last value in the new array, and the * bottommost value is the first value in the array; the array length is a - * 24-bit immediate operand to the instruction. + * 16-bit immediate operand to the instruction. */ -OPDEF(JSOP_NEWARRAY, 222, "newarray", NULL, 4, -1, 1, 19, JOF_UINT24) +OPDEF(JSOP_NEWARRAY, 222, "newarray", NULL, 3, -1, 1, 19, JOF_UINT16) /* * Push a JSVAL_HOLE value onto the stack, representing an omitted property in diff --git a/js/src/jsparse.cpp b/js/src/jsparse.cpp index 39d0d275497d..e46aca9f1480 100644 --- a/js/src/jsparse.cpp +++ b/js/src/jsparse.cpp @@ -6405,9 +6405,15 @@ GeneratorExpr(JSParseNode *pn, JSParseNode *kid, JSTreeContext *tc) if (!funbox) return NULL; - gentc.flags |= TCF_FUN_IS_GENERATOR | TCF_GENEXP_LAMBDA; - if (tc->flags & TCF_HAS_SHARPS) - gentc.flags |= TCF_HAS_SHARPS; + /* + * We assume conservatively that any deoptimization flag in tc->flags + * besides TCF_FUN_PARAM_ARGUMENTS can come from the kid. So we + * propagate these flags into genfn. For code simplicity we also do + * not detect if the flags were only set in the kid and could be + * removed from tc->flags. + */ + gentc.flags |= TCF_FUN_IS_GENERATOR | TCF_GENEXP_LAMBDA | + (tc->flags & (TCF_FUN_FLAGS & ~TCF_FUN_PARAM_ARGUMENTS)); funbox->tcflags |= gentc.flags; genfn->pn_funbox = funbox; genfn->pn_blockid = gentc.bodyid; diff --git a/js/src/jstracer.cpp b/js/src/jstracer.cpp index 072c98f2a66d..4e3d9b158124 100644 --- a/js/src/jstracer.cpp +++ b/js/src/jstracer.cpp @@ -7180,7 +7180,9 @@ TraceRecorder::functionCall(bool constructing, uintN argc) JS_REQUIRES_STACK bool TraceRecorder::record_JSOP_NEW() { - return functionCall(true, GET_ARGC(cx->fp->regs->pc)); + uintN argc = GET_ARGC(cx->fp->regs->pc); + cx->fp->assertValidStackDepth(argc + 2); + return functionCall(true, argc); } JS_REQUIRES_STACK bool @@ -7893,7 +7895,9 @@ TraceRecorder::interpretedFunctionCall(jsval& fval, JSFunction* fun, uintN argc, JS_REQUIRES_STACK bool TraceRecorder::record_JSOP_CALL() { - return functionCall(false, GET_ARGC(cx->fp->regs->pc)); + uintN argc = GET_ARGC(cx->fp->regs->pc); + cx->fp->assertValidStackDepth(argc + 2); + return functionCall(false, argc); } static jsbytecode* apply_imacro_table[] = { @@ -7926,8 +7930,9 @@ TraceRecorder::record_JSOP_APPLY() JSStackFrame* fp = cx->fp; jsbytecode *pc = fp->regs->pc; uintN argc = GET_ARGC(pc); + cx->fp->assertValidStackDepth(argc + 2); + jsval* vp = fp->regs->sp - (argc + 2); - JS_ASSERT(vp >= StackBase(fp)); jsuint length = 0; JSObject* aobj = NULL; LIns* aobj_ins = NULL; @@ -9919,7 +9924,9 @@ TraceRecorder::record_JSOP_NEWARRAY() if (!getClassPrototype(JSProto_Array, proto_ins)) return false; - uint32 len = GET_UINT24(cx->fp->regs->pc); + uint32 len = GET_UINT16(cx->fp->regs->pc); + cx->fp->assertValidStackDepth(len); + LIns* args[] = { lir->insImm(len), proto_ins, cx_ins }; LIns* v_ins = lir->insCall(&js_NewUninitializedArray_ci, args); guard(false, lir->ins_eq0(v_ins), OOM_EXIT); diff --git a/js/src/jsxdrapi.h b/js/src/jsxdrapi.h index dfbe2442b444..be1454e0ab33 100644 --- a/js/src/jsxdrapi.h +++ b/js/src/jsxdrapi.h @@ -204,7 +204,7 @@ JS_XDRFindClassById(JSXDRState *xdr, uint32 id); * before deserialization of bytecode. If the saved version does not match * the current version, abort deserialization and invalidate the file. */ -#define JSXDR_BYTECODE_VERSION (0xb973c0de - 45) +#define JSXDR_BYTECODE_VERSION (0xb973c0de - 46) /* * Library-private functions. diff --git a/js/src/shell/js.cpp b/js/src/shell/js.cpp index d71c0a5a1384..943a60f5e353 100644 --- a/js/src/shell/js.cpp +++ b/js/src/shell/js.cpp @@ -1882,7 +1882,7 @@ Tracing(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) if (cx->tracefp && cx->tracefp != stderr) fclose((FILE *)cx->tracefp); cx->tracefp = file; - cx->tracePrevOp = JSOP_LIMIT; + cx->tracePrevPc = NULL; return JS_TRUE; bad_argument: