mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
sharing data per class analysis instead of per thread
This commit is contained in:
@@ -203,13 +203,6 @@ abstract class Analysis<Res> {
|
||||
public static final int STEPS_LIMIT = 30000;
|
||||
public static final int EQUATION_SIZE_LIMIT = 30;
|
||||
|
||||
protected static final ThreadLocal<State[]> ourPendingStates = new ThreadLocal<State[]>() {
|
||||
@Override
|
||||
protected State[] initialValue() {
|
||||
return new State[STEPS_LIMIT];
|
||||
}
|
||||
};
|
||||
|
||||
final RichControlFlow richControlFlow;
|
||||
final Direction direction;
|
||||
final ControlFlowGraph controlFlow;
|
||||
|
||||
+13
-5
@@ -77,6 +77,13 @@ public class ClassDataIndexer implements DataIndexer<Bytes, HEquations, FileCont
|
||||
|
||||
public static Map<Key, List<Equation<Key, Value>>> processClass(final ClassReader classReader, final String presentableUrl) {
|
||||
|
||||
// It is OK to share pending states, actions and results for analyses.
|
||||
// Analyses are designed in such a way that they first write to states/actions/results and then read only those portion
|
||||
// of states/actions/results which were written by the current pass of the analysis.
|
||||
// Since states/actions/results are quite expensive to create (32K array) for each analysis, we create them once per class analysis.
|
||||
final State[] sharedPendingStates = new State[Analysis.STEPS_LIMIT];
|
||||
final PendingAction[] sharedPendingActions = new PendingAction[Analysis.STEPS_LIMIT];
|
||||
final PResults.PResult[] sharedResults = new PResults.PResult[Analysis.STEPS_LIMIT];
|
||||
final Map<Key, List<Equation<Key, Value>>> equations = new HashMap<Key, List<Equation<Key, Value>>>();
|
||||
|
||||
classReader.accept(new ClassVisitor(Opcodes.ASM5) {
|
||||
@@ -215,7 +222,7 @@ public class ClassDataIndexer implements DataIndexer<Bytes, HEquations, FileCont
|
||||
|
||||
Equation<Key, Value> outEquation =
|
||||
isInterestingResult ?
|
||||
new InOutAnalysis(richControlFlow, Out, origins, stable).analyze() :
|
||||
new InOutAnalysis(richControlFlow, Out, origins, stable, sharedPendingStates).analyze() :
|
||||
null;
|
||||
|
||||
if (isReferenceResult) {
|
||||
@@ -229,7 +236,8 @@ public class ClassDataIndexer implements DataIndexer<Bytes, HEquations, FileCont
|
||||
if (ASMUtils.isReferenceType(argumentTypes[i])) {
|
||||
boolean possibleNPE = false;
|
||||
if (leakingParameters[i]) {
|
||||
NonNullInAnalysis notNullInAnalysis = new NonNullInAnalysis(richControlFlow, new In(i, In.NOT_NULL_MASK), stable);
|
||||
NonNullInAnalysis notNullInAnalysis =
|
||||
new NonNullInAnalysis(richControlFlow, new In(i, In.NOT_NULL_MASK), stable, sharedPendingActions, sharedResults);
|
||||
Equation<Key, Value> notNullParamEquation = notNullInAnalysis.analyze();
|
||||
possibleNPE = notNullInAnalysis.possibleNPE;
|
||||
notNullParam = notNullParamEquation.rhs.equals(FINAL_NOT_NULL);
|
||||
@@ -245,7 +253,7 @@ public class ClassDataIndexer implements DataIndexer<Bytes, HEquations, FileCont
|
||||
result.add(new Equation<Key, Value>(new Key(method, new In(i, In.NULLABLE_MASK), stable), FINAL_TOP));
|
||||
}
|
||||
else {
|
||||
result.add(new NullableInAnalysis(richControlFlow, new In(i, In.NULLABLE_MASK), stable).analyze());
|
||||
result.add(new NullableInAnalysis(richControlFlow, new In(i, In.NULLABLE_MASK), stable, sharedPendingStates).analyze());
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -260,9 +268,9 @@ public class ClassDataIndexer implements DataIndexer<Bytes, HEquations, FileCont
|
||||
}
|
||||
else {
|
||||
// may be null on some branch, running "null->..." analysis
|
||||
result.add(new InOutAnalysis(richControlFlow, new InOut(i, Value.Null), origins, stable).analyze());
|
||||
result.add(new InOutAnalysis(richControlFlow, new InOut(i, Value.Null), origins, stable, sharedPendingStates).analyze());
|
||||
}
|
||||
result.add(new InOutAnalysis(richControlFlow, new InOut(i, Value.NotNull), origins, stable).analyze());
|
||||
result.add(new InOutAnalysis(richControlFlow, new InOut(i, Value.NotNull), origins, stable, sharedPendingStates).analyze());
|
||||
}
|
||||
else {
|
||||
// parameter is not leaking, so a contract is the same as for the whole method
|
||||
|
||||
+3
-2
@@ -41,7 +41,7 @@ class InOutAnalysis extends Analysis<Result<Key, Value>> {
|
||||
static final ResultUtil<Key, Value> resultUtil =
|
||||
new ResultUtil<Key, Value>(new ELattice<Value>(Value.Bot, Value.Top));
|
||||
|
||||
final private State[] pending = ourPendingStates.get();
|
||||
final private State[] pending;
|
||||
private final InOutInterpreter interpreter;
|
||||
private final Value inValue;
|
||||
private final int generalizeShift;
|
||||
@@ -49,8 +49,9 @@ class InOutAnalysis extends Analysis<Result<Key, Value>> {
|
||||
private int id = 0;
|
||||
private int pendingTop = 0;
|
||||
|
||||
protected InOutAnalysis(RichControlFlow richControlFlow, Direction direction, boolean[] resultOrigins, boolean stable) {
|
||||
protected InOutAnalysis(RichControlFlow richControlFlow, Direction direction, boolean[] resultOrigins, boolean stable, State[] pending) {
|
||||
super(richControlFlow, direction, stable);
|
||||
this.pending = pending;
|
||||
interpreter = new InOutInterpreter(direction, richControlFlow.controlFlow.methodNode.instructions, resultOrigins);
|
||||
inValue = direction instanceof InOut ? ((InOut)direction).inValue : null;
|
||||
generalizeShift = (methodNode.access & ACC_STATIC) == 0 ? 1 : 0;
|
||||
|
||||
+14
-22
@@ -167,30 +167,21 @@ class MakeResult implements PendingAction {
|
||||
}
|
||||
|
||||
class NonNullInAnalysis extends Analysis<PResult> {
|
||||
private static final ThreadLocal<PendingAction[]> ourPending = new ThreadLocal<PendingAction[]>() {
|
||||
@Override
|
||||
protected PendingAction[] initialValue() {
|
||||
return new PendingAction[Analysis.STEPS_LIMIT];
|
||||
}
|
||||
};
|
||||
private static final ThreadLocal<PResult[]> ourResults = new ThreadLocal<PResult[]>() {
|
||||
@Override
|
||||
protected PResult[] initialValue() {
|
||||
return new PResult[Analysis.STEPS_LIMIT];
|
||||
}
|
||||
};
|
||||
|
||||
final private PendingAction[] pending = ourPending.get();
|
||||
|
||||
final private PendingAction[] pendingActions;
|
||||
private final PResult[] results;
|
||||
private final NotNullInterpreter interpreter = new NotNullInterpreter();
|
||||
private PResult[] results;
|
||||
|
||||
// Flag saying that at some branch NPE was found. Used later as an evidence that this param is *NOT* @Nullable (optimization).
|
||||
boolean possibleNPE;
|
||||
|
||||
protected NonNullInAnalysis(RichControlFlow richControlFlow, Direction direction, boolean stable) {
|
||||
protected NonNullInAnalysis(RichControlFlow richControlFlow,
|
||||
Direction direction,
|
||||
boolean stable,
|
||||
PendingAction[] pendingActions,
|
||||
PResult[] results) {
|
||||
super(richControlFlow, direction, stable);
|
||||
results = ourResults.get();
|
||||
this.pendingActions = pendingActions;
|
||||
this.results = results;
|
||||
}
|
||||
|
||||
PResult combineResults(PResult delta, int[] subResults) throws AnalyzerException {
|
||||
@@ -232,7 +223,7 @@ class NonNullInAnalysis extends Analysis<PResult> {
|
||||
if (steps >= STEPS_LIMIT) {
|
||||
throw new AnalyzerException(null, "limit is reached, steps: " + steps + " in method " + method);
|
||||
}
|
||||
PendingAction action = pending[--pendingTop];
|
||||
PendingAction action = pendingActions[--pendingTop];
|
||||
if (action instanceof MakeResult) {
|
||||
MakeResult makeResult = (MakeResult) action;
|
||||
PResult result = combineResults(makeResult.subResult, makeResult.indices);
|
||||
@@ -397,7 +388,7 @@ class NonNullInAnalysis extends Analysis<PResult> {
|
||||
if (pendingTop >= STEPS_LIMIT) {
|
||||
throw new AnalyzerException(null, "limit is reached in method " + method);
|
||||
}
|
||||
pending[pendingTop++] = action;
|
||||
pendingActions[pendingTop++] = action;
|
||||
}
|
||||
|
||||
private void execute(Frame<BasicValue> frame, AbstractInsnNode insnNode) throws AnalyzerException {
|
||||
@@ -418,12 +409,13 @@ class NonNullInAnalysis extends Analysis<PResult> {
|
||||
}
|
||||
|
||||
class NullableInAnalysis extends Analysis<PResult> {
|
||||
final private State[] pending = ourPendingStates.get();
|
||||
final private State[] pending;
|
||||
|
||||
private final NullableInterpreter interpreter = new NullableInterpreter();
|
||||
|
||||
protected NullableInAnalysis(RichControlFlow richControlFlow, Direction direction, boolean stable) {
|
||||
protected NullableInAnalysis(RichControlFlow richControlFlow, Direction direction, boolean stable, State[] pending) {
|
||||
super(richControlFlow, direction, stable);
|
||||
this.pending = pending;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
|
||||
Reference in New Issue
Block a user