mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Add interface for accessing PC counter information from chrome code, bug 687134. r=sfink,waldo
This commit is contained in:
parent
ed70a01420
commit
3983e0f31e
@ -60,6 +60,7 @@
|
||||
#include "nsGUIEvent.h"
|
||||
#include "nsIParser.h"
|
||||
#include "nsJSEnvironment.h"
|
||||
#include "nsJSUtils.h"
|
||||
|
||||
#include "nsIViewManager.h"
|
||||
|
||||
@ -1972,3 +1973,105 @@ nsDOMWindowUtils::GetFileReferences(const nsAString& aDatabaseName,
|
||||
*aResult = false;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
static inline JSContext *
|
||||
GetJSContext()
|
||||
{
|
||||
nsCOMPtr<nsIXPConnect> xpc = nsContentUtils::XPConnect();
|
||||
|
||||
// get the xpconnect native call context
|
||||
nsAXPCNativeCallContext *cc = nsnull;
|
||||
xpc->GetCurrentNativeCallContext(&cc);
|
||||
if(!cc)
|
||||
return NULL;
|
||||
|
||||
// Get JSContext of current call
|
||||
JSContext* cx;
|
||||
nsresult rv = cc->GetJSContext(&cx);
|
||||
if(NS_FAILED(rv) || !cx)
|
||||
return NULL;
|
||||
|
||||
return cx;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDOMWindowUtils::StartPCCountProfiling()
|
||||
{
|
||||
JSContext *cx = GetJSContext();
|
||||
if (!cx)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
js::StartPCCountProfiling(cx);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDOMWindowUtils::StopPCCountProfiling()
|
||||
{
|
||||
JSContext *cx = GetJSContext();
|
||||
if (!cx)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
js::StopPCCountProfiling(cx);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDOMWindowUtils::PurgePCCounts()
|
||||
{
|
||||
JSContext *cx = GetJSContext();
|
||||
if (!cx)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
js::PurgePCCounts(cx);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDOMWindowUtils::GetPCCountScriptCount(PRInt32 *result)
|
||||
{
|
||||
JSContext *cx = GetJSContext();
|
||||
if (!cx)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
*result = js::GetPCCountScriptCount(cx);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDOMWindowUtils::GetPCCountScriptSummary(PRInt32 script, nsAString& result)
|
||||
{
|
||||
JSContext *cx = GetJSContext();
|
||||
if (!cx)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
JSString *text = js::GetPCCountScriptSummary(cx, script);
|
||||
if (!text)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
nsDependentJSString str;
|
||||
if (!str.init(cx, text))
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
result = str;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDOMWindowUtils::GetPCCountScriptContents(PRInt32 script, nsAString& result)
|
||||
{
|
||||
JSContext *cx = GetJSContext();
|
||||
if (!cx)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
JSString *text = js::GetPCCountScriptContents(cx, script);
|
||||
if (!text)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
nsDependentJSString str;
|
||||
if (!str.init(cx, text))
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
result = str;
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -69,7 +69,7 @@ interface nsIDOMBlob;
|
||||
interface nsIDOMFile;
|
||||
interface nsIFile;
|
||||
|
||||
[scriptable, uuid(36adf309-e5c4-4912-9152-7fb151dc754a)]
|
||||
[scriptable, uuid(3af3c5ce-6f2a-47e7-acd0-555ed576fa82)]
|
||||
interface nsIDOMWindowUtils : nsISupports {
|
||||
|
||||
/**
|
||||
@ -941,4 +941,38 @@ interface nsIDOMWindowUtils : nsISupports {
|
||||
[optional] out long aDBRefCnt,
|
||||
[optional] out long aSliceRefCnt);
|
||||
|
||||
/**
|
||||
* Begin opcode-level profiling of all JavaScript execution in the window's
|
||||
* runtime.
|
||||
*/
|
||||
void startPCCountProfiling();
|
||||
|
||||
/**
|
||||
* Stop opcode-level profiling of JavaScript execution in the runtime, and
|
||||
* collect all counts for use by getPCCount methods.
|
||||
*/
|
||||
void stopPCCountProfiling();
|
||||
|
||||
/**
|
||||
* Purge collected PC counters.
|
||||
*/
|
||||
void purgePCCounts();
|
||||
|
||||
/**
|
||||
* Get the number of scripts with opcode-level profiling information.
|
||||
*/
|
||||
long getPCCountScriptCount();
|
||||
|
||||
/**
|
||||
* Get a JSON string for a short summary of a script and the PC counts
|
||||
* accumulated for it.
|
||||
*/
|
||||
AString getPCCountScriptSummary(in long script);
|
||||
|
||||
/**
|
||||
* Get a JSON string with full information about a profiled script,
|
||||
* including the decompilation of the script and placement of decompiled
|
||||
* operations within it, and PC counts for each operation.
|
||||
*/
|
||||
AString getPCCountScriptContents(in long script);
|
||||
};
|
||||
|
@ -681,11 +681,13 @@ JSRuntime::JSRuntime()
|
||||
gcBlackRootsData(NULL),
|
||||
gcGrayRootsTraceOp(NULL),
|
||||
gcGrayRootsData(NULL),
|
||||
scriptPCCounters(NULL),
|
||||
NaNValue(UndefinedValue()),
|
||||
negativeInfinityValue(UndefinedValue()),
|
||||
positiveInfinityValue(UndefinedValue()),
|
||||
emptyString(NULL),
|
||||
debugMode(false),
|
||||
profilingScripts(false),
|
||||
hadOutOfMemory(false),
|
||||
data(NULL),
|
||||
#ifdef JS_THREADSAFE
|
||||
|
@ -89,6 +89,9 @@ class JaegerCompartment;
|
||||
class WeakMapBase;
|
||||
class InterpreterFrames;
|
||||
|
||||
class ScriptOpcodeCounts;
|
||||
struct ScriptOpcodeCountsPair;
|
||||
|
||||
/*
|
||||
* GetSrcNote cache to avoid O(n^2) growth in finding a source note for a
|
||||
* given pc in a script. We use the script->code pointer to tag the cache,
|
||||
@ -342,7 +345,8 @@ typedef void
|
||||
|
||||
namespace js {
|
||||
|
||||
typedef js::Vector<JSCompartment *, 0, js::SystemAllocPolicy> CompartmentVector;
|
||||
typedef Vector<JSCompartment *, 0, SystemAllocPolicy> CompartmentVector;
|
||||
typedef Vector<ScriptOpcodeCountsPair, 0, SystemAllocPolicy> ScriptOpcodeCountsVector;
|
||||
|
||||
}
|
||||
|
||||
@ -529,6 +533,9 @@ struct JSRuntime
|
||||
JSTraceDataOp gcGrayRootsTraceOp;
|
||||
void *gcGrayRootsData;
|
||||
|
||||
/* Strong references on scripts held for PCCount profiling API. */
|
||||
js::ScriptOpcodeCountsVector *scriptPCCounters;
|
||||
|
||||
/* Well-known numbers held for use by this runtime's contexts. */
|
||||
js::Value NaNValue;
|
||||
js::Value negativeInfinityValue;
|
||||
@ -545,6 +552,9 @@ struct JSRuntime
|
||||
/* If true, new compartments are initially in debug mode. */
|
||||
bool debugMode;
|
||||
|
||||
/* If true, new scripts must be created with PC counter information. */
|
||||
bool profilingScripts;
|
||||
|
||||
/* Had an out-of-memory error which did not populate an exception. */
|
||||
JSBool hadOutOfMemory;
|
||||
|
||||
|
@ -1672,32 +1672,28 @@ DumpBytecodeScriptCallback(JSContext *cx, void *data, void *thing,
|
||||
JSGCTraceKind traceKind, size_t thingSize)
|
||||
{
|
||||
JS_ASSERT(traceKind == JSTRACE_SCRIPT);
|
||||
JS_ASSERT(!data);
|
||||
JSScript *script = static_cast<JSScript *>(thing);
|
||||
JS_DumpBytecode(cx, script);
|
||||
reinterpret_cast<Vector<JSScript *> *>(data)->append(script);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(void)
|
||||
JS_DumpCompartmentBytecode(JSContext *cx)
|
||||
{
|
||||
IterateCells(cx, cx->compartment, gc::FINALIZE_SCRIPT, NULL, DumpBytecodeScriptCallback);
|
||||
}
|
||||
Vector<JSScript *> scripts(cx);
|
||||
IterateCells(cx, cx->compartment, gc::FINALIZE_SCRIPT, &scripts, DumpBytecodeScriptCallback);
|
||||
|
||||
static void
|
||||
DumpPCCountsScriptCallback(JSContext *cx, void *data, void *thing,
|
||||
JSGCTraceKind traceKind, size_t thingSize)
|
||||
{
|
||||
JS_ASSERT(traceKind == JSTRACE_SCRIPT);
|
||||
JS_ASSERT(!data);
|
||||
JSScript *script = static_cast<JSScript *>(thing);
|
||||
if (script->pcCounters)
|
||||
JS_DumpPCCounts(cx, script);
|
||||
for (size_t i = 0; i < scripts.length(); i++)
|
||||
JS_DumpBytecode(cx, scripts[i]);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(void)
|
||||
JS_DumpCompartmentPCCounts(JSContext *cx)
|
||||
{
|
||||
IterateCells(cx, cx->compartment, gc::FINALIZE_SCRIPT, NULL, DumpPCCountsScriptCallback);
|
||||
for (CellIter i(cx, cx->compartment, gc::FINALIZE_SCRIPT); !i.done(); i.next()) {
|
||||
JSScript *script = i.get<JSScript>();
|
||||
if (script->pcCounters)
|
||||
JS_DumpPCCounts(cx, script);
|
||||
}
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(JSObject *)
|
||||
|
@ -442,6 +442,24 @@ SetPreserveWrapperCallback(JSRuntime *rt, PreserveWrapperCallback callback);
|
||||
#define JSITER_OWNONLY 0x8 /* iterate over obj's own properties only */
|
||||
#define JSITER_HIDDEN 0x10 /* also enumerate non-enumerable properties */
|
||||
|
||||
JS_FRIEND_API(void)
|
||||
StartPCCountProfiling(JSContext *cx);
|
||||
|
||||
JS_FRIEND_API(void)
|
||||
StopPCCountProfiling(JSContext *cx);
|
||||
|
||||
JS_FRIEND_API(void)
|
||||
PurgePCCounts(JSContext *cx);
|
||||
|
||||
JS_FRIEND_API(size_t)
|
||||
GetPCCountScriptCount(JSContext *cx);
|
||||
|
||||
JS_FRIEND_API(JSString *)
|
||||
GetPCCountScriptSummary(JSContext *cx, size_t script);
|
||||
|
||||
JS_FRIEND_API(JSString *)
|
||||
GetPCCountScriptContents(JSContext *cx, size_t script);
|
||||
|
||||
} /* namespace js */
|
||||
#endif
|
||||
|
||||
|
131
js/src/jsgc.cpp
131
js/src/jsgc.cpp
@ -92,6 +92,7 @@
|
||||
#include "vm/Debugger.h"
|
||||
#include "vm/String.h"
|
||||
|
||||
#include "jsinterpinlines.h"
|
||||
#include "jsobjinlines.h"
|
||||
|
||||
#include "vm/CallObject-inl.h"
|
||||
@ -2051,6 +2052,12 @@ MarkRuntime(JSTracer *trc)
|
||||
for (GCLocks::Range r = rt->gcLocksHash.all(); !r.empty(); r.popFront())
|
||||
gc_lock_traversal(r.front(), trc);
|
||||
|
||||
if (rt->scriptPCCounters) {
|
||||
const ScriptOpcodeCountsVector &vec = *rt->scriptPCCounters;
|
||||
for (size_t i = 0; i < vec.length(); i++)
|
||||
MarkRoot(trc, vec[i].script, "scriptPCCounters");
|
||||
}
|
||||
|
||||
js_TraceAtomState(trc);
|
||||
rt->staticStrings.trace(trc);
|
||||
|
||||
@ -2061,6 +2068,15 @@ MarkRuntime(JSTracer *trc)
|
||||
for (GCCompartmentsIter c(rt); !c.done(); c.next()) {
|
||||
if (c->activeAnalysis)
|
||||
c->markTypes(trc);
|
||||
|
||||
/* Do not discard scripts with counters while profiling. */
|
||||
if (rt->profilingScripts) {
|
||||
for (CellIterUnderGC i(c, FINALIZE_SCRIPT); !i.done(); i.next()) {
|
||||
JSScript *script = i.get<JSScript>();
|
||||
if (script->pcCounters)
|
||||
MarkRoot(trc, script, "profilingScripts");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (ThreadDataIter i(rt); !i.empty(); i.popFront())
|
||||
@ -3559,6 +3575,121 @@ VerifyBarriers(JSContext *cx, bool always)
|
||||
|
||||
} /* namespace gc */
|
||||
|
||||
static void ReleaseAllJITCode(JSContext *cx)
|
||||
{
|
||||
#ifdef JS_METHODJIT
|
||||
for (GCCompartmentsIter c(cx->runtime); !c.done(); c.next()) {
|
||||
mjit::ClearAllFrames(c);
|
||||
for (CellIter i(cx, c, FINALIZE_SCRIPT); !i.done(); i.next()) {
|
||||
JSScript *script = i.get<JSScript>();
|
||||
mjit::ReleaseScriptCode(cx, script);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* There are three possible PCCount profiling states:
|
||||
*
|
||||
* 1. None: Neither scripts nor the runtime have counter information.
|
||||
* 2. Profile: Active scripts have counter information, the runtime does not.
|
||||
* 3. Query: Scripts do not have counter information, the runtime does.
|
||||
*
|
||||
* When starting to profile scripts, counting begins immediately, with all JIT
|
||||
* code discarded and recompiled with counters as necessary. Active interpreter
|
||||
* frames will not begin profiling until they begin executing another script
|
||||
* (via a call or return).
|
||||
*
|
||||
* The below API functions manage transitions to new states, according
|
||||
* to the table below.
|
||||
*
|
||||
* Old State
|
||||
* -------------------------
|
||||
* Function None Profile Query
|
||||
* --------
|
||||
* StartPCCountProfiling Profile Profile Profile
|
||||
* StopPCCountProfiling None Query Query
|
||||
* PurgePCCounts None None None
|
||||
*/
|
||||
|
||||
static void
|
||||
ReleaseScriptPCCounters(JSContext *cx)
|
||||
{
|
||||
JSRuntime *rt = cx->runtime;
|
||||
JS_ASSERT(rt->scriptPCCounters);
|
||||
|
||||
ScriptOpcodeCountsVector &vec = *rt->scriptPCCounters;
|
||||
|
||||
for (size_t i = 0; i < vec.length(); i++)
|
||||
vec[i].counters.destroy(cx);
|
||||
|
||||
cx->delete_(rt->scriptPCCounters);
|
||||
rt->scriptPCCounters = NULL;
|
||||
}
|
||||
|
||||
JS_FRIEND_API(void)
|
||||
StartPCCountProfiling(JSContext *cx)
|
||||
{
|
||||
JSRuntime *rt = cx->runtime;
|
||||
AutoLockGC lock(rt);
|
||||
|
||||
if (rt->profilingScripts)
|
||||
return;
|
||||
|
||||
if (rt->scriptPCCounters)
|
||||
ReleaseScriptPCCounters(cx);
|
||||
|
||||
ReleaseAllJITCode(cx);
|
||||
|
||||
rt->profilingScripts = true;
|
||||
}
|
||||
|
||||
JS_FRIEND_API(void)
|
||||
StopPCCountProfiling(JSContext *cx)
|
||||
{
|
||||
JSRuntime *rt = cx->runtime;
|
||||
AutoLockGC lock(rt);
|
||||
|
||||
if (!rt->profilingScripts)
|
||||
return;
|
||||
JS_ASSERT(!rt->scriptPCCounters);
|
||||
|
||||
ReleaseAllJITCode(cx);
|
||||
|
||||
ScriptOpcodeCountsVector *vec = cx->new_<ScriptOpcodeCountsVector>(SystemAllocPolicy());
|
||||
if (!vec)
|
||||
return;
|
||||
|
||||
for (GCCompartmentsIter c(rt); !c.done(); c.next()) {
|
||||
for (CellIter i(cx, c, FINALIZE_SCRIPT); !i.done(); i.next()) {
|
||||
JSScript *script = i.get<JSScript>();
|
||||
if (script->pcCounters && script->types) {
|
||||
ScriptOpcodeCountsPair info;
|
||||
info.script = script;
|
||||
info.counters.steal(script->pcCounters);
|
||||
if (!vec->append(info))
|
||||
info.counters.destroy(cx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
rt->profilingScripts = false;
|
||||
rt->scriptPCCounters = vec;
|
||||
}
|
||||
|
||||
JS_FRIEND_API(void)
|
||||
PurgePCCounts(JSContext *cx)
|
||||
{
|
||||
JSRuntime *rt = cx->runtime;
|
||||
AutoLockGC lock(rt);
|
||||
|
||||
if (!rt->scriptPCCounters)
|
||||
return;
|
||||
JS_ASSERT(!rt->profilingScripts);
|
||||
|
||||
ReleaseScriptPCCounters(cx);
|
||||
}
|
||||
|
||||
} /* namespace js */
|
||||
|
||||
#if JS_HAS_XML_SUPPORT
|
||||
|
@ -1757,6 +1757,9 @@ js::Interpret(JSContext *cx, StackFrame *entryFrame, InterpMode interpMode)
|
||||
Value *argv = regs.fp()->maybeFormalArgs();
|
||||
CHECK_INTERRUPT_HANDLER();
|
||||
|
||||
if (rt->profilingScripts)
|
||||
ENABLE_INTERRUPTS();
|
||||
|
||||
if (!entryFrame)
|
||||
entryFrame = regs.fp();
|
||||
|
||||
@ -1869,6 +1872,12 @@ js::Interpret(JSContext *cx, StackFrame *entryFrame, InterpMode interpMode)
|
||||
{
|
||||
bool moreInterrupts = false;
|
||||
|
||||
if (cx->runtime->profilingScripts) {
|
||||
if (!script->pcCounters)
|
||||
script->initCounts(cx);
|
||||
moreInterrupts = true;
|
||||
}
|
||||
|
||||
if (script->pcCounters) {
|
||||
OpcodeCounts counts = script->getCounts(regs.pc);
|
||||
counts.get(OpcodeCounts::BASE_INTERP)++;
|
||||
|
1058
js/src/jsopcode.cpp
1058
js/src/jsopcode.cpp
File diff suppressed because it is too large
Load Diff
@ -677,6 +677,11 @@ class OpcodeCounts
|
||||
JS_ASSERT(which < capacity);
|
||||
return counts[which];
|
||||
}
|
||||
|
||||
// Boolean conversion, for 'if (counters) ...'
|
||||
operator void*() const {
|
||||
return counts;
|
||||
}
|
||||
};
|
||||
|
||||
} /* namespace js */
|
||||
|
@ -38,6 +38,8 @@
|
||||
|
||||
#include "jsautooplen.h"
|
||||
|
||||
#include "frontend/BytecodeEmitter.h"
|
||||
|
||||
namespace js {
|
||||
|
||||
class BytecodeRange {
|
||||
@ -69,4 +71,80 @@ AdvanceOverBlockchainOp(jsbytecode *pc)
|
||||
return pc;
|
||||
}
|
||||
|
||||
class SrcNoteLineScanner
|
||||
{
|
||||
/* offset of the current JSOp in the bytecode */
|
||||
ptrdiff_t offset;
|
||||
|
||||
/* next src note to process */
|
||||
jssrcnote *sn;
|
||||
|
||||
/* line number of the current JSOp */
|
||||
uint32_t lineno;
|
||||
|
||||
/*
|
||||
* Is the current op the first one after a line change directive? Note that
|
||||
* multiple ops may be "first" if a line directive is used to return to a
|
||||
* previous line (eg, with a for loop increment expression.)
|
||||
*/
|
||||
bool lineHeader;
|
||||
|
||||
public:
|
||||
SrcNoteLineScanner(jssrcnote *sn, uint32_t lineno)
|
||||
: offset(0), sn(sn), lineno(lineno)
|
||||
{
|
||||
}
|
||||
|
||||
/*
|
||||
* This is called repeatedly with always-advancing relpc values. The src
|
||||
* notes are tuples of <PC offset from prev src note, type, args>. Scan
|
||||
* through, updating the lineno, until the next src note is for a later
|
||||
* bytecode.
|
||||
*
|
||||
* When looking at the desired PC offset ('relpc'), the op is first in that
|
||||
* line iff there is a SRC_SETLINE or SRC_NEWLINE src note for that exact
|
||||
* bytecode.
|
||||
*
|
||||
* Note that a single bytecode may have multiple line-modifying notes (even
|
||||
* though only one should ever be needed.)
|
||||
*/
|
||||
void advanceTo(ptrdiff_t relpc) {
|
||||
// Must always advance! If the same or an earlier PC is erroneously
|
||||
// passed in, we will already be past the relevant src notes
|
||||
JS_ASSERT_IF(offset > 0, relpc > offset);
|
||||
|
||||
// Next src note should be for after the current offset
|
||||
JS_ASSERT_IF(offset > 0, SN_IS_TERMINATOR(sn) || SN_DELTA(sn) > 0);
|
||||
|
||||
// The first PC requested is always considered to be a line header
|
||||
lineHeader = (offset == 0);
|
||||
|
||||
if (SN_IS_TERMINATOR(sn))
|
||||
return;
|
||||
|
||||
ptrdiff_t nextOffset;
|
||||
while ((nextOffset = offset + SN_DELTA(sn)) <= relpc && !SN_IS_TERMINATOR(sn)) {
|
||||
offset = nextOffset;
|
||||
SrcNoteType type = (SrcNoteType) SN_TYPE(sn);
|
||||
if (type == SRC_SETLINE || type == SRC_NEWLINE) {
|
||||
if (type == SRC_SETLINE)
|
||||
lineno = js_GetSrcNoteOffset(sn, 0);
|
||||
else
|
||||
lineno++;
|
||||
|
||||
if (offset == relpc)
|
||||
lineHeader = true;
|
||||
}
|
||||
|
||||
sn = SN_NEXT(sn);
|
||||
}
|
||||
}
|
||||
|
||||
bool isLineHeader() const {
|
||||
return lineHeader;
|
||||
}
|
||||
|
||||
uint32_t getLine() const { return lineno; }
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -776,6 +776,11 @@ JSScript::initCounts(JSContext *cx)
|
||||
|
||||
JS_ASSERT(size_t(cursor - base) == bytes);
|
||||
|
||||
/* Enable interrupts in any interpreter frames running on this script. */
|
||||
InterpreterFrames *frames;
|
||||
for (frames = JS_THREAD_DATA(cx)->interpreterFrames; frames; frames = frames->older)
|
||||
frames->enableInterruptsIfRunning(this);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -342,6 +342,7 @@ namespace analyze { class ScriptAnalysis; }
|
||||
class ScriptOpcodeCounts
|
||||
{
|
||||
friend struct ::JSScript;
|
||||
friend struct ScriptOpcodeCountsPair;
|
||||
OpcodeCounts *counts;
|
||||
|
||||
public:
|
||||
@ -349,8 +350,11 @@ class ScriptOpcodeCounts
|
||||
ScriptOpcodeCounts() : counts(NULL) {
|
||||
}
|
||||
|
||||
~ScriptOpcodeCounts() {
|
||||
JS_ASSERT(!counts);
|
||||
inline void destroy(JSContext *cx);
|
||||
|
||||
void steal(ScriptOpcodeCounts &other) {
|
||||
*this = other;
|
||||
js::PodZero(&other);
|
||||
}
|
||||
|
||||
// Boolean conversion, for 'if (counters) ...'
|
||||
@ -849,6 +853,17 @@ js_CallDestroyScriptHook(JSContext *cx, JSScript *script);
|
||||
|
||||
namespace js {
|
||||
|
||||
struct ScriptOpcodeCountsPair
|
||||
{
|
||||
JSScript *script;
|
||||
ScriptOpcodeCounts counters;
|
||||
|
||||
OpcodeCounts &getCounts(jsbytecode *pc) const {
|
||||
JS_ASSERT(unsigned(pc - script->code) < script->length);
|
||||
return counters.counts[pc - script->code];
|
||||
}
|
||||
};
|
||||
|
||||
#ifdef JS_CRASH_DIAGNOSTICS
|
||||
|
||||
void
|
||||
|
@ -132,6 +132,13 @@ CurrentScriptFileLineOrigin(JSContext *cx, const char **file, uintN *linenop, JS
|
||||
CurrentScriptFileLineOriginSlow(cx, file, linenop, origin);
|
||||
}
|
||||
|
||||
inline void
|
||||
ScriptOpcodeCounts::destroy(JSContext *cx)
|
||||
{
|
||||
if (counts)
|
||||
cx->free_(counts);
|
||||
}
|
||||
|
||||
} // namespace js
|
||||
|
||||
inline void
|
||||
|
@ -406,6 +406,9 @@ mjit::Compiler::scanInlineCalls(uint32_t index, uint32_t depth)
|
||||
CompileStatus
|
||||
mjit::Compiler::pushActiveFrame(JSScript *script, uint32_t argc)
|
||||
{
|
||||
if (cx->runtime->profilingScripts && !script->pcCounters)
|
||||
script->initCounts(cx);
|
||||
|
||||
ActiveFrame *newa = cx->new_<ActiveFrame>(cx);
|
||||
if (!newa)
|
||||
return Compile_Error;
|
||||
@ -1396,81 +1399,6 @@ mjit::Compiler::finishThisUp(JITScript **jitp)
|
||||
return Compile_Okay;
|
||||
}
|
||||
|
||||
class SrcNoteLineScanner {
|
||||
/* offset of the current JSOp in the bytecode */
|
||||
ptrdiff_t offset;
|
||||
|
||||
/* next src note to process */
|
||||
jssrcnote *sn;
|
||||
|
||||
/* line number of the current JSOp */
|
||||
uint32_t lineno;
|
||||
|
||||
/*
|
||||
* Is the current op the first one after a line change directive? Note that
|
||||
* multiple ops may be "first" if a line directive is used to return to a
|
||||
* previous line (eg, with a for loop increment expression.)
|
||||
*/
|
||||
bool lineHeader;
|
||||
|
||||
public:
|
||||
SrcNoteLineScanner(jssrcnote *sn, uint32_t lineno)
|
||||
: offset(0), sn(sn), lineno(lineno)
|
||||
{
|
||||
}
|
||||
|
||||
/*
|
||||
* This is called repeatedly with always-advancing relpc values. The src
|
||||
* notes are tuples of <PC offset from prev src note, type, args>. Scan
|
||||
* through, updating the lineno, until the next src note is for a later
|
||||
* bytecode.
|
||||
*
|
||||
* When looking at the desired PC offset ('relpc'), the op is first in that
|
||||
* line iff there is a SRC_SETLINE or SRC_NEWLINE src note for that exact
|
||||
* bytecode.
|
||||
*
|
||||
* Note that a single bytecode may have multiple line-modifying notes (even
|
||||
* though only one should ever be needed.)
|
||||
*/
|
||||
void advanceTo(ptrdiff_t relpc) {
|
||||
// Must always advance! If the same or an earlier PC is erroneously
|
||||
// passed in, we will already be past the relevant src notes
|
||||
JS_ASSERT_IF(offset > 0, relpc > offset);
|
||||
|
||||
// Next src note should be for after the current offset
|
||||
JS_ASSERT_IF(offset > 0, SN_IS_TERMINATOR(sn) || SN_DELTA(sn) > 0);
|
||||
|
||||
// The first PC requested is always considered to be a line header
|
||||
lineHeader = (offset == 0);
|
||||
|
||||
if (SN_IS_TERMINATOR(sn))
|
||||
return;
|
||||
|
||||
ptrdiff_t nextOffset;
|
||||
while ((nextOffset = offset + SN_DELTA(sn)) <= relpc && !SN_IS_TERMINATOR(sn)) {
|
||||
offset = nextOffset;
|
||||
SrcNoteType type = (SrcNoteType) SN_TYPE(sn);
|
||||
if (type == SRC_SETLINE || type == SRC_NEWLINE) {
|
||||
if (type == SRC_SETLINE)
|
||||
lineno = js_GetSrcNoteOffset(sn, 0);
|
||||
else
|
||||
lineno++;
|
||||
|
||||
if (offset == relpc)
|
||||
lineHeader = true;
|
||||
}
|
||||
|
||||
sn = SN_NEXT(sn);
|
||||
}
|
||||
}
|
||||
|
||||
bool isLineHeader() const {
|
||||
return lineHeader;
|
||||
}
|
||||
|
||||
uint32_t getLine() const { return lineno; }
|
||||
};
|
||||
|
||||
#ifdef DEBUG
|
||||
#define SPEW_OPCODE() \
|
||||
JS_BEGIN_MACRO \
|
||||
|
Loading…
Reference in New Issue
Block a user