Properly handle side exits in scripted constructors (originally mrbkap, r=brendan, 453462).

This commit is contained in:
Andreas Gal 2008-09-18 14:13:37 -07:00
Родитель adbbc755c3
Коммит 73e877d0c7
6 изменённых файлов: 70 добавлений и 16 удалений

Просмотреть файл

@ -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(","));