mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
straightforward solver
This commit is contained in:
+7
-7
@@ -99,13 +99,13 @@ public class BytecodeAnalysisConverter implements ApplicationComponent {
|
||||
result = new IntIdFinal(((Final<Key, Value>)rhs).value);
|
||||
} else {
|
||||
Pending<Key, Value> pending = (Pending<Key, Value>)rhs;
|
||||
Set<Set<Key>> deltaOrig = pending.delta;
|
||||
IntIdComponent[] components = new IntIdComponent[deltaOrig.size()];
|
||||
Set<Product<Key, Value>> sumOrigin = pending.sum;
|
||||
IntIdComponent[] components = new IntIdComponent[sumOrigin.size()];
|
||||
int componentI = 0;
|
||||
for (Set<Key> keyComponent : deltaOrig) {
|
||||
int[] ids = new int[keyComponent.size()];
|
||||
for (Product<Key, Value> prod : sumOrigin) {
|
||||
int[] ids = new int[prod.ids.size()];
|
||||
int idI = 0;
|
||||
for (Key id : keyComponent) {
|
||||
for (Key id : prod.ids) {
|
||||
int[] compoundKey = mkCompoundKey(id);
|
||||
int rawId = myCompoundKeyEnumerator.enumerate(compoundKey);
|
||||
if (rawId <= 0) {
|
||||
@@ -114,11 +114,11 @@ public class BytecodeAnalysisConverter implements ApplicationComponent {
|
||||
ids[idI] = id.stable ? rawId : -rawId;
|
||||
idI++;
|
||||
}
|
||||
IntIdComponent intIdComponent = new IntIdComponent(ids);
|
||||
IntIdComponent intIdComponent = new IntIdComponent(prod.value, ids);
|
||||
components[componentI] = intIdComponent;
|
||||
componentI++;
|
||||
}
|
||||
result = new IntIdPending(pending.infinum, pending.rigid, components);
|
||||
result = new IntIdPending(components);
|
||||
}
|
||||
|
||||
int rawKey = myCompoundKeyEnumerator.enumerate(mkCompoundKey(equation.id));
|
||||
|
||||
+12
-14
@@ -91,19 +91,17 @@ public class BytecodeAnalysisIndex extends FileBasedIndexExtension<Integer, Coll
|
||||
IntIdResult rhs = equation.rhs;
|
||||
if (rhs instanceof IntIdFinal) {
|
||||
IntIdFinal finalResult = (IntIdFinal)rhs;
|
||||
out.writeBoolean(true);
|
||||
out.writeBoolean(true); // final flag
|
||||
DataInputOutputUtil.writeINT(out, finalResult.value.ordinal());
|
||||
} else {
|
||||
IntIdPending pendResult = (IntIdPending)rhs;
|
||||
out.writeBoolean(false);
|
||||
DataInputOutputUtil.writeINT(out, pendResult.infinum.ordinal());
|
||||
out.writeBoolean(pendResult.rigid);
|
||||
out.writeBoolean(false); // pending flag
|
||||
DataInputOutputUtil.writeINT(out, pendResult.delta.length);
|
||||
|
||||
for (IntIdComponent component : pendResult.delta) {
|
||||
DataInputOutputUtil.writeINT(out, component.value.ordinal());
|
||||
int[] ids = component.ids;
|
||||
DataInputOutputUtil.writeINT(out, ids.length);
|
||||
|
||||
for (int id : ids) {
|
||||
out.writeInt(id);
|
||||
}
|
||||
@@ -120,27 +118,27 @@ public class BytecodeAnalysisIndex extends FileBasedIndexExtension<Integer, Coll
|
||||
|
||||
for (int x = 0; x < size; x++) {
|
||||
int equationId = in.readInt();
|
||||
boolean isFinal = in.readBoolean();
|
||||
boolean isFinal = in.readBoolean(); // flag
|
||||
if (isFinal) {
|
||||
int ordinal = DataInputOutputUtil.readINT(in);
|
||||
Value value = Value.values()[ordinal];
|
||||
result.add(new IntIdEquation(equationId, new IntIdFinal(value)));
|
||||
} else {
|
||||
int ordinal = DataInputOutputUtil.readINT(in);
|
||||
Value value = Value.values()[ordinal];
|
||||
boolean rigid = in.readBoolean();
|
||||
int deltaLength = DataInputOutputUtil.readINT(in);
|
||||
IntIdComponent[] components = new IntIdComponent[deltaLength];
|
||||
|
||||
for (int i = 0; i < deltaLength; i++) {
|
||||
int sumLength = DataInputOutputUtil.readINT(in);
|
||||
IntIdComponent[] components = new IntIdComponent[sumLength];
|
||||
|
||||
for (int i = 0; i < sumLength; i++) {
|
||||
int ordinal = DataInputOutputUtil.readINT(in);
|
||||
Value value = Value.values()[ordinal];
|
||||
int componentSize = DataInputOutputUtil.readINT(in);
|
||||
int[] ids = new int[componentSize];
|
||||
for (int j = 0; j < componentSize; j++) {
|
||||
ids[j] = in.readInt();
|
||||
}
|
||||
components[i] = new IntIdComponent(ids);
|
||||
components[i] = new IntIdComponent(value, ids);
|
||||
}
|
||||
result.add(new IntIdEquation(equationId, new IntIdPending(value, rigid, components)));
|
||||
result.add(new IntIdEquation(equationId, new IntIdPending(components)));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+5
-7
@@ -36,13 +36,11 @@ class InOutAnalysis extends Analysis<Result<Key, Value>> {
|
||||
|
||||
private final InOutInterpreter interpreter;
|
||||
private final Value inValue;
|
||||
private boolean nullAnalysis;
|
||||
|
||||
protected InOutAnalysis(RichControlFlow richControlFlow, Direction direction, TIntHashSet resultOrigins, boolean stable) {
|
||||
super(richControlFlow, direction, stable);
|
||||
interpreter = new InOutInterpreter(direction, richControlFlow.controlFlow.methodNode.instructions, resultOrigins);
|
||||
inValue = direction instanceof InOut ? ((InOut)direction).inValue : null;
|
||||
nullAnalysis = (direction instanceof InOut) && (((InOut)direction).inValue) == Value.Null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -65,8 +63,10 @@ class InOutAnalysis extends Analysis<Result<Key, Value>> {
|
||||
|
||||
@Override
|
||||
boolean isEarlyResult(Result<Key, Value> res) {
|
||||
Value value = res instanceof Final ? ((Final<?, Value>)res).value : ((Pending<?, Value>)res).infinum;
|
||||
return value == Value.Top;
|
||||
if (res instanceof Final) {
|
||||
return ((Final<?, Value>)res).value == Value.Top;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -126,9 +126,7 @@ class InOutAnalysis extends Analysis<Result<Key, Value>> {
|
||||
}
|
||||
else if (stackTop instanceof CallResultValue) {
|
||||
Set<Key> keys = ((CallResultValue) stackTop).inters;
|
||||
Set<Set<Key>> components = new HashSet<Set<Key>>();
|
||||
components.add(keys);
|
||||
results.put(stateIndex, new Pending<Key, Value>(Value.Bot, false, components));
|
||||
results.put(stateIndex, new Pending<Key, Value>(Collections.singleton(new Product<Key, Value>(Value.Top, keys))));
|
||||
computed.put(insnIndex, append(computed.get(insnIndex), state));
|
||||
}
|
||||
else {
|
||||
|
||||
+3
-3
@@ -153,11 +153,11 @@ class NonNullInAnalysis extends Analysis<PResult> {
|
||||
}
|
||||
else {
|
||||
ConditionalNPE condNpe = (ConditionalNPE) result;
|
||||
Set<Set<Key>> components = new HashSet<Set<Key>>();
|
||||
Set<Product<Key, Value>> components = new HashSet<Product<Key, Value>>();
|
||||
for (Set<Key> prod : condNpe.sop) {
|
||||
components.add(prod);
|
||||
components.add(new Product<Key, Value>(Value.Top, prod));
|
||||
}
|
||||
return new Equation<Key, Value>(aKey, new Pending<Key, Value>(Value.NotNull, false, components));
|
||||
return new Equation<Key, Value>(aKey, new Pending<Key, Value>(components));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+91
-148
@@ -17,10 +17,10 @@ package com.intellij.codeInspection.bytecodeAnalysis;
|
||||
|
||||
import com.intellij.util.containers.IntStack;
|
||||
import com.intellij.util.containers.IntToIntSetMap;
|
||||
import com.sun.istack.internal.NotNull;
|
||||
import gnu.trove.TIntObjectHashMap;
|
||||
|
||||
import java.util.*;
|
||||
import static com.intellij.codeInspection.bytecodeAnalysis.IdUtils.*;
|
||||
|
||||
final class ELattice<T extends Enum<T>> {
|
||||
final T bot;
|
||||
@@ -48,81 +48,60 @@ final class ELattice<T extends Enum<T>> {
|
||||
|
||||
// component specialized for ints
|
||||
final class IntIdComponent {
|
||||
Value value;
|
||||
final int[] ids;
|
||||
|
||||
IntIdComponent(Value value, int[] ids) {
|
||||
this.value = value;
|
||||
this.ids = ids;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (!(o instanceof IntIdComponent)) return false;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
IntIdComponent component = (IntIdComponent)o;
|
||||
IntIdComponent that = (IntIdComponent)o;
|
||||
|
||||
if (!Arrays.equals(ids, component.ids)) return false;
|
||||
if (!Arrays.equals(ids, that.ids)) return false;
|
||||
if (value != that.value) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Arrays.hashCode(ids);
|
||||
return value.ordinal() + Arrays.hashCode(ids);
|
||||
}
|
||||
|
||||
IntIdComponent(int[] ids) {
|
||||
this.ids = ids;
|
||||
}
|
||||
|
||||
public void remove(int id) {
|
||||
IdUtils.remove(ids, id);
|
||||
}
|
||||
|
||||
public boolean isEmptyAndTouched() {
|
||||
return IdUtils.isEmptyAndTouched(ids);
|
||||
public boolean remove(int id) {
|
||||
return IdUtils.remove(ids, id);
|
||||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
return IdUtils.isEmpty(ids);
|
||||
}
|
||||
|
||||
public void removeAndTouch(int id) {
|
||||
IdUtils.removeAndTouch(ids, id);
|
||||
}
|
||||
}
|
||||
|
||||
class IdUtils {
|
||||
// absent value
|
||||
static final int nullId = -1;
|
||||
static final int touchedId = -2;
|
||||
// removed value
|
||||
static final int nullId = 0;
|
||||
|
||||
static boolean contains(int[] ids, int id) {
|
||||
for (int i : ids) {
|
||||
if (i == id) {
|
||||
return true;
|
||||
}
|
||||
for (int id1 : ids) {
|
||||
if (id1 == id) return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static boolean isEmpty(int[] ids) {
|
||||
for (int i : ids) {
|
||||
if (i != nullId && i != touchedId) {
|
||||
return false;
|
||||
}
|
||||
for (int id : ids) {
|
||||
if (id != nullId) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
static boolean isEmptyAndTouched(int[] ids) {
|
||||
boolean touched = false;
|
||||
for (int i : ids) {
|
||||
if (i != nullId && i != touchedId) {
|
||||
return false;
|
||||
}
|
||||
touched = touched || i == touchedId;
|
||||
}
|
||||
return touched;
|
||||
}
|
||||
|
||||
static IntIdComponent[] toArray(Collection<IntIdComponent> set) {
|
||||
IntIdComponent[] result = new IntIdComponent[set.size()];
|
||||
int i = 0;
|
||||
@@ -130,23 +109,19 @@ class IdUtils {
|
||||
result[i] = intIdComponent;
|
||||
i++;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static void remove(int[] ids, int id) {
|
||||
static boolean remove(int[] ids, int id) {
|
||||
boolean removed = false;
|
||||
for (int i = 0; i < ids.length; i++) {
|
||||
if (ids[i] == id) {
|
||||
ids[i] = nullId;
|
||||
removed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void removeAndTouch(int[] ids, int id) {
|
||||
for (int i = 0; i < ids.length; i++) {
|
||||
if (ids[i] == id) {
|
||||
ids[i] = touchedId;
|
||||
}
|
||||
}
|
||||
return removed;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -169,19 +144,55 @@ class ResultUtil<Id, T extends Enum<T>> {
|
||||
return new Final<Id, T>(lattice.join(((Final<?, T>) r1).value, ((Final<?, T>) r2).value));
|
||||
}
|
||||
if (r1 instanceof Final && r2 instanceof Pending) {
|
||||
Final<?, T> f1 = (Final<?, T>)r1;
|
||||
Pending<Id, T> pending = (Pending<Id, T>) r2;
|
||||
return new Pending<Id, T>(lattice.join(((Final<Id, T>) r1).value, pending.infinum), true, pending.delta);
|
||||
Set<Product<Id, T>> sum1 = new HashSet<Product<Id, T>>(pending.sum);
|
||||
sum1.add(new Product<Id, T>(f1.value, Collections.<Id>emptySet()));
|
||||
return new Pending<Id, T>(sum1);
|
||||
}
|
||||
if (r1 instanceof Pending && r2 instanceof Final) {
|
||||
Final<?, T> f2 = (Final<?, T>)r2;
|
||||
Pending<Id, T> pending = (Pending<Id, T>) r1;
|
||||
return new Pending<Id, T>(lattice.join(((Final<Id, T>) r2).value, pending.infinum), true, pending.delta);
|
||||
Set<Product<Id, T>> sum1 = new HashSet<Product<Id, T>>(pending.sum);
|
||||
sum1.add(new Product<Id, T>(f2.value, Collections.<Id>emptySet()));
|
||||
return new Pending<Id, T>(sum1);
|
||||
}
|
||||
Pending<Id, T> pending1 = (Pending<Id, T>) r1;
|
||||
Pending<Id, T> pending2 = (Pending<Id, T>) r2;
|
||||
Set<Set<Id>> delta = new HashSet<Set<Id>>();
|
||||
delta.addAll(pending1.delta);
|
||||
delta.addAll(pending2.delta);
|
||||
return new Pending<Id, T>(lattice.join(pending1.infinum, pending2.infinum), pending1.rigid || pending2.rigid, delta);
|
||||
Set<Product<Id, T>> sum = new HashSet<Product<Id, T>>();
|
||||
sum.addAll(pending1.sum);
|
||||
sum.addAll(pending2.sum);
|
||||
return new Pending<Id, T>(sum);
|
||||
}
|
||||
}
|
||||
|
||||
final class Product<K, V> {
|
||||
@NotNull final V value;
|
||||
@NotNull final Set<K> ids;
|
||||
|
||||
Product(@NotNull V value, @NotNull Set<K> ids) {
|
||||
this.value = value;
|
||||
this.ids = ids;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
Product product = (Product)o;
|
||||
|
||||
if (!ids.equals(product.ids)) return false;
|
||||
if (!value.equals(product.value)) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = value.hashCode();
|
||||
result = 31 * result + ids.hashCode();
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -199,20 +210,12 @@ final class Final<Id, T> implements Result<Id, T> {
|
||||
}
|
||||
|
||||
final class Pending<Id, T> implements Result<Id, T> {
|
||||
final T infinum;
|
||||
final boolean rigid;
|
||||
final Set<Set<Id>> delta;
|
||||
final Set<Product<Id, T>> sum;
|
||||
|
||||
Pending(T infinum, boolean rigid, Set<Set<Id>> delta) {
|
||||
this.infinum = infinum;
|
||||
this.rigid = rigid;
|
||||
this.delta = delta;
|
||||
Pending(Set<Product<Id, T>> sum) {
|
||||
this.sum = sum;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Pending{" + "infinum=" + infinum + ", rigid=" + rigid + ", delta=" + delta + '}';
|
||||
}
|
||||
}
|
||||
|
||||
interface IntIdResult {}
|
||||
@@ -223,14 +226,11 @@ final class IntIdFinal implements IntIdResult {
|
||||
this.value = value;
|
||||
}
|
||||
}
|
||||
|
||||
final class IntIdPending implements IntIdResult {
|
||||
final Value infinum;
|
||||
final boolean rigid;
|
||||
final IntIdComponent[] delta;
|
||||
|
||||
IntIdPending(Value infinum, boolean rigid, IntIdComponent[] delta) {
|
||||
this.infinum = infinum;
|
||||
this.rigid = rigid;
|
||||
IntIdPending(IntIdComponent[] delta) {
|
||||
this.delta = delta;
|
||||
}
|
||||
|
||||
@@ -238,22 +238,13 @@ final class IntIdPending implements IntIdResult {
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (!(o instanceof IntIdPending)) return false;
|
||||
|
||||
IntIdPending pending = (IntIdPending)o;
|
||||
|
||||
if (!Arrays.equals(delta, pending.delta)) return false;
|
||||
if (rigid != pending.rigid) return false;
|
||||
if (infinum != pending.infinum) return false;
|
||||
|
||||
return true;
|
||||
return !Arrays.equals(delta, pending.delta);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = infinum.ordinal();
|
||||
result = 31 * result + (rigid ? 1 : 0);
|
||||
result = 31 * result + Arrays.hashCode(delta);
|
||||
return result;
|
||||
return Arrays.hashCode(delta);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -331,14 +322,9 @@ final class IntIdSolver {
|
||||
moving.push(equation.id);
|
||||
} else if (rhs instanceof IntIdPending) {
|
||||
IntIdPending pendResult = (IntIdPending)rhs;
|
||||
if (pendResult.infinum == lattice.top) {
|
||||
solved.put(equation.id, lattice.top);
|
||||
moving.push(equation.id);
|
||||
} else {
|
||||
for (IntIdComponent component : pendResult.delta) {
|
||||
for (int trigger : component.ids) {
|
||||
dependencies.addOccurence(trigger, equation.id);
|
||||
}
|
||||
for (IntIdComponent component : pendResult.delta) {
|
||||
for (int trigger : component.ids) {
|
||||
dependencies.addOccurence(trigger, equation.id);
|
||||
}
|
||||
pending.put(equation.id, pendResult);
|
||||
}
|
||||
@@ -381,67 +367,24 @@ final class IntIdSolver {
|
||||
|
||||
// substitute id -> value into pending
|
||||
IntIdResult substitute(IntIdPending pending, int id, Value value) {
|
||||
if (value == lattice.bot) {
|
||||
// remove components (products) with bottom
|
||||
ArrayList<IntIdComponent> delta = new ArrayList<IntIdComponent>();
|
||||
for (IntIdComponent component : pending.delta) {
|
||||
if (!contains(component.ids, id)) {
|
||||
delta.add(component);
|
||||
}
|
||||
}
|
||||
if (delta.isEmpty()) {
|
||||
return pending.rigid ? new IntIdFinal(pending.infinum) : new IntIdFinal(lattice.bot);
|
||||
}
|
||||
else {
|
||||
return new IntIdPending(pending.infinum, pending.rigid, toArray(delta));
|
||||
for (IntIdComponent intIdComponent : pending.delta) {
|
||||
if (intIdComponent.remove(id)) {
|
||||
intIdComponent.value = lattice.meet(intIdComponent.value, value);
|
||||
}
|
||||
}
|
||||
else if (value.equals(lattice.top)) {
|
||||
ArrayList<IntIdComponent> delta = new ArrayList<IntIdComponent>();
|
||||
// remove top from components
|
||||
boolean removed = false;
|
||||
for (IntIdComponent component : pending.delta) {
|
||||
component.remove(id);
|
||||
if (!component.isEmptyAndTouched()) {
|
||||
if (component.isEmpty()) {
|
||||
return new IntIdFinal(lattice.top);
|
||||
} else {
|
||||
delta.add(component);
|
||||
}
|
||||
}
|
||||
else {
|
||||
removed = true;
|
||||
}
|
||||
}
|
||||
if (delta.isEmpty()) {
|
||||
return new IntIdFinal(pending.infinum);
|
||||
}
|
||||
else {
|
||||
return new IntIdPending(pending.infinum, pending.rigid || removed, toArray(delta));
|
||||
}
|
||||
}
|
||||
else {
|
||||
Value infinum = lattice.join(pending.infinum, value);
|
||||
if (infinum == lattice.top) {
|
||||
// normalized?
|
||||
Value acc = lattice.bot;
|
||||
for (IntIdComponent intIdComponent : pending.delta) {
|
||||
if (intIdComponent.value == lattice.top && intIdComponent.isEmpty()) {
|
||||
return new IntIdFinal(lattice.top);
|
||||
}
|
||||
ArrayList<IntIdComponent> delta = new ArrayList<IntIdComponent>();
|
||||
boolean removed = false;
|
||||
for (IntIdComponent component : pending.delta) {
|
||||
component.removeAndTouch(id);
|
||||
if (!component.isEmpty()) {
|
||||
delta.add(component);
|
||||
}
|
||||
else {
|
||||
removed = true;
|
||||
}
|
||||
}
|
||||
if (delta.isEmpty()) {
|
||||
return new IntIdFinal(infinum);
|
||||
}
|
||||
else {
|
||||
return new IntIdPending(infinum, pending.rigid || removed, toArray(delta));
|
||||
else if (intIdComponent.value != lattice.bot) {
|
||||
if (intIdComponent.isEmpty())
|
||||
acc = lattice.join(acc, intIdComponent.value);
|
||||
else
|
||||
return pending;
|
||||
}
|
||||
}
|
||||
return new IntIdFinal(acc);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user