Bug 787703. r=terrence
authorJason Orendorff <jorendorff@mozilla.com>
Thu, 25 Oct 2012 17:43:25 -0400
changeset 111582 e1c7f51957048eb824b22d86e5ad92c6b1ce8468
parent 111581 79154a91fb155d1f62899e00d5162f9aeabee98a
child 111583 df8e5da6e69fea91951c3428a18013472c45a1c6
push id93
push usernmatsakis@mozilla.com
push dateWed, 31 Oct 2012 21:26:57 +0000
reviewersterrence
bugs787703
milestone19.0a1
Bug 787703. r=terrence
js/src/gc/Root.h
js/src/jit-test/tests/gc/bug-787703.js
js/src/jspubtd.h
--- a/js/src/gc/Root.h
+++ b/js/src/gc/Root.h
@@ -493,16 +493,44 @@ struct RootKind<T *> { static ThingRootK
 template <typename T>
 struct RootMethods<T *>
 {
     static T *initial() { return NULL; }
     static ThingRootKind kind() { return RootKind<T *>::rootKind(); }
     static bool poisoned(T *v) { return IsPoisonedPtr(v); }
 };
 
+#if !defined(JSGC_ROOT_ANALYSIS) && !defined(JSGC_USE_EXACT_ROOTING)
+template <typename T>
+struct RootSink {
+    static inline void dispose(const T &) {}
+};
+
+/*
+ * The *alleged* killer whale hack (see JS::Anchor<T> in jsapi.h) duplicated
+ * here because using JS::Anchor causes clang to emit bad instructions.
+ *
+ * In exact-gc builds, Rooted<T> always keeps the T reachable. In non-exact-gc
+ * builds, it does not, but conservative scanning usually picks up the slack.
+ * However in the case where the Rooted pointer is no longer used, but some
+ * subobject or malloc'd memory with the same lifetime may be used,
+ * conservative scanning can fail. JSStableString's chars() method makes it
+ * particularly attractive to use that way, so we use some voodoo to convince
+ * the compiler to keep the string pointer on the stack for the full lifetime
+ * of the Rooted<JSStableString *>.
+ */
+template <>
+struct RootSink<JSStableString *> {
+    static void dispose(JSStableString *ptr) {
+        JSStableString * volatile sink;
+        sink = ptr;
+    }
+};
+#endif
+
 template <typename T>
 class RootedBase {};
 
 /*
  * Local variable of type T whose value is always rooted. This is typically
  * used for local variables, or for non-rooted values being passed to a
  * function that requires a handle, e.g. Foo(Root<T>(cx, x)).
  *
@@ -582,16 +610,18 @@ class Rooted : public RootedBase<T>
         init(cx);
     }
 
     ~Rooted()
     {
 #if defined(JSGC_ROOT_ANALYSIS) || defined(JSGC_USE_EXACT_ROOTING)
         JS_ASSERT(*stack == this);
         *stack = prev;
+#else
+        RootSink<T>::dispose(ptr);
 #endif
     }
 
 #if defined(JSGC_ROOT_ANALYSIS) || defined(JSGC_USE_EXACT_ROOTING)
     Rooted<T> *previous() { return prev; }
 #endif
 
     operator T () const { return ptr; }
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/gc/bug-787703.js
@@ -0,0 +1,5 @@
+eval(" function x() {}" + Array(241).join(" "));
+for (var i = 0; i < 100; i++) {
+    gczeal(4, 2);
+    String(x);
+}
--- a/js/src/jspubtd.h
+++ b/js/src/jspubtd.h
@@ -198,16 +198,17 @@ typedef struct JSStackFrame             
 typedef struct JSScript          JSScript;
 typedef struct JSStructuredCloneCallbacks   JSStructuredCloneCallbacks;
 typedef struct JSStructuredCloneReader      JSStructuredCloneReader;
 typedef struct JSStructuredCloneWriter      JSStructuredCloneWriter;
 typedef struct JSTracer                     JSTracer;
 
 #ifdef __cplusplus
 class                                       JSFlatString;
+class                                       JSStableString;  // long story
 class                                       JSString;
 #else
 typedef struct JSFlatString                 JSFlatString;
 typedef struct JSString                     JSString;
 #endif /* !__cplusplus */
 
 #ifdef JS_THREADSAFE
 typedef struct PRCallOnceType    JSCallOnceType;