![JAR search and dependency download from the Maven repository](/logo.png)
com.intellij.codeInspection.bytecodeAnalysis.Solver Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of java-analysis-impl Show documentation
Show all versions of java-analysis-impl Show documentation
A packaging of the IntelliJ Community Edition java-analysis-impl library.
This is release number 1 of trunk branch 142.
The newest version!
/*
* Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.codeInspection.bytecodeAnalysis;
import com.intellij.util.ArrayFactory;
import com.intellij.util.ArrayUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.org.objectweb.asm.tree.analysis.AnalyzerException;
import java.util.*;
final class ELattice> {
final T bot;
final T top;
ELattice(T bot, T top) {
this.bot = bot;
this.top = top;
}
final T join(T x, T y) {
if (x == bot) return y;
if (y == bot) return x;
if (x == y) return x;
return top;
}
final T meet(T x, T y) {
if (x == top) return y;
if (y == top) return x;
if (x == y) return x;
return bot;
}
}
class ResultUtil> {
private final ELattice lattice;
final T top;
ResultUtil(ELattice lattice) {
this.lattice = lattice;
top = lattice.top;
}
Result join(Result r1, Result r2) throws AnalyzerException {
if (r1 instanceof Final && ((Final) r1).value == top) {
return r1;
}
if (r2 instanceof Final && ((Final) r2).value == top) {
return r2;
}
if (r1 instanceof Final && r2 instanceof Final) {
return new Final(lattice.join(((Final, T>) r1).value, ((Final, T>) r2).value));
}
if (r1 instanceof Final && r2 instanceof Pending) {
Final, T> f1 = (Final, T>)r1;
Pending pending = (Pending) r2;
Set> sum1 = new HashSet>(pending.sum);
sum1.add(new Product(f1.value, Collections.emptySet()));
return new Pending(sum1);
}
if (r1 instanceof Pending && r2 instanceof Final) {
Final, T> f2 = (Final, T>)r2;
Pending pending = (Pending) r1;
Set> sum1 = new HashSet>(pending.sum);
sum1.add(new Product(f2.value, Collections.emptySet()));
return new Pending(sum1);
}
Pending pending1 = (Pending) r1;
Pending pending2 = (Pending) r2;
Set> sum = new HashSet>();
sum.addAll(pending1.sum);
sum.addAll(pending2.sum);
checkLimit(sum);
return new Pending(sum);
}
private void checkLimit(Set> sum) throws AnalyzerException {
int size = 0;
for (Product prod : sum) {
size += prod.ids.size();
}
if (size > Analysis.EQUATION_SIZE_LIMIT) {
throw new AnalyzerException(null, "Equation size is too big");
}
}
}
class HResultUtil {
private static final HKey[] EMPTY_PRODUCT = new HKey[0];
private static final ArrayFactory HCOMPONENT_ARRAY_FACTORY = new ArrayFactory() {
@NotNull
@Override
public HComponent[] create(int count) {
return new HComponent[count];
}
};
private final ELattice lattice;
final Value top;
HResultUtil(ELattice lattice) {
this.lattice = lattice;
top = lattice.top;
}
HResult join(HResult r1, HResult r2) {
if (r1 instanceof HFinal && ((HFinal) r1).value == top) {
return r1;
}
if (r2 instanceof HFinal && ((HFinal) r2).value == top) {
return r2;
}
if (r1 instanceof HFinal && r2 instanceof HFinal) {
return new HFinal(lattice.join(((HFinal) r1).value, ((HFinal) r2).value));
}
if (r1 instanceof HFinal && r2 instanceof HPending) {
HFinal f1 = (HFinal)r1;
HPending pending = (HPending) r2;
HComponent[] delta = new HComponent[pending.delta.length + 1];
delta[0] = new HComponent(f1.value, EMPTY_PRODUCT);
System.arraycopy(pending.delta, 0, delta, 1, pending.delta.length);
return new HPending(delta);
}
if (r1 instanceof HPending && r2 instanceof HFinal) {
HFinal f2 = (HFinal)r2;
HPending pending = (HPending) r1;
HComponent[] delta = new HComponent[pending.delta.length + 1];
delta[0] = new HComponent(f2.value, EMPTY_PRODUCT);
System.arraycopy(pending.delta, 0, delta, 1, pending.delta.length);
return new HPending(delta);
}
HPending pending1 = (HPending) r1;
HPending pending2 = (HPending) r2;
return new HPending(ArrayUtil.mergeArrays(pending1.delta, pending2.delta, HCOMPONENT_ARRAY_FACTORY));
}
}
final class Product {
@NotNull final V value;
@NotNull final Set ids;
Product(@NotNull V value, @NotNull Set 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;
}
}
interface Result {}
final class Final implements Result {
final T value;
Final(T value) {
this.value = value;
}
@Override
public String toString() {
return "Final{" + "value=" + value + '}';
}
}
final class Pending implements Result {
final Set> sum;
Pending(Set> sum) {
this.sum = sum;
}
}
final class Solution {
final Id id;
final Val value;
Solution(Id id, Val value) {
this.id = id;
this.value = value;
}
}
final class Equation {
final Id id;
final Result rhs;
Equation(Id id, Result rhs) {
this.id = id;
this.rhs = rhs;
}
@Override
public String toString() {
return "Equation{" + "id=" + id + ", rhs=" + rhs + '}';
}
}
final class CoreHKey {
@NotNull
final byte[] key;
final int dirKey;
CoreHKey(@NotNull byte[] key, int dirKey) {
this.key = key;
this.dirKey = dirKey;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
CoreHKey coreHKey = (CoreHKey)o;
if (dirKey != coreHKey.dirKey) return false;
if (!Arrays.equals(key, coreHKey.key)) return false;
return true;
}
@Override
public int hashCode() {
int result = Arrays.hashCode(key);
result = 31 * result + dirKey;
return result;
}
}
final class Solver {
private final ELattice lattice;
private final HashMap> dependencies = new HashMap>();
private final HashMap pending = new HashMap();
private final HashMap solved = new HashMap();
private final Stack moving = new Stack();
private final HResultUtil resultUtil;
private final HashMap equations = new HashMap();
private final Value unstableValue;
Solver(ELattice lattice, Value unstableValue) {
this.lattice = lattice;
this.unstableValue = unstableValue;
resultUtil = new HResultUtil(lattice);
}
void addEquation(HEquation equation) {
HKey key = equation.key;
CoreHKey coreKey = new CoreHKey(key.key, key.dirKey);
HEquation previousEquation = equations.get(coreKey);
if (previousEquation == null) {
equations.put(coreKey, equation);
} else {
HKey joinKey = new HKey(coreKey.key, coreKey.dirKey, equation.key.stable && previousEquation.key.stable);
HResult joinResult = resultUtil.join(equation.result, previousEquation.result);
HEquation joinEquation = new HEquation(joinKey, joinResult);
equations.put(coreKey, joinEquation);
}
}
void queueEquation(HEquation equation) {
HResult rhs = equation.result;
if (rhs instanceof HFinal) {
solved.put(equation.key, ((HFinal) rhs).value);
moving.push(equation.key);
} else if (rhs instanceof HPending) {
HPending pendResult = ((HPending)rhs).copy();
HResult norm = normalize(pendResult.delta);
if (norm instanceof HFinal) {
solved.put(equation.key, ((HFinal) norm).value);
moving.push(equation.key);
}
else {
HPending pendResult1 = ((HPending)rhs).copy();
for (HComponent component : pendResult1.delta) {
for (HKey trigger : component.ids) {
HashSet set = dependencies.get(trigger);
if (set == null) {
set = new HashSet();
dependencies.put(trigger, set);
}
set.add(equation.key);
}
pending.put(equation.key, pendResult1);
}
}
}
}
HashMap solve() {
for (HEquation hEquation : equations.values()) {
queueEquation(hEquation);
}
while (!moving.empty()) {
HKey id = moving.pop();
Value value = solved.get(id);
HKey[] pIds = id.stable ? new HKey[]{id, id.negate()} : new HKey[]{id.negate(), id};
Value[] pVals = id.stable ? new Value[]{value, value} : new Value[]{value, unstableValue};
for (int i = 0; i < pIds.length; i++) {
HKey pId = pIds[i];
Value pVal = pVals[i];
HashSet dIds = dependencies.get(pId);
if (dIds == null) {
continue;
}
for (HKey dId : dIds) {
HPending pend = pending.remove(dId);
if (pend != null) {
HResult pend1 = substitute(pend, pId, pVal);
if (pend1 instanceof HFinal) {
HFinal fi = (HFinal)pend1;
solved.put(dId, fi.value);
moving.push(dId);
}
else {
pending.put(dId, (HPending)pend1);
}
}
}
}
}
pending.clear();
return solved;
}
// substitute id -> value into pending
HResult substitute(@NotNull HPending pending, @NotNull HKey id, @NotNull Value value) {
HComponent[] sum = pending.delta;
for (HComponent intIdComponent : sum) {
if (intIdComponent.remove(id)) {
intIdComponent.value = lattice.meet(intIdComponent.value, value);
}
}
return normalize(sum);
}
@NotNull HResult normalize(@NotNull HComponent[] sum) {
Value acc = lattice.bot;
boolean computableNow = true;
for (HComponent prod : sum) {
if (prod.isEmpty() || prod.value == lattice.bot) {
acc = lattice.join(acc, prod.value);
} else {
computableNow = false;
}
}
return (acc == lattice.top || computableNow) ? new HFinal(acc) : new HPending(sum);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy