зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1190454 part 3 - PCCounts: Collect throw/catch hit counts. r=bhackett
This commit is contained in:
Родитель
c4218bbf0b
Коммит
f37f92b962
|
@ -808,7 +808,7 @@ BaselineCompiler::emitDebugTrap()
|
|||
void
|
||||
BaselineCompiler::emitCoverage(jsbytecode* pc)
|
||||
{
|
||||
PCCounts* counts = script->getPCCounts(pc);
|
||||
PCCounts* counts = script->maybeGetPCCounts(pc);
|
||||
if (!counts)
|
||||
return;
|
||||
|
||||
|
|
|
@ -693,6 +693,17 @@ HandleExceptionBaseline(JSContext* cx, const JitFrameIterator& frame, ResumeFrom
|
|||
{
|
||||
MOZ_ASSERT(frame.isBaselineJS());
|
||||
|
||||
bool frameOk = false;
|
||||
RootedScript script(cx, frame.baselineFrame()->script());
|
||||
|
||||
if (script->hasScriptCounts()) {
|
||||
PCCounts* counts = script->getThrowCounts(pc);
|
||||
// If we failed to allocate, then skip the increment and continue to
|
||||
// handle the exception.
|
||||
if (counts)
|
||||
counts->numExec()++;
|
||||
}
|
||||
|
||||
// We may be propagating a forced return from the interrupt
|
||||
// callback, which cannot easily force a return.
|
||||
if (cx->isPropagatingForcedReturn()) {
|
||||
|
@ -701,10 +712,7 @@ HandleExceptionBaseline(JSContext* cx, const JitFrameIterator& frame, ResumeFrom
|
|||
return;
|
||||
}
|
||||
|
||||
bool frameOk = false;
|
||||
RootedScript script(cx, frame.baselineFrame()->script());
|
||||
|
||||
again:
|
||||
again:
|
||||
if (cx->isExceptionPending()) {
|
||||
if (!cx->isClosingGenerator()) {
|
||||
switch (Debugger::onExceptionUnwind(cx, frame.baselineFrame())) {
|
||||
|
@ -733,8 +741,12 @@ again:
|
|||
ScopeIter si(cx, frame.baselineFrame(), pc);
|
||||
if (!ProcessTryNotesBaseline(cx, frame, si, rfe, &pc))
|
||||
goto again;
|
||||
if (rfe->kind != ResumeFromException::RESUME_ENTRY_FRAME)
|
||||
if (rfe->kind != ResumeFromException::RESUME_ENTRY_FRAME) {
|
||||
// No need to increment the PCCounts number of execution here,
|
||||
// as the interpreter increments any PCCounts if present.
|
||||
MOZ_ASSERT_IF(script->hasScriptCounts(), script->maybeGetPCCounts(pc));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
frameOk = HandleClosingGeneratorReturn(cx, frame.baselineFrame(), frameOk);
|
||||
|
|
|
@ -170,7 +170,7 @@ js::DumpPCCounts(JSContext* cx, HandleScript script, Sprinter* sp)
|
|||
return;
|
||||
|
||||
Sprint(sp, " {");
|
||||
PCCounts* counts = script->getPCCounts(pc);
|
||||
PCCounts* counts = script->maybeGetPCCounts(pc);
|
||||
double val = counts ? counts->numExec() : 0.0;
|
||||
if (val)
|
||||
Sprint(sp, "\"%s\": %.0f", PCCounts::numExecName, val);
|
||||
|
@ -1746,7 +1746,7 @@ js::GetPCCountScriptSummary(JSContext* cx, size_t index)
|
|||
|
||||
jsbytecode* codeEnd = script->codeEnd();
|
||||
for (jsbytecode* pc = script->code(); pc < codeEnd; pc = GetNextPc(pc)) {
|
||||
const PCCounts* counts = sac.getPCCounts(pc);
|
||||
const PCCounts* counts = sac.maybeGetPCCounts(pc);
|
||||
if (!counts)
|
||||
continue;
|
||||
total += counts->numExec();
|
||||
|
@ -1846,7 +1846,7 @@ GetPCCountJSON(JSContext* cx, const ScriptAndCounts& sac, StringBuffer& buf)
|
|||
buf.append(str);
|
||||
}
|
||||
|
||||
const PCCounts* counts = sac.getPCCounts(pc);
|
||||
const PCCounts* counts = sac.maybeGetPCCounts(pc);
|
||||
|
||||
AppendJSONProperty(buf, "counts");
|
||||
buf.append('{');
|
||||
|
|
|
@ -1297,6 +1297,22 @@ JSScript::initScriptCounts(JSContext* cx)
|
|||
}
|
||||
}
|
||||
|
||||
// Mark catch/finally blocks as being jump targets.
|
||||
if (hasTrynotes()) {
|
||||
JSTryNote* tn = trynotes()->vector;
|
||||
JSTryNote* tnlimit = tn + trynotes()->length;
|
||||
for (; tn < tnlimit; tn++) {
|
||||
jsbytecode* tryStart = mainEntry + tn->start;
|
||||
jsbytecode* tryPc = tryStart - 1;
|
||||
if (JSOp(*tryPc) != JSOP_TRY)
|
||||
continue;
|
||||
|
||||
jsbytecode* tryTarget = tryStart + tn->length;
|
||||
if (!jumpTargets.append(tryTarget))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Sort all pc, and remove duplicates.
|
||||
std::sort(jumpTargets.begin(), jumpTargets.end());
|
||||
auto last = std::unique(jumpTargets.begin(), jumpTargets.end());
|
||||
|
@ -1352,7 +1368,18 @@ static inline ScriptCountsMap::Ptr GetScriptCountsMapEntry(JSScript* script)
|
|||
}
|
||||
|
||||
js::PCCounts*
|
||||
ScriptCounts::getPCCounts(size_t offset) const {
|
||||
ScriptCounts::maybeGetPCCounts(size_t offset) {
|
||||
PCCounts searched = PCCounts(offset);
|
||||
PCCounts* begin = pcCountsVector;
|
||||
PCCounts* end = begin + pcCountsSize;
|
||||
PCCounts* elem = std::lower_bound(begin, end, searched);
|
||||
if (elem == end || elem->pcOffset() != offset)
|
||||
return nullptr;
|
||||
return elem;
|
||||
}
|
||||
|
||||
const js::PCCounts*
|
||||
ScriptCounts::maybeGetPCCounts(size_t offset) const {
|
||||
PCCounts searched = PCCounts(offset);
|
||||
PCCounts* begin = pcCountsVector;
|
||||
PCCounts* end = begin + pcCountsSize;
|
||||
|
@ -1363,10 +1390,45 @@ ScriptCounts::getPCCounts(size_t offset) const {
|
|||
}
|
||||
|
||||
js::PCCounts*
|
||||
JSScript::getPCCounts(jsbytecode* pc) {
|
||||
ScriptCounts::maybeGetThrowCounts(size_t offset) const {
|
||||
PCCounts searched = PCCounts(offset);
|
||||
PCCounts* begin = throwCountsVector;
|
||||
PCCounts* end = throwCountsVector + throwCountsSize;
|
||||
PCCounts* elem = std::lower_bound(begin, end, searched);
|
||||
if (elem == end || elem->pcOffset() != offset)
|
||||
return nullptr;
|
||||
return elem;
|
||||
}
|
||||
|
||||
js::PCCounts*
|
||||
ScriptCounts::getThrowCounts(size_t offset) {
|
||||
PCCounts searched = PCCounts(offset);
|
||||
PCCounts* begin = throwCountsVector;
|
||||
PCCounts* end = throwCountsVector + throwCountsSize;
|
||||
PCCounts* elem = std::lower_bound(begin, end, searched);
|
||||
if (elem == end || elem->pcOffset() != offset) {
|
||||
size_t index = elem - begin;
|
||||
|
||||
size_t numBytes = (1 + throwCountsSize) * sizeof(PCCounts);
|
||||
PCCounts* vec = (PCCounts*) js_realloc(throwCountsVector, numBytes);
|
||||
if (!vec)
|
||||
return nullptr;
|
||||
throwCountsVector = vec;
|
||||
throwCountsSize += 1;
|
||||
|
||||
elem = throwCountsVector + index;
|
||||
end = throwCountsVector + throwCountsSize;
|
||||
std::copy_backward(elem, end - 1, end);
|
||||
*elem = searched;
|
||||
}
|
||||
return elem;
|
||||
}
|
||||
|
||||
js::PCCounts*
|
||||
JSScript::maybeGetPCCounts(jsbytecode* pc) {
|
||||
MOZ_ASSERT(containsPC(pc));
|
||||
ScriptCountsMap::Ptr p = GetScriptCountsMapEntry(this);
|
||||
return p->value().getPCCounts(pcToOffset(pc));
|
||||
return p->value().maybeGetPCCounts(pcToOffset(pc));
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -1380,6 +1442,25 @@ JSScript::setIonScript(JSContext* maybecx, js::jit::IonScript* ionScript)
|
|||
updateBaselineOrIonRaw(maybecx);
|
||||
}
|
||||
|
||||
ScriptCounts&
|
||||
JSScript::getScriptCounts()
|
||||
{
|
||||
ScriptCountsMap::Ptr p = GetScriptCountsMapEntry(this);
|
||||
return p->value();
|
||||
}
|
||||
|
||||
js::PCCounts*
|
||||
JSScript::maybeGetThrowCounts(jsbytecode* pc) {
|
||||
MOZ_ASSERT(containsPC(pc));
|
||||
return getScriptCounts().maybeGetThrowCounts(pcToOffset(pc));
|
||||
}
|
||||
|
||||
js::PCCounts*
|
||||
JSScript::getThrowCounts(jsbytecode* pc) {
|
||||
MOZ_ASSERT(containsPC(pc));
|
||||
return getScriptCounts().getThrowCounts(pcToOffset(pc));
|
||||
}
|
||||
|
||||
void
|
||||
JSScript::addIonCounts(jit::IonScriptCounts* ionCounts)
|
||||
{
|
||||
|
|
|
@ -453,26 +453,50 @@ class ScriptCounts
|
|||
friend class ::JSScript;
|
||||
friend struct ScriptAndCounts;
|
||||
|
||||
/*
|
||||
* This points to a single block that holds an array of PCCounts followed
|
||||
* by an array of doubles. Each element in the PCCounts array has a
|
||||
* pointer into the array of doubles.
|
||||
*/
|
||||
// This sorted array is used to map an offset to the number of times a
|
||||
// branch got visited.
|
||||
PCCounts* pcCountsVector;
|
||||
size_t pcCountsSize;
|
||||
|
||||
/* Information about any Ion compilations for the script. */
|
||||
// This sorted vector is used to map an offset to the number of times an
|
||||
// instruction throw.
|
||||
PCCounts* throwCountsVector;
|
||||
size_t throwCountsSize;
|
||||
|
||||
// Information about any Ion compilations for the script.
|
||||
jit::IonScriptCounts* ionCounts;
|
||||
|
||||
public:
|
||||
ScriptCounts() : pcCountsVector(nullptr), ionCounts(nullptr) { }
|
||||
ScriptCounts()
|
||||
: pcCountsVector(nullptr),
|
||||
pcCountsSize(0),
|
||||
throwCountsVector(nullptr),
|
||||
throwCountsSize(0),
|
||||
ionCounts(nullptr)
|
||||
{ }
|
||||
|
||||
PCCounts* getPCCounts(size_t offset) const;
|
||||
// Return the counter used to count the number of visits. Returns null if
|
||||
// the element is not found.
|
||||
PCCounts* maybeGetPCCounts(size_t offset);
|
||||
const PCCounts* maybeGetPCCounts(size_t offset) const;
|
||||
|
||||
// Return the counter used to count the number of throws. Returns null if
|
||||
// the element is not found.
|
||||
PCCounts* maybeGetThrowCounts(size_t offset) const;
|
||||
|
||||
// Return the counter used to count the number of throws. Allocate it if
|
||||
// none exists yet. Returns null if the allocation failed.
|
||||
PCCounts* getThrowCounts(size_t offset);
|
||||
|
||||
inline void destroy(FreeOp* fop);
|
||||
|
||||
void set(js::ScriptCounts counts) {
|
||||
pcCountsVector = counts.pcCountsVector;
|
||||
pcCountsSize = counts.pcCountsSize;
|
||||
|
||||
throwCountsVector = counts.throwCountsVector;
|
||||
throwCountsSize = counts.throwCountsSize;
|
||||
|
||||
ionCounts = counts.ionCounts;
|
||||
}
|
||||
};
|
||||
|
@ -1612,9 +1636,12 @@ class JSScript : public js::gc::TenuredCell
|
|||
|
||||
public:
|
||||
bool initScriptCounts(JSContext* cx);
|
||||
js::PCCounts* getPCCounts(jsbytecode* pc);
|
||||
js::PCCounts* maybeGetPCCounts(jsbytecode* pc);
|
||||
js::PCCounts* maybeGetThrowCounts(jsbytecode* pc);
|
||||
js::PCCounts* getThrowCounts(jsbytecode* pc);
|
||||
void addIonCounts(js::jit::IonScriptCounts* ionCounts);
|
||||
js::jit::IonScriptCounts* getIonCounts();
|
||||
js::ScriptCounts& getScriptCounts();
|
||||
js::ScriptCounts releaseScriptCounts();
|
||||
void destroyScriptCounts(js::FreeOp* fop);
|
||||
|
||||
|
@ -2340,8 +2367,8 @@ struct ScriptAndCounts
|
|||
JSScript* script;
|
||||
ScriptCounts scriptCounts;
|
||||
|
||||
const PCCounts* getPCCounts(jsbytecode* pc) const {
|
||||
return scriptCounts.getPCCounts(script->pcToOffset(pc));
|
||||
const PCCounts* maybeGetPCCounts(jsbytecode* pc) const {
|
||||
return scriptCounts.maybeGetPCCounts(script->pcToOffset(pc));
|
||||
}
|
||||
|
||||
jit::IonScriptCounts* getIonCounts() const {
|
||||
|
|
|
@ -34,6 +34,7 @@ inline void
|
|||
ScriptCounts::destroy(FreeOp* fop)
|
||||
{
|
||||
fop->free_(pcCountsVector);
|
||||
fop->free_(throwCountsVector);
|
||||
fop->delete_(ionCounts);
|
||||
}
|
||||
|
||||
|
|
|
@ -1451,6 +1451,14 @@ HandleError(JSContext* cx, InterpreterRegs& regs)
|
|||
{
|
||||
MOZ_ASSERT(regs.fp()->script()->containsPC(regs.pc));
|
||||
|
||||
if (regs.fp()->script()->hasScriptCounts()) {
|
||||
PCCounts* counts = regs.fp()->script()->getThrowCounts(regs.pc);
|
||||
// If we failed to allocate, then skip the increment and continue to
|
||||
// handle the exception.
|
||||
if (counts)
|
||||
counts->numExec()++;
|
||||
}
|
||||
|
||||
ScopeIter si(cx, regs.fp(), regs.pc);
|
||||
bool ok = false;
|
||||
|
||||
|
@ -1478,15 +1486,19 @@ HandleError(JSContext* cx, InterpreterRegs& regs)
|
|||
}
|
||||
}
|
||||
|
||||
switch (ProcessTryNotes(cx, si, regs)) {
|
||||
HandleErrorContinuation res = ProcessTryNotes(cx, si, regs);
|
||||
switch (res) {
|
||||
case SuccessfulReturnContinuation:
|
||||
break;
|
||||
case ErrorReturnContinuation:
|
||||
goto again;
|
||||
case CatchContinuation:
|
||||
return CatchContinuation;
|
||||
case FinallyContinuation:
|
||||
return FinallyContinuation;
|
||||
// No need to increment the PCCounts number of execution here, as
|
||||
// the interpreter increments any PCCounts if present.
|
||||
MOZ_ASSERT_IF(regs.fp()->script()->hasScriptCounts(),
|
||||
regs.fp()->script()->maybeGetPCCounts(regs.pc));
|
||||
return res;
|
||||
}
|
||||
|
||||
ok = HandleClosingGeneratorReturn(cx, regs.fp(), ok);
|
||||
|
@ -1968,7 +1980,7 @@ CASE(EnableInterruptsPseudoOpcode)
|
|||
}
|
||||
|
||||
if (script->hasScriptCounts()) {
|
||||
PCCounts* counts = script->getPCCounts(REGS.pc);
|
||||
PCCounts* counts = script->maybeGetPCCounts(REGS.pc);
|
||||
if (counts)
|
||||
counts->numExec()++;
|
||||
moreInterrupts = true;
|
||||
|
|
Загрузка…
Ссылка в новой задаче