mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-28 12:45:27 +00:00
Properly handle side exits in scripted constructors (originally mrbkap, r=brendan, 453462).
This commit is contained in:
parent
adbbc755c3
commit
73e877d0c7
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
@ -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(","));
|
||||
|
Loading…
Reference in New Issue
Block a user