Merge.
authorDavid Anderson <danderson@mozilla.com>
Fri, 18 May 2012 01:00:31 -0700
changeset 95536 ec1aca662dbe7ec67ba40be1ee4e4e125e0c114c
parent 95535 27379ba2220ce31039ef86e2c02d5766831b87e4 (current diff)
parent 95534 0f9317cf68d2a76ed5ef1a6a5032b34acc76dede (diff)
child 95537 8c54899dae8275d23fb45c42e0e97b4da30a72ac
push id916
push userdanderson@mozilla.com
push dateFri, 18 May 2012 08:32:11 +0000
milestone15.0a1
Merge.
--- a/js/src/ion/Ion.cpp
+++ b/js/src/ion/Ion.cpp
@@ -952,18 +952,31 @@ EnterIon(JSContext *cx, StackFrame *fp, 
 
     EnterIonCode enter = cx->compartment->ionCompartment()->enterJITInfallible();
 
     int argc = 0;
     Value *argv = NULL;
 
     void *calleeToken;
     if (fp->isFunctionFrame()) {
+        // CountArgSlot include |this| and the |scopeChain|, -1 is used to
+        // discard the |scopeChain|.
         argc = CountArgSlots(fp->fun()) - 1;
         argv = fp->formalArgs() - 1;
+
+        if (fp->hasOverflowArgs()) {
+            int formalArgc = argc;
+            Value *formalArgv = argv;
+            argc = fp->numActualArgs() + 1;
+            argv = fp->actualArgs() - 1;
+            // The beginning of the actual args is not updated, so we just copy
+            // the formal args into the actual args to get a linear vector which
+            // can be copied by generateEnterJit.
+            memcpy(argv, formalArgv, formalArgc * sizeof(Value));
+        }
         calleeToken = CalleeToToken(fp->callee().toFunction());
     } else {
         calleeToken = CalleeToToken(fp->script());
     }
 
     // Caller must construct |this| before invoking the Ion function.
     JS_ASSERT_IF(fp->isConstructing(), fp->functionThis().isObject());
 
--- a/js/src/ion/IonFrameIterator-inl.h
+++ b/js/src/ion/IonFrameIterator-inl.h
@@ -52,31 +52,50 @@ InlineFrameIterator::forEachCanonicalAct
 {
     unsigned nactual = numActualArgs();
     if (count == unsigned(-1))
         count = nactual - start;
 
     unsigned end = start + count;
     JS_ASSERT(start <= end && end <= nactual);
 
+    unsigned nformal = callee()->nargs;
+    unsigned formalEnd = end;
+    if (!more() && end > nformal) {
+        formalEnd = nformal;
+    } else {
+        // Currently inlining does not support overflow of arguments, we have to
+        // add this feature in IonBuilder.cpp and in Bailouts.cpp before
+        // continuing. We need to add it to Bailouts.cpp because we need to know
+        // how to walk over the oveflow of arguments.
+        JS_ASSERT(end <= nformal);
+    }
+
     SnapshotIterator s(si_);
-    
+
     s.skip(); // scopeChain
     s.skip(); // this
 
     unsigned i = 0;
     for (; i < start; i++)
         s.skip();
-    for (; i < end; i++) {
+    for (; i < formalEnd; i++) {
         // We are not always able to read values from the snapshots, some values
         // such as non-gc things may still be live in registers and cause an
         // error while reading the machine state.
         Value v = s.maybeRead();
         if (!op(i, &v))
             return false;
     }
+    if (formalEnd != end) {
+        Value *argv = frame_->argv() + 1;
+        for (; i < end; i++) {
+            if (!op(i, &argv[i]))
+                return false;
+        }
+    }
     return true;
 }
 
 } // namespace ion
 } // namespace js
 
 #endif // jsion_frame_iterator_inl_h__
--- a/js/src/ion/IonFrameIterator.h
+++ b/js/src/ion/IonFrameIterator.h
@@ -146,16 +146,17 @@ class IonFrameIterator
     bool isConstructing() const;
 
     void *calleeToken() const;
     JSFunction *callee() const;
     JSFunction *maybeCallee() const;
     unsigned numActualArgs() const;
     JSScript *script() const;
     Value *nativeVp() const;
+    Value *argv() const;
 
     // Returns the return address of the frame above this one (that is, the
     // return address that returns back to the current frame).
     uint8 *returnAddressToFp() const {
         return returnAddressToFp_;
     }
 
     // Previous frame information extracted from the current frame.
--- a/js/src/ion/IonFrames.cpp
+++ b/js/src/ion/IonFrames.cpp
@@ -229,16 +229,22 @@ IonFrameIterator::script() const
 
 Value *
 IonFrameIterator::nativeVp() const
 {
     JS_ASSERT(isNative());
     return exitFrame()->nativeVp();
 }
 
+Value *
+IonFrameIterator::argv() const
+{
+    return jsFrame()->argv();
+}
+
 uint8 *
 IonFrameIterator::prevFp() const
 {
     JS_ASSERT(type_ != IonFrame_Entry);
 
     size_t currentSize = SizeOfFramePrefix(type_);
     // This quick fix must be removed as soon as bug 717297 land.  This is
     // needed because the descriptor size of JS-to-JS frame which is just after
@@ -655,17 +661,17 @@ SnapshotIterator::SnapshotIterator()
     fp_(NULL),
     ionScript_(NULL)
 {
 }
 
 bool
 SnapshotIterator::hasLocation(const SnapshotReader::Location &loc)
 {
-    return loc.isStackSlot() && machine_.has(loc.reg());
+    return loc.isStackSlot() || machine_.has(loc.reg());
 }
 
 uintptr_t
 SnapshotIterator::fromLocation(const SnapshotReader::Location &loc)
 {
     if (loc.isStackSlot())
         return ReadFrameSlot(fp_, loc.stackSlot());
     return machine_.read(loc.reg());
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/ion/bug754720.js
@@ -0,0 +1,64 @@
+function f2(a) {
+  return f2.arguments;
+}
+
+// The first eager-compiled call will bailout, do not assert.
+f2();
+
+var o;
+o = f2();
+assertEq(o.length, 0);
+
+o = f2(21);
+assertEq(o.length, 1);
+assertEq(o[0], 21);
+
+o = f2(21,42);
+assertEq(o.length, 2);
+assertEq(o[0], 21);
+assertEq(o[1], 42);
+
+// 100 arguments.
+o = f2(0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,
+       0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,
+       0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,
+       0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,
+       0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9);
+for (var i in o)
+    assertEq(o[i], i % 10);
+
+// 200 arguments.
+o = f2(0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,
+       0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,
+       0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,
+       0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,
+       0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,
+
+       0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,
+       0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,
+       0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,
+       0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,
+       0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9);
+for (var i in o)
+    assertEq(o[i], i % 10);
+
+// 300 arguments.
+o = f2(0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,
+       0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,
+       0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,
+       0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,
+       0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,
+
+       0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,
+       0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,
+       0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,
+       0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,
+       0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,
+
+       0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,
+       0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,
+       0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,
+       0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,
+       0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9);
+for (var i in o)
+    assertEq(o[i], i % 10);
--- a/js/src/vm/Stack.cpp
+++ b/js/src/vm/Stack.cpp
@@ -1478,21 +1478,16 @@ StackIter::numActualArgs() const
 {
     switch (state_) {
       case DONE:
         break;
       case SCRIPTED:
         JS_ASSERT(isFunctionFrame());
         return fp()->numActualArgs();
       case ION:
-        // :TODO: We need to handle actual arguments in IonMonkey.  Currently we
-        // cannot easily read all arguments used for the call and we do not want
-        // to hack around it because a part of Bug 735406 is to instrucment Ion
-        // frames to provide actual arguments.
-        JS_ASSERT(ionInlineFrames_.numActualArgs() <= ionInlineFrames_.callee()->nargs);
         return ionInlineFrames_.numActualArgs();
       case NATIVE:
       case IMPLICIT_NATIVE:
         return nativeArgs().length();
     }
     JS_NOT_REACHED("Unexpected state");
     return 0;
 }