Bug 798834 - Remove reset of non-actual arguments for StackFrame. r=luke a=bajaj
authorNicolas B. Pierron <nicolas.b.pierron@mozilla.com>
Mon, 08 Oct 2012 14:55:39 -0700
changeset 116209 721b1865e7f849b58d4aa38623ec38feedb07f9b
parent 116208 72b50096eab2b5ccc8412ba8b3b9c7e45e378797
child 116210 1260bf2d4bdd65a26ada0520dd9f31da69fb4105
push id1708
push userakeybl@mozilla.com
push dateMon, 19 Nov 2012 21:10:21 +0000
treeherdermozilla-beta@27b14fe50103 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersluke, bajaj
bugs798834
milestone18.0a2
Bug 798834 - Remove reset of non-actual arguments for StackFrame. r=luke a=bajaj
js/src/jit-test/tests/basic/bug798834.js
js/src/vm/ArgumentsObject.cpp
js/src/vm/ArgumentsObject.h
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/basic/bug798834.js
@@ -0,0 +1,5 @@
+(function(start, stop, step) {
+  stop = start;
+  step = arguments[2];
+  assertEq(stop, true);
+})(true);
--- a/js/src/vm/ArgumentsObject.cpp
+++ b/js/src/vm/ArgumentsObject.cpp
@@ -17,50 +17,37 @@
 
 #include "gc/Barrier-inl.h"
 #include "vm/Stack-inl.h"
 #include "vm/ArgumentsObject-inl.h"
 
 using namespace js;
 using namespace js::gc;
 
-/* Erase formals which are not part of the actuals. */
-static void
-SetMissingFormalArgsToUndefined(HeapValue *dstBase, unsigned numActuals, unsigned numFormals)
-{
-    if (numActuals < numFormals) {
-        HeapValue *dst = dstBase + numActuals, *dstEnd = dstBase + numFormals;
-        while (dst != dstEnd)
-            (dst++)->init(UndefinedValue());
-    }
-}
-
 static void
 CopyStackFrameArguments(const StackFrame *fp, HeapValue *dst)
 {
     JS_ASSERT(!fp->beginsIonActivation());
 
-    HeapValue *dstBase = dst;
     unsigned numActuals = fp->numActualArgs();
     unsigned numFormals = fp->callee().nargs;
 
     /* Copy formal arguments. */
     Value *src = fp->formals();
     Value *end = src + numFormals;
     while (src != end)
         (dst++)->init(*src++);
 
     /* Copy actual argument which are not contignous. */
     if (numFormals < numActuals) {
         src = fp->actuals() + numFormals;
         end = src + (numActuals - numFormals);
         while (src != end)
             (dst++)->init(*src++);
     }
-    SetMissingFormalArgsToUndefined(dstBase, numActuals, numFormals);
 }
 
 /* static */ void
 ArgumentsObject::MaybeForwardToCallObject(StackFrame *fp, JSObject *obj, ArgumentsData *data)
 {
     JSScript *script = fp->script();
     if (fp->fun()->isHeavyweight() && script->argsObjAliasesFormals()) {
         obj->initFixedSlot(MAYBE_CALL_SLOT, ObjectValue(fp->callObj()));
@@ -72,20 +59,16 @@ ArgumentsObject::MaybeForwardToCallObjec
 struct CopyStackFrameArgs
 {
     StackFrame *fp_;
 
     CopyStackFrameArgs(StackFrame *fp)
       : fp_(fp)
     { }
 
-    inline JSScript *script() const { return fp_->script(); }
-    inline JSFunction *callee() const { return &fp_->callee(); }
-    unsigned numActualArgs() const { return fp_->numActualArgs(); }
-
     void copyArgs(HeapValue *dst) const {
         CopyStackFrameArguments(fp_, dst);
     }
 
     /*
      * If a call object exists and the arguments object aliases formals, the
      * call object is the canonical location for formals.
      */
@@ -97,79 +80,81 @@ struct CopyStackFrameArgs
 struct CopyStackIterArgs
 {
     StackIter &iter_;
 
     CopyStackIterArgs(StackIter &iter)
       : iter_(iter)
     { }
 
-    inline JSScript *script() const { return iter_.script(); }
-    inline JSFunction *callee() const { return iter_.callee(); }
-    unsigned numActualArgs() const { return iter_.numActualArgs(); }
-
-    void copyArgs(HeapValue *dst) const {
+    void copyArgs(HeapValue *dstBase) const {
         if (!iter_.isIon()) {
-            CopyStackFrameArguments(iter_.fp(), dst);
+            CopyStackFrameArguments(iter_.fp(), dstBase);
             return;
         }
 
+        /* Copy actual arguments. */
+        iter_.ionForEachCanonicalActualArg(CopyToHeap(dstBase));
+
+        /* Define formals which are not part of the actuals. */
         unsigned numActuals = iter_.numActualArgs();
         unsigned numFormals = iter_.callee()->nargs;
-
-        iter_.ionForEachCanonicalActualArg(CopyToHeap(dst));
-        SetMissingFormalArgsToUndefined(dst, numActuals, numFormals);
+       if (numActuals < numFormals) {
+            HeapValue *dst = dstBase + numActuals, *dstEnd = dstBase + numFormals;
+            while (dst != dstEnd)
+                (dst++)->init(UndefinedValue());
+        }
     }
 
     /*
      * Ion frames are copying every argument onto the stack, other locations are
      * invalid.
      */
     void maybeForwardToCallObject(JSObject *obj, ArgumentsData *data) {
         if (!iter_.isIon())
             ArgumentsObject::MaybeForwardToCallObject(iter_.fp(), obj, data);
     }
 };
 
 template <typename CopyArgs>
 /* static */ ArgumentsObject *
-ArgumentsObject::create(JSContext *cx, HandleScript script, HandleFunction callee, CopyArgs &copy)
+ArgumentsObject::create(JSContext *cx, HandleScript script, HandleFunction callee, unsigned numActuals,
+                        CopyArgs &copy)
 {
-    RootedObject proto(cx, copy.callee()->global().getOrCreateObjectPrototype(cx));
+    RootedObject proto(cx, callee->global().getOrCreateObjectPrototype(cx));
     if (!proto)
         return NULL;
 
     RootedTypeObject type(cx, proto->getNewType(cx));
     if (!type)
         return NULL;
 
-    bool strict = copy.callee()->inStrictMode();
+    bool strict = callee->inStrictMode();
     Class *clasp = strict ? &StrictArgumentsObjectClass : &NormalArgumentsObjectClass;
 
     RootedShape shape(cx, EmptyShape::getInitialShape(cx, clasp, TaggedProto(proto),
                                                       proto->getParent(), FINALIZE_KIND,
                                                       BaseShape::INDEXED));
     if (!shape)
         return NULL;
 
-    unsigned numActuals = copy.numActualArgs();
-    unsigned numFormals = copy.callee()->nargs;
+    unsigned numFormals = callee->nargs;
     unsigned numDeletedWords = NumWordsForBitArrayOfLength(numActuals);
     unsigned numArgs = Max(numActuals, numFormals);
     unsigned numBytes = offsetof(ArgumentsData, args) +
                         numDeletedWords * sizeof(size_t) +
                         numArgs * sizeof(Value);
 
     ArgumentsData *data = (ArgumentsData *)cx->malloc_(numBytes);
     if (!data)
         return NULL;
 
     data->numArgs = numArgs;
-    data->callee.init(ObjectValue(*copy.callee()));
-    data->script = copy.script();
+    data->callee.init(ObjectValue(*callee.get()));
+    data->script = script;
 
     /* Copy [0, numArgs) into data->slots. */
     HeapValue *dst = data->args, *dstEnd = data->args + numArgs;
     copy.copyArgs(dst);
 
     data->deletedBits = reinterpret_cast<size_t *>(dstEnd);
     ClearAllBitArrayElements(data->deletedBits, numDeletedWords);
 
@@ -190,40 +175,40 @@ ArgumentsObject::create(JSContext *cx, H
 
 ArgumentsObject *
 ArgumentsObject::createExpected(JSContext *cx, StackFrame *fp)
 {
     JS_ASSERT(fp->script()->needsArgsObj());
     RootedScript script(cx, fp->script());
     RootedFunction callee(cx, &fp->callee());
     CopyStackFrameArgs copy(fp);
-    ArgumentsObject *argsobj = create(cx, script, callee, copy);
+    ArgumentsObject *argsobj = create(cx, script, callee, fp->numActualArgs(), copy);
     if (!argsobj)
         return NULL;
 
     fp->initArgsObj(*argsobj);
     return argsobj;
 }
 
 ArgumentsObject *
 ArgumentsObject::createUnexpected(JSContext *cx, StackIter &iter)
 {
     RootedScript script(cx, iter.script());
     RootedFunction callee(cx, iter.callee());
     CopyStackIterArgs copy(iter);
-    return create(cx, script, callee, copy);
+    return create(cx, script, callee, iter.numActualArgs(), copy);
 }
 
 ArgumentsObject *
 ArgumentsObject::createUnexpected(JSContext *cx, StackFrame *fp)
 {
     RootedScript script(cx, fp->script());
     RootedFunction callee(cx, &fp->callee());
     CopyStackFrameArgs copy(fp);
-    return create(cx, script, callee, copy);
+    return create(cx, script, callee, fp->numActualArgs(), copy);
 }
 
 static JSBool
 args_delProperty(JSContext *cx, HandleObject obj, HandleId id, MutableHandleValue vp)
 {
     ArgumentsObject &argsobj = obj->asArguments();
     if (JSID_IS_INT(id)) {
         unsigned arg = unsigned(JSID_TO_INT(id));
--- a/js/src/vm/ArgumentsObject.h
+++ b/js/src/vm/ArgumentsObject.h
@@ -99,18 +99,18 @@ class ArgumentsObject : public JSObject
     static const uint32_t INITIAL_LENGTH_SLOT = 0;
     static const uint32_t DATA_SLOT = 1;
     static const uint32_t MAYBE_CALL_SLOT = 2;
 
     static const uint32_t LENGTH_OVERRIDDEN_BIT = 0x1;
     static const uint32_t PACKED_BITS_COUNT = 1;
 
     template <typename CopyArgs>
-    static ArgumentsObject *create(JSContext *cx, HandleScript script,
-                                   HandleFunction callee, CopyArgs &copy);
+    static ArgumentsObject *create(JSContext *cx, HandleScript script, HandleFunction callee,
+                                   unsigned numActuals, CopyArgs &copy);
 
     inline ArgumentsData *data() const;
 
   public:
     static const uint32_t RESERVED_SLOTS = 3;
     static const gc::AllocKind FINALIZE_KIND = gc::FINALIZE_OBJECT4;
 
     /* Create an arguments object for a frame that is expecting them. */