Bug 1196634 - Part 0: Define a JS::ubi::CoarseType enum; r=sfink
authorNick Fitzgerald <fitzgen@gmail.com>
Thu, 27 Aug 2015 16:16:57 -0700
changeset 259746 c7bdb99e57436e9d089b8b24ed6f51547fe60c7f
parent 259745 171e29626ffc02c79cd4ba842585cf58157fee94
child 259747 885334756aed01089a44eecf50179f725f9c5e4c
push id29290
push userryanvm@gmail.com
push dateFri, 28 Aug 2015 12:48:48 +0000
treeherdermozilla-central@008d4d76f387 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssfink
bugs1196634
milestone43.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 1196634 - Part 0: Define a JS::ubi::CoarseType enum; r=sfink This commit defines the JS::ubi::CoarseType enum and a corresponding method coarseType() on JS::ubi::Node base and concrete classes. It implements the overrides for all concrete specializations whose referent does not belong to the default Other type.
js/public/UbiNode.h
js/src/jit/IonCode.h
js/src/jsapi-tests/testUbiNode.cpp
js/src/jsscript.h
js/src/vm/UbiNode.cpp
--- a/js/public/UbiNode.h
+++ b/js/public/UbiNode.h
@@ -432,16 +432,35 @@ class ConcreteStackFrame<void> : public 
 };
 
 bool ConstructSavedFrameStackSlow(JSContext* cx, JS::ubi::StackFrame& frame,
                                   MutableHandleObject outSavedFrameStack);
 
 
 /*** ubi::Node ************************************************************************************/
 
+// A concrete node specialization can claim its referent is a member of a
+// particular "coarse type" which is less specific than the actual
+// implementation type but generally more palatable for web developers. For
+// example, JitCode can be considered to have a coarse type of "Script". This is
+// used by some analyses for putting nodes into different buckets. The default,
+// if a concrete specialization does not provide its own mapping to a CoarseType
+// variant, is "Other".
+//
+// NB: the values associated with a particular enum variant must not change or
+// be reused for new variants. Doing so will cause inspecting ubi::Node's backed
+// by an offline heap snapshot from an older SpiderMonkey/Firefox version to
+// break. Consider this enum append only.
+enum class CoarseType: uint32_t {
+    Object = 0,
+    Script = 1,
+    String = 2,
+    Other  = 3
+};
+
 // The base class implemented by each ubi::Node referent type. Subclasses must
 // not add data members to this class.
 class Base {
     friend class Node;
 
     // For performance's sake, we'd prefer to avoid a virtual destructor; and
     // an empty constructor seems consistent with the 'lightweight value type'
     // visible behavior we're trying to achieve. But if the destructor isn't
@@ -480,16 +499,19 @@ class Base {
     using Id = uint64_t;
     virtual Id identifier() const { return reinterpret_cast<Id>(ptr); }
 
     // Returns true if this node is pointing to something on the live heap, as
     // opposed to something from a deserialized core dump. Returns false,
     // otherwise.
     virtual bool isLive() const { return true; };
 
+    // Return the coarse-grained type-of-thing that this node represents.
+    virtual CoarseType coarseType() const { return CoarseType::Other; }
+
     // Return a human-readable name for the referent's type. The result should
     // be statically allocated. (You can use MOZ_UTF16("strings") for this.)
     //
     // This must always return Concrete<T>::concreteTypeName; we use that
     // pointer as a tag for this particular referent type.
     virtual const char16_t* typeName() const = 0;
 
     // Return the size of this node, in bytes. Include any structures that this
@@ -675,16 +697,17 @@ class Node {
     }
 
     // If this node refers to something that can be represented as a JavaScript
     // value that is safe to expose to JavaScript code, return that value.
     // Otherwise return UndefinedValue(). JSStrings, JS::Symbols, and some (but
     // not all!) JSObjects can be exposed.
     JS::Value exposeToJS() const;
 
+    CoarseType coarseType()         const { return base()->coarseType(); }
     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);
     }
@@ -958,57 +981,71 @@ class TracerConcreteWithCompartment : pu
     static void construct(void* storage, Referent* ptr) {
         new (storage) TracerConcreteWithCompartment(ptr);
     }
 };
 
 // Define specializations for some commonly-used public JSAPI types.
 // These can use the generic templates above.
 template<> struct Concrete<JS::Symbol> : TracerConcrete<JS::Symbol> { };
-template<> struct Concrete<JSScript> : TracerConcreteWithCompartment<JSScript> { };
+
+template<> struct Concrete<JSScript> : TracerConcreteWithCompartment<JSScript> {
+    CoarseType coarseType() const final { return CoarseType::Script; }
+
+  protected:
+    explicit Concrete(JSScript *ptr) : TracerConcreteWithCompartment<JSScript>(ptr) { }
+
+  public:
+    static void construct(void *storage, JSScript *ptr) { new (storage) Concrete(ptr); }
+};
 
 // 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 size(mozilla::MallocSizeOf mallocSizeOf) const override;
 
     bool hasAllocationStack() const override;
     StackFrame allocationStack() const override;
 
+    CoarseType coarseType() const final { return CoarseType::Object; }
+
   protected:
     explicit Concrete(JSObject* ptr) : TracerConcreteWithCompartment(ptr) { }
 
   public:
     static void construct(void* storage, JSObject* ptr) {
         new (storage) Concrete(ptr);
     }
 };
 
 // For JSString, we extend the generic template with a 'size' implementation.
 template<> struct Concrete<JSString> : TracerConcrete<JSString> {
     Size size(mozilla::MallocSizeOf mallocSizeOf) const override;
 
+    CoarseType coarseType() const final { return CoarseType::String; }
+
   protected:
     explicit Concrete(JSString *ptr) : TracerConcrete<JSString>(ptr) { }
 
   public:
     static void construct(void *storage, JSString *ptr) { new (storage) Concrete(ptr); }
 };
 
 // The ubi::Node null pointer. Any attempt to operate on a null ubi::Node asserts.
 template<>
 class Concrete<void> : public Base {
     const char16_t* typeName() const override;
     Size size(mozilla::MallocSizeOf mallocSizeOf) const override;
     UniquePtr<EdgeRange> edges(JSContext* cx, bool wantNames) const override;
     JS::Zone* zone() const override;
     JSCompartment* compartment() const override;
+    CoarseType coarseType() const final;
 
     explicit Concrete(void* ptr) : Base(ptr) { }
 
   public:
     static void construct(void* storage, void* ptr) { new (storage) Concrete(ptr); }
     static const char16_t concreteTypeName[];
 };
 
--- a/js/src/jit/IonCode.h
+++ b/js/src/jit/IonCode.h
@@ -771,13 +771,23 @@ IsMarked(const jit::VMFunction*)
 } // namespace gc
 
 } // namespace js
 
 // JS::ubi::Nodes can point to js::jit::JitCode instances; they're js::gc::Cell
 // instances with no associated compartment.
 namespace JS {
 namespace ubi {
-template<> struct Concrete<js::jit::JitCode> : TracerConcrete<js::jit::JitCode> { };
+template<>
+struct Concrete<js::jit::JitCode> : TracerConcrete<js::jit::JitCode> {
+    CoarseType coarseType() const final { return CoarseType::Script; }
+
+  protected:
+    explicit Concrete(js::jit::JitCode *ptr) : TracerConcrete<js::jit::JitCode>(ptr) { }
+
+  public:
+    static void construct(void *storage, js::jit::JitCode *ptr) { new (storage) Concrete(ptr); }
+};
+
 } // namespace ubi
 } // namespace JS
 
 #endif /* jit_IonCode_h */
--- a/js/src/jsapi-tests/testUbiNode.cpp
+++ b/js/src/jsapi-tests/testUbiNode.cpp
@@ -190,8 +190,36 @@ BEGIN_TEST(test_ubiStackFrame)
     CHECK(ubiFrame.line() == 1);
 
     ubiFrame = ubiFrame.parent();
     CHECK(!ubiFrame);
 
     return true;
 }
 END_TEST(test_ubiStackFrame)
+
+BEGIN_TEST(test_ubiCoarseType)
+{
+    // Test that our explicit coarseType() overrides work as expected.
+
+    JSObject* obj = nullptr;
+    CHECK(JS::ubi::Node(obj).coarseType() == JS::ubi::CoarseType::Object);
+
+    JSScript* script = nullptr;
+    CHECK(JS::ubi::Node(script).coarseType() == JS::ubi::CoarseType::Script);
+
+    js::LazyScript* lazyScript = nullptr;
+    CHECK(JS::ubi::Node(lazyScript).coarseType() == JS::ubi::CoarseType::Script);
+
+    js::jit::JitCode* jitCode = nullptr;
+    CHECK(JS::ubi::Node(jitCode).coarseType() == JS::ubi::CoarseType::Script);
+
+    JSString* str = nullptr;
+    CHECK(JS::ubi::Node(str).coarseType() == JS::ubi::CoarseType::String);
+
+    // Test that the default when coarseType() is not overridden is Other.
+
+    JS::Symbol* sym = nullptr;
+    CHECK(JS::ubi::Node(sym).coarseType() == JS::ubi::CoarseType::Other);
+
+    return true;
+}
+END_TEST(test_ubiCoarseType)
--- a/js/src/jsscript.h
+++ b/js/src/jsscript.h
@@ -2403,13 +2403,22 @@ JSScript*
 CloneGlobalScript(JSContext* cx, Handle<ScopeObject*> enclosingScope, HandleScript src);
 
 } /* namespace js */
 
 // JS::ubi::Nodes can point to js::LazyScripts; they're js::gc::Cell instances
 // with no associated compartment.
 namespace JS {
 namespace ubi {
-template<> struct Concrete<js::LazyScript> : TracerConcrete<js::LazyScript> { };
+template<>
+struct Concrete<js::LazyScript> : TracerConcrete<js::LazyScript> {
+    CoarseType coarseType() const final { return CoarseType::Script; }
+
+  protected:
+    explicit Concrete(js::LazyScript *ptr) : TracerConcrete<js::LazyScript>(ptr) { }
+
+  public:
+    static void construct(void *storage, js::LazyScript *ptr) { new (storage) Concrete(ptr); }
+};
 } // namespace ubi
 } // namespace JS
 
 #endif /* jsscript_h */
--- a/js/src/vm/UbiNode.cpp
+++ b/js/src/vm/UbiNode.cpp
@@ -37,16 +37,17 @@
 using mozilla::Some;
 using mozilla::RangedPtr;
 using mozilla::UniquePtr;
 using JS::DispatchTraceKindTyped;
 using JS::HandleValue;
 using JS::Value;
 using JS::ZoneSet;
 using JS::ubi::AtomOrTwoByteChars;
+using JS::ubi::CoarseType;
 using JS::ubi::Concrete;
 using JS::ubi::Edge;
 using JS::ubi::EdgeRange;
 using JS::ubi::Node;
 using JS::ubi::SimpleEdge;
 using JS::ubi::SimpleEdgeVector;
 using JS::ubi::StackFrame;
 using JS::ubi::TracerConcrete;
@@ -267,16 +268,17 @@ Node::getCanonicalTypeName(const char16_
 
         return nullptr;
     }
 
     return nullptr;
 }
 
 // All operations on null ubi::Nodes crash.
+CoarseType Concrete<void>::coarseType() const      { MOZ_CRASH("null ubi::Node"); }
 const char16_t* Concrete<void>::typeName() const   { MOZ_CRASH("null ubi::Node"); }
 JS::Zone* Concrete<void>::zone() const             { MOZ_CRASH("null ubi::Node"); }
 JSCompartment* Concrete<void>::compartment() const { MOZ_CRASH("null ubi::Node"); }
 
 UniquePtr<EdgeRange>
 Concrete<void>::edges(JSContext*, bool) const {
     MOZ_CRASH("null ubi::Node");
 }