From 38779e6762057d8790e93487cdfe97c7f6731106 Mon Sep 17 00:00:00 2001 From: David Mandelin Date: Thu, 17 Sep 2009 18:00:01 -0700 Subject: [PATCH] Bug 516062: detect overridden arguments.length on trace for JSOP_ARGCNT, r=dvander --- js/src/jstracer.cpp | 25 ++++++++++++++++--- .../tests/basic/setArgumentsLength.js | 14 +++++++++++ 2 files changed, 35 insertions(+), 4 deletions(-) create mode 100644 js/src/trace-test/tests/basic/setArgumentsLength.js diff --git a/js/src/jstracer.cpp b/js/src/jstracer.cpp index f720a557d0e..1b792555b00 100644 --- a/js/src/jstracer.cpp +++ b/js/src/jstracer.cpp @@ -12704,11 +12704,28 @@ TraceRecorder::record_JSOP_ARGSUB() JS_REQUIRES_STACK JSRecordingStatus TraceRecorder::record_JSOP_ARGCNT() { - if (!(cx->fp->fun->flags & JSFUN_HEAVYWEIGHT)) { - stack(0, lir->insImmf(cx->fp->argc)); - return JSRS_CONTINUE; + if (cx->fp->fun->flags & JSFUN_HEAVYWEIGHT) + ABORT_TRACE("can't trace heavyweight JSOP_ARGCNT"); + + // argc is fixed on trace, so ideally we would simply generate LIR for + // constant argc. But the user can mutate arguments.length in the + // interpreter, so we have to check for that in the trace entry frame. + LIns *a_ins = get(&cx->fp->argsobj); + if (callDepth == 0) { + LIns *br = lir->insBranch(LIR_jt, lir->ins_peq0(a_ins), NULL); + + // The following implements IsOverriddenArgsLength on trace. + // The '2' bit is set set if length was overridden. + const uint32 JSSLOT_ARGS_LENGTH = JSSLOT_PRIVATE + 1; + LIns *len_ins = stobj_get_fslot(a_ins, JSSLOT_ARGS_LENGTH); + LIns *ovr_ins = lir->ins2(LIR_piand, len_ins, INS_CONSTWORD(2)); + + guard(true, lir->ins_peq0(ovr_ins), snapshot(BRANCH_EXIT)); + LIns *label = lir->ins0(LIR_label); + br->setTarget(label); } - ABORT_TRACE("can't trace heavyweight JSOP_ARGCNT"); + stack(0, lir->insImmf(cx->fp->argc)); + return JSRS_CONTINUE; } JS_REQUIRES_STACK JSRecordingStatus diff --git a/js/src/trace-test/tests/basic/setArgumentsLength.js b/js/src/trace-test/tests/basic/setArgumentsLength.js new file mode 100644 index 00000000000..775d3ef9f2c --- /dev/null +++ b/js/src/trace-test/tests/basic/setArgumentsLength.js @@ -0,0 +1,14 @@ +var count = 0; + +function f() { + arguments.length--; + for (var i = 0; i < arguments.length; ++i) { + ++count; + } +} + +f(1, 2); +f(1, 2); +f(2, 2); + +assertEq(count, 3);