mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 1050500: Add SpiderMonkey API for reporting JavaScript entry points. r=shu
This commit is contained in:
parent
47669df31d
commit
f89382e8da
@ -318,6 +318,48 @@ onPromiseSettled(JSContext* cx, HandleObject promise);
|
||||
JS_PUBLIC_API(bool)
|
||||
IsDebugger(JS::Value val);
|
||||
|
||||
|
||||
// Hooks for reporting where JavaScript execution began.
|
||||
//
|
||||
// Our performance tools would like to be able to label blocks of JavaScript
|
||||
// execution with the function name and source location where execution began:
|
||||
// the event handler, the callback, etc.
|
||||
//
|
||||
// Construct an instance of this class on the stack, providing a JSContext
|
||||
// belonging to the runtime in which execution will occur. Each time we enter
|
||||
// JavaScript --- specifically, each time we push a JavaScript stack frame that
|
||||
// has no older JS frames younger than this AutoEntryMonitor --- we will
|
||||
// call the appropriate |Entry| member function to indicate where we've begun
|
||||
// execution.
|
||||
|
||||
class MOZ_STACK_CLASS AutoEntryMonitor {
|
||||
JSRuntime* runtime_;
|
||||
AutoEntryMonitor* savedMonitor_;
|
||||
|
||||
public:
|
||||
explicit AutoEntryMonitor(JSContext* cx);
|
||||
~AutoEntryMonitor();
|
||||
|
||||
// SpiderMonkey reports the JavaScript entry points occuring within this
|
||||
// AutoEntryMonitor's scope to the following member functions, which the
|
||||
// embedding is expected to override.
|
||||
|
||||
// We have begun executing |function|. Note that |function| may not be the
|
||||
// actual closure we are running, but only the canonical function object to
|
||||
// which the script refers.
|
||||
virtual void Entry(JSContext* cx, JSFunction* function) = 0;
|
||||
|
||||
// Execution has begun at the entry point of |script|, which is not a
|
||||
// function body. (This is probably being executed by 'eval' or some
|
||||
// JSAPI equivalent.)
|
||||
virtual void Entry(JSContext* cx, JSScript* script) = 0;
|
||||
|
||||
// Execution of the function or script has ended.
|
||||
virtual void Exit(JSContext* cx) { }
|
||||
};
|
||||
|
||||
|
||||
|
||||
} // namespace dbg
|
||||
} // namespace JS
|
||||
|
||||
|
@ -744,8 +744,12 @@ CallAsmJS(JSContext* cx, unsigned argc, Value* vp)
|
||||
// that the optimized asm.js-to-Ion FFI call path (which we want to be
|
||||
// very fast) can avoid doing so. The JitActivation is marked as
|
||||
// inactive so stack iteration will skip over it.
|
||||
//
|
||||
// We needn't provide an entry script pointer; that's only used for
|
||||
// reporting entry points to performance-monitoring tools, and asm.js ->
|
||||
// Ion calls will never be entry points.
|
||||
AsmJSActivation activation(cx, module);
|
||||
JitActivation jitActivation(cx, /* active */ false);
|
||||
JitActivation jitActivation(cx, /* entryScript */ nullptr, /* active */ false);
|
||||
|
||||
// Call the per-exported-function trampoline created by GenerateEntry.
|
||||
AsmJSModule::CodePtr enter = module.entryTrampoline(func);
|
||||
|
50
js/src/jit-test/tests/profiler/AutoEntryMonitor-01.js
Normal file
50
js/src/jit-test/tests/profiler/AutoEntryMonitor-01.js
Normal file
@ -0,0 +1,50 @@
|
||||
// AutoEntryMonitor should catch all entry points into JavaScript.
|
||||
|
||||
load(libdir + 'array-compare.js');
|
||||
|
||||
function cold_and_warm(f, params, expected) {
|
||||
print(uneval(params));
|
||||
print(uneval(entryPoints(params)));
|
||||
assertEq(arraysEqual(entryPoints(params), expected), true);
|
||||
|
||||
// Warm up the function a bit, so the JITs will compile it, and try again.
|
||||
if (f)
|
||||
for (i = 0; i < 10; i++)
|
||||
f();
|
||||
|
||||
assertEq(arraysEqual(entryPoints(params), expected), true);
|
||||
}
|
||||
|
||||
function entry1() { }
|
||||
cold_and_warm(entry1, { function: entry1 }, [ "entry1" ]);
|
||||
|
||||
var getx = { get x() { } };
|
||||
cold_and_warm(Object.getOwnPropertyDescriptor(getx, 'x').get,
|
||||
{ object: getx, property: 'x' }, [ "getx.x" ]);
|
||||
|
||||
var sety = { set y(v) { } };
|
||||
cold_and_warm(Object.getOwnPropertyDescriptor(sety, 'y').set,
|
||||
{ object: sety, property: 'y', value: 'glerk' }, [ "sety.y" ]);
|
||||
|
||||
cold_and_warm(Object.prototype.toString, { ToString: {} }, []);
|
||||
|
||||
var toS = { toString: function myToString() { return "string"; } };
|
||||
cold_and_warm(toS.toString, { ToString: toS }, [ "myToString" ]);
|
||||
|
||||
cold_and_warm(undefined, { ToNumber: {} }, []);
|
||||
|
||||
var vOf = { valueOf: function myValueOf() { return 42; } };
|
||||
cold_and_warm(vOf.valueOf, { ToNumber: vOf }, [ "myValueOf" ]);
|
||||
|
||||
var toSvOf = { toString: function relations() { return Object; },
|
||||
valueOf: function wallpaper() { return 17; } };
|
||||
cold_and_warm(() => { toSvOf.toString(); toSvOf.valueOf(); },
|
||||
{ ToString: toSvOf }, [ "relations", "wallpaper" ]);
|
||||
|
||||
var vOftoS = { toString: function ettes() { return "6-inch lengths"; },
|
||||
valueOf: function deathBy() { return Math; } };
|
||||
cold_and_warm(() => { vOftoS.valueOf(); vOftoS.toString(); },
|
||||
{ ToNumber: vOftoS }, [ "deathBy", "ettes" ]);
|
||||
|
||||
|
||||
cold_and_warm(() => 0, { eval: "Math.atan2(1,1);" }, [ "eval:entryPoint eval" ]);
|
12
js/src/jit-test/tests/profiler/AutoEntryMonitor-02.js
Normal file
12
js/src/jit-test/tests/profiler/AutoEntryMonitor-02.js
Normal file
@ -0,0 +1,12 @@
|
||||
// Nested uses of AutoEntryMonitor should behave with decorum.
|
||||
|
||||
load(libdir + 'array-compare.js');
|
||||
|
||||
function Cobb() {
|
||||
var twoShot = { toString: function Saito() { return Object; },
|
||||
valueOf: function Fischer() { return "Ariadne"; } };
|
||||
assertEq(arraysEqual(entryPoints({ ToString: twoShot }),
|
||||
[ "Saito", "Fischer" ]), true);
|
||||
}
|
||||
|
||||
assertEq(arraysEqual(entryPoints({ function: Cobb }), ["Cobb"]), true);
|
@ -115,7 +115,7 @@ EnterBaseline(JSContext* cx, EnterJitData& data)
|
||||
data.result.setInt32(data.numActualArgs);
|
||||
{
|
||||
AssertCompartmentUnchanged pcc(cx);
|
||||
JitActivation activation(cx);
|
||||
JitActivation activation(cx, data.calleeToken);
|
||||
|
||||
if (data.osrFrame)
|
||||
data.osrFrame->setRunningInJit();
|
||||
|
@ -2384,7 +2384,7 @@ EnterIon(JSContext* cx, EnterJitData& data)
|
||||
data.result.setInt32(data.numActualArgs);
|
||||
{
|
||||
AssertCompartmentUnchanged pcc(cx);
|
||||
JitActivation activation(cx);
|
||||
JitActivation activation(cx, data.calleeToken);
|
||||
|
||||
CALL_GENERATED_CODE(enter, data.jitcode, data.maxArgc, data.maxArgv, /* osrFrame = */nullptr, data.calleeToken,
|
||||
/* scopeChain = */ nullptr, 0, data.result.address());
|
||||
@ -2481,14 +2481,15 @@ jit::FastInvoke(JSContext* cx, HandleFunction fun, CallArgs& args)
|
||||
{
|
||||
JS_CHECK_RECURSION(cx, return JitExec_Error);
|
||||
|
||||
IonScript* ion = fun->nonLazyScript()->ionScript();
|
||||
RootedScript script(cx, fun->nonLazyScript());
|
||||
IonScript* ion = script->ionScript();
|
||||
JitCode* code = ion->method();
|
||||
void* jitcode = code->raw();
|
||||
|
||||
MOZ_ASSERT(jit::IsIonEnabled(cx));
|
||||
MOZ_ASSERT(!ion->bailoutExpected());
|
||||
|
||||
JitActivation activation(cx);
|
||||
JitActivation activation(cx, CalleeToToken(script));
|
||||
|
||||
EnterJitCode enter = cx->runtime()->jitRuntime()->enterIon();
|
||||
void* calleeToken = CalleeToToken(fun, /* constructing = */ false);
|
||||
|
@ -23,6 +23,8 @@ namespace js {
|
||||
namespace js {
|
||||
namespace jit {
|
||||
|
||||
typedef void * CalleeToken;
|
||||
|
||||
enum FrameType
|
||||
{
|
||||
// A JS frame is analagous to a js::InterpreterFrame, representing one scripted
|
||||
|
@ -18,8 +18,6 @@
|
||||
namespace js {
|
||||
namespace jit {
|
||||
|
||||
typedef void * CalleeToken;
|
||||
|
||||
enum CalleeTokenTag
|
||||
{
|
||||
CalleeToken_Function = 0x0, // untagged
|
||||
|
@ -4512,6 +4512,205 @@ ReflectTrackedOptimizations(JSContext* cx, unsigned argc, Value* vp)
|
||||
return true;
|
||||
}
|
||||
|
||||
namespace shell {
|
||||
|
||||
class ShellAutoEntryMonitor : JS::dbg::AutoEntryMonitor {
|
||||
Vector<UniqueChars, 1, js::SystemAllocPolicy> log;
|
||||
bool oom;
|
||||
bool enteredWithoutExit;
|
||||
|
||||
public:
|
||||
explicit ShellAutoEntryMonitor(JSContext *cx)
|
||||
: AutoEntryMonitor(cx),
|
||||
oom(false),
|
||||
enteredWithoutExit(false)
|
||||
{ }
|
||||
|
||||
~ShellAutoEntryMonitor() {
|
||||
MOZ_ASSERT(!enteredWithoutExit);
|
||||
}
|
||||
|
||||
void Entry(JSContext* cx, JSFunction* function) override {
|
||||
MOZ_ASSERT(!enteredWithoutExit);
|
||||
enteredWithoutExit = true;
|
||||
|
||||
RootedString displayId(cx, JS_GetFunctionDisplayId(function));
|
||||
if (displayId) {
|
||||
UniqueChars displayIdStr(JS_EncodeStringToUTF8(cx, displayId));
|
||||
oom = !displayIdStr || !log.append(mozilla::Move(displayIdStr));
|
||||
return;
|
||||
}
|
||||
|
||||
oom = !log.append(make_string_copy("anonymous"));
|
||||
}
|
||||
|
||||
void Entry(JSContext* cx, JSScript* script) override {
|
||||
MOZ_ASSERT(!enteredWithoutExit);
|
||||
enteredWithoutExit = true;
|
||||
|
||||
UniqueChars label(JS_smprintf("eval:%s", JS_GetScriptFilename(script)));
|
||||
oom = !label || !log.append(mozilla::Move(label));
|
||||
}
|
||||
|
||||
void Exit(JSContext* cx) {
|
||||
MOZ_ASSERT(enteredWithoutExit);
|
||||
enteredWithoutExit = false;
|
||||
}
|
||||
|
||||
bool buildResult(JSContext *cx, MutableHandleValue resultValue) {
|
||||
if (oom) {
|
||||
JS_ReportOutOfMemory(cx);
|
||||
return false;
|
||||
}
|
||||
|
||||
RootedObject result(cx, JS_NewArrayObject(cx, log.length()));
|
||||
if (!result)
|
||||
return false;
|
||||
|
||||
for (size_t i = 0; i < log.length(); i++) {
|
||||
char *name = log[i].get();
|
||||
RootedString string(cx, Atomize(cx, name, strlen(name)));
|
||||
if (!string)
|
||||
return false;
|
||||
RootedValue value(cx, StringValue(string));
|
||||
if (!JS_SetElement(cx, result, i, value))
|
||||
return false;
|
||||
}
|
||||
|
||||
resultValue.setObject(*result.get());
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace shell
|
||||
|
||||
static bool
|
||||
EntryPoints(JSContext* cx, unsigned argc, Value* vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
|
||||
if (args.length() != 1) {
|
||||
JS_ReportError(cx, "Wrong number of arguments");
|
||||
return false;
|
||||
}
|
||||
|
||||
RootedObject opts(cx, ToObject(cx, args[0]));
|
||||
if (!opts)
|
||||
return false;
|
||||
|
||||
// { function: f } --- Call f.
|
||||
{
|
||||
RootedValue fun(cx), dummy(cx);
|
||||
|
||||
if (!JS_GetProperty(cx, opts, "function", &fun))
|
||||
return false;
|
||||
if (!fun.isUndefined()) {
|
||||
shell::ShellAutoEntryMonitor sarep(cx);
|
||||
if (!Call(cx, UndefinedHandleValue, fun, JS::HandleValueArray::empty(), &dummy))
|
||||
return false;
|
||||
return sarep.buildResult(cx, args.rval());
|
||||
}
|
||||
}
|
||||
|
||||
// { object: o, property: p, value: v } --- Fetch o[p], or if
|
||||
// v is present, assign o[p] = v.
|
||||
{
|
||||
RootedValue objectv(cx), propv(cx), valuev(cx);
|
||||
|
||||
if (!JS_GetProperty(cx, opts, "object", &objectv) ||
|
||||
!JS_GetProperty(cx, opts, "property", &propv))
|
||||
return false;
|
||||
if (!objectv.isUndefined() && !propv.isUndefined()) {
|
||||
RootedObject object(cx, ToObject(cx, objectv));
|
||||
if (!object)
|
||||
return false;
|
||||
|
||||
RootedString string(cx, ToString(cx, propv));
|
||||
if (!string)
|
||||
return false;
|
||||
RootedId id(cx);
|
||||
if (!JS_StringToId(cx, string, &id))
|
||||
return false;
|
||||
|
||||
if (!JS_GetProperty(cx, opts, "value", &valuev))
|
||||
return false;
|
||||
|
||||
shell::ShellAutoEntryMonitor sarep(cx);
|
||||
|
||||
if (!valuev.isUndefined()) {
|
||||
if (!JS_SetPropertyById(cx, object, id, valuev))
|
||||
return false;
|
||||
} else {
|
||||
if (!JS_GetPropertyById(cx, object, id, &valuev))
|
||||
return false;
|
||||
}
|
||||
|
||||
return sarep.buildResult(cx, args.rval());
|
||||
}
|
||||
}
|
||||
|
||||
// { ToString: v } --- Apply JS::ToString to v.
|
||||
{
|
||||
RootedValue v(cx);
|
||||
|
||||
if (!JS_GetProperty(cx, opts, "ToString", &v))
|
||||
return false;
|
||||
if (!v.isUndefined()) {
|
||||
shell::ShellAutoEntryMonitor sarep(cx);
|
||||
if (!JS::ToString(cx, v))
|
||||
return false;
|
||||
return sarep.buildResult(cx, args.rval());
|
||||
}
|
||||
}
|
||||
|
||||
// { ToNumber: v } --- Apply JS::ToNumber to v.
|
||||
{
|
||||
RootedValue v(cx);
|
||||
double dummy;
|
||||
|
||||
if (!JS_GetProperty(cx, opts, "ToNumber", &v))
|
||||
return false;
|
||||
if (!v.isUndefined()) {
|
||||
shell::ShellAutoEntryMonitor sarep(cx);
|
||||
if (!JS::ToNumber(cx, v, &dummy))
|
||||
return false;
|
||||
return sarep.buildResult(cx, args.rval());
|
||||
}
|
||||
}
|
||||
|
||||
// { eval: code } --- Apply ToString and then Evaluate to code.
|
||||
{
|
||||
RootedValue code(cx), dummy(cx);
|
||||
|
||||
if (!JS_GetProperty(cx, opts, "eval", &code))
|
||||
return false;
|
||||
if (!code.isUndefined()) {
|
||||
RootedString codeString(cx, ToString(cx, code));
|
||||
if (!codeString || !codeString->ensureFlat(cx))
|
||||
return false;
|
||||
|
||||
AutoStableStringChars stableChars(cx);
|
||||
if (!stableChars.initTwoByte(cx, codeString))
|
||||
return false;
|
||||
const char16_t* chars = stableChars.twoByteRange().start().get();
|
||||
size_t length = codeString->length();
|
||||
|
||||
CompileOptions options(cx);
|
||||
options.setIntroductionType("entryPoint eval")
|
||||
.setFileAndLine("entryPoint eval", 1);
|
||||
|
||||
shell::ShellAutoEntryMonitor sarep(cx);
|
||||
if (!JS::Evaluate(cx, options, chars, length, &dummy))
|
||||
return false;
|
||||
return sarep.buildResult(cx, args.rval());
|
||||
}
|
||||
}
|
||||
|
||||
JS_ReportError(cx, "bad 'params' object");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
static const JSFunctionSpecWithHelp shell_functions[] = {
|
||||
JS_FN_HELP("version", Version, 0, 0,
|
||||
"version([number])",
|
||||
@ -4867,6 +5066,30 @@ static const JSFunctionSpecWithHelp shell_functions[] = {
|
||||
" Return an int32 value which corresponds to the offset of the latest stack\n"
|
||||
" pointer, such that one can take the differences of 2 to estimate a frame-size."),
|
||||
|
||||
JS_FN_HELP("entryPoints", EntryPoints, 1, 0,
|
||||
"entryPoints(params)",
|
||||
"Carry out some JSAPI operation as directed by |params|, and return an array of\n"
|
||||
"objects describing which JavaScript entry points were invoked as a result.\n"
|
||||
"|params| is an object whose properties indicate what operation to perform. Here\n"
|
||||
"are the recognized groups of properties:\n"
|
||||
"\n"
|
||||
"{ function }: Call the object |params.function| with no arguments.\n"
|
||||
"\n"
|
||||
"{ object, property }: Fetch the property named |params.property| of\n"
|
||||
"|params.object|.\n"
|
||||
"\n"
|
||||
"{ ToString }: Apply JS::ToString to |params.toString|.\n"
|
||||
"\n"
|
||||
"{ ToNumber }: Apply JS::ToNumber to |params.toNumber|.\n"
|
||||
"\n"
|
||||
"{ eval }: Apply JS::Evaluate to |params.eval|.\n"
|
||||
"\n"
|
||||
"The return value is an array of strings, with one element for each\n"
|
||||
"JavaScript invocation that occurred as a result of the given\n"
|
||||
"operation. Each element is the name of the function invoked, or the\n"
|
||||
"string 'eval:FILENAME' if the code was invoked by 'eval' or something\n"
|
||||
"similar.\n"),
|
||||
|
||||
JS_FS_HELP_END
|
||||
};
|
||||
|
||||
|
@ -39,6 +39,7 @@
|
||||
|
||||
using namespace js;
|
||||
|
||||
using JS::dbg::AutoEntryMonitor;
|
||||
using JS::dbg::Builder;
|
||||
using js::frontend::IsIdentifier;
|
||||
using mozilla::ArrayLength;
|
||||
@ -7801,6 +7802,21 @@ Builder::newObject(JSContext* cx)
|
||||
return Object(cx, *this, obj);
|
||||
}
|
||||
|
||||
|
||||
/*** JS::dbg::AutoEntryMonitor ******************************************************************/
|
||||
|
||||
AutoEntryMonitor::AutoEntryMonitor(JSContext* cx)
|
||||
: runtime_(cx->runtime()),
|
||||
savedMonitor_(cx->runtime()->entryMonitor)
|
||||
{
|
||||
runtime_->entryMonitor = this;
|
||||
}
|
||||
|
||||
AutoEntryMonitor::~AutoEntryMonitor()
|
||||
{
|
||||
runtime_->entryMonitor = savedMonitor_;
|
||||
}
|
||||
|
||||
|
||||
/*** Glue ****************************************************************************************/
|
||||
|
||||
|
@ -191,7 +191,7 @@ DebuggerMemory::drainAllocationsLog(JSContext* cx, unsigned argc, Value* vp)
|
||||
return false;
|
||||
|
||||
// Don't pop the AllocationSite yet. The queue's links are followed by
|
||||
// the GC to find the AllocationSite, but are not barried, so we must
|
||||
// the GC to find the AllocationSite, but are not barriered, so we must
|
||||
// edit them with great care. Use the queue entry in place, and then
|
||||
// pop and delete together.
|
||||
Debugger::AllocationSite* allocSite = dbg->allocationsLog.getFirst();
|
||||
|
@ -126,6 +126,7 @@ JSRuntime::JSRuntime(JSRuntime* parentRuntime)
|
||||
asmJSActivationStack_(nullptr),
|
||||
asyncStackForNewActivations(nullptr),
|
||||
asyncCauseForNewActivations(nullptr),
|
||||
entryMonitor(nullptr),
|
||||
parentRuntime(parentRuntime),
|
||||
interrupt_(false),
|
||||
telemetryCallback(nullptr),
|
||||
|
@ -680,6 +680,9 @@ struct JSRuntime : public JS::shadow::Runtime,
|
||||
*/
|
||||
JSString* asyncCauseForNewActivations;
|
||||
|
||||
/* If non-null, report JavaScript entry points to this monitor. */
|
||||
JS::dbg::AutoEntryMonitor* entryMonitor;
|
||||
|
||||
js::Activation* const* addressOfActivation() const {
|
||||
return &activation_;
|
||||
}
|
||||
|
@ -16,6 +16,7 @@
|
||||
|
||||
#include "jit/BaselineFrame.h"
|
||||
#include "jit/RematerializedFrame.h"
|
||||
#include "js/Debug.h"
|
||||
#include "vm/GeneratorObject.h"
|
||||
#include "vm/ScopeObject.h"
|
||||
|
||||
@ -846,10 +847,12 @@ Activation::Activation(JSContext* cx, Kind kind)
|
||||
hideScriptedCallerCount_(0),
|
||||
asyncStack_(cx, cx->runtime_->asyncStackForNewActivations),
|
||||
asyncCause_(cx, cx->runtime_->asyncCauseForNewActivations),
|
||||
entryMonitor_(cx->runtime_->entryMonitor),
|
||||
kind_(kind)
|
||||
{
|
||||
cx->runtime_->asyncStackForNewActivations = nullptr;
|
||||
cx->runtime_->asyncCauseForNewActivations = nullptr;
|
||||
cx->runtime_->entryMonitor = nullptr;
|
||||
cx->runtime_->activation_ = this;
|
||||
}
|
||||
|
||||
@ -859,6 +862,7 @@ Activation::~Activation()
|
||||
MOZ_ASSERT(cx_->runtime_->activation_ == this);
|
||||
MOZ_ASSERT(hideScriptedCallerCount_ == 0);
|
||||
cx_->runtime_->activation_ = prev_;
|
||||
cx_->runtime_->entryMonitor = entryMonitor_;
|
||||
cx_->runtime_->asyncCauseForNewActivations = asyncCause_;
|
||||
cx_->runtime_->asyncStackForNewActivations = asyncStack_;
|
||||
}
|
||||
@ -896,6 +900,13 @@ InterpreterActivation::InterpreterActivation(RunState& state, JSContext* cx,
|
||||
regs_.prepareToRun(*entryFrame, state.script());
|
||||
MOZ_ASSERT(regs_.pc == state.script()->code());
|
||||
MOZ_ASSERT_IF(entryFrame_->isEvalFrame(), state.script()->isActiveEval());
|
||||
|
||||
if (entryMonitor_) {
|
||||
if (entryFrame->isFunctionFrame())
|
||||
entryMonitor_->Entry(cx_, entryFrame->fun());
|
||||
else
|
||||
entryMonitor_->Entry(cx_, entryFrame->script());
|
||||
}
|
||||
}
|
||||
|
||||
InterpreterActivation::~InterpreterActivation()
|
||||
@ -908,6 +919,9 @@ InterpreterActivation::~InterpreterActivation()
|
||||
MOZ_ASSERT(oldFrameCount_ == cx->runtime()->interpreterStack().frameCount_);
|
||||
MOZ_ASSERT_IF(oldFrameCount_ == 0, cx->runtime()->interpreterStack().allocator_.used() == 0);
|
||||
|
||||
if (entryMonitor_)
|
||||
entryMonitor_->Exit(cx_);
|
||||
|
||||
if (entryFrame_)
|
||||
cx->runtime()->interpreterStack().releaseFrame(entryFrame_);
|
||||
}
|
||||
|
@ -1388,7 +1388,7 @@ AbstractFramePtr::hasPushedSPSFrame() const
|
||||
return false;
|
||||
}
|
||||
|
||||
jit::JitActivation::JitActivation(JSContext* cx, bool active)
|
||||
jit::JitActivation::JitActivation(JSContext* cx, CalleeToken entryPoint, bool active)
|
||||
: Activation(cx, Jit),
|
||||
active_(active),
|
||||
isLazyLinkExitFrame_(false),
|
||||
@ -1411,10 +1411,22 @@ jit::JitActivation::JitActivation(JSContext* cx, bool active)
|
||||
prevJitJSContext_ = nullptr;
|
||||
prevJitActivation_ = nullptr;
|
||||
}
|
||||
|
||||
if (entryMonitor_) {
|
||||
MOZ_ASSERT(entryPoint);
|
||||
|
||||
if (CalleeTokenIsFunction(entryPoint))
|
||||
entryMonitor_->Entry(cx_, CalleeTokenToFunction(entryPoint));
|
||||
else
|
||||
entryMonitor_->Entry(cx_, CalleeTokenToScript(entryPoint));
|
||||
}
|
||||
}
|
||||
|
||||
jit::JitActivation::~JitActivation()
|
||||
{
|
||||
if (entryMonitor_)
|
||||
entryMonitor_->Exit(cx_);
|
||||
|
||||
if (active_) {
|
||||
if (isProfiling())
|
||||
unregisterProfiling();
|
||||
|
@ -21,6 +21,12 @@
|
||||
|
||||
struct JSCompartment;
|
||||
|
||||
namespace JS {
|
||||
namespace dbg {
|
||||
class AutoEntryMonitor;
|
||||
}
|
||||
}
|
||||
|
||||
namespace js {
|
||||
|
||||
class ArgumentsObject;
|
||||
@ -1091,6 +1097,11 @@ class Activation
|
||||
// Value of asyncCause to be attached to asyncStack_.
|
||||
RootedString asyncCause_;
|
||||
|
||||
// The entry point monitor that was set on cx_->runtime() when this
|
||||
// Activation was created. Subclasses should report their entry frame's
|
||||
// function or script here.
|
||||
JS::dbg::AutoEntryMonitor* entryMonitor_;
|
||||
|
||||
enum Kind { Interpreter, Jit, AsmJS };
|
||||
Kind kind_;
|
||||
|
||||
@ -1340,7 +1351,11 @@ class JitActivation : public Activation
|
||||
#endif
|
||||
|
||||
public:
|
||||
explicit JitActivation(JSContext* cx, bool active = true);
|
||||
// If non-null, |entryScript| should be the script we're about to begin
|
||||
// executing, for the benefit of performance tooling. We can pass null for
|
||||
// entryScript when we know we couldn't possibly be entering JS directly
|
||||
// from the JSAPI: OSR, asm.js -> Ion transitions, and so on.
|
||||
explicit JitActivation(JSContext* cx, CalleeToken entryPoint, bool active = true);
|
||||
~JitActivation();
|
||||
|
||||
bool isActive() const {
|
||||
|
Loading…
Reference in New Issue
Block a user