Bug 1134865 - Part 3: Add JS::ubi::Node::jsObjectConstructorName; r=djvj
authorNick Fitzgerald <fitzgen@gmail.com>
Mon, 27 Apr 2015 10:57:06 -0700
changeset 271172 ada25868ffa642d6a5b0e4c0db2e1f769656e09f
parent 271171 626f0dd608b0a52e58e9fa9a655db2819f0c51a9
child 271173 600207b620204b60e41164b70e552cf764a80b7c
push id4830
push userjlund@mozilla.com
push dateMon, 29 Jun 2015 20:18:48 +0000
treeherdermozilla-beta@4c2175bb0420 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdjvj
bugs1134865
milestone40.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 1134865 - Part 3: Add JS::ubi::Node::jsObjectConstructorName; r=djvj
js/public/UbiNode.h
js/src/jsapi-tests/testUbiNode.cpp
js/src/vm/UbiNode.cpp
--- a/js/public/UbiNode.h
+++ b/js/public/UbiNode.h
@@ -8,16 +8,17 @@
 #define js_UbiNode_h
 
 #include "mozilla/Alignment.h"
 #include "mozilla/Assertions.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/Maybe.h"
 #include "mozilla/MemoryReporting.h"
 #include "mozilla/Move.h"
+#include "mozilla/UniquePtr.h"
 
 #include "jspubtd.h"
 
 #include "js/GCAPI.h"
 #include "js/HashTable.h"
 #include "js/TracingAPI.h"
 #include "js/TypeDecls.h"
 #include "js/Vector.h"
@@ -137,16 +138,17 @@
 // If this restriction prevents us from implementing interesting tools, we may
 // teach the GC how to root ubi::Nodes, fix up hash tables that use them as
 // keys, etc.
 
 namespace JS {
 namespace ubi {
 
 using mozilla::Maybe;
+using mozilla::UniquePtr;
 
 class Edge;
 class EdgeRange;
 
 // The base class implemented by each ubi::Node referent type. Subclasses must
 // not add data members to this class.
 class Base {
     friend class Node;
@@ -201,21 +203,36 @@ class Base {
     virtual JS::Zone* zone() const { return nullptr; }
 
     // Return the compartment for this node. Some ubi::Node referents are not
     // associated with JSCompartments, such as JSStrings (which are associated
     // with Zones). When the referent is not associated with a compartment,
     // nullptr is returned.
     virtual JSCompartment* compartment() const { return nullptr; }
 
-    // If this node references a JSObject in the live heap, or represents a
-    // previously existing JSObject from some deserialized heap snapshot, return
-    // the object's [[Class]]'s name. Otherwise, return nullptr.
+    // Methods for JSObject Referents
+    //
+    // These methods are only semantically valid if the referent is either a
+    // JSObject in the live heap, or represents a previously existing JSObject
+    // from some deserialized heap snapshot.
+
+    // Return the object's [[Class]]'s name.
     virtual const char* jsObjectClassName() const { return nullptr; }
 
+    // If this object was constructed with `new` and we have the data available,
+    // place the contructor function's display name in the out parameter.
+    // Otherwise, place nullptr in the out parameter. Caller maintains ownership
+    // of the out parameter. True is returned on success, false is returned on
+    // OOM.
+    virtual bool jsObjectConstructorName(JSContext* cx,
+                                         UniquePtr<char16_t[], JS::FreePolicy>& outName) const {
+        outName.reset(nullptr);
+        return true;
+    }
+
   private:
     Base(const Base& rhs) = delete;
     Base& operator=(const Base& rhs) = delete;
 };
 
 // A traits template with a specialization for each referent type that
 // ubi::Node supports. The specialization must be the concrete subclass of
 // Base that represents a pointer to the referent type. It must also
@@ -331,16 +348,20 @@ class Node {
     // Otherwise return UndefinedValue(). JSStrings, JS::Symbols, and some (but
     // not all!) JSObjects can be exposed.
     JS::Value exposeToJS() const;
 
     const char16_t* typeName()      const { return base()->typeName(); }
     JS::Zone* zone()                const { return base()->zone(); }
     JSCompartment* compartment()    const { return base()->compartment(); }
     const char* jsObjectClassName() const { return base()->jsObjectClassName(); }
+    bool jsObjectConstructorName(JSContext* cx,
+                                 UniquePtr<char16_t[], JS::FreePolicy>& outName) const {
+        return base()->jsObjectConstructorName(cx, outName);
+    }
 
     size_t size(mozilla::MallocSizeOf mallocSizeof) const {
         return base()->size(mallocSizeof);
     }
 
     EdgeRange* edges(JSContext* cx, bool wantNames = true) const {
         return base()->edges(cx, wantNames);
     }
@@ -569,16 +590,18 @@ class TracerConcreteWithCompartment : pu
 // These can use the generic templates above.
 template<> struct Concrete<JS::Symbol> : TracerConcrete<JS::Symbol> { };
 template<> struct Concrete<JSScript> : TracerConcreteWithCompartment<JSScript> { };
 
 // The JSObject specialization.
 template<>
 class Concrete<JSObject> : public TracerConcreteWithCompartment<JSObject> {
     const char* jsObjectClassName() const override;
+    bool jsObjectConstructorName(JSContext* cx,
+                                 UniquePtr<char16_t[], JS::FreePolicy>& outName) const override;
     size_t size(mozilla::MallocSizeOf mallocSizeOf) const override;
 
   protected:
     explicit Concrete(JSObject* ptr) : TracerConcreteWithCompartment(ptr) { }
 
   public:
     static void construct(void* storage, JSObject* ptr) {
         new (storage) Concrete(ptr);
--- a/js/src/jsapi-tests/testUbiNode.cpp
+++ b/js/src/jsapi-tests/testUbiNode.cpp
@@ -83,8 +83,23 @@ BEGIN_TEST(test_ubiNodeCompartment)
 
         CHECK(JS::ubi::Node(script1).compartment() == global1->compartment());
         CHECK(JS::ubi::Node(script2).compartment() == global2->compartment());
     }
 
     return true;
 }
 END_TEST(test_ubiNodeCompartment)
+
+BEGIN_TEST(test_ubiNodeJSObjectConstructorName)
+{
+    JS::RootedValue val(cx);
+    EVAL("this.Ctor = function Ctor() {}; new Ctor", &val);
+    CHECK(val.isObject());
+
+    mozilla::UniquePtr<char16_t[], JS::FreePolicy> ctorName;
+    CHECK(JS::ubi::Node(&val.toObject()).jsObjectConstructorName(cx, ctorName));
+    CHECK(ctorName);
+    CHECK(js_strcmp(ctorName.get(), MOZ_UTF16("Ctor")) == 0);
+
+    return true;
+}
+END_TEST(test_ubiNodeJSObjectConstructorName)
--- a/js/src/vm/UbiNode.cpp
+++ b/js/src/vm/UbiNode.cpp
@@ -3,16 +3,17 @@
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "js/UbiNode.h"
 
 #include "mozilla/Assertions.h"
 #include "mozilla/Attributes.h"
+#include "mozilla/Range.h"
 #include "mozilla/Scoped.h"
 #include "mozilla/UniquePtr.h"
 
 #include "jscntxt.h"
 #include "jsobj.h"
 #include "jsscript.h"
 #include "jsstr.h"
 
@@ -27,16 +28,17 @@
 #include "vm/Shape.h"
 #include "vm/String.h"
 #include "vm/Symbol.h"
 
 #include "jsobjinlines.h"
 #include "vm/Debugger-inl.h"
 
 using mozilla::Some;
+using mozilla::UniquePtr;
 using JS::HandleValue;
 using JS::Value;
 using JS::ZoneSet;
 using JS::ubi::Concrete;
 using JS::ubi::Edge;
 using JS::ubi::EdgeRange;
 using JS::ubi::Node;
 using JS::ubi::SimpleEdge;
@@ -223,16 +225,41 @@ TracerConcreteWithCompartment<Referent>:
 }
 
 const char*
 Concrete<JSObject>::jsObjectClassName() const
 {
     return Concrete::get().getClass()->name;
 }
 
+bool
+Concrete<JSObject>::jsObjectConstructorName(JSContext* cx,
+                                            UniquePtr<char16_t[], JS::FreePolicy>& outName) const
+{
+    JSAtom* name = Concrete::get().maybeConstructorDisplayAtom();
+    if (!name) {
+        outName.reset(nullptr);
+        return true;
+    }
+
+    auto len = JS_GetStringLength(name);
+    auto size = len + 1;
+
+    outName.reset(cx->pod_malloc<char16_t>(size * sizeof(char16_t)));
+    if (!outName)
+        return false;
+
+    mozilla::Range<char16_t> chars(outName.get(), size);
+    if (!JS_CopyStringChars(cx, chars, name))
+        return false;
+
+    outName[len] = '\0';
+    return true;
+}
+
 template<> const char16_t TracerConcrete<JS::Symbol>::concreteTypeName[] =
     MOZ_UTF16("JS::Symbol");
 template<> const char16_t TracerConcrete<JSScript>::concreteTypeName[] =
     MOZ_UTF16("JSScript");
 template<> const char16_t TracerConcrete<js::LazyScript>::concreteTypeName[] =
     MOZ_UTF16("js::LazyScript");
 template<> const char16_t TracerConcrete<js::jit::JitCode>::concreteTypeName[] =
     MOZ_UTF16("js::jit::JitCode");