Bug 1301377 - Disallow GC while using ProfilingFrameIterator r=jandem

This commit is contained in:
Jon Coppeard 2016-10-14 17:13:47 +01:00
parent 7b7d057eda
commit c50fa1fd48
4 changed files with 71 additions and 24 deletions

View File

@ -11,6 +11,7 @@
#include "mozilla/Maybe.h"
#include "jsbytecode.h"
#include "js/GCAPI.h"
#include "js/TypeDecls.h"
#include "js/Utility.h"
@ -39,6 +40,10 @@ struct ForEachTrackedOptimizationTypeInfoOp;
// arbitrary pc. To provide acurate results, profiling must have been enabled
// (via EnableRuntimeProfilingStack) before executing the callstack being
// unwound.
//
// Note that the caller must not do anything that could cause GC to happen while
// the iterator is alive, since this could invalidate Ion code and cause its
// contents to become out of date.
class JS_PUBLIC_API(ProfilingFrameIterator)
{
JSRuntime* rt_;
@ -50,6 +55,8 @@ class JS_PUBLIC_API(ProfilingFrameIterator)
// activation (if any) comes around.
void* savedPrevJitTop_;
JS::AutoCheckCannotGC nogc_;
static const unsigned StorageSpace = 8 * sizeof(void*);
mozilla::AlignedStorage<StorageSpace> storage_;
js::wasm::ProfilingFrameIterator& asmJSIter() {

View File

@ -1639,34 +1639,30 @@ ReadSPSProfilingStack(JSContext* cx, unsigned argc, Value* vp)
return true;
}
RootedObject inlineStack(cx);
RootedObject inlineFrameInfo(cx);
RootedString frameKind(cx);
RootedString frameLabel(cx);
RootedId idx(cx);
struct InlineFrameInfo
{
InlineFrameInfo(const char* kind, UniqueChars&& label)
: kind(kind), label(mozilla::Move(label)) {}
const char* kind;
UniqueChars label;
};
Vector<Vector<InlineFrameInfo, 0, TempAllocPolicy>, 0, TempAllocPolicy> frameInfo(cx);
JS::ProfilingFrameIterator::RegisterState state;
uint32_t physicalFrameNo = 0;
const unsigned propAttrs = JSPROP_ENUMERATE;
for (JS::ProfilingFrameIterator i(cx, state); !i.done(); ++i, ++physicalFrameNo) {
for (JS::ProfilingFrameIterator i(cx, state); !i.done(); ++i) {
MOZ_ASSERT(i.stackAddress() != nullptr);
// Array holding all inline frames in a single physical jit stack frame.
inlineStack = NewDenseEmptyArray(cx);
if (!inlineStack)
if (!frameInfo.emplaceBack(cx))
return false;
JS::ProfilingFrameIterator::Frame frames[16];
uint32_t nframes = i.extractStack(frames, 0, 16);
for (uint32_t inlineFrameNo = 0; inlineFrameNo < nframes; inlineFrameNo++) {
// Object holding frame info.
inlineFrameInfo = NewBuiltinClassInstance<PlainObject>(cx);
if (!inlineFrameInfo)
return false;
const size_t MaxInlineFrames = 16;
JS::ProfilingFrameIterator::Frame frames[MaxInlineFrames];
uint32_t nframes = i.extractStack(frames, 0, MaxInlineFrames);
MOZ_ASSERT(nframes <= MaxInlineFrames);
for (uint32_t i = 0; i < nframes; i++) {
const char* frameKindStr = nullptr;
switch (frames[inlineFrameNo].kind) {
switch (frames[i].kind) {
case JS::ProfilingFrameIterator::Frame_Baseline:
frameKindStr = "baseline";
break;
@ -1679,14 +1675,41 @@ ReadSPSProfilingStack(JSContext* cx, unsigned argc, Value* vp)
default:
frameKindStr = "unknown";
}
frameKind = NewStringCopyZ<CanGC>(cx, frameKindStr);
if (!frameInfo.back().emplaceBack(frameKindStr, mozilla::Move(frames[i].label)))
return false;
}
}
RootedObject inlineFrameInfo(cx);
RootedString frameKind(cx);
RootedString frameLabel(cx);
RootedId idx(cx);
const unsigned propAttrs = JSPROP_ENUMERATE;
uint32_t physicalFrameNo = 0;
for (auto& frame : frameInfo) {
// Array holding all inline frames in a single physical jit stack frame.
RootedObject inlineStack(cx, NewDenseEmptyArray(cx));
if (!inlineStack)
return false;
uint32_t inlineFrameNo = 0;
for (auto& inlineFrame : frame) {
// Object holding frame info.
RootedObject inlineFrameInfo(cx, NewBuiltinClassInstance<PlainObject>(cx));
if (!inlineFrameInfo)
return false;
frameKind = NewStringCopyZ<CanGC>(cx, inlineFrame.kind);
if (!frameKind)
return false;
if (!JS_DefineProperty(cx, inlineFrameInfo, "kind", frameKind, propAttrs))
return false;
auto chars = frames[inlineFrameNo].label.release();
auto chars = inlineFrame.label.release();
frameLabel = NewString<CanGC>(cx, reinterpret_cast<Latin1Char*>(chars), strlen(chars));
if (!frameLabel)
return false;
@ -1697,12 +1720,16 @@ ReadSPSProfilingStack(JSContext* cx, unsigned argc, Value* vp)
idx = INT_TO_JSID(inlineFrameNo);
if (!JS_DefinePropertyById(cx, inlineStack, idx, inlineFrameInfo, 0))
return false;
++inlineFrameNo;
}
// Push inline array into main array.
idx = INT_TO_JSID(physicalFrameNo);
if (!JS_DefinePropertyById(cx, stack, idx, inlineStack, 0))
return false;
++physicalFrameNo;
}
args.rval().setObject(*stack);

View File

@ -0,0 +1,12 @@
var lfLogBuffer = `
gczeal(14);
enableSPSProfiling();
gczeal(15,3);
var s = "";
for (let i = 0; i != 30; i+=2) {}
readSPSProfilingStack(s, "c0d1c0d1c0d1c0d1c0d1c0d1c0d1c0");
`;
loadFile(lfLogBuffer);
function loadFile(lfVarx) {
evaluate(lfVarx);
}

View File

@ -1723,7 +1723,8 @@ JS::ProfilingFrameIterator::ProfilingFrameIterator(JSContext* cx, const Register
: rt_(cx),
sampleBufferGen_(sampleBufferGen),
activation_(nullptr),
savedPrevJitTop_(nullptr)
savedPrevJitTop_(nullptr),
nogc_(cx)
{
if (!cx->spsProfiler.enabled())
MOZ_CRASH("ProfilingFrameIterator called when spsProfiler not enabled for runtime.");