diff --git a/src/main/java/pascal/taie/analysis/dataflow/analysis/availexp/AvailableExpression.java b/src/main/java/pascal/taie/analysis/dataflow/analysis/availexp/AvailableExpression.java index d426f27b1..58868ebf3 100644 --- a/src/main/java/pascal/taie/analysis/dataflow/analysis/availexp/AvailableExpression.java +++ b/src/main/java/pascal/taie/analysis/dataflow/analysis/availexp/AvailableExpression.java @@ -25,7 +25,6 @@ import pascal.taie.analysis.dataflow.analysis.AbstractDataflowAnalysis; import pascal.taie.analysis.dataflow.analysis.AnalysisDriver; import pascal.taie.analysis.dataflow.fact.SetFact; -import pascal.taie.analysis.dataflow.fact.ToppedSetFact; import pascal.taie.analysis.graph.cfg.CFG; import pascal.taie.config.AnalysisConfig; import pascal.taie.ir.exp.BinaryExp; @@ -36,6 +35,9 @@ import pascal.taie.ir.exp.Var; import pascal.taie.ir.stmt.DefinitionStmt; import pascal.taie.ir.stmt.Stmt; +import pascal.taie.util.Indexer; +import pascal.taie.util.SimpleIndexer; +import pascal.taie.util.collection.IndexerBitSet; /** * Available expression analysis on local variables. @@ -61,8 +63,18 @@ protected Analysis makeAnalysis(CFG cfg) { private static class Analysis extends AbstractDataflowAnalysis> { + private final Indexer expIndexer; + + /** + * Set of all expressions in cfg. + * Used to fast create universal set (via copy). + */ + private final SetFact universalSet; + private Analysis(CFG cfg) { super(cfg); + expIndexer = new SimpleIndexer<>(); + universalSet = computeUniversalSet(cfg, expIndexer); } @Override @@ -72,12 +84,12 @@ public boolean isForward() { @Override public SetFact newBoundaryFact() { - return new ToppedSetFact<>(false); + return new SetFact<>(new IndexerBitSet<>(expIndexer, false)); } @Override public SetFact newInitialFact() { - return new ToppedSetFact<>(true); + return universalSet.copy(); } @Override @@ -87,21 +99,16 @@ public void meetInto(SetFact fact, SetFact target) { @Override public boolean transferNode(Stmt stmt, SetFact in, SetFact out) { - if (((ToppedSetFact) in).isTop()) { - // valid data facts have not arrived yet, just skip and return - // true to ensure that the successor Stmts will be analyzed later - return true; - } SetFact oldOut = out.copy(); out.set(in); - if (stmt instanceof DefinitionStmt) { - Exp lvalue = ((DefinitionStmt) stmt).getLValue(); + if (stmt instanceof DefinitionStmt defStmt) { + Exp lvalue = defStmt.getLValue(); if (lvalue instanceof Var defVar) { // kill affected expressions out.removeIf(expWrapper -> expWrapper.get().getUses().contains(defVar)); } - Exp rvalue = ((DefinitionStmt) stmt).getRValue(); + Exp rvalue = defStmt.getRValue(); if (isRelevant(rvalue)) { // generate available expressions out.add(new ExpWrapper(rvalue)); @@ -110,6 +117,22 @@ public boolean transferNode(Stmt stmt, SetFact in, SetFact computeUniversalSet( + CFG cfg, Indexer expIndexer) { + SetFact set = new SetFact<>( + new IndexerBitSet<>(expIndexer, false)); + cfg.forEach(stmt -> { + if (stmt instanceof DefinitionStmt defStmt + && isRelevant(defStmt.getRValue())) { + set.add(new ExpWrapper(defStmt.getRValue())); + } + }); + return set; + } + /** * Checks if an expression is relevant to available expressions. * We only consider these expressions as available expressions. diff --git a/src/main/java/pascal/taie/analysis/dataflow/fact/ToppedSetFact.java b/src/main/java/pascal/taie/analysis/dataflow/fact/ToppedSetFact.java deleted file mode 100644 index b453004b6..000000000 --- a/src/main/java/pascal/taie/analysis/dataflow/fact/ToppedSetFact.java +++ /dev/null @@ -1,179 +0,0 @@ -/* - * Tai-e: A Static Analysis Framework for Java - * - * Copyright (C) 2022 Tian Tan - * Copyright (C) 2022 Yue Li - * - * This file is part of Tai-e. - * - * Tai-e is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation, either version 3 - * of the License, or (at your option) any later version. - * - * Tai-e is distributed in the hope that it will be useful,but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General - * Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with Tai-e. If not, see . - */ - -package pascal.taie.analysis.dataflow.fact; - -import pascal.taie.util.Hashes; - -import java.util.Collection; -import java.util.function.Predicate; -import java.util.stream.Stream; - -/** - * Represents set-like data-flow facts. - * This fact can represent a top element in the lattice, i.e., Universe. - * Note that the top element is conceptual, i.e., it is mock and does not - * really contain all elements in the domain, thus remove and iteration - * operations on the top element are unsupported. - * - * @param type of elements - */ -public class ToppedSetFact extends SetFact { - - private boolean isTop; - - public ToppedSetFact(boolean isTop) { - this.isTop = isTop; - } - - public ToppedSetFact(Collection c) { - super(c); - this.isTop = false; - } - - public boolean isTop() { - return isTop; - } - - public void setTop(boolean top) { - isTop = top; - if (isTop) { - // top element is mock and does not need to store any values. - set.clear(); - } - } - - @Override - public boolean contains(E e) { - return isTop || super.contains(e); - } - - @Override - public boolean add(E e) { - return !isTop && super.add(e); - } - - @Override - public boolean remove(E e) { - if (isTop) { - throw new UnsupportedOperationException(); - } - return super.remove(e); - } - - @Override - public boolean removeIf(Predicate filter) { - if (isTop) { - throw new UnsupportedOperationException(); - } - return super.removeIf(filter); - } - - @Override - public boolean union(SetFact other) { - if (isTop) { - return false; - } - ToppedSetFact fact = (ToppedSetFact) other; - if (fact.isTop) { - setTop(true); - return true; - } - return super.union(other); - } - - @Override - public boolean intersect(SetFact other) { - ToppedSetFact fact = (ToppedSetFact) other; - if (fact.isTop) { - return false; - } - if (isTop) { - set(other); - return true; - } - return super.intersect(other); - } - - @Override - public void set(SetFact other) { - ToppedSetFact fact = (ToppedSetFact) other; - isTop = fact.isTop; - super.set(other); - } - - @Override - public ToppedSetFact copy() { - ToppedSetFact copy = new ToppedSetFact<>(set); - copy.setTop(isTop); - return copy; - } - - @Override - public void clear() { - isTop = false; - super.clear(); - } - - @Override - public boolean isEmpty() { - return !isTop && super.isEmpty(); - } - - @Override - public Stream stream() { - if (isTop) { - throw new UnsupportedOperationException(); - } - return super.stream(); - } - - @Override - public int size() { - if (isTop) { - throw new UnsupportedOperationException(); - } - return super.size(); - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - ToppedSetFact that = (ToppedSetFact) o; - return isTop == that.isTop && super.equals(that); - } - - @Override - public int hashCode() { - return Hashes.hash(isTop, super.hashCode()); - } - - @Override - public String toString() { - return isTop ? "{TOP}" : super.toString(); - } -} diff --git a/src/test/java/pascal/taie/analysis/dataflow/fact/FactTest.java b/src/test/java/pascal/taie/analysis/dataflow/fact/FactTest.java index eb08d2659..5d6b521f4 100644 --- a/src/test/java/pascal/taie/analysis/dataflow/fact/FactTest.java +++ b/src/test/java/pascal/taie/analysis/dataflow/fact/FactTest.java @@ -25,37 +25,12 @@ import org.junit.jupiter.api.Test; import java.util.Arrays; -import java.util.List; import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; - public class FactTest { - @Test - void testToppedSetFact() { - ToppedSetFact top = new ToppedSetFact<>(true); - ToppedSetFact fact1 = top.copy(); - fact1.intersect(top); - assertTrue(fact1.isTop()); - - ToppedSetFact fact2 = new ToppedSetFact<>(List.of(1, 2, 3)); - fact1.intersect(fact2); - assertFalse(fact1.isTop()); - fact2.union(top); - assertTrue(fact2.isTop()); - - ToppedSetFact fact3 = new ToppedSetFact<>(List.of(8, 9, 10)); - fact2.union(fact3); - assertTrue(fact2.isTop()); - fact2.intersect(top); - assertTrue(fact2.isTop()); - fact2.intersect(fact3); - assertFalse(fact2.isTop()); - } - @Test void testUnionNormal() { // Union overlapped sets