Bug 802319 - Various rooting fixes. r=terrence
authorSteve Fink <sfink@mozilla.com>
Mon, 15 Oct 2012 16:23:33 -0700
changeset 110567 ef8010af9fe64de113d0226b10523b47b09dd1a6
parent 110566 8c22cd5e4f35d3866425ca2c32330fc287f1b82f
child 110568 b21bafeb5b50c4c8f2d7502ef80e796458d253a7
push id23700
push userryanvm@gmail.com
push dateThu, 18 Oct 2012 02:10:26 +0000
treeherdermozilla-central@5142bbd4da12 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersterrence
bugs802319
milestone19.0a1
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 802319 - Various rooting fixes. r=terrence js/src/tests (jstests) currently passes all tests with rooting analysis on with this patch applied.
js/src/ion/CodeGenerator.cpp
js/src/jsarray.cpp
js/src/jsinterp.cpp
js/src/jsinterp.h
js/src/shell/js.cpp
js/src/vm/Stack.cpp
js/src/vm/Stack.h
--- a/js/src/ion/CodeGenerator.cpp
+++ b/js/src/ion/CodeGenerator.cpp
@@ -3057,17 +3057,17 @@ CodeGenerator::visitOutOfLineUnboxDouble
     return true;
 }
 
 typedef bool (*GetPropertyOrNameFn)(JSContext *, HandleObject, HandlePropertyName, Value *);
 
 bool
 CodeGenerator::visitCallGetProperty(LCallGetProperty *lir)
 {
-    typedef bool (*pf)(JSContext *, HandleValue, PropertyName *, MutableHandleValue);
+    typedef bool (*pf)(JSContext *, HandleValue, HandlePropertyName, MutableHandleValue);
     static const VMFunction Info = FunctionInfo<pf>(GetProperty);
 
     pushArg(ImmGCPtr(lir->mir()->name()));
     pushArg(ToValue(lir, LCallGetProperty::Value));
     return callVM(Info, lir);
 }
 
 bool
--- a/js/src/jsarray.cpp
+++ b/js/src/jsarray.cpp
@@ -3088,17 +3088,17 @@ array_readonlyCommon(JSContext *cx, Call
         js_ReportMissingArg(cx, args.calleev(), 0);
         return false;
     }
     RootedObject callable(cx, ValueToCallable(cx, &args[0]));
     if (!callable)
         return false;
 
     /* Step 5. */
-    Value thisv = args.length() >= 2 ? args[1] : UndefinedValue();
+    RootedValue thisv(cx, args.length() >= 2 ? args[1] : UndefinedValue());
 
     /* Step 6. */
     uint32_t k = 0;
 
     /* Step 7. */
     RootedValue kValue(cx);
     FastInvokeGuard fig(cx, ObjectValue(*callable));
     InvokeArgsGuard &ag = fig.args();
@@ -3181,17 +3181,17 @@ array_map(JSContext *cx, unsigned argc, 
         js_ReportMissingArg(cx, args.calleev(), 0);
         return false;
     }
     RootedObject callable(cx, ValueToCallable(cx, &args[0]));
     if (!callable)
         return false;
 
     /* Step 5. */
-    Value thisv = args.length() >= 2 ? args[1] : UndefinedValue();
+    RootedValue thisv(cx, args.length() >= 2 ? args[1] : UndefinedValue());
 
     /* Step 6. */
     RootedObject arr(cx, NewDenseAllocatedArray(cx, len));
     if (!arr)
         return false;
     TypeObject *newtype = GetTypeCallerInitObject(cx, JSProto_Array);
     if (!newtype)
         return false;
@@ -3259,17 +3259,17 @@ array_filter(JSContext *cx, unsigned arg
         js_ReportMissingArg(cx, args.calleev(), 0);
         return false;
     }
     RootedObject callable(cx, ValueToCallable(cx, &args[0]));
     if (!callable)
         return false;
 
     /* Step 5. */
-    Value thisv = args.length() >= 2 ? args[1] : UndefinedValue();
+    RootedValue thisv(cx, args.length() >= 2 ? args[1] : UndefinedValue());
 
     /* Step 6. */
     RootedObject arr(cx, NewDenseAllocatedArray(cx, 0));
     if (!arr)
         return false;
     TypeObject *newtype = GetTypeCallerInitObject(cx, JSProto_Array);
     if (!newtype)
         return false;
--- a/js/src/jsinterp.cpp
+++ b/js/src/jsinterp.cpp
@@ -3845,17 +3845,17 @@ bool
 js::Throw(JSContext *cx, HandleValue v)
 {
     JS_ASSERT(!cx->isExceptionPending());
     cx->setPendingException(v);
     return false;
 }
 
 bool
-js::GetProperty(JSContext *cx, HandleValue v, PropertyName *name, MutableHandleValue vp)
+js::GetProperty(JSContext *cx, HandleValue v, HandlePropertyName name, MutableHandleValue vp)
 {
     if (name == cx->names().length) {
         // Fast path for strings, arrays and arguments.
         if (GetLengthProperty(v, vp))
             return true;
     }
 
     RootedObject obj(cx, ToObjectFromStack(cx, v));
--- a/js/src/jsinterp.h
+++ b/js/src/jsinterp.h
@@ -313,17 +313,17 @@ Debug_SetValueRangeToCrashOnTouch(HeapVa
     Debug_SetValueRangeToCrashOnTouch((Value *) vec, len);
 #endif
 }
 
 bool
 Throw(JSContext *cx, HandleValue v);
 
 bool
-GetProperty(JSContext *cx, HandleValue value, PropertyName *name, MutableHandleValue vp);
+GetProperty(JSContext *cx, HandleValue value, HandlePropertyName name, MutableHandleValue vp);
 
 bool
 GetScopeName(JSContext *cx, HandleObject obj, HandlePropertyName name, MutableHandleValue vp);
 
 bool
 GetScopeNameForTypeOf(JSContext *cx, HandleObject obj, HandlePropertyName name,
                       MutableHandleValue vp);
 
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -2028,16 +2028,17 @@ DumpHeap(JSContext *cx, unsigned argc, j
     void* startThing;
     JSGCTraceKind startTraceKind;
     const char *badTraceArg;
     void *thingToFind;
     size_t maxDepth;
     void *thingToIgnore;
     FILE *dumpFile;
     bool ok;
+    AssertCanGC();
 
     const char *fileName = NULL;
     JSAutoByteString fileNameBytes;
     if (argc > 0) {
         v = JS_ARGV(cx, vp)[0];
         if (!JSVAL_IS_NULL(v)) {
             JSString *str;
 
@@ -2046,16 +2047,30 @@ DumpHeap(JSContext *cx, unsigned argc, j
                 return false;
             JS_ARGV(cx, vp)[0] = STRING_TO_JSVAL(str);
             if (!fileNameBytes.encode(cx, str))
                 return false;
             fileName = fileNameBytes.ptr();
         }
     }
 
+    // Grab the depth param first, because JS_ValueToECMAUint32 can GC, and
+    // there's no easy way to root the traceable void* parameters below.
+    maxDepth = (size_t)-1;
+    if (argc > 3) {
+        v = JS_ARGV(cx, vp)[3];
+        if (!JSVAL_IS_NULL(v)) {
+            uint32_t depth;
+
+            if (!JS_ValueToECMAUint32(cx, v, &depth))
+                return false;
+            maxDepth = depth;
+        }
+    }
+
     startThing = NULL;
     startTraceKind = JSTRACE_OBJECT;
     if (argc > 1) {
         v = JS_ARGV(cx, vp)[1];
         if (JSVAL_IS_TRACEABLE(v)) {
             startThing = JSVAL_TO_TRACEABLE(v);
             startTraceKind = JSVAL_TRACE_KIND(v);
         } else if (!JSVAL_IS_NULL(v)) {
@@ -2070,28 +2085,16 @@ DumpHeap(JSContext *cx, unsigned argc, j
         if (JSVAL_IS_TRACEABLE(v)) {
             thingToFind = JSVAL_TO_TRACEABLE(v);
         } else if (!JSVAL_IS_NULL(v)) {
             badTraceArg = "toFind";
             goto not_traceable_arg;
         }
     }
 
-    maxDepth = (size_t)-1;
-    if (argc > 3) {
-        v = JS_ARGV(cx, vp)[3];
-        if (!JSVAL_IS_NULL(v)) {
-            uint32_t depth;
-
-            if (!JS_ValueToECMAUint32(cx, v, &depth))
-                return false;
-            maxDepth = depth;
-        }
-    }
-
     thingToIgnore = NULL;
     if (argc > 4) {
         v = JS_ARGV(cx, vp)[4];
         if (JSVAL_IS_TRACEABLE(v)) {
             thingToIgnore = JSVAL_TO_TRACEABLE(v);
         } else if (!JSVAL_IS_NULL(v)) {
             badTraceArg = "toIgnore";
             goto not_traceable_arg;
--- a/js/src/vm/Stack.cpp
+++ b/js/src/vm/Stack.cpp
@@ -1465,17 +1465,18 @@ StackIter::settleOnNewState()
 
         /* Pop the call and keep looking. */
         popCall();
     }
 }
 
 StackIter::StackIter(JSContext *cx, SavedOption savedOption)
   : maybecx_(cx),
-    savedOption_(savedOption)
+    savedOption_(savedOption),
+    script_(cx, NULL)
 #ifdef JS_ION
     , ionActivations_(cx),
     ionFrames_((uint8_t *)NULL),
     ionInlineFrames_((js::ion::IonFrameIterator*) NULL)
 #endif
 {
 #ifdef JS_METHODJIT
     CompartmentVector &v = cx->runtime->compartments;
@@ -1487,32 +1488,51 @@ StackIter::StackIter(JSContext *cx, Save
         startOnSegment(seg);
         settleOnNewState();
     } else {
         state_ = DONE;
     }
 }
 
 StackIter::StackIter(JSRuntime *rt, StackSegment &seg)
-  : maybecx_(NULL), savedOption_(STOP_AT_SAVED)
+  : maybecx_(NULL), savedOption_(STOP_AT_SAVED),
+    script_(rt, NULL)
 #ifdef JS_ION
     , ionActivations_(rt),
     ionFrames_((uint8_t *)NULL),
     ionInlineFrames_((js::ion::IonFrameIterator*) NULL)
 #endif
 {
 #ifdef JS_METHODJIT
     CompartmentVector &v = rt->compartments;
     for (size_t i = 0; i < v.length(); i++)
         mjit::ExpandInlineFrames(v[i]);
 #endif
     startOnSegment(&seg);
     settleOnNewState();
 }
 
+StackIter::StackIter(const StackIter &other)
+  : maybecx_(other.maybecx_),
+    savedOption_(other.savedOption_),
+    state_(other.state_),
+    fp_(other.fp_),
+    calls_(other.calls_),
+    seg_(other.seg_),
+    pc_(other.pc_),
+    script_(other.maybecx_ ? other.maybecx_->runtime : TlsRuntime.get(), other.script_),
+    args_(other.args_)
+#ifdef JS_ION
+    , ionActivations_(other.ionActivations_),
+    ionFrames_(other.ionFrames_),
+    ionInlineFrames_(other.ionInlineFrames_)
+#endif
+{
+}
+
 #ifdef JS_ION
 void
 StackIter::popIonFrame()
 {
     AutoAssertNoGC nogc;
     // Keep fp which describes all ion frames.
     poisonRegs();
     if (ionFrames_.isScripted() && ionInlineFrames_.more()) {
--- a/js/src/vm/Stack.h
+++ b/js/src/vm/Stack.h
@@ -1719,18 +1719,18 @@ class StackIter
 
     State        state_;
 
     StackFrame   *fp_;
     CallArgsList *calls_;
 
     StackSegment *seg_;
     jsbytecode   *pc_;
-    JSScript     *script_;
-    CallArgs     args_;
+    RootedScript  script_;
+    CallArgs      args_;
 
 #ifdef JS_ION
     ion::IonActivationIterator ionActivations_;
     ion::IonFrameIterator ionFrames_;
     ion::InlineFrameIterator ionInlineFrames_;
 #endif
 
     void poisonRegs();
@@ -1741,16 +1741,17 @@ class StackIter
 #endif
     void settleOnNewSegment();
     void settleOnNewState();
     void startOnSegment(StackSegment *seg);
 
   public:
     StackIter(JSContext *cx, SavedOption = STOP_AT_SAVED);
     StackIter(JSRuntime *rt, StackSegment &seg);
+    StackIter(const StackIter &iter);
 
     bool done() const { return state_ == DONE; }
     StackIter &operator++();
 
     bool operator==(const StackIter &rhs) const;
     bool operator!=(const StackIter &rhs) const { return !(*this == rhs); }
 
     JSCompartment *compartment() const;