diff --git a/js/src/jsfun.cpp b/js/src/jsfun.cpp index dbc0237433ba..2aa88e03636c 100644 --- a/js/src/jsfun.cpp +++ b/js/src/jsfun.cpp @@ -1773,7 +1773,7 @@ fun_applyConstructor(JSContext *cx, uintN argc, jsval *vp) sp++; } - ok = js_InvokeConstructor(cx, length, invokevp); + ok = js_InvokeConstructor(cx, length, JS_TRUE, invokevp); *vp = *invokevp; out: js_FreeStack(cx, mark); diff --git a/js/src/jsinterp.cpp b/js/src/jsinterp.cpp index 7c2f68686bee..cc2dee339bc2 100644 --- a/js/src/jsinterp.cpp +++ b/js/src/jsinterp.cpp @@ -1005,7 +1005,7 @@ NoSuchMethod(JSContext *cx, uintN argc, jsval *vp, uint32 flags) } else { invokevp[3] = OBJECT_TO_JSVAL(argsobj); ok = (flags & JSINVOKE_CONSTRUCT) - ? js_InvokeConstructor(cx, 2, invokevp) + ? js_InvokeConstructor(cx, 2, JS_TRUE, invokevp) : js_Invoke(cx, 2, invokevp, flags); vp[0] = invokevp[0]; } @@ -1720,7 +1720,7 @@ js_StrictlyEqual(JSContext *cx, jsval lval, jsval rval) } JSBool -js_InvokeConstructor(JSContext *cx, uintN argc, jsval *vp) +js_InvokeConstructor(JSContext *cx, uintN argc, JSBool clampReturn, jsval *vp) { JSFunction *fun, *fun2; JSObject *obj, *obj2, *proto, *parent; @@ -1781,7 +1781,7 @@ js_InvokeConstructor(JSContext *cx, uintN argc, jsval *vp) /* Check the return value and if it's primitive, force it to be obj. */ rval = *vp; - if (JSVAL_IS_PRIMITIVE(rval)) { + if (clampReturn && JSVAL_IS_PRIMITIVE(rval)) { if (!fun) { /* native [[Construct]] returning primitive is error */ JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, @@ -2931,6 +2931,16 @@ js_Interpret(JSContext *cx) */ ASSERT_NOT_THROWING(cx); JS_ASSERT(regs.sp == StackBase(fp)); + if ((fp->flags & JSFRAME_CONSTRUCTING) && + JSVAL_IS_PRIMITIVE(fp->rval)) { + if (!fp->fun) { + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, + JSMSG_BAD_NEW_RESULT, + js_ValueToPrintableString(cx, rval)); + goto error; + } + fp->rval = OBJECT_TO_JSVAL(fp->thisp); + } ok = JS_TRUE; if (inlineCallCount) inline_return: @@ -4749,7 +4759,7 @@ js_Interpret(JSContext *cx) } } - if (!js_InvokeConstructor(cx, argc, vp)) + if (!js_InvokeConstructor(cx, argc, JS_FALSE, vp)) goto error; regs.sp = vp + 1; LOAD_INTERRUPT_HANDLER(cx); diff --git a/js/src/jsinterp.h b/js/src/jsinterp.h index 320ca1ceb48e..d54501c23256 100644 --- a/js/src/jsinterp.h +++ b/js/src/jsinterp.h @@ -455,7 +455,7 @@ js_Execute(JSContext *cx, JSObject *chain, JSScript *script, JSStackFrame *down, uintN flags, jsval *result); extern JSBool -js_InvokeConstructor(JSContext *cx, uintN argc, jsval *vp); +js_InvokeConstructor(JSContext *cx, uintN argc, JSBool clampReturn, jsval *vp); extern JSBool js_Interpret(JSContext *cx); diff --git a/js/src/jstracer.cpp b/js/src/jstracer.cpp index 26bc7c6ae634..fb59cae65761 100644 --- a/js/src/jstracer.cpp +++ b/js/src/jstracer.cpp @@ -2040,10 +2040,13 @@ js_SynthesizeFrame(JSContext* cx, const FrameInfo& fi) newifp->frame.callee = fi.callee; newifp->frame.fun = fun; - newifp->frame.argc = fi.s.argc; + uint16 argc = fi.s.argc & 0x7fff; + bool constructing = fi.s.argc & 0x8000; + + newifp->frame.argc = argc; newifp->callerRegs.pc = fi.callpc; newifp->callerRegs.sp = cx->fp->slots + fi.s.spdist; - newifp->frame.argv = newifp->callerRegs.sp - JS_MAX(fun->nargs, fi.s.argc); + newifp->frame.argv = newifp->callerRegs.sp - JS_MAX(fun->nargs, argc); JS_ASSERT(newifp->frame.argv >= StackBase(cx->fp)); newifp->frame.rval = JSVAL_VOID; @@ -2052,7 +2055,7 @@ js_SynthesizeFrame(JSContext* cx, const FrameInfo& fi) newifp->frame.scopeChain = OBJ_GET_PARENT(cx, fi.callee); newifp->frame.sharpDepth = 0; newifp->frame.sharpArray = NULL; - newifp->frame.flags = 0; + newifp->frame.flags = constructing ? JSFRAME_CONSTRUCTING : 0; newifp->frame.dormantNext = NULL; newifp->frame.xmlNamespace = NULL; newifp->frame.blockChain = NULL; @@ -4052,7 +4055,7 @@ TraceRecorder::record_JSOP_NEW() LIns* tv_ins = lir->insCall(F_FastNewObject, args); guard(false, lir->ins_eq0(tv_ins), OOM_EXIT); set(&tval, tv_ins); - return interpretedFunctionCall(fval, fun, argc); + return interpretedFunctionCall(fval, fun, argc, true); } static JSTraceableNative knownNatives[] = { @@ -4596,7 +4599,7 @@ TraceRecorder::guardShapelessCallee(jsval& callee) } bool -TraceRecorder::interpretedFunctionCall(jsval& fval, JSFunction* fun, uintN argc) +TraceRecorder::interpretedFunctionCall(jsval& fval, JSFunction* fun, uintN argc, bool constructing) { if (JS_GetGlobalForObject(cx, JSVAL_TO_OBJECT(fval)) != globalObj) ABORT_TRACE("JSOP_CALL or JSOP_NEW crosses global scopes"); @@ -4620,12 +4623,15 @@ TraceRecorder::interpretedFunctionCall(jsval& fval, JSFunction* fun, uintN argc) FORALL_SLOTS_IN_PENDING_FRAMES(cx, 0/*callDepth*/, *m++ = determineSlotType(vp); ); - + + if (argc >= 0x8000) + ABORT_TRACE("too many arguments"); + FrameInfo fi = { JSVAL_TO_OBJECT(fval), fp->regs->pc, typemap, - { { fp->regs->sp - fp->slots, argc } } + { { fp->regs->sp - fp->slots, argc | (constructing ? 0x8000 : 0) } } }; unsigned callDepth = getCallDepth(); @@ -4691,7 +4697,7 @@ TraceRecorder::record_JSOP_CALL() JSFunction* fun = GET_FUNCTION_PRIVATE(cx, JSVAL_TO_OBJECT(fval)); if (FUN_INTERPRETED(fun)) - return interpretedFunctionCall(fval, fun, argc); + return interpretedFunctionCall(fval, fun, argc, false); if (FUN_SLOW_NATIVE(fun)) ABORT_TRACE("slow native"); @@ -4789,7 +4795,7 @@ TraceRecorder::record_JSOP_CALL() sp[i] = argv[i]; } applyingArguments = true; - return interpretedFunctionCall(tval, tfun, argc); + return interpretedFunctionCall(tval, tfun, argc, false); } if (aval_ins->fid() != F_Array_1str) diff --git a/js/src/jstracer.h b/js/src/jstracer.h index d6f445f0dfde..a6b6e2ddc9a9 100644 --- a/js/src/jstracer.h +++ b/js/src/jstracer.h @@ -326,7 +326,7 @@ class TraceRecorder { nanojit::LIns* dslots_ins, nanojit::LIns* idx_ins); void clearFrameSlotsFromCache(); bool guardShapelessCallee(jsval& callee); - bool interpretedFunctionCall(jsval& fval, JSFunction* fun, uintN argc); + bool interpretedFunctionCall(jsval& fval, JSFunction* fun, uintN argc, bool constructing); bool forInLoop(jsval* vp); void trackCfgMerges(jsbytecode* pc); diff --git a/js/src/trace-test.js b/js/src/trace-test.js index 1d8dc0500c7a..8e86738eb132 100644 --- a/js/src/trace-test.js +++ b/js/src/trace-test.js @@ -1348,6 +1348,44 @@ function testPrimitiveConstructorPrototype() { testPrimitiveConstructorPrototype.expected = "ok"; test(testPrimitiveConstructorPrototype); +function testSideExitInConstructor() { + var FCKConfig = {}; + FCKConfig.CoreStyles = + { + 'Bold': { }, + 'Italic': { }, + 'FontFace': { }, + 'Size' : + { + Overrides: [ ] + }, + + 'Color' : + { + Element: '', + Styles: { }, + Overrides: [ ] + }, + 'BackColor': { + Element : '', + Styles : { 'background-color' : '' } + }, + + }; + var FCKStyle = function(A) { + A.Element; + }; + + var pass = true; + for (var s in FCKConfig.CoreStyles) { + var x = new FCKStyle(FCKConfig.CoreStyles[s]); + if (!x) pass = false; + } + return pass; +} +testSideExitInConstructor.expected = true; +test(testSideExitInConstructor); + /* Keep these at the end so that we can see the summary after the trace-debug spew. */ print("\npassed:", passes.length && passes.join(",")); print("\nFAILED:", fails.length && fails.join(","));