Bug 1187062 - Part 2: Implement a concrete JS::ubi::StackFrame class backed by js::SavedFrame; r=sfink
authorNick Fitzgerald <fitzgen@gmail.com>
Fri, 14 Aug 2015 17:49:06 -0700
changeset 257944 40ffe3eacef1cbbc600250f67d9a483c0f4be3d0
parent 257943 ae29da8d7f809822f9d535c32fa686692f7c5a46
child 257945 638c65c33cfab3411ff26eb0c06836062c20ca5d
push id29238
push userryanvm@gmail.com
push dateMon, 17 Aug 2015 13:06:57 +0000
treeherdermozilla-central@a6eeb28458fd [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssfink
bugs1187062
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 1187062 - Part 2: Implement a concrete JS::ubi::StackFrame class backed by js::SavedFrame; r=sfink
js/public/UbiNode.h
js/src/vm/SavedFrame.h
js/src/vm/SavedStacks.cpp
js/src/vm/UbiNode.cpp
--- a/js/public/UbiNode.h
+++ b/js/public/UbiNode.h
@@ -951,16 +951,19 @@ template<> struct Concrete<JSScript> : T
 // 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;
 
+    bool hasAllocationStack() const override;
+    StackFrame allocationStack() const override;
+
   protected:
     explicit Concrete(JSObject* ptr) : TracerConcreteWithCompartment(ptr) { }
 
   public:
     static void construct(void* storage, JSObject* ptr) {
         new (storage) Concrete(ptr);
     }
 };
--- a/js/src/vm/SavedFrame.h
+++ b/js/src/vm/SavedFrame.h
@@ -2,16 +2,18 @@
  * vim: set ts=8 sts=4 et sw=4 tw=99:
  * 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/. */
 
 #ifndef vm_SavedFrame_h
 #define vm_SavedFrame_h
 
+#include "js/UbiNode.h"
+
 namespace js {
 
 class SavedFrame : public NativeObject {
     friend class SavedStacks;
 
   public:
     static const Class          class_;
     static const JSPropertySpec protoAccessors[];
@@ -104,9 +106,54 @@ struct SavedFrame::HashPolicy
 };
 
 // Assert that if the given object is not null, that it must be either a
 // SavedFrame object or wrapper (Xray or CCW) around a SavedFrame object.
 inline void AssertObjectIsSavedFrameOrWrapper(JSContext* cx, HandleObject stack);
 
 } // namespace js
 
+namespace JS {
+namespace ubi {
+
+using js::SavedFrame;
+
+// A concrete JS::ubi::StackFrame that is backed by a live SavedFrame object.
+template<>
+class ConcreteStackFrame<SavedFrame> : public BaseStackFrame {
+    explicit ConcreteStackFrame(SavedFrame* ptr) : BaseStackFrame(ptr) { }
+    SavedFrame& get() const { return *static_cast<SavedFrame*>(ptr); }
+
+  public:
+    static void construct(void* storage, SavedFrame* ptr) { new (storage) ConcreteStackFrame(ptr); }
+
+    StackFrame parent() const override { return get().getParent(); }
+    uint32_t line() const override { return get().getLine(); }
+    uint32_t column() const override { return get().getColumn(); }
+
+    AtomOrTwoByteChars source() const override {
+        auto source = get().getSource();
+        return AtomOrTwoByteChars(source);
+    }
+
+    AtomOrTwoByteChars functionDisplayName() const override {
+        auto name = get().getFunctionDisplayName();
+        return AtomOrTwoByteChars(name);
+    }
+
+    void trace(JSTracer* trc) override {
+        JSObject* obj = &get();
+        js::TraceManuallyBarrieredEdge(trc, &obj, "ConcreteStackFrame<SavedFrame>::ptr");
+        ptr = obj;
+    }
+
+    bool isSelfHosted() const override { return get().isSelfHosted(); }
+
+    bool isSystem() const override;
+
+    bool constructSavedFrameStack(JSContext* cx,
+                                 MutableHandleObject outSavedFrameStack) const override;
+};
+
+} // namespace ubi
+} // namespace JS
+
 #endif // vm_SavedFrame_h
--- a/js/src/vm/SavedStacks.cpp
+++ b/js/src/vm/SavedStacks.cpp
@@ -1370,8 +1370,34 @@ CompartmentChecker::check(SavedStacks* s
         printf("*** Compartment SavedStacks mismatch: %p vs. %p\n",
                (void*) &compartment->savedStacks(), stacks);
         MOZ_CRASH();
     }
 }
 #endif /* JS_CRASH_DIAGNOSTICS */
 
 } /* namespace js */
+
+namespace JS {
+namespace ubi {
+
+bool
+ConcreteStackFrame<SavedFrame>::isSystem() const
+{
+    auto trustedPrincipals = get().runtimeFromAnyThread()->trustedPrincipals();
+    return get().getPrincipals() == trustedPrincipals;
+}
+
+bool
+ConcreteStackFrame<SavedFrame>::constructSavedFrameStack(JSContext* cx,
+                                                         MutableHandleObject outSavedFrameStack)
+    const
+{
+    outSavedFrameStack.set(&get());
+    if (!cx->compartment()->wrap(cx, outSavedFrameStack)) {
+        outSavedFrameStack.set(nullptr);
+        return false;
+    }
+    return true;
+}
+
+} // namespace ubi
+} // namespace JS
--- a/js/src/vm/UbiNode.cpp
+++ b/js/src/vm/UbiNode.cpp
@@ -6,55 +6,121 @@
 
 #include "js/UbiNode.h"
 
 #include "mozilla/Assertions.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/Range.h"
 #include "mozilla/Scoped.h"
 
+#include <algorithm>
+
 #include "jscntxt.h"
 #include "jsobj.h"
 #include "jsscript.h"
 #include "jsstr.h"
 
 #include "jit/IonCode.h"
 #include "js/Debug.h"
 #include "js/TracingAPI.h"
 #include "js/TypeDecls.h"
 #include "js/Utility.h"
 #include "js/Vector.h"
+#include "vm/Debugger.h"
 #include "vm/GlobalObject.h"
 #include "vm/ScopeObject.h"
 #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::RangedPtr;
 using mozilla::UniquePtr;
 using JS::DispatchTraceKindTyped;
 using JS::HandleValue;
 using JS::Value;
 using JS::ZoneSet;
+using JS::ubi::AtomOrTwoByteChars;
 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;
 using JS::ubi::TracerConcreteWithCompartment;
 
+template<typename CharT>
+static size_t
+copyToBuffer(const CharT* src, RangedPtr<char16_t> dest, size_t length)
+{
+    size_t i = 0;
+    for ( ; i < length; i++)
+        dest[i] = src[i];
+    return i;
+}
+
+struct CopyToBufferMatcher
+{
+    using ReturnType = size_t;
+
+    RangedPtr<char16_t> destination;
+    size_t              maxLength;
+
+    CopyToBufferMatcher(RangedPtr<char16_t> destination, size_t maxLength)
+      : destination(destination)
+      , maxLength(maxLength)
+    { }
+
+    size_t
+    match(JSAtom* atom)
+    {
+        if (!atom)
+            return 0;
+
+        size_t length = std::min(atom->length(), maxLength);
+        JS::AutoCheckCannotGC noGC;
+        return atom->hasTwoByteChars()
+            ? copyToBuffer(atom->twoByteChars(noGC), destination, length)
+            : copyToBuffer(atom->latin1Chars(noGC), destination, length);
+    }
+
+    size_t
+    match(const char16_t* chars)
+    {
+        if (!chars)
+            return 0;
+
+        size_t length = std::min(js_strlen(chars), maxLength);
+        return copyToBuffer(chars, destination, length);
+    }
+};
+
+size_t
+StackFrame::source(RangedPtr<char16_t> destination, size_t length) const
+{
+    CopyToBufferMatcher m(destination, length);
+    return source().match(m);
+}
+
+size_t
+StackFrame::functionDisplayName(RangedPtr<char16_t> destination, size_t length) const
+{
+    CopyToBufferMatcher m(destination, length);
+    return functionDisplayName().match(m);
+}
+
 // All operations on null ubi::Nodes crash.
-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"); }
+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");
 }
 
 size_t
 Concrete<void>::size(mozilla::MallocSizeOf mallocSizeof) const
@@ -213,16 +279,29 @@ TracerConcrete<Referent>::edges(JSContex
 
 template<typename Referent>
 JSCompartment*
 TracerConcreteWithCompartment<Referent>::compartment() const
 {
     return TracerBase::get().compartment();
 }
 
+bool
+Concrete<JSObject>::hasAllocationStack() const
+{
+    return !!js::Debugger::getObjectAllocationSite(get());
+}
+
+StackFrame
+Concrete<JSObject>::allocationStack() const
+{
+    MOZ_ASSERT(hasAllocationStack());
+    return StackFrame(js::Debugger::getObjectAllocationSite(get()));
+}
+
 const char*
 Concrete<JSObject>::jsObjectClassName() const
 {
     return Concrete::get().getClass()->name;
 }
 
 bool
 Concrete<JSObject>::jsObjectConstructorName(JSContext* cx,