diff --git a/js/src/jit-test/tests/ion/bug1128490.js b/js/src/jit-test/tests/ion/bug1128490.js new file mode 100644 index 00000000000..09963b9b26e --- /dev/null +++ b/js/src/jit-test/tests/ion/bug1128490.js @@ -0,0 +1,10 @@ + +for (var i = 0; i < 1000; ++i) { + function isNotEmpty(obj) { + for (var i = 0 ; i < arguments.length; i++) { + minorgc(); + var o = arguments[i]; + } + }; + isNotEmpty([1]); +} diff --git a/js/src/jit/BacktrackingAllocator.cpp b/js/src/jit/BacktrackingAllocator.cpp index 36cafadf24e..f84336f7f1c 100644 --- a/js/src/jit/BacktrackingAllocator.cpp +++ b/js/src/jit/BacktrackingAllocator.cpp @@ -171,11 +171,16 @@ BacktrackingAllocator::canAddToGroup(VirtualRegisterGroup *group, BacktrackingVi return true; } +static bool +IsArgumentSlotDefinition(LDefinition *def) +{ + return def->policy() == LDefinition::FIXED && def->output()->isArgument(); +} + static bool IsThisSlotDefinition(LDefinition *def) { - return def->policy() == LDefinition::FIXED && - def->output()->isArgument() && + return IsArgumentSlotDefinition(def) && def->output()->toArgument()->index() < THIS_FRAME_ARGSLOT + sizeof(Value); } @@ -199,6 +204,16 @@ BacktrackingAllocator::tryGroupRegisters(uint32_t vreg0, uint32_t vreg1) return true; } + // Registers which might spill to the frame's argument slots can only be + // grouped with other such registers if the frame might access those + // arguments through a lazy arguments object. + if ((IsArgumentSlotDefinition(reg0->def()) || IsArgumentSlotDefinition(reg1->def())) && + graph.mir().entryBlock()->info().script()->argumentsAliasesFormals()) + { + if (*reg0->def()->output() != *reg1->def()->output()) + return true; + } + VirtualRegisterGroup *group0 = reg0->group(), *group1 = reg1->group(); if (!group0 && group1) diff --git a/js/src/jit/JitFrames.cpp b/js/src/jit/JitFrames.cpp index dd9fa059b48..43490b305d7 100644 --- a/js/src/jit/JitFrames.cpp +++ b/js/src/jit/JitFrames.cpp @@ -971,17 +971,21 @@ ReadAllocation(const JitFrameIterator &frame, const LAllocation *a) #endif static void -MarkThisAndExtraActualArguments(JSTracer *trc, const JitFrameIterator &frame) +MarkThisAndArguments(JSTracer *trc, const JitFrameIterator &frame) { // Mark |this| and any extra actual arguments for an Ion frame. Marking of - // formal arguments is taken care of by the frame's safepoint/snapshot. + // formal arguments is taken care of by the frame's safepoint/snapshot, + // except when the script's lazy arguments object aliases those formals, + // in which case we mark them as well. JitFrameLayout *layout = frame.jsFrame(); size_t nargs = frame.numActualArgs(); size_t nformals = 0; - if (CalleeTokenIsFunction(layout->calleeToken())) - nformals = CalleeTokenToFunction(layout->calleeToken())->nargs(); + if (CalleeTokenIsFunction(layout->calleeToken())) { + JSFunction *fun = CalleeTokenToFunction(layout->calleeToken()); + nformals = fun->nonLazyScript()->argumentsAliasesFormals() ? 0 : fun->nargs(); + } Value *argv = layout->argv(); @@ -1023,7 +1027,7 @@ MarkIonJSFrame(JSTracer *trc, const JitFrameIterator &frame) ionScript = frame.ionScriptFromCalleeToken(); } - MarkThisAndExtraActualArguments(trc, frame); + MarkThisAndArguments(trc, frame); const SafepointIndex *si = ionScript->getSafepointIndex(frame.returnAddressToFp()); @@ -1082,7 +1086,7 @@ MarkBailoutFrame(JSTracer *trc, const JitFrameIterator &frame) // We have to mark the list of actual arguments, as only formal arguments // are represented in the Snapshot. - MarkThisAndExtraActualArguments(trc, frame); + MarkThisAndArguments(trc, frame); // Under a bailout, do not have a Safepoint to only iterate over GC-things. // Thus we use a SnapshotIterator to trace all the locations which would be