diff --git a/js/public/UbiNode.h b/js/public/UbiNode.h index 9b4333ceb9e3..905fef5389f6 100644 --- a/js/public/UbiNode.h +++ b/js/public/UbiNode.h @@ -956,6 +956,9 @@ class Concrete : public TracerConcreteWithCompartment { UniquePtr& 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) { } diff --git a/js/src/vm/SavedFrame.h b/js/src/vm/SavedFrame.h index df878d288884..2005759e01b1 100644 --- a/js/src/vm/SavedFrame.h +++ b/js/src/vm/SavedFrame.h @@ -7,6 +7,8 @@ #ifndef vm_SavedFrame_h #define vm_SavedFrame_h +#include "js/UbiNode.h" + namespace js { class SavedFrame : public NativeObject { @@ -109,4 +111,49 @@ 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 : public BaseStackFrame { + explicit ConcreteStackFrame(SavedFrame* ptr) : BaseStackFrame(ptr) { } + SavedFrame& get() const { return *static_cast(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::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 diff --git a/js/src/vm/SavedStacks.cpp b/js/src/vm/SavedStacks.cpp index d4a7a28f8506..dc23a89db0a0 100644 --- a/js/src/vm/SavedStacks.cpp +++ b/js/src/vm/SavedStacks.cpp @@ -1375,3 +1375,29 @@ CompartmentChecker::check(SavedStacks* stacks) #endif /* JS_CRASH_DIAGNOSTICS */ } /* namespace js */ + +namespace JS { +namespace ubi { + +bool +ConcreteStackFrame::isSystem() const +{ + auto trustedPrincipals = get().runtimeFromAnyThread()->trustedPrincipals(); + return get().getPrincipals() == trustedPrincipals; +} + +bool +ConcreteStackFrame::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 diff --git a/js/src/vm/UbiNode.cpp b/js/src/vm/UbiNode.cpp index 5bd529a0a512..d252d612b693 100644 --- a/js/src/vm/UbiNode.cpp +++ b/js/src/vm/UbiNode.cpp @@ -11,6 +11,8 @@ #include "mozilla/Range.h" #include "mozilla/Scoped.h" +#include + #include "jscntxt.h" #include "jsobj.h" #include "jsscript.h" @@ -22,6 +24,7 @@ #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" @@ -32,24 +35,87 @@ #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 +static size_t +copyToBuffer(const CharT* src, RangedPtr 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 destination; + size_t maxLength; + + CopyToBufferMatcher(RangedPtr 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 destination, size_t length) const +{ + CopyToBufferMatcher m(destination, length); + return source().match(m); +} + +size_t +StackFrame::functionDisplayName(RangedPtr destination, size_t length) const +{ + CopyToBufferMatcher m(destination, length); + return functionDisplayName().match(m); +} + // All operations on null ubi::Nodes crash. -const char16_t* Concrete::typeName() const { MOZ_CRASH("null ubi::Node"); } -JS::Zone* Concrete::zone() const { MOZ_CRASH("null ubi::Node"); } -JSCompartment* Concrete::compartment() const { MOZ_CRASH("null ubi::Node"); } +const char16_t* Concrete::typeName() const { MOZ_CRASH("null ubi::Node"); } +JS::Zone* Concrete::zone() const { MOZ_CRASH("null ubi::Node"); } +JSCompartment* Concrete::compartment() const { MOZ_CRASH("null ubi::Node"); } UniquePtr Concrete::edges(JSContext*, bool) const { @@ -218,6 +284,19 @@ TracerConcreteWithCompartment::compartment() const return TracerBase::get().compartment(); } +bool +Concrete::hasAllocationStack() const +{ + return !!js::Debugger::getObjectAllocationSite(get()); +} + +StackFrame +Concrete::allocationStack() const +{ + MOZ_ASSERT(hasAllocationStack()); + return StackFrame(js::Debugger::getObjectAllocationSite(get())); +} + const char* Concrete::jsObjectClassName() const {