Bug 1447244 Part 2 - Track source ID in saved frames, r=jimb.

--HG--
extra : rebase_source : 6d585a37588dae528e0d37d53d0629f9b509e82d
This commit is contained in:
Brian Hackett 2019-01-16 11:59:03 -10:00
parent 8e9fd6140b
commit e2c9ceed8d
7 changed files with 88 additions and 7 deletions

View File

@ -287,6 +287,10 @@ class ConcreteStackFrame<DeserializedStackFrame> : public BaseStackFrame {
AtomOrTwoByteChars source() const override {
return AtomOrTwoByteChars(get().source);
}
uint32_t sourceId() const override {
// Source IDs are local to their host process and are not serialized.
return 0;
}
AtomOrTwoByteChars functionDisplayName() const override {
return AtomOrTwoByteChars(get().functionDisplayName);
}

View File

@ -65,6 +65,15 @@ extern JS_PUBLIC_API SavedFrameResult GetSavedFrameSource(
MutableHandle<JSString*> sourcep,
SavedFrameSelfHosted selfHosted = SavedFrameSelfHosted::Include);
/**
* Given a SavedFrame JSObject, get an ID identifying its ScriptSource.
* Defaults to 0.
*/
extern JS_PUBLIC_API SavedFrameResult GetSavedFrameSourceId(
JSContext* cx, JSPrincipals* principals, Handle<JSObject*> savedFrame,
uint32_t* sourceIdp,
SavedFrameSelfHosted selfHosted = SavedFrameSelfHosted::Include);
/**
* Given a SavedFrame JSObject, get its line property. Defaults to 0.
*/

View File

@ -247,6 +247,9 @@ class BaseStackFrame {
// Get this frame's source name. Never null.
virtual AtomOrTwoByteChars source() const = 0;
// Get a unique per-process ID for this frame's source. Defaults to zero.
virtual uint32_t sourceId() const = 0;
// Return this frame's function name if named, otherwise the inferred
// display name. Can be null.
virtual AtomOrTwoByteChars functionDisplayName() const = 0;
@ -414,6 +417,7 @@ class StackFrame {
uint32_t line() const { return base()->line(); }
uint32_t column() const { return base()->column(); }
AtomOrTwoByteChars source() const { return base()->source(); }
uint32_t sourceId() const { return base()->sourceId(); }
AtomOrTwoByteChars functionDisplayName() const {
return base()->functionDisplayName();
}
@ -464,6 +468,7 @@ class ConcreteStackFrame<void> : public BaseStackFrame {
AtomOrTwoByteChars source() const override {
MOZ_CRASH("null JS::ubi::StackFrame");
}
uint32_t sourceId() const override { MOZ_CRASH("null JS::ubi::StackFrame"); }
AtomOrTwoByteChars functionDisplayName() const override {
MOZ_CRASH("null JS::ubi::StackFrame");
}

View File

@ -31,6 +31,7 @@ class SavedFrame : public NativeObject {
// 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 sourceIdProperty(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,
@ -44,6 +45,7 @@ class SavedFrame : public NativeObject {
// Convenient getters for SavedFrame's reserved slots for use from C++.
JSAtom* getSource();
uint32_t getSourceId();
uint32_t getLine();
uint32_t getColumn();
JSAtom* getFunctionDisplayName();
@ -129,6 +131,7 @@ class SavedFrame : public NativeObject {
HandleObject proto);
void initFromLookup(JSContext* cx, HandleLookup lookup);
void initSource(JSAtom* source);
void initSourceId(uint32_t id);
void initLine(uint32_t line);
void initColumn(uint32_t column);
void initFunctionDisplayName(JSAtom* maybeName);
@ -140,6 +143,7 @@ class SavedFrame : public NativeObject {
enum {
// The reserved slots in the SavedFrame class.
JSSLOT_SOURCE,
JSSLOT_SOURCEID,
JSSLOT_LINE,
JSSLOT_COLUMN,
JSSLOT_FUNCTIONDISPLAYNAME,
@ -260,6 +264,8 @@ class ConcreteStackFrame<SavedFrame> : public BaseStackFrame {
return AtomOrTwoByteChars(source);
}
uint32_t sourceId() const override { return get().getSourceId(); }
AtomOrTwoByteChars functionDisplayName() const override {
auto name = get().getFunctionDisplayName();
return AtomOrTwoByteChars(name);

View File

@ -173,12 +173,13 @@ void LiveSavedFrameCache::findWithoutInvalidation(
}
struct SavedFrame::Lookup {
Lookup(JSAtom* source, uint32_t line, uint32_t column,
Lookup(JSAtom* source, uint32_t sourceId, uint32_t line, uint32_t column,
JSAtom* functionDisplayName, JSAtom* asyncCause, SavedFrame* parent,
JSPrincipals* principals,
const Maybe<LiveSavedFrameCache::FramePtr>& framePtr = Nothing(),
jsbytecode* pc = nullptr, Activation* activation = nullptr)
: source(source),
sourceId(sourceId),
line(line),
column(column),
functionDisplayName(functionDisplayName),
@ -197,6 +198,7 @@ struct SavedFrame::Lookup {
explicit Lookup(SavedFrame& savedFrame)
: source(savedFrame.getSource()),
sourceId(savedFrame.getSourceId()),
line(savedFrame.getLine()),
column(savedFrame.getColumn()),
functionDisplayName(savedFrame.getFunctionDisplayName()),
@ -210,6 +212,7 @@ struct SavedFrame::Lookup {
}
JSAtom* source;
uint32_t sourceId;
uint32_t line;
uint32_t column;
JSAtom* functionDisplayName;
@ -370,6 +373,7 @@ const Class SavedFrame::protoClass_ = {
/* static */ const JSPropertySpec SavedFrame::protoAccessors[] = {
JS_PSG("source", SavedFrame::sourceProperty, 0),
JS_PSG("sourceId", SavedFrame::sourceIdProperty, 0),
JS_PSG("line", SavedFrame::lineProperty, 0),
JS_PSG("column", SavedFrame::columnProperty, 0),
JS_PSG("functionDisplayName", SavedFrame::functionDisplayNameProperty, 0),
@ -393,6 +397,11 @@ JSAtom* SavedFrame::getSource() {
return &s->asAtom();
}
uint32_t SavedFrame::getSourceId() {
const Value& v = getReservedSlot(JSSLOT_SOURCEID);
return v.toPrivateUint32();
}
uint32_t SavedFrame::getLine() {
const Value& v = getReservedSlot(JSSLOT_LINE);
return v.toPrivateUint32();
@ -439,6 +448,10 @@ void SavedFrame::initSource(JSAtom* source) {
initReservedSlot(JSSLOT_SOURCE, StringValue(source));
}
void SavedFrame::initSourceId(uint32_t sourceId) {
initReservedSlot(JSSLOT_SOURCEID, PrivateUint32Value(sourceId));
}
void SavedFrame::initLine(uint32_t line) {
initReservedSlot(JSSLOT_LINE, PrivateUint32Value(line));
}
@ -494,6 +507,7 @@ void SavedFrame::initFromLookup(JSContext* cx,
}
initSource(lookup->source);
initSourceId(lookup->sourceId);
initLine(lookup->line);
initColumn(lookup->column);
initFunctionDisplayName(lookup->functionDisplayName);
@ -728,6 +742,25 @@ JS_PUBLIC_API SavedFrameResult GetSavedFrameSource(
return SavedFrameResult::Ok;
}
JS_PUBLIC_API SavedFrameResult GetSavedFrameSourceId(
JSContext* cx, JSPrincipals* principals, HandleObject savedFrame,
uint32_t* sourceIdp,
SavedFrameSelfHosted selfHosted /* = SavedFrameSelfHosted::Include */) {
js::AssertHeapIsIdle();
CHECK_THREAD(cx);
MOZ_RELEASE_ASSERT(cx->realm());
bool skippedAsync;
js::RootedSavedFrame frame(cx, UnwrapSavedFrame(cx, principals, savedFrame,
selfHosted, skippedAsync));
if (!frame) {
*sourceIdp = 0;
return SavedFrameResult::AccessDenied;
}
*sourceIdp = frame->getSourceId();
return SavedFrameResult::Ok;
}
JS_PUBLIC_API SavedFrameResult GetSavedFrameLine(
JSContext* cx, JSPrincipals* principals, HandleObject savedFrame,
uint32_t* linep,
@ -1058,6 +1091,20 @@ namespace js {
return true;
}
/* static */ bool SavedFrame::sourceIdProperty(JSContext* cx, unsigned argc,
Value* vp) {
THIS_SAVEDFRAME(cx, argc, vp, "(get sourceId)", args, frame);
JSPrincipals* principals = cx->realm()->principals();
uint32_t sourceId;
if (JS::GetSavedFrameSourceId(cx, principals, frame, &sourceId) ==
JS::SavedFrameResult::Ok) {
args.rval().setNumber(sourceId);
} else {
args.rval().setNull();
}
return true;
}
/* static */ bool SavedFrame::lineProperty(JSContext* cx, unsigned argc,
Value* vp) {
THIS_SAVEDFRAME(cx, argc, vp, "(get line)", args, frame);
@ -1346,7 +1393,8 @@ bool SavedStacks::insertFrames(JSContext* cx, MutableHandleSavedFrame frame,
MOZ_ASSERT_IF(framePtr && !iter.isWasm(), iter.pc());
if (!stackChain->emplaceBack(
location.source(), location.line(), location.column(), displayAtom,
location.source(), location.sourceId(),
location.line(), location.column(), displayAtom,
nullptr, // asyncCause
nullptr, // parent (not known yet)
principals, framePtr, iter.pc(), &activation)) {
@ -1656,11 +1704,12 @@ bool SavedStacks::getLocation(JSContext* cx, const FrameIter& iter,
return false;
}
uint32_t sourceId = script->scriptSource()->id();
uint32_t column;
uint32_t line = PCToLineNumber(script, pc, &column);
// Make the column 1-based. See comment above.
LocationValue value(source, line, column + 1);
LocationValue value(source, sourceId, line, column + 1);
if (!pcLocationMap.add(p, key, value)) {
ReportOutOfMemory(cx);
return false;
@ -1842,7 +1891,8 @@ JS_PUBLIC_API bool ConstructSavedFrameStackSlow(
auto principals =
js::ReconstructedSavedFramePrincipals::getSingleton(ubiFrame.get());
if (!stackChain->emplaceBack(source, ubiFrame.get().line(),
if (!stackChain->emplaceBack(source, ubiFrame.get().sourceId(),
ubiFrame.get().line(),
ubiFrame.get().column(), functionDisplayName,
/* asyncCause */ nullptr,
/* parent */ nullptr, principals)) {

View File

@ -243,9 +243,9 @@ class SavedStacks {
public:
struct LocationValue {
LocationValue() : source(nullptr), line(0), column(0) {}
LocationValue(JSAtom* source, size_t line, uint32_t column)
: source(source), line(line), column(column) {}
LocationValue() : source(nullptr), sourceId(0), line(0), column(0) {}
LocationValue(JSAtom* source, uint32_t sourceId, size_t line, uint32_t column)
: source(source), sourceId(sourceId), line(line), column(column) {}
void trace(JSTracer* trc) {
TraceNullableEdge(trc, &source, "SavedStacks::LocationValue::source");
@ -261,6 +261,7 @@ class SavedStacks {
}
HeapPtr<JSAtom*> source;
uint32_t sourceId;
size_t line;
uint32_t column;
};
@ -299,6 +300,7 @@ class SavedStacks {
template <typename Wrapper>
struct WrappedPtrOperations<SavedStacks::LocationValue, Wrapper> {
JSAtom* source() const { return loc().source; }
uint32_t sourceId() const { return loc().sourceId; }
size_t line() const { return loc().line; }
uint32_t column() const { return loc().column; }
@ -312,6 +314,7 @@ template <typename Wrapper>
struct MutableWrappedPtrOperations<SavedStacks::LocationValue, Wrapper>
: public WrappedPtrOperations<SavedStacks::LocationValue, Wrapper> {
void setSource(JSAtom* v) { loc().source = v; }
void setSourceId(uint32_t v) { loc().sourceId = v; }
void setLine(size_t v) { loc().line = v; }
void setColumn(uint32_t v) { loc().column = v; }

View File

@ -2820,6 +2820,10 @@ JSObject* JSStructuredCloneReader::readSavedFrame(uint32_t principalsTag) {
}
savedFrame->initColumn(column);
// Don't specify a source ID when reading a cloned saved frame, as these IDs
// are only valid within a specific process.
savedFrame->initSourceId(0);
RootedValue name(context());
if (!startRead(&name) || !(name.isString() || name.isNull())) {
return nullptr;