mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 757188 - Refactor FlowGraphSummary; r=jorendorff
This commit is contained in:
parent
354c267523
commit
24695b4e50
@ -2888,7 +2888,7 @@ DebuggerScript_getOffsetLine(JSContext *cx, unsigned argc, Value *vp)
|
||||
return true;
|
||||
}
|
||||
|
||||
class BytecodeRangeWithLineNumbers : private BytecodeRange
|
||||
class BytecodeRangeWithPosition : private BytecodeRange
|
||||
{
|
||||
public:
|
||||
using BytecodeRange::empty;
|
||||
@ -2896,12 +2896,13 @@ class BytecodeRangeWithLineNumbers : private BytecodeRange
|
||||
using BytecodeRange::frontOpcode;
|
||||
using BytecodeRange::frontOffset;
|
||||
|
||||
BytecodeRangeWithLineNumbers(JSContext *cx, JSScript *script)
|
||||
: BytecodeRange(cx, script), lineno(script->lineno), sn(script->notes()), snpc(script->code)
|
||||
BytecodeRangeWithPosition(JSContext *cx, JSScript *script)
|
||||
: BytecodeRange(cx, script), lineno(script->lineno), column(0),
|
||||
sn(script->notes()), snpc(script->code)
|
||||
{
|
||||
if (!SN_IS_TERMINATOR(sn))
|
||||
snpc += SN_DELTA(sn);
|
||||
updateLine();
|
||||
updatePosition();
|
||||
while (frontPC() != script->main())
|
||||
popFront();
|
||||
}
|
||||
@ -2909,23 +2910,34 @@ class BytecodeRangeWithLineNumbers : private BytecodeRange
|
||||
void popFront() {
|
||||
BytecodeRange::popFront();
|
||||
if (!empty())
|
||||
updateLine();
|
||||
updatePosition();
|
||||
}
|
||||
|
||||
size_t frontLineNumber() const { return lineno; }
|
||||
size_t frontColumnNumber() const { return column; }
|
||||
|
||||
private:
|
||||
void updateLine() {
|
||||
void updatePosition() {
|
||||
/*
|
||||
* Determine the current line number by reading all source notes up to
|
||||
* and including the current offset.
|
||||
*/
|
||||
while (!SN_IS_TERMINATOR(sn) && snpc <= frontPC()) {
|
||||
SrcNoteType type = (SrcNoteType) SN_TYPE(sn);
|
||||
if (type == SRC_SETLINE)
|
||||
if (type == SRC_COLSPAN) {
|
||||
ptrdiff_t colspan = js_GetSrcNoteOffset(sn, 0);
|
||||
|
||||
if (colspan >= SN_COLSPAN_DOMAIN / 2)
|
||||
colspan -= SN_COLSPAN_DOMAIN;
|
||||
JS_ASSERT(ptrdiff_t(column) + colspan >= 0);
|
||||
column += colspan;
|
||||
} if (type == SRC_SETLINE) {
|
||||
lineno = size_t(js_GetSrcNoteOffset(sn, 0));
|
||||
else if (type == SRC_NEWLINE)
|
||||
column = 0;
|
||||
} else if (type == SRC_NEWLINE) {
|
||||
lineno++;
|
||||
column = 0;
|
||||
}
|
||||
|
||||
sn = SN_NEXT(sn);
|
||||
snpc += SN_DELTA(sn);
|
||||
@ -2933,76 +2945,143 @@ class BytecodeRangeWithLineNumbers : private BytecodeRange
|
||||
}
|
||||
|
||||
size_t lineno;
|
||||
size_t column;
|
||||
jssrcnote *sn;
|
||||
jsbytecode *snpc;
|
||||
};
|
||||
|
||||
static const size_t NoEdges = -1;
|
||||
static const size_t MultipleEdges = -2;
|
||||
|
||||
/*
|
||||
* FlowGraphSummary::populate(cx, script) computes a summary of script's
|
||||
* control flow graph used by DebuggerScript_{getAllOffsets,getLineOffsets}.
|
||||
*
|
||||
* jumpData[offset] is:
|
||||
* - NoEdges if offset isn't the offset of an instruction, or if the
|
||||
* instruction is apparently unreachable;
|
||||
* - MultipleEdges if you can arrive at that instruction from
|
||||
* instructions on multiple different lines OR it's the first
|
||||
* instruction of the script;
|
||||
* - otherwise, the (unique) line number of all instructions that can
|
||||
* precede the instruction at offset.
|
||||
* An instruction on a given line is an entry point for that line if it can be
|
||||
* reached from (an instruction on) a different line. We distinguish between the
|
||||
* following cases:
|
||||
* - hasNoEdges:
|
||||
* The instruction cannot be reached, so the instruction is not an entry
|
||||
* point for the line it is on.
|
||||
* - hasSingleEdge:
|
||||
* - hasMultipleEdgesFromSingleLine:
|
||||
* The instruction can be reached from a single line. If this line is
|
||||
* different from the line the instruction is on, the instruction is an
|
||||
* entry point for that line.
|
||||
* - hasMultipleEdgesFromMultipleLines:
|
||||
* The instruction can be reached from multiple lines. At least one of
|
||||
* these lines is guaranteed to be different from the line the instruction
|
||||
* is on, so the instruction is an entry point for that line.
|
||||
*
|
||||
* The generated graph does not contain edges for JSOP_RETSUB, which appears at
|
||||
* the end of finally blocks. The algorithm that uses this information works
|
||||
* anyway, because in non-exception cases, JSOP_RETSUB always returns to a
|
||||
* !FlowsIntoNext instruction (JSOP_GOTO/GOTOX or JSOP_RETRVAL) which generates
|
||||
* an edge if needed.
|
||||
* Similarly, an instruction on a given position (line/column pair) is an
|
||||
* entry point for that position if it can be reached from (an instruction on) a
|
||||
* different position. Again, we distinguish between the following cases:
|
||||
* - hasNoEdges:
|
||||
* The instruction cannot be reached, so the instruction is not an entry
|
||||
* point for the position it is on.
|
||||
* - hasSingleEdge:
|
||||
* The instruction can be reached from a single position. If this line is
|
||||
* different from the position the instruction is on, the instruction is
|
||||
* an entry point for that position.
|
||||
* - hasMultipleEdgesFromSingleLine:
|
||||
* - hasMultipleEdgesFromMultipleLines:
|
||||
* The instruction can be reached from multiple positions. At least one
|
||||
* of these positions is guaranteed to be different from the position the
|
||||
* instruction is on, so the instruction is an entry point for that
|
||||
* position.
|
||||
*/
|
||||
class FlowGraphSummary : public Vector<size_t> {
|
||||
class FlowGraphSummary {
|
||||
public:
|
||||
typedef Vector<size_t> Base;
|
||||
FlowGraphSummary(JSContext *cx) : Base(cx) {}
|
||||
class Entry {
|
||||
public:
|
||||
static Entry createWithNoEdges() {
|
||||
return Entry(-1, 0);
|
||||
}
|
||||
|
||||
void addEdge(size_t sourceLine, size_t targetOffset) {
|
||||
FlowGraphSummary &self = *this;
|
||||
if (self[targetOffset] == NoEdges)
|
||||
self[targetOffset] = sourceLine;
|
||||
else if (self[targetOffset] != sourceLine)
|
||||
self[targetOffset] = MultipleEdges;
|
||||
}
|
||||
static Entry createWithSingleEdge(size_t lineno, size_t column) {
|
||||
return Entry(lineno, column);
|
||||
}
|
||||
|
||||
void addEdgeFromAnywhere(size_t targetOffset) {
|
||||
(*this)[targetOffset] = MultipleEdges;
|
||||
static Entry createWithMultipleEdgesFromSingleLine(size_t lineno) {
|
||||
return Entry(lineno, -1);
|
||||
}
|
||||
|
||||
static Entry createWithMultipleEdgesFromMultipleLines() {
|
||||
return Entry(-1, -1);
|
||||
}
|
||||
|
||||
Entry() {}
|
||||
|
||||
bool hasNoEdges() const {
|
||||
return lineno_ == -1 && column_ != -1;
|
||||
}
|
||||
|
||||
bool hasSingleEdge() const {
|
||||
return lineno_ != -1 && column_ != -1;
|
||||
}
|
||||
|
||||
bool hasMultipleEdgesFromSingleLine() const {
|
||||
return lineno_ != -1 && column_ == -1;
|
||||
}
|
||||
|
||||
bool hasMultipleEdgesFromMultipleLines() const {
|
||||
return lineno_ == -1 && column_ == -1;
|
||||
}
|
||||
|
||||
bool operator==(const Entry &other) const {
|
||||
return lineno_ == other.lineno_ && column_ == other.column_;
|
||||
}
|
||||
|
||||
bool operator!=(const Entry &other) const {
|
||||
return lineno_ != other.lineno_ || column_ != other.column_;
|
||||
}
|
||||
|
||||
size_t lineno() const {
|
||||
return lineno_;
|
||||
}
|
||||
|
||||
size_t column() const {
|
||||
return column_;
|
||||
}
|
||||
|
||||
private:
|
||||
Entry(size_t lineno, size_t column) : lineno_(lineno), column_(column) {}
|
||||
|
||||
size_t lineno_;
|
||||
size_t column_;
|
||||
};
|
||||
|
||||
FlowGraphSummary(JSContext *cx) : entries_(cx) {}
|
||||
|
||||
Entry &operator[](size_t index) {
|
||||
return entries_[index];
|
||||
}
|
||||
|
||||
bool populate(JSContext *cx, JSScript *script) {
|
||||
if (!growBy(script->length))
|
||||
if (!entries_.growBy(script->length))
|
||||
return false;
|
||||
FlowGraphSummary &self = *this;
|
||||
unsigned mainOffset = script->main() - script->code;
|
||||
self[mainOffset] = MultipleEdges;
|
||||
entries_[mainOffset] = Entry::createWithMultipleEdgesFromMultipleLines();
|
||||
for (size_t i = mainOffset + 1; i < script->length; i++)
|
||||
self[i] = NoEdges;
|
||||
entries_[i] = Entry::createWithNoEdges();
|
||||
|
||||
size_t prevLine = script->lineno;
|
||||
size_t prevLineno = script->lineno;
|
||||
size_t prevColumn = 0;
|
||||
JSOp prevOp = JSOP_NOP;
|
||||
for (BytecodeRangeWithLineNumbers r(cx, script); !r.empty(); r.popFront()) {
|
||||
for (BytecodeRangeWithPosition r(cx, script); !r.empty(); r.popFront()) {
|
||||
size_t lineno = r.frontLineNumber();
|
||||
size_t column = r.frontColumnNumber();
|
||||
JSOp op = r.frontOpcode();
|
||||
|
||||
if (FlowsIntoNext(prevOp))
|
||||
addEdge(prevLine, r.frontOffset());
|
||||
addEdge(prevLineno, prevColumn, r.frontOffset());
|
||||
|
||||
if (js_CodeSpec[op].type() == JOF_JUMP) {
|
||||
addEdge(lineno, r.frontOffset() + GET_JUMP_OFFSET(r.frontPC()));
|
||||
addEdge(lineno, column, r.frontOffset() + GET_JUMP_OFFSET(r.frontPC()));
|
||||
} else if (op == JSOP_TABLESWITCH) {
|
||||
jsbytecode *pc = r.frontPC();
|
||||
size_t offset = r.frontOffset();
|
||||
ptrdiff_t step = JUMP_OFFSET_LEN;
|
||||
size_t defaultOffset = offset + GET_JUMP_OFFSET(pc);
|
||||
pc += step;
|
||||
addEdge(lineno, defaultOffset);
|
||||
addEdge(lineno, column, defaultOffset);
|
||||
|
||||
int32_t low = GET_JUMP_OFFSET(pc);
|
||||
pc += JUMP_OFFSET_LEN;
|
||||
@ -3011,17 +3090,30 @@ class FlowGraphSummary : public Vector<size_t> {
|
||||
|
||||
for (int i = 0; i < ncases; i++) {
|
||||
size_t target = offset + GET_JUMP_OFFSET(pc);
|
||||
addEdge(lineno, target);
|
||||
addEdge(lineno, column, target);
|
||||
pc += step;
|
||||
}
|
||||
}
|
||||
|
||||
prevLineno = lineno;
|
||||
prevColumn = column;
|
||||
prevOp = op;
|
||||
prevLine = lineno;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
void addEdge(size_t sourceLineno, size_t sourceColumn, size_t targetOffset) {
|
||||
if (entries_[targetOffset].hasNoEdges())
|
||||
entries_[targetOffset] = Entry::createWithSingleEdge(sourceLineno, sourceColumn);
|
||||
else if (entries_[targetOffset].lineno() != sourceLineno)
|
||||
entries_[targetOffset] = Entry::createWithMultipleEdgesFromMultipleLines();
|
||||
else if (entries_[targetOffset].column() != sourceColumn)
|
||||
entries_[targetOffset] = Entry::createWithMultipleEdgesFromSingleLine(sourceLineno);
|
||||
}
|
||||
|
||||
Vector<Entry> entries_;
|
||||
};
|
||||
|
||||
static JSBool
|
||||
@ -3041,12 +3133,12 @@ DebuggerScript_getAllOffsets(JSContext *cx, unsigned argc, Value *vp)
|
||||
RootedObject result(cx, NewDenseEmptyArray(cx));
|
||||
if (!result)
|
||||
return false;
|
||||
for (BytecodeRangeWithLineNumbers r(cx, script); !r.empty(); r.popFront()) {
|
||||
for (BytecodeRangeWithPosition r(cx, script); !r.empty(); r.popFront()) {
|
||||
size_t offset = r.frontOffset();
|
||||
size_t lineno = r.frontLineNumber();
|
||||
|
||||
/* Make a note, if the current instruction is an entry point for the current line. */
|
||||
if (flowData[offset] != NoEdges && flowData[offset] != lineno) {
|
||||
if (!flowData[offset].hasNoEdges() && flowData[offset].lineno() != lineno) {
|
||||
/* Get the offsets array for this line. */
|
||||
RootedObject offsets(cx);
|
||||
RootedValue offsetsv(cx);
|
||||
@ -3122,13 +3214,13 @@ DebuggerScript_getLineOffsets(JSContext *cx, unsigned argc, Value *vp)
|
||||
RootedObject result(cx, NewDenseEmptyArray(cx));
|
||||
if (!result)
|
||||
return false;
|
||||
for (BytecodeRangeWithLineNumbers r(cx, script); !r.empty(); r.popFront()) {
|
||||
for (BytecodeRangeWithPosition r(cx, script); !r.empty(); r.popFront()) {
|
||||
size_t offset = r.frontOffset();
|
||||
|
||||
/* If the op at offset is an entry point, append offset to result. */
|
||||
if (r.frontLineNumber() == lineno &&
|
||||
flowData[offset] != NoEdges &&
|
||||
flowData[offset] != lineno)
|
||||
!flowData[offset].hasNoEdges() &&
|
||||
flowData[offset].lineno() != lineno)
|
||||
{
|
||||
if (!js_NewbornArrayPush(cx, result, NumberValue(offset)))
|
||||
return false;
|
||||
|
Loading…
Reference in New Issue
Block a user