Bug 932837 part 2. Create a refcounted object to manage the lifetime of a JS::StackDescription. r=mccr8, terrence
authorBoris Zbarsky <bzbarsky@mit.edu>
Tue, 07 Jan 2014 19:53:17 -0500 (2014-01-08)
changeset 162455 a3427a45608df38c83b7d5f68b4a99645f87b14d
parent 162454 db68ac22b0424afc81235a8ab21b2b5f67316a25
child 162456 e0de03b97222e6ce7d6c2a1c402690eb23ea35f1
push id38202
push userbzbarsky@mozilla.com
push dateWed, 08 Jan 2014 00:53:59 +0000 (2014-01-08)
treeherdermozilla-inbound@8e95a6fcee23 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmccr8, terrence
bugs932837
milestone29.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 932837 part 2. Create a refcounted object to manage the lifetime of a JS::StackDescription. r=mccr8, terrence
dom/bindings/Exceptions.cpp
js/public/OldDebugAPI.h
js/public/Tracer.h
js/src/gc/Tracer.cpp
js/src/vm/OldDebugAPI.cpp
xpcom/base/CycleCollectedJSRuntime.cpp
xpcom/glue/nsCycleCollectionParticipant.cpp
xpcom/glue/nsCycleCollectionParticipant.h
--- a/dom/bindings/Exceptions.cpp
+++ b/dom/bindings/Exceptions.cpp
@@ -198,16 +198,72 @@ GetCurrentJSStack()
          caller) {
     stack = caller;
   }
   return stack.forget();
 }
 
 namespace exceptions {
 
+class StackDescriptionOwner {
+public:
+  StackDescriptionOwner(JS::StackDescription* aDescription)
+    : mDescription(aDescription)
+  {
+    mozilla::HoldJSObjects(this);
+  }
+
+  ~StackDescriptionOwner()
+  {
+    // Make sure to set mDescription to null before calling DropJSObjects, since
+    // in debug builds DropJSObjects try to trace us and we don't want to trace
+    // a dead StackDescription.
+    if (mDescription) {
+      JS::FreeStackDescription(nullptr, mDescription);
+      mDescription = nullptr;
+    }
+    mozilla::DropJSObjects(this);
+  }
+
+  NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(StackDescriptionOwner)
+  NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(StackDescriptionOwner)
+
+  JS::FrameDescription& FrameAt(size_t aIndex)
+  {
+    MOZ_ASSERT(aIndex < mDescription->nframes);
+    return mDescription->frames[aIndex];
+  }
+
+private:
+  JS::StackDescription* mDescription;
+};
+
+NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(StackDescriptionOwner, AddRef)
+NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(StackDescriptionOwner, Release)
+
+NS_IMPL_CYCLE_COLLECTION_CLASS(StackDescriptionOwner)
+NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(StackDescriptionOwner)
+  if (tmp->mDescription) {
+    JS::FreeStackDescription(nullptr, tmp->mDescription);
+    tmp->mDescription = nullptr;
+  }
+NS_IMPL_CYCLE_COLLECTION_UNLINK_END
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(StackDescriptionOwner)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
+NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(StackDescriptionOwner)
+  JS::StackDescription* desc = tmp->mDescription;
+  if (tmp->mDescription) {
+    for (size_t i = 0; i < desc->nframes; ++i) {
+      NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mDescription->frames[i].script());
+      NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mDescription->frames[i].fun());
+    }
+  }
+NS_IMPL_CYCLE_COLLECTION_TRACE_END
+
 class JSStackFrame : public nsIStackFrame
 {
 public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSISTACKFRAME
 
   JSStackFrame();
   virtual ~JSStackFrame();
@@ -351,16 +407,18 @@ JSStackFrame::CreateStack(JSContext* cx)
   nsRefPtr<JSStackFrame> first = new JSStackFrame();
   nsRefPtr<JSStackFrame> self = first;
 
   JS::StackDescription* desc = JS::DescribeStack(cx, MAX_FRAMES);
   if (!desc) {
     return nullptr;
   }
 
+  nsRefPtr<StackDescriptionOwner> descOwner = new StackDescriptionOwner(desc);
+
   for (size_t i = 0; i < desc->nframes && self; i++) {
     self->mLanguage = nsIProgrammingLanguage::JAVASCRIPT;
 
     JSAutoCompartment ac(cx, desc->frames[i].script());
     const char* filename = JS_GetScriptFilename(cx, desc->frames[i].script());
     if (filename) {
       self->mFilename =
         (char*)nsMemory::Clone(filename, sizeof(char)*(strlen(filename)+1));
@@ -383,18 +441,16 @@ JSStackFrame::CreateStack(JSContext* cx)
       }
     }
 
     nsRefPtr<JSStackFrame> frame = new JSStackFrame();
     self->mCaller = frame;
     self.swap(frame);
   }
 
-  JS::FreeStackDescription(cx, desc);
-
   return first.forget();
 }
 
 /* static */ already_AddRefed<nsIStackFrame>
 JSStackFrame::CreateStackFrameLocation(uint32_t aLanguage,
                                        const char* aFilename,
                                        const char* aFunctionName,
                                        int32_t aLineNumber,
--- a/js/public/OldDebugAPI.h
+++ b/js/public/OldDebugAPI.h
@@ -43,27 +43,27 @@ class FrameDescription
     unsigned lineno() {
         if (!linenoComputed) {
             lineno_ = JS_PCToLineNumber(nullptr, script_, pc_);
             linenoComputed = true;
         }
         return lineno_;
     }
 
-    JSScript *script() const {
+    Heap<JSScript*> &script() {
         return script_;
     }
 
-    JSFunction *fun() const {
+    Heap<JSFunction*> &fun() {
         return fun_;
     }
 
   private:
-    JSScript *script_;
-    JSFunction *fun_;
+    Heap<JSScript*> script_;
+    Heap<JSFunction*> fun_;
     jsbytecode *pc_;
     unsigned lineno_;
     bool linenoComputed;
 };
 
 struct StackDescription
 {
     unsigned nframes;
--- a/js/public/Tracer.h
+++ b/js/public/Tracer.h
@@ -152,16 +152,19 @@ extern JS_PUBLIC_API(void)
 JS_CallHeapObjectTracer(JSTracer *trc, JS::Heap<JSObject *> *objp, const char *name);
 
 extern JS_PUBLIC_API(void)
 JS_CallHeapStringTracer(JSTracer *trc, JS::Heap<JSString *> *strp, const char *name);
 
 extern JS_PUBLIC_API(void)
 JS_CallHeapScriptTracer(JSTracer *trc, JS::Heap<JSScript *> *scriptp, const char *name);
 
+extern JS_PUBLIC_API(void)
+JS_CallHeapFunctionTracer(JSTracer *trc, JS::Heap<JSFunction *> *funp, const char *name);
+
 template <typename HashSetEnum>
 inline void
 JS_CallHashSetObjectTracer(JSTracer *trc, HashSetEnum &e, JSObject *const &key, const char *name)
 {
     JSObject *updated = key;
     JS_SET_TRACING_LOCATION(trc, reinterpret_cast<void *>(&const_cast<JSObject *&>(key)));
     JS_CallObjectTracer(trc, &updated, name);
     if (updated != key)
--- a/js/src/gc/Tracer.cpp
+++ b/js/src/gc/Tracer.cpp
@@ -74,16 +74,22 @@ JS_CallHeapStringTracer(JSTracer *trc, J
 
 JS_PUBLIC_API(void)
 JS_CallHeapScriptTracer(JSTracer *trc, JS::Heap<JSScript *> *scriptp, const char *name)
 {
     MarkScriptUnbarriered(trc, scriptp->unsafeGet(), name);
 }
 
 JS_PUBLIC_API(void)
+JS_CallHeapFunctionTracer(JSTracer *trc, JS::Heap<JSFunction *> *funp, const char *name)
+{
+    MarkObjectUnbarriered(trc, funp->unsafeGet(), name);
+}
+
+JS_PUBLIC_API(void)
 JS_CallTenuredObjectTracer(JSTracer *trc, JS::TenuredHeap<JSObject *> *objp, const char *name)
 {
     JSObject *obj = objp->getPtr();
     if (!obj)
         return;
 
     JS_SET_TRACING_LOCATION(trc, (void*)objp);
     MarkObjectUnbarriered(trc, &obj, name);
--- a/js/src/vm/OldDebugAPI.cpp
+++ b/js/src/vm/OldDebugAPI.cpp
@@ -948,17 +948,19 @@ JS::DescribeStack(JSContext *cx, unsigne
     desc->nframes = frames.length();
     desc->frames = frames.extractRawBuffer();
     return desc;
 }
 
 JS_PUBLIC_API(void)
 JS::FreeStackDescription(JSContext *cx, JS::StackDescription *desc)
 {
-    js_delete(desc->frames);
+    for (size_t i = 0; i < desc->nframes; ++i)
+        desc->frames[i].~FrameDescription();
+    js_free(desc->frames);
     js_delete(desc);
 }
 
 namespace {
 
 class AutoPropertyDescArray
 {
     JSContext *cx_;
--- a/xpcom/base/CycleCollectedJSRuntime.cpp
+++ b/xpcom/base/CycleCollectedJSRuntime.cpp
@@ -745,16 +745,19 @@ struct JsGcTracer : public TraceCallback
     JS_CallHeapObjectTracer(static_cast<JSTracer*>(closure), p, name);
   }
   virtual void Trace(JS::Heap<JSString *> *p, const char *name, void *closure) const MOZ_OVERRIDE {
     JS_CallHeapStringTracer(static_cast<JSTracer*>(closure), p, name);
   }
   virtual void Trace(JS::Heap<JSScript *> *p, const char *name, void *closure) const MOZ_OVERRIDE {
     JS_CallHeapScriptTracer(static_cast<JSTracer*>(closure), p, name);
   }
+  virtual void Trace(JS::Heap<JSFunction *> *p, const char *name, void *closure) const MOZ_OVERRIDE {
+    JS_CallHeapFunctionTracer(static_cast<JSTracer*>(closure), p, name);
+  }
 };
 
 static PLDHashOperator
 TraceJSHolder(void* aHolder, nsScriptObjectTracer*& aTracer, void* aArg)
 {
   aTracer->Trace(aHolder, JsGcTracer(), aArg);
 
   return PL_DHASH_NEXT;
@@ -797,16 +800,21 @@ struct ClearJSHolder : TraceCallbacks
   {
     *aPtr = nullptr;
   }
 
   virtual void Trace(JS::Heap<JSScript*>* aPtr, const char*, void*) const MOZ_OVERRIDE
   {
     *aPtr = nullptr;
   }
+
+  virtual void Trace(JS::Heap<JSFunction*>* aPtr, const char*, void*) const MOZ_OVERRIDE
+  {
+    *aPtr = nullptr;
+  }
 };
 
 void
 CycleCollectedJSRuntime::RemoveJSHolder(void* aHolder)
 {
   nsScriptObjectTracer* tracer = mJSHolders.Get(aHolder);
   if (!tracer) {
     return;
--- a/xpcom/glue/nsCycleCollectionParticipant.cpp
+++ b/xpcom/glue/nsCycleCollectionParticipant.cpp
@@ -83,16 +83,22 @@ TraceCallbackFunc::Trace(JS::Heap<jsid>*
 
 void
 TraceCallbackFunc::Trace(JS::Heap<JSObject*>* p, const char* name, void* closure) const
 {
   mCallback(*p, name, closure);
 }
 
 void
+TraceCallbackFunc::Trace(JS::Heap<JSFunction*>* p, const char* name, void* closure) const
+{
+  mCallback(*p, name, closure);
+}
+
+void
 TraceCallbackFunc::Trace(JS::Heap<JSString*>* p, const char* name, void* closure) const
 {
   mCallback(*p, name, closure);
 }
 
 void
 TraceCallbackFunc::Trace(JS::Heap<JSScript*>* p, const char* name, void* closure) const
 {
--- a/xpcom/glue/nsCycleCollectionParticipant.h
+++ b/xpcom/glue/nsCycleCollectionParticipant.h
@@ -55,16 +55,17 @@ template <class T> class Heap;
  */
 struct TraceCallbacks
 {
     virtual void Trace(JS::Heap<JS::Value>* p, const char* name, void* closure) const = 0;
     virtual void Trace(JS::Heap<jsid>* p, const char* name, void* closure) const = 0;
     virtual void Trace(JS::Heap<JSObject*>* p, const char* name, void* closure) const = 0;
     virtual void Trace(JS::Heap<JSString*>* p, const char* name, void* closure) const = 0;
     virtual void Trace(JS::Heap<JSScript*>* p, const char* name, void* closure) const = 0;
+    virtual void Trace(JS::Heap<JSFunction*>* p, const char* name, void* closure) const = 0;
 };
 
 /*
  * An implementation of TraceCallbacks that calls a single function for all JS
  * GC thing types encountered.
  */
 struct TraceCallbackFunc : public TraceCallbacks
 {
@@ -72,16 +73,17 @@ struct TraceCallbackFunc : public TraceC
 
     explicit TraceCallbackFunc(Func cb) : mCallback(cb) {}
 
     virtual void Trace(JS::Heap<JS::Value>* p, const char* name, void* closure) const MOZ_OVERRIDE;
     virtual void Trace(JS::Heap<jsid>* p, const char* name, void* closure) const MOZ_OVERRIDE;
     virtual void Trace(JS::Heap<JSObject*>* p, const char* name, void* closure) const MOZ_OVERRIDE;
     virtual void Trace(JS::Heap<JSString*>* p, const char* name, void* closure) const MOZ_OVERRIDE;
     virtual void Trace(JS::Heap<JSScript*>* p, const char* name, void* closure) const MOZ_OVERRIDE;
+    virtual void Trace(JS::Heap<JSFunction*>* p, const char* name, void* closure) const MOZ_OVERRIDE;
 
   private:
     Func mCallback;
 };
 
 /**
  * Participant implementation classes
  */