diff --git a/js/src/jit-test/tests/arguments/apply-closed-over-arguments.js b/js/src/jit-test/tests/arguments/apply-closed-over-arguments.js new file mode 100644 index 000000000000..708d4cdb0919 --- /dev/null +++ b/js/src/jit-test/tests/arguments/apply-closed-over-arguments.js @@ -0,0 +1,14 @@ +function bar(x,y) { + return x + y; +} + +function foo(x, y) { + function closeOver() { return x; } + return bar.apply({}, arguments); +} + +var sum = 0; +for (var i = 0; i < 100; i++) { + sum += foo(1,2); +} +assertEq(sum, 300) diff --git a/js/src/vm/ArgumentsObject.cpp b/js/src/vm/ArgumentsObject.cpp index b5c127f88b31..99d7d3979c02 100644 --- a/js/src/vm/ArgumentsObject.cpp +++ b/js/src/vm/ArgumentsObject.cpp @@ -99,6 +99,7 @@ void ArgumentsObject::MaybeForwardToCallObject(AbstractFramePtr frame, for (PositionalFormalParameterIter fi(script); fi; fi++) { if (fi.closedOver()) { data->args[fi.argumentSlot()] = MagicEnvSlotValue(fi.location().slot()); + obj->markArgumentForwarded(); } } } @@ -117,6 +118,7 @@ void ArgumentsObject::MaybeForwardToCallObject(jit::JitFrameLayout* frame, for (PositionalFormalParameterIter fi(script); fi; fi++) { if (fi.closedOver()) { data->args[fi.argumentSlot()] = MagicEnvSlotValue(fi.location().slot()); + obj->markArgumentForwarded(); } } } diff --git a/js/src/vm/ArgumentsObject.h b/js/src/vm/ArgumentsObject.h index 23a36ba4ce47..a39c8f01f199 100644 --- a/js/src/vm/ArgumentsObject.h +++ b/js/src/vm/ArgumentsObject.h @@ -168,7 +168,9 @@ class ArgumentsObject : public NativeObject { static const uint32_t ITERATOR_OVERRIDDEN_BIT = 0x2; static const uint32_t ELEMENT_OVERRIDDEN_BIT = 0x4; static const uint32_t CALLEE_OVERRIDDEN_BIT = 0x8; - static const uint32_t PACKED_BITS_COUNT = 4; + static const uint32_t FORWARDED_ARGUMENTS_BIT = 0x10; + static const uint32_t PACKED_BITS_COUNT = 5; + static const uint32_t PACKED_BITS_MASK = (1 << PACKED_BITS_COUNT) - 1; static_assert(ARGS_LENGTH_MAX <= (UINT32_MAX >> PACKED_BITS_COUNT), "Max arguments length must fit in available bits"); @@ -370,9 +372,21 @@ class ArgumentsObject : public NativeObject { bool argIsForwarded(unsigned i) const { MOZ_ASSERT(i < data()->numArgs); const Value& v = data()->args[i]; + MOZ_ASSERT_IF(IsMagicScopeSlotValue(v), anyArgIsForwarded()); return IsMagicScopeSlotValue(v); } + bool anyArgIsForwarded() const { + const Value& v = getFixedSlot(INITIAL_LENGTH_SLOT); + return v.toInt32() & FORWARDED_ARGUMENTS_BIT; + } + + void markArgumentForwarded() { + uint32_t v = + getFixedSlot(INITIAL_LENGTH_SLOT).toInt32() | FORWARDED_ARGUMENTS_BIT; + setFixedSlot(INITIAL_LENGTH_SLOT, Int32Value(v)); + } + /* * Attempt to speedily and efficiently access the i-th element of this * arguments object. Return true if the element was speedily returned.