官方文档,代码仓库,ISSTA 2023 论文,静态程序分析框架“太阿”的设计之道。
已完成全部作业,简单看下 Tai-e 科研版是如何实现作业的,以及作业涉及的部分接口和类的源码。
在分析的实现中,Stream 使用的比较多,然后就是某些比较好用的 API 在作业中没有注意到,代码中也有使用高版本 Java 的某些新特性。基本上每个包都有 package-info.java
文件,描述当前包的关键信息,还是很不错的。我没怎么看和作业关系不大的源码,它涉及到的东西比较多,需要额外的理论知识。
IR
FieldRef
特点:私有构造函数和静态工厂方法;Record Classes;缓存实例对象;向方法传递 Runnable
类型的对象来实现回调。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| public class FieldRef extends MemberRef {
private static final ConcurrentMap<Key, FieldRef> map = Maps.newConcurrentMap(4096);
static { World.registerResetCallback(map::clear); }
public static FieldRef get( JClass declaringClass, String name, Type type, boolean isStatic) { Key key = new Key(declaringClass, name, type); return map.computeIfAbsent(key, k -> new FieldRef(k, isStatic)); }
private FieldRef(Key key, boolean isStatic) { ... }
private record Key(JClass declaringClass, String name, Type type) { } }
|
Var
特点:使用内部类存储和当前 Var
相关的语句,而不是直接包含在当前类中;使用 transient
、writeObject
和 readObject
显示控制序列化,避免反序列化创建多个单例对象;使用 Collections.unmodifiableList
方法返回不可修改的列表。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| public class Var implements LValue, RValue, Indexable {
private transient RelevantStmts relevantStmts = RelevantStmts.EMPTY;
@Serial private void writeObject(ObjectOutputStream s) throws IOException { s.defaultWriteObject(); if (relevantStmts == RelevantStmts.EMPTY) { s.writeObject(null); } else { s.writeObject(relevantStmts); } }
@Serial private void readObject(ObjectInputStream s) throws IOException, ClassNotFoundException { s.defaultReadObject(); relevantStmts = (RelevantStmts) s.readObject(); if (relevantStmts == null) { relevantStmts = RelevantStmts.EMPTY; } }
private static class RelevantStmts implements Serializable {
private static final RelevantStmts EMPTY = new RelevantStmts();
private static <T> List<T> unmodifiable(List<T> list) { return list.isEmpty() ? list : Collections.unmodifiableList(list); } } }
|
Stmt
特点:Stmt
包含以 StmtVisitor
类型作为参数的 accept
泛型方法,可以用于实现访问者模式。
1 2 3 4
| public interface Stmt extends Indexable, Serializable {
<T> T accept(StmtVisitor<T> visitor); }
|
1 2 3 4 5 6 7 8 9 10 11
| public interface StmtVisitor<T> {
default T visit(New stmt) { return visitDefault(stmt); }
default T visitDefault(Stmt stmt) { return null; } }
|
DefinitionStmt
特点:使用 <L extends LValue, R extends RValue>
泛型,对表达式进行限定,所有具体的子类都会使用具体的类型替换限定的类型。
1 2
| DefinitionStmt<L extends LValue, R extends RValue> Invoke extends DefinitionStmt<Var, InvokeExp>
|
Analysis
特点:LiveVariable
的实现,删除变量使用 ifPresent
+ lambda 处理,代码比较简洁。ConstantPropagation
的 newBoundaryFact
使用 Stream 来实现,而我是使用普通的方式实现的。Evaluator
类中的 evaluate
方法,使用了扩展的 Switch Expressions,可以省略 break
。InterConstantPropagation
实现 Alias-Aware 时,使用访问者模式处理 Load 和 Store 语句。指针分析和作业时区别比较大,没有细看。
核心组成