optimizations

This commit is contained in:
Ilya Klyuchnikov
2014-09-01 17:51:26 +04:00
parent f28955f810
commit ff2cd3cc05
2 changed files with 45 additions and 81 deletions
@@ -18,8 +18,6 @@ package com.intellij.codeInspection.bytecodeAnalysis;
import com.intellij.codeInspection.bytecodeAnalysis.asm.*;
import com.intellij.openapi.progress.ProcessCanceledException;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.util.NotNullLazyValue;
import com.intellij.openapi.util.NullableLazyValue;
import com.intellij.openapi.util.Pair;
import com.intellij.util.indexing.DataIndexer;
import com.intellij.util.indexing.FileContent;
@@ -31,8 +29,8 @@ import org.jetbrains.org.objectweb.asm.tree.analysis.AnalyzerException;
import java.security.MessageDigest;
import java.util.*;
import static com.intellij.codeInspection.bytecodeAnalysis.ProjectBytecodeAnalysis.LOG;
import static com.intellij.codeInspection.bytecodeAnalysis.Direction.*;
import static com.intellij.codeInspection.bytecodeAnalysis.ProjectBytecodeAnalysis.LOG;
/**
* @author lambdamix
@@ -173,13 +171,13 @@ public class ClassDataIndexer implements DataIndexer<Bytes, HEquations, FileCont
}
private List<Equation<Key, Value>> processBranchingMethod(final Method method,
final MethodNode methodNode,
final RichControlFlow richControlFlow,
Type[] argumentTypes,
boolean isReferenceResult,
boolean isInterestingResult,
final boolean stable,
boolean jsr) throws AnalyzerException {
final MethodNode methodNode,
final RichControlFlow richControlFlow,
Type[] argumentTypes,
boolean isReferenceResult,
boolean isInterestingResult,
final boolean stable,
boolean jsr) throws AnalyzerException {
List<Equation<Key, Value>> result = new ArrayList<Equation<Key, Value>>(argumentTypes.length * 4 + 2);
boolean maybeLeakingParameter = isInterestingResult;
@@ -192,42 +190,25 @@ public class ClassDataIndexer implements DataIndexer<Bytes, HEquations, FileCont
final LeakingParameters leakingParametersAndFrames =
maybeLeakingParameter ? leakingParametersAndFrames(method, methodNode, argumentTypes, jsr) : null;
boolean[] leakingParameters =
leakingParametersAndFrames != null ? leakingParametersAndFrames.parameters : null;
boolean[] leakingNullableParameters =
leakingParametersAndFrames != null ? leakingParametersAndFrames.nullableParameters : null;
final NullableLazyValue<boolean[]> origins = new NullableLazyValue<boolean[]>() {
@Override
protected boolean[] compute() {
try {
return OriginsAnalysis.resultOrigins(leakingParametersAndFrames.frames, methodNode.instructions, richControlFlow.controlFlow);
}
catch (AnalyzerException e) {
LOG.debug("when processing " + method + " in " + presentableUrl, e);
return null;
}
}
};
final boolean[] origins =
isInterestingResult ?
OriginsAnalysis.resultOrigins(leakingParametersAndFrames.frames, methodNode.instructions, richControlFlow.controlFlow) :
null;
NotNullLazyValue<Equation<Key, Value>> outEquation = new NotNullLazyValue<Equation<Key, Value>>() {
@NotNull
@Override
protected Equation<Key, Value> compute() {
if (origins.getValue() != null) {
try {
return new InOutAnalysis(richControlFlow, Out, origins.getValue(), stable).analyze();
}
catch (AnalyzerException ignored) {
}
}
return new Equation<Key, Value>(new Key(method, Out, stable), FINAL_TOP);
}
};
Equation<Key, Value> outEquation =
isInterestingResult ?
new InOutAnalysis(richControlFlow, Out, origins, stable).analyze() :
null;
if (isReferenceResult) {
result.add(outEquation.getValue());
result.add(new Equation<Key, Value>(new Key(method, NullableOut, stable), NullableMethodAnalysis.analyze(methodNode, origins.getValue(), jsr)));
result.add(outEquation);
result.add(new Equation<Key, Value>(new Key(method, NullableOut, stable), NullableMethodAnalysis.analyze(methodNode, origins, jsr)));
}
for (int i = 0; i < argumentTypes.length; i++) {
@@ -261,47 +242,31 @@ public class ClassDataIndexer implements DataIndexer<Bytes, HEquations, FileCont
}
if (isReferenceArg && isInterestingResult) {
if (leakingParameters[i]) {
if (origins.getValue() != null) {
// result origins analysis was ok
if (!notNullParam) {
// may be null on some branch, running "null->..." analysis
result.add(new InOutAnalysis(richControlFlow, new InOut(i, Value.Null), origins.getValue(), stable).analyze());
}
else {
// @NotNull, so "null->fail"
result.add(new Equation<Key, Value>(new Key(method, new InOut(i, Value.Null), stable), FINAL_BOT));
}
result.add(new InOutAnalysis(richControlFlow, new InOut(i, Value.NotNull), origins.getValue(), stable).analyze());
if (!notNullParam) {
// may be null on some branch, running "null->..." analysis
result.add(new InOutAnalysis(richControlFlow, new InOut(i, Value.Null), origins, stable).analyze());
}
else {
// result origins analysis failed, approximating to Top
result.add(new Equation<Key, Value>(new Key(method, new InOut(i, Value.Null), stable), FINAL_TOP));
result.add(new Equation<Key, Value>(new Key(method, new InOut(i, Value.NotNull), stable), FINAL_TOP));
// @NotNull, so "null->fail"
result.add(new Equation<Key, Value>(new Key(method, new InOut(i, Value.Null), stable), FINAL_BOT));
}
result.add(new InOutAnalysis(richControlFlow, new InOut(i, Value.NotNull), origins, stable).analyze());
}
else {
// parameter is not leaking, so a contract is the same as for the whole method
result.add(new Equation<Key, Value>(new Key(method, new InOut(i, Value.Null), stable), outEquation.getValue().rhs));
result.add(new Equation<Key, Value>(new Key(method, new InOut(i, Value.NotNull), stable), outEquation.getValue().rhs));
result.add(new Equation<Key, Value>(new Key(method, new InOut(i, Value.Null), stable), outEquation.rhs));
result.add(new Equation<Key, Value>(new Key(method, new InOut(i, Value.NotNull), stable), outEquation.rhs));
}
}
if (ASMUtils.isBooleanType(argumentTypes[i]) && isInterestingResult) {
if (leakingParameters[i]) {
if (origins.getValue() != null) {
// result origins analysis was ok
result.add(new InOutAnalysis(richControlFlow, new InOut(i, Value.False), origins.getValue(), stable).analyze());
result.add(new InOutAnalysis(richControlFlow, new InOut(i, Value.True), origins.getValue(), stable).analyze());
}
else {
// result origins analysis failed, approximating to Top
result.add(new Equation<Key, Value>(new Key(method, new InOut(i, Value.False), stable), FINAL_TOP));
result.add(new Equation<Key, Value>(new Key(method, new InOut(i, Value.True), stable), FINAL_TOP));
}
result.add(new InOutAnalysis(richControlFlow, new InOut(i, Value.False), origins, stable).analyze());
result.add(new InOutAnalysis(richControlFlow, new InOut(i, Value.True), origins, stable).analyze());
}
else {
// parameter is not leaking, so a contract is the same as for the whole method
result.add(new Equation<Key, Value>(new Key(method, new InOut(i, Value.False), stable), outEquation.getValue().rhs));
result.add(new Equation<Key, Value>(new Key(method, new InOut(i, Value.True), stable), outEquation.getValue().rhs));
result.add(new Equation<Key, Value>(new Key(method, new InOut(i, Value.False), stable), outEquation.rhs));
result.add(new Equation<Key, Value>(new Key(method, new InOut(i, Value.True), stable), outEquation.rhs));
}
}
}
@@ -309,11 +274,11 @@ public class ClassDataIndexer implements DataIndexer<Bytes, HEquations, FileCont
}
private List<Equation<Key, Value>> processNonBranchingMethod(Method method,
Type[] argumentTypes,
ControlFlowGraph graph,
boolean isReferenceResult,
boolean isBooleanResult,
boolean stable) throws AnalyzerException {
Type[] argumentTypes,
ControlFlowGraph graph,
boolean isReferenceResult,
boolean isBooleanResult,
boolean stable) throws AnalyzerException {
List<Equation<Key, Value>> result = new ArrayList<Equation<Key, Value>>(argumentTypes.length * 4 + 2);
CombinedAnalysis analyzer = new CombinedAnalysis(method, graph);
analyzer.analyze();
@@ -341,10 +306,10 @@ public class ClassDataIndexer implements DataIndexer<Bytes, HEquations, FileCont
}
private List<Equation<Key, Value>> topEquations(Method method,
Type[] argumentTypes,
boolean isReferenceResult,
boolean isInterestingResult,
boolean stable) {
Type[] argumentTypes,
boolean isReferenceResult,
boolean isInterestingResult,
boolean stable) {
List<Equation<Key, Value>> result = new ArrayList<Equation<Key, Value>>(argumentTypes.length * 4 + 2);
if (isReferenceResult) {
result.add(new Equation<Key, Value>(new Key(method, Out, stable), FINAL_TOP));
@@ -18,10 +18,10 @@ package com.intellij.codeInspection.bytecodeAnalysis;
import com.intellij.codeInspection.bytecodeAnalysis.asm.AnalyzerExt;
import com.intellij.codeInspection.bytecodeAnalysis.asm.InterpreterExt;
import com.intellij.codeInspection.bytecodeAnalysis.asm.LiteAnalyzerExt;
import com.intellij.util.SingletonSet;
import gnu.trove.TIntHashSet;
import gnu.trove.TIntIterator;
import gnu.trove.TIntProcedure;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.org.objectweb.asm.Opcodes;
import org.jetbrains.org.objectweb.asm.Type;
import org.jetbrains.org.objectweb.asm.tree.*;
@@ -40,7 +40,6 @@ import static com.intellij.codeInspection.bytecodeAnalysis.NullableMethodAnalysi
interface NullableMethodAnalysisData {
Type NullType = Type.getObjectType("null");
Type ThisType = Type.getObjectType("this");
Type ObjectType = Type.getObjectType("java/lang/Object");
Type CallType = Type.getObjectType("/Call");
final class LabeledNull extends BasicValue {
@@ -159,7 +158,7 @@ class NullableMethodAnalysis {
Calls calls = ((Calls)result);
Set<Product<Key, Value>> sum = new HashSet<Product<Key, Value>>(calls.keys.size());
for (Key key : calls.keys) {
sum.add(new Product<Key, Value>(Value.Null, new SingletonSet<Key>(key)));
sum.add(new Product<Key, Value>(Value.Null, Collections.singleton(key)));
}
return new Pending<Key, Value>(sum);
}
@@ -344,7 +343,7 @@ class NullableMethodInterpreter extends BasicInterpreter implements InterpreterE
(values.get(0) == ThisValue);
MethodInsnNode mNode = ((MethodInsnNode)insn);
Method method = new Method(mNode.owner, mNode.name, mNode.desc);
return new Calls(new SingletonSet<Key>(new Key(method, Direction.NullableOut, stable)));
return new Calls(Collections.singleton(new Key(method, Direction.NullableOut, stable)));
}
break;
default:
@@ -442,7 +441,7 @@ class NullableMethodInterpreter extends BasicInterpreter implements InterpreterE
}
}
static TIntHashSet merge(TIntHashSet set1, TIntHashSet set2) {
static TIntHashSet merge(@Nullable TIntHashSet set1, TIntHashSet set2) {
if (set1 == null || set1.isEmpty()) {
return set2;
}
@@ -463,7 +462,7 @@ class NullableMethodInterpreter extends BasicInterpreter implements InterpreterE
}
}
static Set<Key> merge(Set<Key> set1, Set<Key> set2) {
static Set<Key> merge(@Nullable Set<Key> set1, Set<Key> set2) {
if (set1 == null || set1.isEmpty()) {
return set2;
}