Bug 623301 - Properly root arguments names during a call to Function(). r=brendan
authorJeff Walden <jwalden@mit.edu>
Wed, 05 Jan 2011 16:50:30 -0600
changeset 60555 b55e045d0fc3612600e16e9be3bff31a72b5b4e4
parent 60554 e272d471f4c447c11a10270e26dbff520d5a9618
child 60556 64139fb1b3fe1a860db25cffbf3f871d8052fc16
push id18037
push usercleary@mozilla.com
push dateFri, 14 Jan 2011 17:42:55 +0000
treeherdermozilla-central@4e0501a0c5e5 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbrendan
bugs623301
milestone2.0b9pre
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 623301 - Properly root arguments names during a call to Function(). r=brendan
js/src/jscntxt.h
js/src/jsfun.cpp
js/src/jsgc.cpp
js/src/jsscript.cpp
js/src/tests/ecma_5/Function/Function-arguments-gc.js
js/src/tests/ecma_5/Function/jstests.list
--- a/js/src/jscntxt.h
+++ b/js/src/jscntxt.h
@@ -2313,17 +2313,18 @@ class AutoGCRooter {
         DESCRIPTORS =  -7, /* js::AutoPropDescArrayRooter */
         NAMESPACES =   -8, /* js::AutoNamespaceArray */
         XML =          -9, /* js::AutoXMLRooter */
         OBJECT =      -10, /* js::AutoObjectRooter */
         ID =          -11, /* js::AutoIdRooter */
         VALVECTOR =   -12, /* js::AutoValueVector */
         DESCRIPTOR =  -13, /* js::AutoPropertyDescriptorRooter */
         STRING =      -14, /* js::AutoStringRooter */
-        IDVECTOR =    -15  /* js::AutoIdVector */
+        IDVECTOR =    -15, /* js::AutoIdVector */
+        BINDINGS =    -16  /* js::Bindings */
     };
 
     private:
     /* No copy or assignment semantics. */
     AutoGCRooter(AutoGCRooter &ida);
     void operator=(AutoGCRooter &ida);
 };
 
@@ -2630,122 +2631,199 @@ class AutoEnumStateRooter : private Auto
   private:
     Value stateValue;
     JS_DECL_USE_GUARD_OBJECT_NOTIFIER
 };
 
 #ifdef JS_HAS_XML_SUPPORT
 class AutoXMLRooter : private AutoGCRooter {
   public:
-    AutoXMLRooter(JSContext *cx, JSXML *xml)
+    AutoXMLRooter(JSContext *cx, JSXML *xml
+                  JS_GUARD_OBJECT_NOTIFIER_PARAM)
       : AutoGCRooter(cx, XML), xml(xml)
     {
+        JS_GUARD_OBJECT_NOTIFIER_INIT;
         JS_ASSERT(xml);
     }
 
     friend void AutoGCRooter::trace(JSTracer *trc);
     friend void MarkRuntime(JSTracer *trc);
 
   private:
     JSXML * const xml;
+    JS_DECL_USE_GUARD_OBJECT_NOTIFIER
 };
 #endif /* JS_HAS_XML_SUPPORT */
 
+class AutoBindingsRooter : private AutoGCRooter {
+  public:
+    AutoBindingsRooter(JSContext *cx, Bindings &bindings
+                       JS_GUARD_OBJECT_NOTIFIER_PARAM)
+      : AutoGCRooter(cx, BINDINGS), bindings(bindings)
+    {
+        JS_GUARD_OBJECT_NOTIFIER_INIT;
+    }
+
+    friend void AutoGCRooter::trace(JSTracer *trc);
+
+  private:
+    Bindings &bindings;
+    JS_DECL_USE_GUARD_OBJECT_NOTIFIER
+};
+
 class AutoLockGC {
-private:
+  public:
+    explicit AutoLockGC(JSRuntime *rt
+                        JS_GUARD_OBJECT_NOTIFIER_PARAM)
+      : rt(rt)
+    {
+        JS_GUARD_OBJECT_NOTIFIER_INIT;
+        JS_LOCK_GC(rt);
+    }
+    ~AutoLockGC() { JS_UNLOCK_GC(rt); }
+
+  private:
     JSRuntime *rt;
-public:
-    explicit AutoLockGC(JSRuntime *rt) : rt(rt) { JS_LOCK_GC(rt); }
-    ~AutoLockGC() { JS_UNLOCK_GC(rt); }
+    JS_DECL_USE_GUARD_OBJECT_NOTIFIER
 };
 
 class AutoUnlockGC {
-private:
+  private:
     JSRuntime *rt;
-public:
-    explicit AutoUnlockGC(JSRuntime *rt) : rt(rt) { JS_UNLOCK_GC(rt); }
+    JS_DECL_USE_GUARD_OBJECT_NOTIFIER
+
+  public:
+    explicit AutoUnlockGC(JSRuntime *rt
+                          JS_GUARD_OBJECT_NOTIFIER_PARAM)
+      : rt(rt)
+    {
+        JS_GUARD_OBJECT_NOTIFIER_INIT;
+        JS_UNLOCK_GC(rt);
+    }
     ~AutoUnlockGC() { JS_LOCK_GC(rt); }
 };
 
 class AutoLockDefaultCompartment {
   private:
-      JSContext *cx;
+    JSContext *cx;
+    JS_DECL_USE_GUARD_OBJECT_NOTIFIER
+
   public:
-    AutoLockDefaultCompartment(JSContext *cx) : cx(cx) {
+    AutoLockDefaultCompartment(JSContext *cx
+                               JS_GUARD_OBJECT_NOTIFIER_PARAM)
+      : cx(cx)
+    {
+        JS_GUARD_OBJECT_NOTIFIER_INIT;
         JS_LOCK(cx, &cx->runtime->atomState.lock);
 #ifdef JS_THREADSAFE
         cx->runtime->defaultCompartmentIsLocked = true;
 #endif
     }
     ~AutoLockDefaultCompartment() {
 #ifdef JS_THREADSAFE
         cx->runtime->defaultCompartmentIsLocked = false;
 #endif
         JS_UNLOCK(cx, &cx->runtime->atomState.lock);
     }
 };
 
 class AutoUnlockDefaultCompartment {
-  private:
-      JSContext *cx;
+    JSContext *cx;
+    JS_DECL_USE_GUARD_OBJECT_NOTIFIER
+
   public:
-    AutoUnlockDefaultCompartment(JSContext *cx) : cx(cx) {
+    AutoUnlockDefaultCompartment(JSContext *cx
+                                 JS_GUARD_OBJECT_NOTIFIER_PARAM)
+      : cx(cx)
+    {
+        JS_GUARD_OBJECT_NOTIFIER_INIT;
 #ifdef JS_THREADSAFE
         cx->runtime->defaultCompartmentIsLocked = false;
 #endif
         JS_UNLOCK(cx, &cx->runtime->atomState.lock);
     }
     ~AutoUnlockDefaultCompartment() {
         JS_LOCK(cx, &cx->runtime->atomState.lock);
 #ifdef JS_THREADSAFE
         cx->runtime->defaultCompartmentIsLocked = true;
 #endif
     }
 };
 
 class AutoKeepAtoms {
     JSRuntime *rt;
+    JS_DECL_USE_GUARD_OBJECT_NOTIFIER
+
   public:
-    explicit AutoKeepAtoms(JSRuntime *rt) : rt(rt) { JS_KEEP_ATOMS(rt); }
+    explicit AutoKeepAtoms(JSRuntime *rt
+                           JS_GUARD_OBJECT_NOTIFIER_PARAM)
+      : rt(rt)
+    {
+        JS_GUARD_OBJECT_NOTIFIER_INIT;
+        JS_KEEP_ATOMS(rt);
+    }
     ~AutoKeepAtoms() { JS_UNKEEP_ATOMS(rt); }
 };
 
 class AutoArenaAllocator {
     JSArenaPool *pool;
     void        *mark;
+    JS_DECL_USE_GUARD_OBJECT_NOTIFIER
+
   public:
-    explicit AutoArenaAllocator(JSArenaPool *pool) : pool(pool) { mark = JS_ARENA_MARK(pool); }
+    explicit AutoArenaAllocator(JSArenaPool *pool
+                                JS_GUARD_OBJECT_NOTIFIER_PARAM)
+      : pool(pool), mark(JS_ARENA_MARK(pool))
+    {
+        JS_GUARD_OBJECT_NOTIFIER_INIT;
+    }
     ~AutoArenaAllocator() { JS_ARENA_RELEASE(pool, mark); }
 
     template <typename T>
     T *alloc(size_t elems) {
         void *ptr;
         JS_ARENA_ALLOCATE(ptr, pool, elems * sizeof(T));
         return static_cast<T *>(ptr);
     }
 };
 
 class AutoReleasePtr {
     JSContext   *cx;
     void        *ptr;
+    JS_DECL_USE_GUARD_OBJECT_NOTIFIER
+
     AutoReleasePtr operator=(const AutoReleasePtr &other);
+
   public:
-    explicit AutoReleasePtr(JSContext *cx, void *ptr) : cx(cx), ptr(ptr) {}
+    explicit AutoReleasePtr(JSContext *cx, void *ptr
+                            JS_GUARD_OBJECT_NOTIFIER_PARAM)
+      : cx(cx), ptr(ptr)
+    {
+        JS_GUARD_OBJECT_NOTIFIER_INIT;
+    }
     ~AutoReleasePtr() { cx->free(ptr); }
 };
 
 /*
  * FIXME: bug 602774: cleaner API for AutoReleaseNullablePtr
  */
 class AutoReleaseNullablePtr {
     JSContext   *cx;
     void        *ptr;
+    JS_DECL_USE_GUARD_OBJECT_NOTIFIER
+
     AutoReleaseNullablePtr operator=(const AutoReleaseNullablePtr &other);
+
   public:
-    explicit AutoReleaseNullablePtr(JSContext *cx, void *ptr) : cx(cx), ptr(ptr) {}
+    explicit AutoReleaseNullablePtr(JSContext *cx, void *ptr
+                                    JS_GUARD_OBJECT_NOTIFIER_PARAM)
+      : cx(cx), ptr(ptr)
+    {
+        JS_GUARD_OBJECT_NOTIFIER_INIT;
+    }
     void reset(void *ptr2) {
         if (ptr)
             cx->free(ptr);
         ptr = ptr2;
     }
     ~AutoReleaseNullablePtr() { if (ptr) cx->free(ptr); }
 };
 
--- a/js/src/jsfun.cpp
+++ b/js/src/jsfun.cpp
@@ -2425,16 +2425,17 @@ Function(JSContext *cx, uintN argc, Valu
      * js_CheckContentSecurityPolicy is defined in jsobj.cpp
      */
     if (!js_CheckContentSecurityPolicy(cx)) {
         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CSP_BLOCKED_FUNCTION);
         return JS_FALSE;
     }
 
     Bindings bindings(cx);
+    AutoBindingsRooter root(cx, bindings);
 
     Value *argv = vp + 2;
     uintN n = argc ? argc - 1 : 0;
     if (n > 0) {
         enum { OK, BAD, BAD_FORMAL } state;
 
         /*
          * Collect the function-argument arguments into one string, separated
--- a/js/src/jsgc.cpp
+++ b/js/src/jsgc.cpp
@@ -1596,16 +1596,21 @@ AutoGCRooter::trace(JSTracer *trc)
             MarkString(trc, str, "js::AutoStringRooter.str");
         return;
 
       case IDVECTOR: {
         Vector<jsid, 8> &vector = static_cast<js::AutoIdVector *>(this)->vector;
         MarkIdRange(trc, vector.length(), vector.begin(), "js::AutoIdVector.vector");
         return;
       }
+
+      case BINDINGS: {
+        static_cast<js::AutoBindingsRooter *>(this)->bindings.trace(trc);
+        return;
+      }
     }
 
     JS_ASSERT(tag >= 0);
     MarkValueRange(trc, tag, static_cast<AutoArrayRooter *>(this)->array, "js::AutoArrayRooter.array");
 }
 
 namespace js {
 
--- a/js/src/jsscript.cpp
+++ b/js/src/jsscript.cpp
@@ -396,16 +396,17 @@ js_XDRScript(JSXDRState *xdr, JSScript *
         JS_ASSERT((paddingUpvars >> 16) == 0);
         nupvars = paddingUpvars & 0xFFFF;
     }
     JS_ASSERT(nargs != Bindings::BINDING_COUNT_LIMIT);
     JS_ASSERT(nvars != Bindings::BINDING_COUNT_LIMIT);
     JS_ASSERT(nupvars != Bindings::BINDING_COUNT_LIMIT);
 
     Bindings bindings(cx);
+    AutoBindingsRooter rooter(cx, bindings);
     uint32 nameCount = nargs + nvars + nupvars;
     if (nameCount > 0) {
         struct AutoMark {
           JSArenaPool * const pool;
           void * const mark;
           AutoMark(JSArenaPool *pool) : pool(pool), mark(JS_ARENA_MARK(pool)) { }
           ~AutoMark() {
             JS_ARENA_RELEASE(pool, mark);
new file mode 100644
--- /dev/null
+++ b/js/src/tests/ecma_5/Function/Function-arguments-gc.js
@@ -0,0 +1,38 @@
+/*
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/licenses/publicdomain/
+ * Contributor:
+ *   Christian Holler <decoder@own-hero.net>
+ */
+
+//-----------------------------------------------------------------------------
+var BUGNUMBER = 623301;
+var summary = "Properly root argument names during Function()";
+print(BUGNUMBER + ": " + summary);
+
+/**************
+ * BEGIN TEST *
+ **************/
+
+if (typeof gczeal === "function")
+  gczeal(2);
+
+function crashMe(n)
+{
+  var nasty = [];
+  while (n--)
+    nasty.push("a" + n);
+  return Function.apply(null, nasty);
+}
+
+var count = 64; // exact value not important
+assertEq(crashMe(count + 1).length, count);
+
+gczeal(0); // reset
+
+/******************************************************************************/
+
+if (typeof reportCompare === "function")
+  reportCompare(true, true);
+
+print("All tests passed!");
--- a/js/src/tests/ecma_5/Function/jstests.list
+++ b/js/src/tests/ecma_5/Function/jstests.list
@@ -4,8 +4,9 @@ script 15.3.4.3-01.js
 script arguments-caller-callee.js
 script function-caller.js
 script strict-arguments.js
 script arguments-property-attributes.js
 script function-bind.js
 script function-call.js
 script redefine-arguments-length.js
 script builtin-no-prototype.js
+script Function-arguments-gc.js