mirror of
https://github.com/classilla/tenfourfox.git
synced 2024-06-25 20:29:33 +00:00
307 lines
10 KiB
C++
307 lines
10 KiB
C++
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
|
* 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 "jswrapper.h"
|
|
|
|
#include "js/GCHashTable.h"
|
|
#include "js/UbiNode.h"
|
|
|
|
namespace js {
|
|
|
|
class SavedFrame : public NativeObject {
|
|
friend class SavedStacks;
|
|
friend struct ::JSStructuredCloneReader;
|
|
|
|
public:
|
|
static const Class class_;
|
|
static const JSPropertySpec protoAccessors[];
|
|
static const JSFunctionSpec protoFunctions[];
|
|
static const JSFunctionSpec staticFunctions[];
|
|
|
|
// Prototype methods and properties to be exposed to JS.
|
|
static bool construct(JSContext* cx, unsigned argc, Value* vp);
|
|
static bool sourceProperty(JSContext* cx, unsigned argc, Value* vp);
|
|
static bool lineProperty(JSContext* cx, unsigned argc, Value* vp);
|
|
static bool columnProperty(JSContext* cx, unsigned argc, Value* vp);
|
|
static bool functionDisplayNameProperty(JSContext* cx, unsigned argc, Value* vp);
|
|
static bool asyncCauseProperty(JSContext* cx, unsigned argc, Value* vp);
|
|
static bool asyncParentProperty(JSContext* cx, unsigned argc, Value* vp);
|
|
static bool parentProperty(JSContext* cx, unsigned argc, Value* vp);
|
|
static bool toStringMethod(JSContext* cx, unsigned argc, Value* vp);
|
|
|
|
static void finalize(FreeOp* fop, JSObject* obj);
|
|
|
|
// Convenient getters for SavedFrame's reserved slots for use from C++.
|
|
JSAtom* getSource();
|
|
uint32_t getLine();
|
|
uint32_t getColumn();
|
|
JSAtom* getFunctionDisplayName();
|
|
JSAtom* getAsyncCause();
|
|
SavedFrame* getParent() const;
|
|
JSPrincipals* getPrincipals();
|
|
bool isSelfHosted();
|
|
|
|
// Iterators for use with C++11 range based for loops, eg:
|
|
//
|
|
// SavedFrame* stack = getSomeSavedFrameStack();
|
|
// for (const SavedFrame* frame : *stack) {
|
|
// ...
|
|
// }
|
|
//
|
|
// If you need to keep each frame rooted during iteration, you can use
|
|
// `SavedFrame::RootedRange`. Each frame yielded by
|
|
// `SavedFrame::RootedRange` is only a valid handle to a rooted `SavedFrame`
|
|
// within the loop's block for a single loop iteration. When the next
|
|
// iteration begins, the value is invalidated.
|
|
//
|
|
// RootedSavedFrame stack(cx, getSomeSavedFrameStack());
|
|
// for (HandleSavedFrame frame : SavedFrame::RootedRange(cx, stack)) {
|
|
// ...
|
|
// }
|
|
|
|
class Iterator {
|
|
SavedFrame* frame_;
|
|
public:
|
|
explicit Iterator(SavedFrame* frame) : frame_(frame) { }
|
|
SavedFrame& operator*() const { MOZ_ASSERT(frame_); return *frame_; }
|
|
bool operator!=(const Iterator& rhs) const { return rhs.frame_ != frame_; }
|
|
inline void operator++();
|
|
};
|
|
|
|
Iterator begin() { return Iterator(this); }
|
|
Iterator end() { return Iterator(nullptr); }
|
|
|
|
class ConstIterator {
|
|
const SavedFrame* frame_;
|
|
public:
|
|
explicit ConstIterator(const SavedFrame* frame) : frame_(frame) { }
|
|
const SavedFrame& operator*() const { MOZ_ASSERT(frame_); return *frame_; }
|
|
bool operator!=(const ConstIterator& rhs) const { return rhs.frame_ != frame_; }
|
|
inline void operator++();
|
|
};
|
|
|
|
ConstIterator begin() const { return ConstIterator(this); }
|
|
ConstIterator end() const { return ConstIterator(nullptr); }
|
|
|
|
class RootedRange;
|
|
|
|
class MOZ_STACK_CLASS RootedIterator {
|
|
friend class RootedRange;
|
|
RootedRange* range_;
|
|
// For use by RootedRange::end() only.
|
|
explicit RootedIterator() : range_(nullptr) { }
|
|
|
|
public:
|
|
explicit RootedIterator(RootedRange& range) : range_(&range) { }
|
|
HandleSavedFrame operator*() { MOZ_ASSERT(range_); return range_->frame_; }
|
|
bool operator!=(const RootedIterator& rhs) const {
|
|
// We should only ever compare to the null range, aka we are just
|
|
// testing if this range is done.
|
|
MOZ_ASSERT(rhs.range_ == nullptr);
|
|
return range_->frame_ != nullptr;
|
|
}
|
|
inline void operator++();
|
|
};
|
|
|
|
class MOZ_STACK_CLASS RootedRange {
|
|
friend class RootedIterator;
|
|
RootedSavedFrame frame_;
|
|
|
|
public:
|
|
RootedRange(JSContext* cx, HandleSavedFrame frame) : frame_(cx, frame) { }
|
|
RootedIterator begin() { return RootedIterator(*this); }
|
|
RootedIterator end() { return RootedIterator(); }
|
|
};
|
|
|
|
static bool isSavedFrameAndNotProto(JSObject& obj) {
|
|
return obj.is<SavedFrame>() &&
|
|
!obj.as<SavedFrame>().getReservedSlot(JSSLOT_SOURCE).isNull();
|
|
}
|
|
|
|
static bool isSavedFrameOrWrapperAndNotProto(JSObject& obj) {
|
|
auto unwrapped = CheckedUnwrap(&obj);
|
|
if (!unwrapped)
|
|
return false;
|
|
return isSavedFrameAndNotProto(*unwrapped);
|
|
}
|
|
|
|
struct Lookup;
|
|
struct HashPolicy;
|
|
|
|
typedef GCHashSet<js::ReadBarriered<SavedFrame*>,
|
|
HashPolicy,
|
|
SystemAllocPolicy> Set;
|
|
|
|
class AutoLookupVector;
|
|
|
|
class MOZ_STACK_CLASS HandleLookup {
|
|
friend class AutoLookupVector;
|
|
|
|
Lookup& lookup;
|
|
|
|
explicit HandleLookup(Lookup& lookup) : lookup(lookup) { }
|
|
|
|
public:
|
|
inline Lookup& get() { return lookup; }
|
|
inline Lookup* operator->() { return &lookup; }
|
|
};
|
|
|
|
private:
|
|
static SavedFrame* create(JSContext* cx);
|
|
static bool finishSavedFrameInit(JSContext* cx, HandleObject ctor, HandleObject proto);
|
|
void initFromLookup(HandleLookup lookup);
|
|
void initSource(JSAtom* source);
|
|
void initLine(uint32_t line);
|
|
void initColumn(uint32_t column);
|
|
void initFunctionDisplayName(JSAtom* maybeName);
|
|
void initAsyncCause(JSAtom* maybeCause);
|
|
void initParent(SavedFrame* maybeParent);
|
|
void initPrincipalsAlreadyHeld(JSPrincipals* principals);
|
|
void initPrincipals(JSPrincipals* principals);
|
|
|
|
enum {
|
|
// The reserved slots in the SavedFrame class.
|
|
JSSLOT_SOURCE,
|
|
JSSLOT_LINE,
|
|
JSSLOT_COLUMN,
|
|
JSSLOT_FUNCTIONDISPLAYNAME,
|
|
JSSLOT_ASYNCCAUSE,
|
|
JSSLOT_PARENT,
|
|
JSSLOT_PRINCIPALS,
|
|
|
|
// The total number of reserved slots in the SavedFrame class.
|
|
JSSLOT_COUNT
|
|
};
|
|
|
|
static bool checkThis(JSContext* cx, CallArgs& args, const char* fnName,
|
|
MutableHandleObject frame);
|
|
};
|
|
|
|
struct SavedFrame::HashPolicy
|
|
{
|
|
typedef SavedFrame::Lookup Lookup;
|
|
typedef MovableCellHasher<SavedFrame*> SavedFramePtrHasher;
|
|
typedef PointerHasher<JSPrincipals*, 3> JSPrincipalsPtrHasher;
|
|
|
|
static HashNumber hash(const Lookup& lookup);
|
|
static bool match(SavedFrame* existing, const Lookup& lookup);
|
|
|
|
typedef ReadBarriered<SavedFrame*> Key;
|
|
static void rekey(Key& key, const Key& newKey);
|
|
};
|
|
|
|
// 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);
|
|
|
|
// When we reconstruct a SavedFrame stack from a JS::ubi::StackFrame, we may not
|
|
// have access to the principals that the original stack was captured
|
|
// with. Instead, we use these two singleton principals based on whether
|
|
// JS::ubi::StackFrame::isSystem or not. These singletons should never be passed
|
|
// to the subsumes callback, and should be special cased with a shortcut before
|
|
// that.
|
|
struct ReconstructedSavedFramePrincipals : public JSPrincipals
|
|
{
|
|
explicit ReconstructedSavedFramePrincipals()
|
|
: JSPrincipals()
|
|
{
|
|
MOZ_ASSERT(is(this));
|
|
this->refcount = 1;
|
|
}
|
|
|
|
bool write(JSContext* cx, JSStructuredCloneWriter* writer) override {
|
|
MOZ_ASSERT(false, "ReconstructedSavedFramePrincipals should never be exposed to embedders");
|
|
return false;
|
|
}
|
|
|
|
static ReconstructedSavedFramePrincipals IsSystem;
|
|
static ReconstructedSavedFramePrincipals IsNotSystem;
|
|
|
|
// Return true if the given JSPrincipals* points to one of the
|
|
// ReconstructedSavedFramePrincipals singletons, false otherwise.
|
|
static bool is(JSPrincipals* p) { return p == &IsSystem || p == &IsNotSystem;}
|
|
|
|
// Get the appropriate ReconstructedSavedFramePrincipals singleton for the
|
|
// given JS::ubi::StackFrame that is being reconstructed as a SavedFrame
|
|
// stack.
|
|
static JSPrincipals* getSingleton(JS::ubi::StackFrame& f) {
|
|
return f.isSystem() ? &IsSystem : &IsNotSystem;
|
|
}
|
|
};
|
|
|
|
inline void
|
|
SavedFrame::Iterator::operator++()
|
|
{
|
|
frame_ = frame_->getParent();
|
|
}
|
|
|
|
inline void
|
|
SavedFrame::ConstIterator::operator++()
|
|
{
|
|
frame_ = frame_->getParent();
|
|
}
|
|
|
|
inline void
|
|
SavedFrame::RootedIterator::operator++()
|
|
{
|
|
MOZ_ASSERT(range_);
|
|
range_->frame_ = range_->frame_->getParent();
|
|
}
|
|
|
|
} // 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* prev = &get();
|
|
JSObject* next = prev;
|
|
js::TraceRoot(trc, &next, "ConcreteStackFrame<SavedFrame>::ptr");
|
|
if (next != prev)
|
|
ptr = next;
|
|
}
|
|
|
|
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
|