From 10c3276674cbed384a4739f1a4b94f5441e7b8db Mon Sep 17 00:00:00 2001 From: Tagir Valeev Date: Mon, 4 May 2020 12:41:57 +0700 Subject: [PATCH] DefUseUtil: make the traversal non-recursive to avoid possible SOE for huge methods (EA-144050) GitOrigin-RevId: 02df88e041af9be7a4259a734bbfe3b7b0e3cd93 --- .../intellij/psi/controlFlow/DefUseUtil.java | 89 ++++++++++--------- 1 file changed, 47 insertions(+), 42 deletions(-) diff --git a/java/java-psi-impl/src/com/intellij/psi/controlFlow/DefUseUtil.java b/java/java-psi-impl/src/com/intellij/psi/controlFlow/DefUseUtil.java index b5a003224594..1a1019ca19ec 100644 --- a/java/java-psi-impl/src/com/intellij/psi/controlFlow/DefUseUtil.java +++ b/java/java-psi-impl/src/com/intellij/psi/controlFlow/DefUseUtil.java @@ -13,6 +13,7 @@ import com.intellij.util.containers.Queue; import com.intellij.util.containers.Stack; import gnu.trove.THashMap; import gnu.trove.THashSet; +import gnu.trove.TIntArrayList; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -391,7 +392,8 @@ public class DefUseUtil { final boolean [] visited = new boolean[instructions.size() + 1]; visited [visited.length-1] = true; // stop on the code end - int elem = defs() ? flow.getStartOffset(refOrDef) : flow.getEndOffset(refOrDef); + final boolean defs = defs(); + int elem = defs ? flow.getStartOffset(refOrDef) : flow.getEndOffset(refOrDef); // hack: ControlFlow doesn't contains parameters initialization if (elem == -1 && def instanceof PsiParameter) { @@ -399,62 +401,65 @@ public class DefUseUtil { } if (elem != -1) { - if (!defs () && instructions.get(elem) instanceof ReadVariableInstruction) { + if (!defs && instructions.get(elem) instanceof ReadVariableInstruction) { LOG.assertTrue(nNext(elem) == 1); LOG.assertTrue(getNext(elem,0) == elem+1); elem += 1; } final Set<@NotNull PsiElement> res = new THashSet<>(); - class Inner { - private void traverse(int index) { - if (visited[index]) { - return; - } - visited [index] = true; + // hack: ControlFlow doesn't contains parameters initialization + int startIndex = elem; - if (defs ()) { - final Instruction instruction = instructions.get(index); - processInstruction(res, instruction, index); - if (instruction instanceof WriteVariableInstruction) { - WriteVariableInstruction instructionW = (WriteVariableInstruction)instruction; - if (instructionW.variable == def) { - return; - } - } + TIntArrayList workQueue = new TIntArrayList(); + workQueue.add(startIndex); - // hack: ControlFlow doesn't contains parameters initialization - if (index == 0 && def instanceof PsiParameter) { - PsiIdentifier identifier = def.getNameIdentifier(); - if (identifier != null) { - res.add(identifier); - } + while (!workQueue.isEmpty()) { + int index = workQueue.remove(workQueue.size() - 1); + if (visited[index]) { + continue; + } + visited [index] = true; + + if (defs) { + final Instruction instruction = instructions.get(index); + processInstruction(res, instruction, index); + if (instruction instanceof WriteVariableInstruction) { + WriteVariableInstruction instructionW = (WriteVariableInstruction)instruction; + if (instructionW.variable == def) { + continue; } } - final int nNext = nNext (index); - for (int i = 0; i < nNext; i++) { - final int prev = getNext(index, i); - if (!visited [prev]) { - if (!defs ()) { - final Instruction instruction = instructions.get(prev); - if (instruction instanceof WriteVariableInstruction) { - WriteVariableInstruction instructionW = (WriteVariableInstruction)instruction; - if (instructionW.variable == def) { - continue; - } - } - else { - processInstruction(res, instruction, prev); - } - } - traverse (prev); - + // hack: ControlFlow doesn't contains parameters initialization + if (index == 0 && def instanceof PsiParameter) { + PsiIdentifier identifier = def.getNameIdentifier(); + if (identifier != null) { + res.add(identifier); } } } + + final int nNext = nNext (index); + for (int i = 0; i < nNext; i++) { + final int prev = getNext(index, i); + if (!visited [prev]) { + if (!defs) { + final Instruction instruction = instructions.get(prev); + if (instruction instanceof WriteVariableInstruction) { + WriteVariableInstruction instructionW = (WriteVariableInstruction)instruction; + if (instructionW.variable == def) { + continue; + } + } + else { + processInstruction(res, instruction, prev); + } + } + workQueue.add(prev); + } + } } - new Inner ().traverse(elem); return PsiUtilCore.toPsiElementArray(res); } return PsiElement.EMPTY_ARRAY;