mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Efficiency improvements in ScriptAnalysis::analyzeSSA, bug 725920. r=dvander
This commit is contained in:
parent
ef7237dbbe
commit
794ea5c208
@ -1218,38 +1218,39 @@ ScriptAnalysis::analyzeSSA(JSContext *cx)
|
||||
* Current value of each variable and stack value. Empty for missing or
|
||||
* untracked entries, i.e. escaping locals and arguments.
|
||||
*/
|
||||
SSAValue *values = (SSAValue *)
|
||||
cx->calloc_((numSlots + maxDepth) * sizeof(SSAValue));
|
||||
SSAValueInfo *values = (SSAValueInfo *)
|
||||
cx->calloc_((numSlots + maxDepth) * sizeof(SSAValueInfo));
|
||||
if (!values) {
|
||||
setOOM(cx);
|
||||
return;
|
||||
}
|
||||
struct FreeSSAValues {
|
||||
JSContext *cx;
|
||||
SSAValue *values;
|
||||
FreeSSAValues(JSContext *cx, SSAValue *values) : cx(cx), values(values) {}
|
||||
SSAValueInfo *values;
|
||||
FreeSSAValues(JSContext *cx, SSAValueInfo *values) : cx(cx), values(values) {}
|
||||
~FreeSSAValues() { cx->free_(values); }
|
||||
} free(cx, values);
|
||||
|
||||
SSAValue *stack = values + numSlots;
|
||||
SSAValueInfo *stack = values + numSlots;
|
||||
uint32_t stackDepth = 0;
|
||||
|
||||
for (uint32_t slot = ArgSlot(0); slot < numSlots; slot++) {
|
||||
if (trackSlot(slot))
|
||||
values[slot].initInitial(slot);
|
||||
values[slot].v.initInitial(slot);
|
||||
}
|
||||
|
||||
/*
|
||||
* All target offsets for forward jumps we in the middle of. We lazily add
|
||||
* pending entries at these targets for the original value of variables
|
||||
* modified before the branch rejoins.
|
||||
* All target offsets for forward jumps we have seen (including ones whose
|
||||
* target we have advanced past). We lazily add pending entries at these
|
||||
* targets for the original value of variables modified before the branch
|
||||
* rejoins.
|
||||
*/
|
||||
Vector<uint32_t> branchTargets(cx);
|
||||
|
||||
/*
|
||||
* Subset of branchTargets which are also exception handlers. Any value of
|
||||
* a variable modified before the target is reached is a potential value
|
||||
* at that target, along with the lazily added original value.
|
||||
* Subset of branchTargets which are exception handlers at future offsets.
|
||||
* Any new value of a variable modified before the target is reached is a
|
||||
* potential value at that target, along with the lazy original value.
|
||||
*/
|
||||
Vector<uint32_t> exceptionTargets(cx);
|
||||
|
||||
@ -1266,6 +1267,17 @@ ScriptAnalysis::analyzeSSA(JSContext *cx)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (code->exceptionEntry) {
|
||||
/* Remove from exception targets list, which reflects only future targets. */
|
||||
for (size_t i = 0; i < exceptionTargets.length(); i++) {
|
||||
if (exceptionTargets[i] == offset) {
|
||||
exceptionTargets[i] = exceptionTargets.back();
|
||||
exceptionTargets.popBack();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (code->stackDepth > stackDepth)
|
||||
PodZero(stack + stackDepth, code->stackDepth - stackDepth);
|
||||
stackDepth = code->stackDepth;
|
||||
@ -1287,9 +1299,7 @@ ScriptAnalysis::analyzeSSA(JSContext *cx)
|
||||
* loops), but in such cases the original value is pushed back.
|
||||
*/
|
||||
Vector<SlotValue> *&pending = code->pendingValues;
|
||||
if (pending) {
|
||||
removeBranchTarget(branchTargets, exceptionTargets, offset);
|
||||
} else {
|
||||
if (!pending) {
|
||||
pending = cx->new_< Vector<SlotValue> >(cx);
|
||||
if (!pending) {
|
||||
setOOM(cx);
|
||||
@ -1305,7 +1315,7 @@ ScriptAnalysis::analyzeSSA(JSContext *cx)
|
||||
for (unsigned i = 0; i < pending->length(); i++) {
|
||||
SlotValue &v = (*pending)[i];
|
||||
if (v.slot < numSlots && liveness(v.slot).firstWrite(code->loop) != UINT32_MAX) {
|
||||
if (v.value.kind() != SSAValue::PHI || v.value.phiOffset() < offset) {
|
||||
if (v.value.kind() != SSAValue::PHI || v.value.phiOffset() != offset) {
|
||||
SSAValue ov = v.value;
|
||||
if (!makePhi(cx, v.slot, offset, &ov))
|
||||
return;
|
||||
@ -1314,9 +1324,9 @@ ScriptAnalysis::analyzeSSA(JSContext *cx)
|
||||
}
|
||||
}
|
||||
if (code->fallthrough || code->jumpFallthrough)
|
||||
mergeValue(cx, offset, values[v.slot], &v);
|
||||
mergeBranchTarget(cx, values[v.slot], v.slot, branchTargets);
|
||||
values[v.slot] = v.value;
|
||||
mergeValue(cx, offset, values[v.slot].v, &v);
|
||||
mergeBranchTarget(cx, values[v.slot], v.slot, branchTargets, offset - 1);
|
||||
values[v.slot].v = v.value;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1331,7 +1341,7 @@ ScriptAnalysis::analyzeSSA(JSContext *cx)
|
||||
continue;
|
||||
if (liveness(slot).firstWrite(code->loop) == UINT32_MAX)
|
||||
continue;
|
||||
if (values[slot].kind() == SSAValue::PHI && values[slot].phiOffset() == offset) {
|
||||
if (values[slot].v.kind() == SSAValue::PHI && values[slot].v.phiOffset() == offset) {
|
||||
/* There is already a pending entry for this slot. */
|
||||
continue;
|
||||
}
|
||||
@ -1339,9 +1349,9 @@ ScriptAnalysis::analyzeSSA(JSContext *cx)
|
||||
if (!makePhi(cx, slot, offset, &ov))
|
||||
return;
|
||||
if (code->fallthrough || code->jumpFallthrough)
|
||||
insertPhi(cx, ov, values[slot]);
|
||||
mergeBranchTarget(cx, values[slot], slot, branchTargets);
|
||||
values[slot] = ov;
|
||||
insertPhi(cx, ov, values[slot].v);
|
||||
mergeBranchTarget(cx, values[slot], slot, branchTargets, offset - 1);
|
||||
values[slot].v = ov;
|
||||
if (!pending->append(SlotValue(slot, ov))) {
|
||||
setOOM(cx);
|
||||
return;
|
||||
@ -1358,16 +1368,16 @@ ScriptAnalysis::analyzeSSA(JSContext *cx)
|
||||
* that values written inside the block but not subsequently
|
||||
* overwritten are picked up.
|
||||
*/
|
||||
bool exception = removeBranchTarget(branchTargets, exceptionTargets, offset);
|
||||
bool exception = getCode(offset).exceptionEntry;
|
||||
Vector<SlotValue> *pending = code->pendingValues;
|
||||
for (unsigned i = 0; i < pending->length(); i++) {
|
||||
SlotValue &v = (*pending)[i];
|
||||
if (code->fallthrough || code->jumpFallthrough ||
|
||||
(exception && values[v.slot].kind() != SSAValue::EMPTY)) {
|
||||
mergeValue(cx, offset, values[v.slot], &v);
|
||||
(exception && values[v.slot].v.kind() != SSAValue::EMPTY)) {
|
||||
mergeValue(cx, offset, values[v.slot].v, &v);
|
||||
}
|
||||
mergeBranchTarget(cx, values[v.slot], v.slot, branchTargets);
|
||||
values[v.slot] = v.value;
|
||||
mergeBranchTarget(cx, values[v.slot], v.slot, branchTargets, offset);
|
||||
values[v.slot].v = v.value;
|
||||
}
|
||||
freezeNewValues(cx, offset);
|
||||
}
|
||||
@ -1390,7 +1400,7 @@ ScriptAnalysis::analyzeSSA(JSContext *cx)
|
||||
return;
|
||||
}
|
||||
for (unsigned i = 0; i < nuses; i++) {
|
||||
SSAValue &v = stack[stackDepth - 1 - i];
|
||||
SSAValue &v = stack[stackDepth - 1 - i].v;
|
||||
code->poppedValues[i] = v;
|
||||
v.clear();
|
||||
}
|
||||
@ -1401,7 +1411,7 @@ ScriptAnalysis::analyzeSSA(JSContext *cx)
|
||||
*/
|
||||
uint32_t slot = GetBytecodeSlot(script, pc);
|
||||
if (trackSlot(slot))
|
||||
code->poppedValues[nuses] = values[slot];
|
||||
code->poppedValues[nuses] = values[slot].v;
|
||||
else
|
||||
code->poppedValues[nuses].clear();
|
||||
}
|
||||
@ -1430,7 +1440,7 @@ ScriptAnalysis::analyzeSSA(JSContext *cx)
|
||||
stackDepth -= nuses;
|
||||
|
||||
for (unsigned i = 0; i < ndefs; i++)
|
||||
stack[stackDepth + i].initPushed(offset, i);
|
||||
stack[stackDepth + i].v.initPushed(offset, i);
|
||||
|
||||
unsigned xdefs = ExtendedDef(pc) ? ndefs + 1 : ndefs;
|
||||
if (xdefs) {
|
||||
@ -1447,9 +1457,9 @@ ScriptAnalysis::analyzeSSA(JSContext *cx)
|
||||
if (BytecodeUpdatesSlot(op)) {
|
||||
uint32_t slot = GetBytecodeSlot(script, pc);
|
||||
if (trackSlot(slot)) {
|
||||
mergeBranchTarget(cx, values[slot], slot, branchTargets);
|
||||
mergeExceptionTarget(cx, values[slot], slot, exceptionTargets);
|
||||
values[slot].initWritten(slot, offset);
|
||||
mergeBranchTarget(cx, values[slot], slot, branchTargets, offset);
|
||||
mergeExceptionTarget(cx, values[slot].v, slot, exceptionTargets);
|
||||
values[slot].v.initWritten(slot, offset);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1462,7 +1472,7 @@ ScriptAnalysis::analyzeSSA(JSContext *cx)
|
||||
* Propagate the current value of the local to the pushed value,
|
||||
* and remember it with an extended use on the opcode.
|
||||
*/
|
||||
stack[stackDepth - 1] = code->poppedValues[0] = values[slot];
|
||||
stack[stackDepth - 1].v = code->poppedValues[0] = values[slot].v;
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -1470,34 +1480,34 @@ ScriptAnalysis::analyzeSSA(JSContext *cx)
|
||||
/* Short circuit ops which push back one of their operands. */
|
||||
|
||||
case JSOP_MOREITER:
|
||||
stack[stackDepth - 2] = code->poppedValues[0];
|
||||
stack[stackDepth - 2].v = code->poppedValues[0];
|
||||
break;
|
||||
|
||||
case JSOP_INITPROP:
|
||||
case JSOP_INITMETHOD:
|
||||
stack[stackDepth - 1] = code->poppedValues[1];
|
||||
stack[stackDepth - 1].v = code->poppedValues[1];
|
||||
break;
|
||||
|
||||
case JSOP_INITELEM:
|
||||
stack[stackDepth - 1] = code->poppedValues[2];
|
||||
stack[stackDepth - 1].v = code->poppedValues[2];
|
||||
break;
|
||||
|
||||
case JSOP_DUP:
|
||||
stack[stackDepth - 1] = stack[stackDepth - 2] = code->poppedValues[0];
|
||||
stack[stackDepth - 1].v = stack[stackDepth - 2].v = code->poppedValues[0];
|
||||
break;
|
||||
|
||||
case JSOP_DUP2:
|
||||
stack[stackDepth - 1] = stack[stackDepth - 3] = code->poppedValues[0];
|
||||
stack[stackDepth - 2] = stack[stackDepth - 4] = code->poppedValues[1];
|
||||
stack[stackDepth - 1].v = stack[stackDepth - 3].v = code->poppedValues[0];
|
||||
stack[stackDepth - 2].v = stack[stackDepth - 4].v = code->poppedValues[1];
|
||||
break;
|
||||
|
||||
case JSOP_SWAP:
|
||||
/* Swap is like pick 1. */
|
||||
case JSOP_PICK: {
|
||||
unsigned pickedDepth = (op == JSOP_SWAP ? 1 : pc[1]);
|
||||
stack[stackDepth - 1] = code->poppedValues[pickedDepth];
|
||||
stack[stackDepth - 1].v = code->poppedValues[pickedDepth];
|
||||
for (unsigned i = 0; i < pickedDepth; i++)
|
||||
stack[stackDepth - 2 - i] = code->poppedValues[i];
|
||||
stack[stackDepth - 2 - i].v = code->poppedValues[i];
|
||||
break;
|
||||
}
|
||||
|
||||
@ -1514,14 +1524,19 @@ ScriptAnalysis::analyzeSSA(JSContext *cx)
|
||||
jsint high = GET_JUMP_OFFSET(pc2);
|
||||
pc2 += JUMP_OFFSET_LEN;
|
||||
|
||||
checkBranchTarget(cx, defaultOffset, branchTargets, values, stackDepth);
|
||||
Vector<SlotValue> *pending = NULL;
|
||||
uint32_t pendingOffset = 0;
|
||||
|
||||
for (jsint i = low; i <= high; i++) {
|
||||
unsigned targetOffset = offset + GET_JUMP_OFFSET(pc2);
|
||||
if (targetOffset != offset)
|
||||
checkBranchTarget(cx, targetOffset, branchTargets, values, stackDepth);
|
||||
checkBranchTarget(cx, targetOffset, branchTargets, values, stackDepth,
|
||||
&pending, &pendingOffset);
|
||||
pc2 += JUMP_OFFSET_LEN;
|
||||
}
|
||||
|
||||
checkBranchTarget(cx, defaultOffset, branchTargets, values, stackDepth,
|
||||
&pending, &pendingOffset);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -1531,15 +1546,20 @@ ScriptAnalysis::analyzeSSA(JSContext *cx)
|
||||
unsigned npairs = GET_UINT16(pc2);
|
||||
pc2 += UINT16_LEN;
|
||||
|
||||
checkBranchTarget(cx, defaultOffset, branchTargets, values, stackDepth);
|
||||
Vector<SlotValue> *pending = NULL;
|
||||
uint32_t pendingOffset = 0;
|
||||
|
||||
while (npairs) {
|
||||
pc2 += INDEX_LEN;
|
||||
unsigned targetOffset = offset + GET_JUMP_OFFSET(pc2);
|
||||
checkBranchTarget(cx, targetOffset, branchTargets, values, stackDepth);
|
||||
checkBranchTarget(cx, targetOffset, branchTargets, values, stackDepth,
|
||||
&pending, &pendingOffset);
|
||||
pc2 += JUMP_OFFSET_LEN;
|
||||
npairs--;
|
||||
}
|
||||
|
||||
checkBranchTarget(cx, defaultOffset, branchTargets, values, stackDepth,
|
||||
&pending, &pendingOffset);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -1676,7 +1696,7 @@ ScriptAnalysis::mergeValue(JSContext *cx, uint32_t offset, const SSAValue &v, Sl
|
||||
if (v == pv->value)
|
||||
return;
|
||||
|
||||
if (pv->value.kind() != SSAValue::PHI || pv->value.phiOffset() < offset) {
|
||||
if (pv->value.kind() != SSAValue::PHI || pv->value.phiOffset() != offset) {
|
||||
SSAValue ov = pv->value;
|
||||
if (makePhi(cx, pv->slot, offset, &pv->value)) {
|
||||
insertPhi(cx, pv->value, v);
|
||||
@ -1685,7 +1705,6 @@ ScriptAnalysis::mergeValue(JSContext *cx, uint32_t offset, const SSAValue &v, Sl
|
||||
return;
|
||||
}
|
||||
|
||||
JS_ASSERT(pv->value.phiOffset() == offset);
|
||||
insertPhi(cx, pv->value, v);
|
||||
}
|
||||
|
||||
@ -1707,7 +1726,8 @@ ScriptAnalysis::checkPendingValue(JSContext *cx, const SSAValue &v, uint32_t slo
|
||||
void
|
||||
ScriptAnalysis::checkBranchTarget(JSContext *cx, uint32_t targetOffset,
|
||||
Vector<uint32_t> &branchTargets,
|
||||
SSAValue *values, uint32_t stackDepth)
|
||||
SSAValueInfo *values, uint32_t stackDepth,
|
||||
Vector<SlotValue> **ppending, uint32_t *ppendingOffset)
|
||||
{
|
||||
unsigned targetDepth = getCode(targetOffset).stackDepth;
|
||||
JS_ASSERT(targetDepth <= stackDepth);
|
||||
@ -1721,14 +1741,28 @@ ScriptAnalysis::checkBranchTarget(JSContext *cx, uint32_t targetOffset,
|
||||
if (pending) {
|
||||
for (unsigned i = 0; i < pending->length(); i++) {
|
||||
SlotValue &v = (*pending)[i];
|
||||
mergeValue(cx, targetOffset, values[v.slot], &v);
|
||||
mergeValue(cx, targetOffset, values[v.slot].v, &v);
|
||||
}
|
||||
} else {
|
||||
pending = cx->new_< Vector<SlotValue> >(cx);
|
||||
if (!pending || !branchTargets.append(targetOffset)) {
|
||||
if (ppending && *ppending) {
|
||||
JS_ASSERT(*ppendingOffset != targetOffset);
|
||||
pending = *ppending;
|
||||
getCode(Min(targetOffset, *ppendingOffset)).switchSharesPending = true;
|
||||
} else {
|
||||
pending = cx->new_< Vector<SlotValue> >(cx);
|
||||
if (!pending) {
|
||||
setOOM(cx);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (!branchTargets.append(targetOffset)) {
|
||||
setOOM(cx);
|
||||
return;
|
||||
}
|
||||
if (ppending) {
|
||||
*ppending = pending;
|
||||
*ppendingOffset = Max(targetOffset, *ppendingOffset);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1739,7 +1773,7 @@ ScriptAnalysis::checkBranchTarget(JSContext *cx, uint32_t targetOffset,
|
||||
*/
|
||||
for (unsigned i = 0; i < targetDepth; i++) {
|
||||
uint32_t slot = StackSlot(script, i);
|
||||
checkPendingValue(cx, values[slot], slot, pending);
|
||||
checkPendingValue(cx, values[slot].v, slot, pending);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1747,6 +1781,8 @@ void
|
||||
ScriptAnalysis::checkExceptionTarget(JSContext *cx, uint32_t catchOffset,
|
||||
Vector<uint32_t> &exceptionTargets)
|
||||
{
|
||||
JS_ASSERT(getCode(catchOffset).exceptionEntry);
|
||||
|
||||
/*
|
||||
* The catch offset will already be in the branch targets, just check
|
||||
* whether this is already a known exception target.
|
||||
@ -1760,8 +1796,8 @@ ScriptAnalysis::checkExceptionTarget(JSContext *cx, uint32_t catchOffset,
|
||||
}
|
||||
|
||||
void
|
||||
ScriptAnalysis::mergeBranchTarget(JSContext *cx, const SSAValue &value, uint32_t slot,
|
||||
const Vector<uint32_t> &branchTargets)
|
||||
ScriptAnalysis::mergeBranchTarget(JSContext *cx, SSAValueInfo &value, uint32_t slot,
|
||||
const Vector<uint32_t> &branchTargets, uint32_t currentOffset)
|
||||
{
|
||||
if (slot >= numSlots) {
|
||||
/*
|
||||
@ -1777,11 +1813,27 @@ ScriptAnalysis::mergeBranchTarget(JSContext *cx, const SSAValue &value, uint32_t
|
||||
/*
|
||||
* Before changing the value of a variable, make sure the old value is
|
||||
* marked at the target of any branches jumping over the current opcode.
|
||||
* Only look at new branch targets which have appeared since the last time
|
||||
* the variable was written.
|
||||
*/
|
||||
for (unsigned i = 0; i < branchTargets.length(); i++) {
|
||||
Vector<SlotValue> *pending = getCode(branchTargets[i]).pendingValues;
|
||||
checkPendingValue(cx, value, slot, pending);
|
||||
for (int i = branchTargets.length() - 1; i >= value.branchSize; i--) {
|
||||
if (branchTargets[i] <= currentOffset)
|
||||
continue;
|
||||
|
||||
const Bytecode &code = getCode(branchTargets[i]);
|
||||
|
||||
/*
|
||||
* If the pending array for this offset is shared with a later branch
|
||||
* target, it will be updated when that offset is handled.
|
||||
*/
|
||||
if (code.switchSharesPending)
|
||||
continue;
|
||||
|
||||
Vector<SlotValue> *pending = code.pendingValues;
|
||||
checkPendingValue(cx, value.v, slot, pending);
|
||||
}
|
||||
|
||||
value.branchSize = branchTargets.length();
|
||||
}
|
||||
|
||||
void
|
||||
@ -1818,7 +1870,7 @@ ScriptAnalysis::mergeExceptionTarget(JSContext *cx, const SSAValue &value, uint3
|
||||
}
|
||||
|
||||
void
|
||||
ScriptAnalysis::mergeAllExceptionTargets(JSContext *cx, SSAValue *values,
|
||||
ScriptAnalysis::mergeAllExceptionTargets(JSContext *cx, SSAValueInfo *values,
|
||||
const Vector<uint32_t> &exceptionTargets)
|
||||
{
|
||||
for (unsigned i = 0; i < exceptionTargets.length(); i++) {
|
||||
@ -1826,36 +1878,11 @@ ScriptAnalysis::mergeAllExceptionTargets(JSContext *cx, SSAValue *values,
|
||||
for (unsigned i = 0; i < pending->length(); i++) {
|
||||
const SlotValue &v = (*pending)[i];
|
||||
if (trackSlot(v.slot))
|
||||
mergeExceptionTarget(cx, values[v.slot], v.slot, exceptionTargets);
|
||||
mergeExceptionTarget(cx, values[v.slot].v, v.slot, exceptionTargets);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
ScriptAnalysis::removeBranchTarget(Vector<uint32_t> &branchTargets,
|
||||
Vector<uint32_t> &exceptionTargets,
|
||||
uint32_t offset)
|
||||
{
|
||||
bool exception = false;
|
||||
for (unsigned i = 0; i < exceptionTargets.length(); i++) {
|
||||
if (exceptionTargets[i] == offset) {
|
||||
exceptionTargets[i] = branchTargets.back();
|
||||
exceptionTargets.popBack();
|
||||
exception = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (unsigned i = 0; i < branchTargets.length(); i++) {
|
||||
if (branchTargets[i] == offset) {
|
||||
branchTargets[i] = branchTargets.back();
|
||||
branchTargets.popBack();
|
||||
return exception;
|
||||
}
|
||||
}
|
||||
JS_ASSERT(OOM());
|
||||
return exception;
|
||||
}
|
||||
|
||||
void
|
||||
ScriptAnalysis::freezeNewValues(JSContext *cx, uint32_t offset)
|
||||
{
|
||||
@ -1866,7 +1893,8 @@ ScriptAnalysis::freezeNewValues(JSContext *cx, uint32_t offset)
|
||||
|
||||
unsigned count = pending->length();
|
||||
if (count == 0) {
|
||||
cx->delete_(pending);
|
||||
if (!code.switchSharesPending)
|
||||
cx->delete_(pending);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1881,7 +1909,8 @@ ScriptAnalysis::freezeNewValues(JSContext *cx, uint32_t offset)
|
||||
code.newValues[count].slot = 0;
|
||||
code.newValues[count].value.clear();
|
||||
|
||||
cx->delete_(pending);
|
||||
if (!code.switchSharesPending)
|
||||
cx->delete_(pending);
|
||||
}
|
||||
|
||||
CrossSSAValue
|
||||
|
@ -142,6 +142,12 @@ class Bytecode
|
||||
bool getStringElement:1; /* GETELEM which has accessed string properties. */
|
||||
bool accessGetter: 1; /* Property read on a shape with a getter hook. */
|
||||
|
||||
/*
|
||||
* Switch target other than the last one, which shares its pending values
|
||||
* with a later offset during SSA analysis.
|
||||
*/
|
||||
bool switchSharesPending : 1;
|
||||
|
||||
/* Stack depth before this opcode. */
|
||||
uint32_t stackDepth;
|
||||
|
||||
@ -1190,6 +1196,19 @@ class ScriptAnalysis
|
||||
inline void extendVariable(JSContext *cx, LifetimeVariable &var, unsigned start, unsigned end);
|
||||
inline void ensureVariable(LifetimeVariable &var, unsigned until);
|
||||
|
||||
/* Current value for a variable or stack value, as tracked during SSA. */
|
||||
struct SSAValueInfo
|
||||
{
|
||||
SSAValue v;
|
||||
|
||||
/*
|
||||
* Sizes of branchTargets the last time this slot was written. Branches less
|
||||
* than this threshold do not need to be inspected if the slot is written
|
||||
* again, as they will already reflect the slot's value at the branch.
|
||||
*/
|
||||
int32_t branchSize;
|
||||
};
|
||||
|
||||
/* SSA helpers */
|
||||
bool makePhi(JSContext *cx, uint32_t slot, uint32_t offset, SSAValue *pv);
|
||||
void insertPhi(JSContext *cx, SSAValue &phi, const SSAValue &v);
|
||||
@ -1197,18 +1216,16 @@ class ScriptAnalysis
|
||||
void checkPendingValue(JSContext *cx, const SSAValue &v, uint32_t slot,
|
||||
Vector<SlotValue> *pending);
|
||||
void checkBranchTarget(JSContext *cx, uint32_t targetOffset, Vector<uint32_t> &branchTargets,
|
||||
SSAValue *values, uint32_t stackDepth);
|
||||
SSAValueInfo *values, uint32_t stackDepth,
|
||||
Vector<SlotValue> **ppending = NULL, uint32_t *ppendingOffset = NULL);
|
||||
void checkExceptionTarget(JSContext *cx, uint32_t catchOffset,
|
||||
Vector<uint32_t> &exceptionTargets);
|
||||
void mergeBranchTarget(JSContext *cx, const SSAValue &value, uint32_t slot,
|
||||
const Vector<uint32_t> &branchTargets);
|
||||
void mergeBranchTarget(JSContext *cx, SSAValueInfo &value, uint32_t slot,
|
||||
const Vector<uint32_t> &branchTargets, uint32_t currentOffset);
|
||||
void mergeExceptionTarget(JSContext *cx, const SSAValue &value, uint32_t slot,
|
||||
const Vector<uint32_t> &exceptionTargets);
|
||||
void mergeAllExceptionTargets(JSContext *cx, SSAValue *values,
|
||||
void mergeAllExceptionTargets(JSContext *cx, SSAValueInfo *values,
|
||||
const Vector<uint32_t> &exceptionTargets);
|
||||
bool removeBranchTarget(Vector<uint32_t> &branchTargets,
|
||||
Vector<uint32_t> &exceptionTargets,
|
||||
uint32_t offset);
|
||||
void freezeNewValues(JSContext *cx, uint32_t offset);
|
||||
|
||||
struct TypeInferenceState {
|
||||
|
Loading…
Reference in New Issue
Block a user