Bug 1238786 - Part 1: Allow null pointers in public tracing APIs; r=sfink
authorTerrence Cole <terrence@mozilla.com>
Tue, 12 Jan 2016 13:07:53 -0800
changeset 314815 560e1ee498a5662d02806b21db11107359f95d13
parent 314814 cf9a5f6f14db0c2e914285a3ef36de9b8dd3cc6a
child 314816 a9935197c5b73c8f8fe2e736587393379ec38ffc
push id5703
push userraliiev@mozilla.com
push dateMon, 07 Mar 2016 14:18:41 +0000
treeherdermozilla-beta@31e373ad5b5f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssfink
bugs1238786
milestone46.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 1238786 - Part 1: Allow null pointers in public tracing APIs; r=sfink
js/public/TracingAPI.h
js/src/gc/Marking.cpp
--- a/js/public/TracingAPI.h
+++ b/js/public/TracingAPI.h
@@ -289,32 +289,32 @@ namespace JS {
 //
 // The argument to JS::TraceEdge is an in-out param: when the function returns,
 // the garbage collector might have moved the GC thing. In this case, the
 // reference passed to JS::TraceEdge will be updated to the thing's new
 // location. Callers of this method are responsible for updating any state that
 // is dependent on the object's address. For example, if the object's address
 // is used as a key in a hashtable, then the object must be removed and
 // re-inserted with the correct hash.
+//
+// Note that while |edgep| must never be null, it is fine for |*edgep| to be
+// nullptr.
 template <typename T>
 extern JS_PUBLIC_API(void)
 TraceEdge(JSTracer* trc, JS::Heap<T>* edgep, const char* name);
 
-// As with JS::TraceEdge, but checks if *edgep is a nullptr before proceeding.
-// Note that edgep itself must always be non-null.
-template <typename T>
 extern JS_PUBLIC_API(void)
-TraceNullableEdge(JSTracer* trc, JS::Heap<T>* edgep, const char* name);
-
-extern JS_PUBLIC_API(void)
-TraceNullableEdge(JSTracer* trc, JS::TenuredHeap<JSObject*>* edgep, const char* name);
+TraceEdge(JSTracer* trc, JS::TenuredHeap<JSObject*>* edgep, const char* name);
 
 // Edges that are always traced as part of root marking do not require
 // incremental barriers. This function allows for marking non-barriered
 // pointers, but asserts that this happens during root marking.
+//
+// Note that while |edgep| must never be null, it is fine for |*edgep| to be
+// nullptr.
 template <typename T>
 extern JS_PUBLIC_API(void)
 UnsafeTraceRoot(JSTracer* trc, T* edgep, const char* name);
 
 extern JS_PUBLIC_API(void)
 TraceChildren(JSTracer* trc, GCCellPtr thing);
 
 typedef js::HashSet<Zone*, js::DefaultHasher<Zone*>, js::SystemAllocPolicy> ZoneSet;
@@ -327,16 +327,22 @@ typedef js::HashSet<Zone*, js::DefaultHa
 extern JS_PUBLIC_API(void)
 JS_TraceIncomingCCWs(JSTracer* trc, const JS::ZoneSet& zones);
 
 extern JS_PUBLIC_API(void)
 JS_GetTraceThingInfo(char* buf, size_t bufsize, JSTracer* trc,
                      void* thing, JS::TraceKind kind, bool includeDetails);
 
 namespace js {
+
+// Trace an edge that is not a GC root and is not wrapped in a barriered
+// wrapper for some reason.
+//
+// This method does not check if |*edgep| is non-null before tracing through
+// it, so callers must check any nullable pointer before calling this method.
 template <typename T>
 extern JS_PUBLIC_API(void)
 UnsafeTraceManuallyBarrieredEdge(JSTracer* trc, T* edgep, const char* name);
 
 namespace gc {
 template <typename T>
 extern JS_PUBLIC_API(bool)
 EdgeNeedsSweep(JS::Heap<T>* edgep);
--- a/js/src/gc/Marking.cpp
+++ b/js/src/gc/Marking.cpp
@@ -397,30 +397,23 @@ js::TraceEdge(JSTracer* trc, WriteBarrie
 {
     DispatchToTracer(trc, ConvertToBase(thingp->unsafeUnbarrieredForTracing()), name);
 }
 
 template <typename T>
 JS_PUBLIC_API(void)
 JS::TraceEdge(JSTracer* trc, JS::Heap<T>* thingp, const char* name)
 {
-    DispatchToTracer(trc, ConvertToBase(thingp->unsafeGet()), name);
-}
-
-template <typename T>
-JS_PUBLIC_API(void)
-JS::TraceNullableEdge(JSTracer* trc, JS::Heap<T>* thingp, const char* name)
-{
     MOZ_ASSERT(thingp);
     if (InternalGCMethods<T>::isMarkable(thingp->get()))
         DispatchToTracer(trc, ConvertToBase(thingp->unsafeGet()), name);
 }
 
 JS_PUBLIC_API(void)
-JS::TraceNullableEdge(JSTracer* trc, JS::TenuredHeap<JSObject*>* thingp, const char* name)
+JS::TraceEdge(JSTracer* trc, JS::TenuredHeap<JSObject*>* thingp, const char* name)
 {
     MOZ_ASSERT(thingp);
     if (JSObject* ptr = thingp->getPtr()) {
         DispatchToTracer(trc, &ptr, name);
         thingp->setPtr(ptr);
     }
 }
 
@@ -454,23 +447,16 @@ template <typename T>
 void
 js::TraceRoot(JSTracer* trc, T* thingp, const char* name)
 {
     AssertRootMarkingPhase(trc);
     DispatchToTracer(trc, ConvertToBase(thingp), name);
 }
 
 template <typename T>
-JS_PUBLIC_API(void)
-JS::UnsafeTraceRoot(JSTracer* trc, T* thingp, const char* name)
-{
-    js::TraceRoot(trc, thingp, name);
-}
-
-template <typename T>
 void
 js::TraceRoot(JSTracer* trc, ReadBarriered<T>* thingp, const char* name)
 {
     TraceRoot(trc, thingp->unsafeGet(), name);
 }
 
 template <typename T>
 void
@@ -484,16 +470,24 @@ js::TraceNullableRoot(JSTracer* trc, T* 
 template <typename T>
 void
 js::TraceNullableRoot(JSTracer* trc, ReadBarriered<T>* thingp, const char* name)
 {
     TraceNullableRoot(trc, thingp->unsafeGet(), name);
 }
 
 template <typename T>
+JS_PUBLIC_API(void)
+JS::UnsafeTraceRoot(JSTracer* trc, T* thingp, const char* name)
+{
+    MOZ_ASSERT(thingp);
+    js::TraceNullableRoot(trc, thingp, name);
+}
+
+template <typename T>
 void
 js::TraceRange(JSTracer* trc, size_t len, WriteBarrieredBase<T>* vec, const char* name)
 {
     JS::AutoTracingIndex index(trc);
     for (auto i : MakeRange(len)) {
         if (InternalGCMethods<T>::isMarkable(vec[i].get()))
             DispatchToTracer(trc, ConvertToBase(vec[i].unsafeUnbarrieredForTracing()), name);
         ++index;
@@ -524,18 +518,16 @@ js::TraceRootRange(JSTracer* trc, size_t
     template void js::TraceNullableRoot<type>(JSTracer*, ReadBarriered<type>*, const char*); \
     template void js::TraceRange<type>(JSTracer*, size_t, WriteBarrieredBase<type>*, const char*); \
     template void js::TraceRootRange<type>(JSTracer*, size_t, type*, const char*);
 FOR_EACH_GC_POINTER_TYPE(INSTANTIATE_ALL_VALID_TRACE_FUNCTIONS)
 #undef INSTANTIATE_ALL_VALID_TRACE_FUNCTIONS
 
 #define INSTANTIATE_PUBLIC_TRACE_FUNCTIONS(type) \
     template JS_PUBLIC_API(void) JS::TraceEdge<type>(JSTracer*, JS::Heap<type>*, const char*); \
-    template JS_PUBLIC_API(void) JS::TraceNullableEdge<type>(JSTracer*, JS::Heap<type>*, \
-                                                             const char*); \
     template JS_PUBLIC_API(void) JS::UnsafeTraceRoot<type>(JSTracer*, type*, const char*); \
     template JS_PUBLIC_API(void) js::UnsafeTraceManuallyBarrieredEdge<type>(JSTracer*, type*, \
                                                                             const char*);
 FOR_EACH_PUBLIC_GC_POINTER_TYPE(INSTANTIATE_PUBLIC_TRACE_FUNCTIONS)
 #undef INSTANTIATE_PUBLIC_TRACE_FUNCTIONS
 
 template <typename T>
 void