提交 9c431514 编辑于 作者: Ricolove's avatar Ricolove
浏览文件

assi 5 finished

上级 c3f529bd
......@@ -2,7 +2,7 @@
## Where Should I Start?
本次实验对接口阅读的需求非常大,我习惯从最顶层的 `analyze` 开始,然后先实现 `propagate``addEdge` 这两个过程内分析也需要的函数,然后再是过程间分析的 `processCall``addReachable`.
本次实验对算法理解和接口阅读的需求非常大,我习惯从最顶层的 `analyze` 开始,然后先实现 `propagate``addEdge` 这两个过程内分析也需要的函数,然后再是过程间分析的 `processCall``addReachable`.
......@@ -40,7 +40,7 @@
### 静态方法的处理
### 新规则的处理
本节主要是介绍新引入的 static/array 部分如何处理。
......@@ -78,3 +78,53 @@
## Tai-e FAQ You Need to Know
### `analyze`
<img src="img/Assignment 5/image-20211112220003102.png" alt="image-20211112220003102" style="zoom: 67%;" />
* 前面已经提到,`initialize` 已经完成了开头两个语句,所以不需要再 `analyze` 里面做了。
* 算法中的 `delta = ...``propagate(n, delta)` 在代码框架中被合并成了一个函数。确实你可以把计算 `delta` 的语句独立到 `propagate` 之外,但是考虑到要实现 `propagate` 要返回 `delta` 的语义,还是把它们合起来做吧。
* `foreach x.f = y in S do ...` 这几个算法里,如何获取 `x.f = y` 的对应语句在上一节已经提到过了,这里就不再赘述。这里的问题是,如何把 `o.f` 提取出来。
我们首先需要知道 `f` 是什么,这个问题可以看手册 2.4 addReachable 2) 来解决。然后,我们该怎么把 `o_i``f` 拼起来得到 `o_i.f` 呢?相应的 API 在 `pointerFlowGraph` 里面,请记住 `o_i.f` 这种东西叫做:
![image-20211112220846683](img/Assignment 5/image-20211112220846683.png)
* 为了不混淆 `addPFGEdge` 的 source 和 target,你可以令自己把 o_f, y 这些变量显式地写出来,然后再简洁地写上 `addPFGEdge(y, o.f)`,这虽然没有全写到一行干净利落,但是便于你 debug。
* 不要忘了处理 array.
* 由于 pointer 有 4 种类型,你可能会想要不要 `if n represents an instanceField o_f then` 这样子,给算法加加码。强调一下,不用!
### `addPFGEdge`
* 这个没什么好说的,就是调用 PFG 提供的 API 就好了。
### `propagate`
![image-20211112221737810](img/Assignment 5/image-20211112221737810.png)
* 关于 `delta` 的计算,你可以遍历 `pts`,跳过其中 `pt(n)` 有的元素,逐个构成 `delta`。不过,考虑到 `PointToSet.objects()` 返回的是一个 `stream`,你也可以用 `stream` 的方法来生成一个 `delta`。酷炫就完事了。(我试了,能行,但是我没用这个代码,所以把它贴出来,哈哈哈)
```java
pointsToSet.objects().filter(ptsObj -> pointer.getPointsToSet().objects().noneMatch(ptnObj -> ptnObj.equals(ptsObj))).forEach(delta::addObject);
```
### `processCall`
<img src="img/Assignment 5/image-20211112222247197.png" alt="image-20211112222247197" style="zoom:67%;" />
* 首先,static call 也是同样的处理逻辑,但是不需要 dispatch o_i,也不需要把 o_i 加到 m_this 里面(静态的哪来 object),但是 `processCall` 在语义上要求处理 instance call,所以还是不要把它改成能处理 static call 的样子,并把 `foreach l: r = x.k(...) in S do` 分拆到函数外。推荐把后面相同的处理逻辑提取一个新的函数出来,然后在 `processCall``addReachable` 都去调用。
* `Solver.resolveCallee()` 能处理所有种类的 invoke,所以不需要专门为 virtual call 从 hierarchy 里面拿 dispatch 函数出来了。事实上,如果你去看它的内部实现,在遇到 virtual call 时确实也去调了 `dispatch`。有更加全能,更兼容的 API,当然要用啦!
* `Solver.resolveCallee()` 返回的是 `JMethod`,但是如何根据 `JMethod` 拿到对应的 `this` 变量呢?答案是 `getIR`,IR 可以提供 `this` 变量。同样的,后面的 `return` 变量也是在 IR 里获取。
* 连接 CG 的边,逻辑是和 Assignment 4 一样的,但是 `getCallKind` 所属的 `CallGraphs.java` 在本次作业中放到了 `lib` 里,所以 IDEA 可能不会立刻给你补全。
### `addReachable` / `StmtProcessor`
![image-20211112223932920](img/Assignment 5/image-20211112223932920.png)
* 前面已经提到过 `S` 在代码实现中的修改,这里不再赘述。总之,你在 `addReachable` 里面要做的事情就是遍历新 reach 到的方法的每一个 stmt,并根据其是否属于 New, Copy 等,分别作出处理。这个遍历的方法既可以是一个个 `instanceof`,也可以用 `stmt.accept(stmtProcessor)` 来充分利用框架提供的 visitor 模式。
* 你可能注意到了,`int a = 1`, `String b = "word"` 这样的语句在本次实验中并不会出现,所以不需要针对它们做支持。
*`addReachable` 只需要处理 `New`, `Copy`, 以及静态的 `Inoke`, `StoreField`, `LoadField`,不需要多处理别的。
* 对于静态的 `Invoke`,其处理逻辑与 `processCall` 基本相同。需要注意的是,手册中 `1) do not need to dispatch on the receiver object` 说的是不需要**对 `recv` 做 dispatch**(因为 `recv == null`),但是不代表你不需要做 dispatch,这里依旧是调用 `resolveCallee` 就好了。
* 如果你是和我一样先写的 `analyze` ,那么你应该知道 `T.f` 应该去什么地方找了。
\ No newline at end of file
Supports Markdown
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册