diff --git a/.gitbook/assets/concurrentProgram (1).png b/.gitbook/assets/concurrentProgram (1).png
new file mode 100644
index 0000000..b993b8e
Binary files /dev/null and b/.gitbook/assets/concurrentProgram (1).png differ
diff --git a/.gitbook/assets/harmonyOS (1).png b/.gitbook/assets/harmonyOS (1).png
new file mode 100644
index 0000000..885b3a2
Binary files /dev/null and b/.gitbook/assets/harmonyOS (1).png differ
diff --git a/ch4/04-01-inter-analysis-spa.assets/image-20201029224401395.png b/.gitbook/assets/image-20201029224401395.png
similarity index 100%
rename from ch4/04-01-inter-analysis-spa.assets/image-20201029224401395.png
rename to .gitbook/assets/image-20201029224401395.png
diff --git a/ch4/04-01-inter-analysis-spa.assets/image-20201029224437136.png b/.gitbook/assets/image-20201029224437136.png
similarity index 100%
rename from ch4/04-01-inter-analysis-spa.assets/image-20201029224437136.png
rename to .gitbook/assets/image-20201029224437136.png
diff --git a/ch4/04-01-inter-analysis-spa.assets/image-20201029224506176.png b/.gitbook/assets/image-20201029224506176.png
similarity index 100%
rename from ch4/04-01-inter-analysis-spa.assets/image-20201029224506176.png
rename to .gitbook/assets/image-20201029224506176.png
diff --git a/ch4/04-01-inter-analysis-spa.assets/image-20201029224736803.png b/.gitbook/assets/image-20201029224736803.png
similarity index 100%
rename from ch4/04-01-inter-analysis-spa.assets/image-20201029224736803.png
rename to .gitbook/assets/image-20201029224736803.png
diff --git a/ch4/04-01-inter-analysis-spa.assets/image-20201029224820647.png b/.gitbook/assets/image-20201029224820647.png
similarity index 100%
rename from ch4/04-01-inter-analysis-spa.assets/image-20201029224820647.png
rename to .gitbook/assets/image-20201029224820647.png
diff --git a/ch4/04-01-inter-analysis-spa.assets/image-20201029224941882.png b/.gitbook/assets/image-20201029224941882.png
similarity index 100%
rename from ch4/04-01-inter-analysis-spa.assets/image-20201029224941882.png
rename to .gitbook/assets/image-20201029224941882.png
diff --git a/ch4/04-01-inter-analysis-spa.assets/image-20201029225106724.png b/.gitbook/assets/image-20201029225106724.png
similarity index 100%
rename from ch4/04-01-inter-analysis-spa.assets/image-20201029225106724.png
rename to .gitbook/assets/image-20201029225106724.png
diff --git a/ch4/04-01-inter-analysis-spa.assets/image-20201029225304889.png b/.gitbook/assets/image-20201029225304889.png
similarity index 100%
rename from ch4/04-01-inter-analysis-spa.assets/image-20201029225304889.png
rename to .gitbook/assets/image-20201029225304889.png
diff --git a/ch4/04-01-inter-analysis-spa.assets/image-20201029225350619.png b/.gitbook/assets/image-20201029225350619.png
similarity index 100%
rename from ch4/04-01-inter-analysis-spa.assets/image-20201029225350619.png
rename to .gitbook/assets/image-20201029225350619.png
diff --git a/ch4/04-01-inter-analysis-spa.assets/image-20201029230138054.png b/.gitbook/assets/image-20201029230138054.png
similarity index 100%
rename from ch4/04-01-inter-analysis-spa.assets/image-20201029230138054.png
rename to .gitbook/assets/image-20201029230138054.png
diff --git a/ch4/04-01-inter-analysis-spa.assets/image-20201029230224316.png b/.gitbook/assets/image-20201029230224316.png
similarity index 100%
rename from ch4/04-01-inter-analysis-spa.assets/image-20201029230224316.png
rename to .gitbook/assets/image-20201029230224316.png
diff --git a/ch4/04-01-inter-analysis-spa.assets/image-20201029230504891.png b/.gitbook/assets/image-20201029230504891.png
similarity index 100%
rename from ch4/04-01-inter-analysis-spa.assets/image-20201029230504891.png
rename to .gitbook/assets/image-20201029230504891.png
diff --git a/ch4/04-01-inter-analysis-spa.assets/image-20201029230535984.png b/.gitbook/assets/image-20201029230535984.png
similarity index 100%
rename from ch4/04-01-inter-analysis-spa.assets/image-20201029230535984.png
rename to .gitbook/assets/image-20201029230535984.png
diff --git a/ch4/04-01-inter-analysis-spa.assets/image-20201029230622120.png b/.gitbook/assets/image-20201029230622120.png
similarity index 100%
rename from ch4/04-01-inter-analysis-spa.assets/image-20201029230622120.png
rename to .gitbook/assets/image-20201029230622120.png
diff --git a/ch4/04-01-inter-analysis-spa.assets/image-20201029230909895.png b/.gitbook/assets/image-20201029230909895.png
similarity index 100%
rename from ch4/04-01-inter-analysis-spa.assets/image-20201029230909895.png
rename to .gitbook/assets/image-20201029230909895.png
diff --git a/ch4/04-01-inter-analysis-spa.assets/image-20201029231106891.png b/.gitbook/assets/image-20201029231106891.png
similarity index 100%
rename from ch4/04-01-inter-analysis-spa.assets/image-20201029231106891.png
rename to .gitbook/assets/image-20201029231106891.png
diff --git a/ch4/04-01-inter-analysis-spa.assets/image-20201029231132412.png b/.gitbook/assets/image-20201029231132412.png
similarity index 100%
rename from ch4/04-01-inter-analysis-spa.assets/image-20201029231132412.png
rename to .gitbook/assets/image-20201029231132412.png
diff --git a/ch4/04-01-inter-analysis-spa.assets/image-20201029231155238.png b/.gitbook/assets/image-20201029231155238.png
similarity index 100%
rename from ch4/04-01-inter-analysis-spa.assets/image-20201029231155238.png
rename to .gitbook/assets/image-20201029231155238.png
diff --git a/ch4/04-01-inter-analysis-spa.assets/image-20201029231304304.png b/.gitbook/assets/image-20201029231304304.png
similarity index 100%
rename from ch4/04-01-inter-analysis-spa.assets/image-20201029231304304.png
rename to .gitbook/assets/image-20201029231304304.png
diff --git a/ch4/04-01-inter-analysis-spa.assets/image-20201029231543567.png b/.gitbook/assets/image-20201029231543567.png
similarity index 100%
rename from ch4/04-01-inter-analysis-spa.assets/image-20201029231543567.png
rename to .gitbook/assets/image-20201029231543567.png
diff --git a/ch4/04-01-inter-analysis-spa.assets/image-20201029231611608.png b/.gitbook/assets/image-20201029231611608.png
similarity index 100%
rename from ch4/04-01-inter-analysis-spa.assets/image-20201029231611608.png
rename to .gitbook/assets/image-20201029231611608.png
diff --git a/ch4/04-01-inter-analysis-spa.assets/image-20201029231706834.png b/.gitbook/assets/image-20201029231706834.png
similarity index 100%
rename from ch4/04-01-inter-analysis-spa.assets/image-20201029231706834.png
rename to .gitbook/assets/image-20201029231706834.png
diff --git a/ch4/04-01-inter-analysis-spa.assets/image-20201029231908883.png b/.gitbook/assets/image-20201029231908883.png
similarity index 100%
rename from ch4/04-01-inter-analysis-spa.assets/image-20201029231908883.png
rename to .gitbook/assets/image-20201029231908883.png
diff --git a/ch4/04-01-inter-analysis-spa.assets/image-20201029231936719.png b/.gitbook/assets/image-20201029231936719.png
similarity index 100%
rename from ch4/04-01-inter-analysis-spa.assets/image-20201029231936719.png
rename to .gitbook/assets/image-20201029231936719.png
diff --git a/ch4/04-01-inter-analysis-spa.assets/image-20201029231952670.png b/.gitbook/assets/image-20201029231952670.png
similarity index 100%
rename from ch4/04-01-inter-analysis-spa.assets/image-20201029231952670.png
rename to .gitbook/assets/image-20201029231952670.png
diff --git a/.gitbook/assets/image-20201105183618529.png b/.gitbook/assets/image-20201105183618529.png
new file mode 100644
index 0000000..10bd49a
Binary files /dev/null and b/.gitbook/assets/image-20201105183618529.png differ
diff --git a/.gitbook/assets/image-20201105184327763.png b/.gitbook/assets/image-20201105184327763.png
new file mode 100644
index 0000000..52cb86a
Binary files /dev/null and b/.gitbook/assets/image-20201105184327763.png differ
diff --git a/.gitbook/assets/image-20201105184919660.png b/.gitbook/assets/image-20201105184919660.png
new file mode 100644
index 0000000..4ca6dd2
Binary files /dev/null and b/.gitbook/assets/image-20201105184919660.png differ
diff --git a/.gitbook/assets/image-20201105185230667.png b/.gitbook/assets/image-20201105185230667.png
new file mode 100644
index 0000000..5ec9490
Binary files /dev/null and b/.gitbook/assets/image-20201105185230667.png differ
diff --git a/.gitbook/assets/image-20201105185431196.png b/.gitbook/assets/image-20201105185431196.png
new file mode 100644
index 0000000..6d8f27b
Binary files /dev/null and b/.gitbook/assets/image-20201105185431196.png differ
diff --git a/.gitbook/assets/image-20201105185630758.png b/.gitbook/assets/image-20201105185630758.png
new file mode 100644
index 0000000..682bd11
Binary files /dev/null and b/.gitbook/assets/image-20201105185630758.png differ
diff --git a/.gitbook/assets/image-20201105185806532.png b/.gitbook/assets/image-20201105185806532.png
new file mode 100644
index 0000000..b2dad83
Binary files /dev/null and b/.gitbook/assets/image-20201105185806532.png differ
diff --git a/.gitbook/assets/image-20201105190333596.png b/.gitbook/assets/image-20201105190333596.png
new file mode 100644
index 0000000..9bc3c06
Binary files /dev/null and b/.gitbook/assets/image-20201105190333596.png differ
diff --git a/.gitbook/assets/image-20201105190439805.png b/.gitbook/assets/image-20201105190439805.png
new file mode 100644
index 0000000..f684484
Binary files /dev/null and b/.gitbook/assets/image-20201105190439805.png differ
diff --git a/.gitbook/assets/image-20201105191248594.png b/.gitbook/assets/image-20201105191248594.png
new file mode 100644
index 0000000..ff0c688
Binary files /dev/null and b/.gitbook/assets/image-20201105191248594.png differ
diff --git a/.gitbook/assets/image-20201105191705757.png b/.gitbook/assets/image-20201105191705757.png
new file mode 100644
index 0000000..bf42ed6
Binary files /dev/null and b/.gitbook/assets/image-20201105191705757.png differ
diff --git a/.gitbook/assets/image-20201105194030384.png b/.gitbook/assets/image-20201105194030384.png
new file mode 100644
index 0000000..95e448e
Binary files /dev/null and b/.gitbook/assets/image-20201105194030384.png differ
diff --git a/.gitbook/assets/image-20201105194707507.png b/.gitbook/assets/image-20201105194707507.png
new file mode 100644
index 0000000..a8c3c44
Binary files /dev/null and b/.gitbook/assets/image-20201105194707507.png differ
diff --git a/.gitbook/assets/image-20201105195029800.png b/.gitbook/assets/image-20201105195029800.png
new file mode 100644
index 0000000..308d318
Binary files /dev/null and b/.gitbook/assets/image-20201105195029800.png differ
diff --git a/.gitbook/assets/image-20201105195154527.png b/.gitbook/assets/image-20201105195154527.png
new file mode 100644
index 0000000..73b2849
Binary files /dev/null and b/.gitbook/assets/image-20201105195154527.png differ
diff --git a/.gitbook/assets/image-20201105195524932.png b/.gitbook/assets/image-20201105195524932.png
new file mode 100644
index 0000000..bfeee20
Binary files /dev/null and b/.gitbook/assets/image-20201105195524932.png differ
diff --git a/.gitbook/assets/image-20201105195843958.png b/.gitbook/assets/image-20201105195843958.png
new file mode 100644
index 0000000..8643416
Binary files /dev/null and b/.gitbook/assets/image-20201105195843958.png differ
diff --git a/.gitbook/assets/image-20201105195943007.png b/.gitbook/assets/image-20201105195943007.png
new file mode 100644
index 0000000..ce9b2ed
Binary files /dev/null and b/.gitbook/assets/image-20201105195943007.png differ
diff --git a/.gitbook/assets/image-20201105200112512.png b/.gitbook/assets/image-20201105200112512.png
new file mode 100644
index 0000000..ae81be7
Binary files /dev/null and b/.gitbook/assets/image-20201105200112512.png differ
diff --git a/.gitbook/assets/image-20201105200123601.png b/.gitbook/assets/image-20201105200123601.png
new file mode 100644
index 0000000..c7244d4
Binary files /dev/null and b/.gitbook/assets/image-20201105200123601.png differ
diff --git a/.gitbook/assets/image-20201105200412145.png b/.gitbook/assets/image-20201105200412145.png
new file mode 100644
index 0000000..f7cfdb3
Binary files /dev/null and b/.gitbook/assets/image-20201105200412145.png differ
diff --git a/.gitbook/assets/image-20201105200815104.png b/.gitbook/assets/image-20201105200815104.png
new file mode 100644
index 0000000..7ad90d7
Binary files /dev/null and b/.gitbook/assets/image-20201105200815104.png differ
diff --git a/.gitbook/assets/image-20201105201018655.png b/.gitbook/assets/image-20201105201018655.png
new file mode 100644
index 0000000..0df99f0
Binary files /dev/null and b/.gitbook/assets/image-20201105201018655.png differ
diff --git a/.gitbook/assets/image-20201105201421501.png b/.gitbook/assets/image-20201105201421501.png
new file mode 100644
index 0000000..c95e162
Binary files /dev/null and b/.gitbook/assets/image-20201105201421501.png differ
diff --git a/.gitbook/assets/image-20201105201746860.png b/.gitbook/assets/image-20201105201746860.png
new file mode 100644
index 0000000..1f243f7
Binary files /dev/null and b/.gitbook/assets/image-20201105201746860.png differ
diff --git a/.gitbook/assets/image-20201105201939088.png b/.gitbook/assets/image-20201105201939088.png
new file mode 100644
index 0000000..dee8eda
Binary files /dev/null and b/.gitbook/assets/image-20201105201939088.png differ
diff --git a/.gitbook/assets/image-20201105202101633.png b/.gitbook/assets/image-20201105202101633.png
new file mode 100644
index 0000000..12862bc
Binary files /dev/null and b/.gitbook/assets/image-20201105202101633.png differ
diff --git a/.gitbook/assets/image-20201105235312349.png b/.gitbook/assets/image-20201105235312349.png
new file mode 100644
index 0000000..e39e1d2
Binary files /dev/null and b/.gitbook/assets/image-20201105235312349.png differ
diff --git a/.gitbook/assets/image-20201109140057119.png b/.gitbook/assets/image-20201109140057119.png
new file mode 100644
index 0000000..af792bf
Binary files /dev/null and b/.gitbook/assets/image-20201109140057119.png differ
diff --git a/.gitbook/assets/image-20201109140605829.png b/.gitbook/assets/image-20201109140605829.png
new file mode 100644
index 0000000..734b311
Binary files /dev/null and b/.gitbook/assets/image-20201109140605829.png differ
diff --git a/.gitbook/assets/image-20201109154728420.png b/.gitbook/assets/image-20201109154728420.png
new file mode 100644
index 0000000..5dfc9c5
Binary files /dev/null and b/.gitbook/assets/image-20201109154728420.png differ
diff --git a/.gitbook/assets/image-20201109154844509.png b/.gitbook/assets/image-20201109154844509.png
new file mode 100644
index 0000000..a87a615
Binary files /dev/null and b/.gitbook/assets/image-20201109154844509.png differ
diff --git a/.gitbook/assets/image-20201112191544354.png b/.gitbook/assets/image-20201112191544354.png
new file mode 100644
index 0000000..41999c5
Binary files /dev/null and b/.gitbook/assets/image-20201112191544354.png differ
diff --git a/.gitbook/assets/image-20201112191630283.png b/.gitbook/assets/image-20201112191630283.png
new file mode 100644
index 0000000..2df8e4a
Binary files /dev/null and b/.gitbook/assets/image-20201112191630283.png differ
diff --git a/.gitbook/assets/image-20201112193329365.png b/.gitbook/assets/image-20201112193329365.png
new file mode 100644
index 0000000..e147402
Binary files /dev/null and b/.gitbook/assets/image-20201112193329365.png differ
diff --git a/.gitbook/assets/image-20201112193357268.png b/.gitbook/assets/image-20201112193357268.png
new file mode 100644
index 0000000..b87fb5c
Binary files /dev/null and b/.gitbook/assets/image-20201112193357268.png differ
diff --git a/.gitbook/assets/image-20201112194234928.png b/.gitbook/assets/image-20201112194234928.png
new file mode 100644
index 0000000..13f5e68
Binary files /dev/null and b/.gitbook/assets/image-20201112194234928.png differ
diff --git a/.gitbook/assets/image-20201112194358502.png b/.gitbook/assets/image-20201112194358502.png
new file mode 100644
index 0000000..4017d84
Binary files /dev/null and b/.gitbook/assets/image-20201112194358502.png differ
diff --git a/.gitbook/assets/image-20201112194555582.png b/.gitbook/assets/image-20201112194555582.png
new file mode 100644
index 0000000..8479076
Binary files /dev/null and b/.gitbook/assets/image-20201112194555582.png differ
diff --git a/.gitbook/assets/image-20201112195502575.png b/.gitbook/assets/image-20201112195502575.png
new file mode 100644
index 0000000..9a8995a
Binary files /dev/null and b/.gitbook/assets/image-20201112195502575.png differ
diff --git a/.gitbook/assets/image-20201123205009821.png b/.gitbook/assets/image-20201123205009821.png
new file mode 100644
index 0000000..88c7a74
Binary files /dev/null and b/.gitbook/assets/image-20201123205009821.png differ
diff --git a/.gitbook/assets/image-20201126184745576.png b/.gitbook/assets/image-20201126184745576.png
new file mode 100644
index 0000000..cf2f33e
Binary files /dev/null and b/.gitbook/assets/image-20201126184745576.png differ
diff --git a/.gitbook/assets/image-20201126185008506.png b/.gitbook/assets/image-20201126185008506.png
new file mode 100644
index 0000000..09b059d
Binary files /dev/null and b/.gitbook/assets/image-20201126185008506.png differ
diff --git a/.gitbook/assets/image-20201126185233403.png b/.gitbook/assets/image-20201126185233403.png
new file mode 100644
index 0000000..95ebc7b
Binary files /dev/null and b/.gitbook/assets/image-20201126185233403.png differ
diff --git a/.gitbook/assets/image-20201126191225969.png b/.gitbook/assets/image-20201126191225969.png
new file mode 100644
index 0000000..5e5d3a7
Binary files /dev/null and b/.gitbook/assets/image-20201126191225969.png differ
diff --git a/.gitbook/assets/image-20201126191650221.png b/.gitbook/assets/image-20201126191650221.png
new file mode 100644
index 0000000..dfe4105
Binary files /dev/null and b/.gitbook/assets/image-20201126191650221.png differ
diff --git a/.gitbook/assets/image-20201126194125039.png b/.gitbook/assets/image-20201126194125039.png
new file mode 100644
index 0000000..8a4297f
Binary files /dev/null and b/.gitbook/assets/image-20201126194125039.png differ
diff --git a/.gitbook/assets/image-20201126195311513.png b/.gitbook/assets/image-20201126195311513.png
new file mode 100644
index 0000000..c580c62
Binary files /dev/null and b/.gitbook/assets/image-20201126195311513.png differ
diff --git a/.gitbook/assets/image-20201126195425756.png b/.gitbook/assets/image-20201126195425756.png
new file mode 100644
index 0000000..989236e
Binary files /dev/null and b/.gitbook/assets/image-20201126195425756.png differ
diff --git a/.gitbook/assets/image-20201126201000426.png b/.gitbook/assets/image-20201126201000426.png
new file mode 100644
index 0000000..407c3e5
Binary files /dev/null and b/.gitbook/assets/image-20201126201000426.png differ
diff --git a/.gitbook/assets/image-20201126221950557.png b/.gitbook/assets/image-20201126221950557.png
new file mode 100644
index 0000000..c10ac7b
Binary files /dev/null and b/.gitbook/assets/image-20201126221950557.png differ
diff --git a/.gitbook/assets/image-20201126230831572.png b/.gitbook/assets/image-20201126230831572.png
new file mode 100644
index 0000000..e56c02b
Binary files /dev/null and b/.gitbook/assets/image-20201126230831572.png differ
diff --git a/.gitbook/assets/image-20201126231116221.png b/.gitbook/assets/image-20201126231116221.png
new file mode 100644
index 0000000..191d4dd
Binary files /dev/null and b/.gitbook/assets/image-20201126231116221.png differ
diff --git a/.gitbook/assets/image-20201126231403264.png b/.gitbook/assets/image-20201126231403264.png
new file mode 100644
index 0000000..a231743
Binary files /dev/null and b/.gitbook/assets/image-20201126231403264.png differ
diff --git a/.gitbook/assets/image-20201126231437769.png b/.gitbook/assets/image-20201126231437769.png
new file mode 100644
index 0000000..359e541
Binary files /dev/null and b/.gitbook/assets/image-20201126231437769.png differ
diff --git a/.gitbook/assets/image-20201126231722298.png b/.gitbook/assets/image-20201126231722298.png
new file mode 100644
index 0000000..5061652
Binary files /dev/null and b/.gitbook/assets/image-20201126231722298.png differ
diff --git a/.gitbook/assets/image-20201127170432941.png b/.gitbook/assets/image-20201127170432941.png
new file mode 100644
index 0000000..1cc3832
Binary files /dev/null and b/.gitbook/assets/image-20201127170432941.png differ
diff --git a/.gitbook/assets/market.png b/.gitbook/assets/market.png
index 63386c7..d71e22b 100644
Binary files a/.gitbook/assets/market.png and b/.gitbook/assets/market.png differ
diff --git a/README.md b/README.md
index 87e313b..32d9f2b 100644
--- a/README.md
+++ b/README.md
@@ -1,149 +1,155 @@
# 简介
-[《静态程序分析》Gitbook在线阅读地址](https://ranger-nju.gitbook.io/static-program-analysis-book/)
+## 简介
-[《静态程序分析》GitHub项目地址](https://github.com/RangerNJU/Static-Program-Analysis-Book)
+Getting started with static program analysis. Read this and start writing your first static program analyzer! We focus on the problem:
-Getting started with static program analysis. Read this and start writing your first static program analyzer!
+> ❓ How to automatically and efficiently guarantee software quality
-静态程序分析入门。阅读此书并着手编写你的第一个静态程序分析器吧!
+静态程序分析入门。阅读此书并着手编写你的第一个静态程序分析器吧!本仓库关注一个非常重要的问题:
-## 表达你的声音
+> ❓ 如何自动化地高效保障软件质量
-- **批评的意见很有价值。** 这是我第一次书写教程,一定有很多做得不好的地方。如果你觉得有值得修改或值得讨论的地方(包括但不仅限于行文风格,内容准确性,图例与解释的易读性等等),可以选择:
- 1. 加入QQ群(951182704)匿名或实名表达你的意见与看法
- 2. 提issue
- 3. 通过邮箱联系我(ranger.nju#gmail.com)
-- 如果你觉得我写得不错,可以到GitHub仓库中给我一个Star,也可以在自己的社交圈子中宣传,让更多的人了解这个项目。
+* [《静态程序分析》Gitbook在线阅读地址](https://ranger-nju.gitbook.io/static-program-analysis-book/)
+* [《静态程序分析》GitHub项目地址](https://github.com/RangerNJU/Static-Program-Analysis-Book)
+* 离线阅读方式
+ 1. 将本仓库**下载**到本地(安装Git后,在命令行中执行命令`git clone https://github.com/RangerNJU/Static-Program-Analysis-Book.git`)
+ 2. 周期性地**更新**,在仓库目录下执行`git pull`
+ 3. 使用[Typora](https://typora.io/)等本地Markdown阅读器**阅读**
-## 更新记录与里程碑事件
+### 表达你的声音 👂
-1. Oct, 2020. 设立Repo
-2. 16th, Oct. 第一次Star和Fork
-3. 29th, Oct . 更新第七课《Interprocedural Analysis》
-4. 30th, Oct. 第一次PR
-5. 5th, Dec. 将一至六课的文稿暂时移出仓库,晚上更新第八课《Pointer Analysis》
+* **批评的意见很有价值。** 这是我第一次书写教程,一定有很多做得不好的地方。如果你觉得有值得修改或值得讨论的地方(包括但不仅限于行文风格,内容准确性,图例与解释的易读性等等),可以选择:
+1. 加入QQ群(951182704)匿名或实名表达你的意见与看法
+2. 提issue
+3. 通过邮箱联系我(ranger.nju\#gmail.com\)
+ * 如果你觉得我写得不错,可以到GitHub仓库中给我一个Star,也可以在自己的社交圈子中宣传,让更多的人了解这个项目。
-# 这一《静态程序分析》教程对谁有用?
+~~~~👋 ~~根据不完全统计,已经有数千次首页访问,每天都会有数十位世界各地的新读者到访,不过收到的意见和建议寥寥。~~
+
+### 更新记录与里程碑事件
+
+1. Oct, 2020. 设立Repo,一个月内获得Star、Fork和PR 🥳
+2. Nov. 将IR与Data Flow Analysis的相关内容暂时移出仓库,更新七至十课——Interprocedural Analysis、Pointer Analysis-Introduction and Foundations。
+
+## 这一《静态程序分析》教程对谁有用?
学生,开发者,研究者……几乎所有当代生活者都能从中受益。
-- 学习方向与程序有关的**学生。**
- - 计算机方向的学生可以通过深入学习这一领域知识而为自己建立独特的学术和就业优势,也能加深对编程的理解以降低自己写出bug的频率。
- - 其他方向的学生既然已经开始阅读这一页面,想必对计算机方向的内容有一定兴趣。你可以通过了解这一技术,了解静态分析软件(包括其内置于编译器,集成开发环境的部分)能够为你提供怎样的功能和便利,以及如何更好地使用这些软件,以此保证你所关心的程序质量。
-- 工作内容与程序有关的**开发者。**
- - 无论你希望更好地理解[Wiki](https://en.wikipedia.org/wiki/List_of_tools_for_static_code_analysis)上众多的开源或是闭源的静态程序分析技术,还是希望自己开发一个适用于眼下工作内容的静态程序分析器以保证程序质量,了解静态程序分析都会有所帮助。
-- 研究领域与程序相关的**研究者。** 或许你希望微调研究方向,却因没有合适的入门材料而苦恼;或许你希望了解计算机领域的相关知识以期获得启发……这一教程可以作为你的入门材料或是闲暇读物。
-- 生活与程序相关的**每个人**
- - 软件质量是信息化时代的重要议题之一,在这个时代生活与工作,你一定会遇到相关的问题。
- - 在大多数学校和企业中,没有开设该领域的课程。
+* 学习方向与程序有关的**学生。**
+ * 计算机方向的学生可以通过深入学习这一领域知识而为自己建立独特的学术和就业优势,也能加深对编程的理解以降低自己写出bug的频率。
+ * 其他方向的学生既然已经开始阅读这一页面,想必对计算机方向的内容有一定兴趣。你可以通过了解这一技术,了解静态分析软件(包括其内置于编译器,集成开发环境的部分)能够为你提供怎样的功能和便利,以及如何更好地使用这些软件,以此保证你所关心的程序质量。
+* 工作内容与程序有关的**开发者。**
+ * 无论你希望更好地理解[Wiki](https://en.wikipedia.org/wiki/List_of_tools_for_static_code_analysis)上众多的开源或是闭源的静态程序分析技术,还是希望自己开发一个适用于眼下工作内容的静态程序分析器以保证程序质量,了解静态程序分析都会有所帮助。
+* 研究领域与程序相关的**研究者。** 或许你希望微调研究方向,却因没有合适的入门材料而苦恼;或许你希望了解计算机领域的相关知识以期获得启发……这一教程可以作为你的入门材料或是闲暇读物。
+* 生活与程序相关的**每个人**
+ * 软件质量是信息化时代的重要议题之一,在这个时代生活与工作,你一定会遇到相关的问题。
+ * 在大多数学校和企业中,没有开设该领域的课程。
-# 什么是静态程序分析?
+## 什么是静态程序分析?
-## 静态程序分析在计算机科学领域中的定位
+### 静态程序分析在计算机科学领域中的定位
-
+![](.gitbook/assets/PL.png)
**静态程序分析**是**编程语言**中**应用**层面下的一个细分领域,它是一个非常重要的核心内容。
在理论部分,考虑的是如何设计一个语言的语法和语义,如何设计语言的类型系统等等问题;有了语言的语法、语义和类型系统之后,我们需要支撑语言的运行。因此,在环境部分,需要考虑如何为运行中的程序提供运行时环境——如何设计编译器,在运行时需要怎样的支持(如内存的分配管理)等等;应用部分则关注如何保证语言所写出程序的效率、安全性和可靠性,主要考虑如何对程序进行分析,验证和合成(如何自动合成一个程序)。
-### 编程语言的分类
+#### 编程语言的分类
-当今的计算机世界,面对这样一条恶龙:
+当今的计算机世界,面对这样一条恶龙: 👇
-> 数十年来语言的核心没有变化,但软件的规模和复杂性增长迅速,如何保证程序的可靠性?
+> 数十年来语言的核心没有变化,但软件的规模和复杂性增长迅速,如何保证程序的可靠性?
-尽管新的语言和特性层出不穷,但现在编程语言无非三大类 *(如果你对其中的某个语言不熟悉,可以到语言的官网或英文Wiki页面查看相关示例,也可以利用搜索引擎做初步的了解。本教程内容主要关注于针对命令式语言JAVA的分析。)* :
+尽管新的语言和特性层出不穷,但现在编程语言无非三大类 _\(如果你对其中的某个语言不熟悉,可以到语言的官网或英文Wiki页面查看相关示例,也可以利用搜索引擎做初步的了解。本教程内容主要关注于针对命令式语言JAVA的分析。\)_ :
* 命令式(C、C++、JAVA)
* 函数式([Scala](https://www.scala-lang.org/)、[Haskell](https://www.haskell.org/))
* 逻辑式([Prolog](https://en.wikipedia.org/wiki/Prolog))
-## 静态程序分析的应用
+### 静态程序分析的应用
-静态程序分析即是屠龙的宝刀之一,举例来说这一技术可以处理以下问题(*以下概念只需要了解,重要的应用在后文中会详细讲解。*):
+静态程序分析即是屠龙的宝刀之一,举例来说这一技术可以处理以下问题\(_以下概念只需要了解,重要的应用在后文中会详细讲解。_\):
1. 提高程序可靠性
- - Null pointer dereference, memory leak, etc.
- - 空指针引用与内存泄漏等:几乎每个程序编写者都被这两个问题所困扰过
+ * Null pointer dereference, memory leak, etc.
+ * 空指针引用与内存泄漏等:几乎每个程序编写者都被这两个问题所困扰过
2. 提高程序安全性
- - Private information leak, injection attack, etc.
- - 隐私信息泄漏:这一问题在移动应用中较为普遍,如果你感兴趣,可以参考[这篇论文](https://www.ieee-security.org/TC/SP2012/posters/ScanDal.pdf)。
- - [注入攻击](https://en.wikipedia.org/wiki/Code_injection):这是网络安全中非常常见的议题。不熟悉的读者可以查看[W3School](https://www.w3schools.com/sql/sql_injection.asp)或[Wiki](https://en.wikipedia.org/wiki/SQL_injection)上关于SQL注入攻击的例子。
+ * Private information leak, injection attack, etc.
+ * 隐私信息泄漏:这一问题在移动应用中较为普遍,如果你感兴趣,可以参考[这篇论文](https://www.ieee-security.org/TC/SP2012/posters/ScanDal.pdf)。
+ * [注入攻击](https://en.wikipedia.org/wiki/Code_injection):这是网络安全中非常常见的议题。不熟悉的读者可以查看[W3School](https://www.w3schools.com/sql/sql_injection.asp)或[Wiki](https://en.wikipedia.org/wiki/SQL_injection)上关于SQL注入攻击的例子。
3. 为编译优化提供基础技术
- - Dead code elimination, code motion, etc.
- - [死代码消除](https://en.wikipedia.org/wiki/Dead_code_elimination):在编译器的机器无关优化环节,将不会对程序执行结果产生影响的代码(即死代码)删除。
- - [循环不变量的代码移动](https://en.wikipedia.org/wiki/Loop-invariant_code_motion):在编译器的机器无关优化环节,在保证不影响程序执行结果的情况下,将循环中的特定语句移动到循环外,使得程序运行时执行的语句数减少。更为详细的解释可以参考[StackOverFlow上的回答](https://stackoverflow.com/questions/5607762/what-does-code-motion-mean-for-loop-invariant-code-motion)。
+ * Dead code elimination, code motion, etc.
+ * [死代码消除](https://en.wikipedia.org/wiki/Dead_code_elimination):在编译器的机器无关优化环节,将不会对程序执行结果产生影响的代码(即死代码)删除。
+ * [循环不变量的代码移动](https://en.wikipedia.org/wiki/Loop-invariant_code_motion):在编译器的机器无关优化环节,在保证不影响程序执行结果的情况下,将循环中的特定语句移动到循环外,使得程序运行时执行的语句数减少。更为详细的解释可以参考[StackOverFlow上的回答](https://stackoverflow.com/questions/5607762/what-does-code-motion-mean-for-loop-invariant-code-motion)。
4. 有助于程序理解
- - IDE call hierarchy, type indication, etc.
- - 为集成开发环境的功能提供帮助:当你使用VS/Idea/Clion/Eclipse/Android Studio等等IDE时,将鼠标悬停在代码上,IDE能够动态地分析并提示你所悬停对象的相关信息,背后使用的技术就是静态程序分析。
+ * IDE call hierarchy, type indication, etc.
+ * 为集成开发环境的功能提供帮助:当你使用VS/Idea/Clion/Eclipse/Android Studio等等IDE时,将鼠标悬停在代码上,IDE能够动态地分析并提示你所悬停对象的相关信息,背后使用的技术就是静态程序分析。
此外,静态程序分析技术也可以分析多线程程序,这是一个有难度的研究领域。主要困难在于处理多线程间的interleaving。本书定位入门,不会涉及相关内容。
-## 静态程序分析的市场
+### 静态程序分析的市场
-
+![](.gitbook/assets/market.png)
-- 在学术界,静态程序分析技术几乎可以应用于所有关于程序的研究方向。
-- 在工业界,国外的Google,IBM等大企业已经初步建立了自己的静态程序分析团队。国内的华为和阿里等企业也正在积极寻找静态程序分析方面的人才。
-- **无论你将来想在学术界还是工业界深入发展,学习这一领域的知识都能为你建立独特的优势。**
+* 在学术界,静态程序分析技术几乎可以应用于所有关于程序的研究方向。
+* 在工业界,国外的Google,IBM等大企业已经初步建立了自己的静态程序分析团队。国内的华为和阿里等企业也正在积极寻找静态程序分析方面的人才。
+* **无论你将来想在学术界还是工业界深入发展,学习这一领域的知识都能为你建立独特的优势。**
-## 静态程序分析与类似技术的对比
+### 静态程序分析与类似技术的对比
-> Testing shows the presence, not the absence of bugs. --Edsger W. Dijkstra
+> Testing shows the presence, not the absence of bugs. --Edsger W. Dijkstra
动态的软件测试和形式化语义的验证的作用与静态程序分析类似,这一部分对这三个细分方向做简单的对比。
-### 静态程序分析
-
-- 优点:在选定的精度下能够保证没有bug。这在教程中会详细介绍。
-- 缺点:
-
- 1. 学术门槛相对高。目前国内高校只有北京大学和南京大学开设有关课程,且暂无教材。作为一门计算机专业的高年级选修课,入门和提高都较困难。
- 2. You tell me.
-
-### 动态软件测试
-
-- 优点:在工程中被广泛应用,并且有效。实现简单,便于自动化。
+#### 静态程序分析
-- 缺点:
+* 优点:在选定的精度下能够保证没有bug。这在教程中会详细介绍。
+* 缺点:
+ 1. 学术门槛相对高。目前国内高校只有北京大学和南京大学开设有关课程,且暂无教材。作为一门计算机专业的高年级选修课,入门和提高都较困难。
+ 2. You tell me.
- 1. **无法保证没有bug。** 这是无法遍历所有可能的程序输入的必然结果。
- 2. 在当今的由多核与网络应用带来的**并发环境下作用有限。** 某个bug可能只在特定情况下发生,因而难以稳定地复现。如果你对并发程序的动态测试细节感兴趣,可以参考[《拧龙头法测试并发程序》](https://zhuanlan.zhihu.com/p/51341151)。(截图来自南京大学《形式化语义》课程资料)
-
-
+#### 动态软件测试
-### 形式化语义验证
+* 优点:在工程中被广泛应用,并且有效。实现简单,便于自动化。
+* 缺点:
+ 1. **无法保证没有bug。** 这是无法遍历所有可能的程序输入的必然结果。
+ 2. 在当今的由多核与网络应用带来的**并发环境下作用有限。** 某个bug可能只在特定情况下发生,因而难以稳定地复现。如果你对并发程序的动态测试细节感兴趣,可以参考[《拧龙头法测试并发程序》](https://zhuanlan.zhihu.com/p/51341151)。(截图来自南京大学《形式化语义》课程资料)
-- 优点:由于用数学的方法对程序做了抽象,能够保证没有bug。
+![](.gitbook/assets/concurrentProgram.png)
-- 缺点:
+#### 形式化语义验证
- 1. 学术门槛较高,学习者必须有良好的数学基础才能入门。
- 2. 验证代价较高,一般来说非常重要的项目会使用这一方式保证程序质量。甚至在操作系统这样重要的软件中,也并不一定会使用。(截图来自鸿蒙OS直播发布会)
+* 优点:由于用数学的方法对程序做了抽象,能够保证没有bug。
+* 缺点:
+ 1. 学术门槛较高,学习者必须有良好的数学基础才能入门。
+ 2. 验证代价较高,一般来说非常重要的项目会使用这一方式保证程序质量。甚至在操作系统这样重要的软件中,也并不一定会使用。\(截图来自鸿蒙OS直播发布会\)
-
+![](.gitbook/assets/harmonyOS%20%281%29.png)
-# 加入项目/How to contribute
+## 加入项目/How to contribute
> 觉得有所帮助的话可以点个star支持哦。
欢迎希望添加更好的讲解资料或对教程内容进行扩充的小伙伴 `fork, modify, PR` 三连。
-# 本地化/Localization
+## 本地化/Localization
-## English
+We'd love help translating this book! Open a new issue to start working on a new language. Feel free to start :\)
-If you wanna translate this project into English, I can proofread for you. All you need to do is `fork, translate, PR` .
+## 其他相关项目
-## 日本語
-
-このプロジェクトを日本語に翻訳したい場合は、翻訳されたコンテンツの校正をお手伝いします. `fork, translate, PR` で始めましょう!
-
-# 其他相关项目
+### 软件质量保障相关
[《软件测试简介》Gitbook在线阅读地址](https://ranger-nju.gitbook.io/software-testing-intro)
[《软件测试简介》GitHub项目地址](https://github.com/RangerNJU/Software-Testing-Intro)
+
+### 前辈们写过的优秀笔记
+
+[适合预习和同步阅读,CSDN+简书](https://blog.csdn.net/panhewu9919/article/details/106007155)
+
+[适合复习,个人博客笔记](https://fancypei.github.io/SA/)
+
diff --git a/SUMMARY.md b/SUMMARY.md
index 05dc767..adeb5cc 100644
--- a/SUMMARY.md
+++ b/SUMMARY.md
@@ -1,12 +1,13 @@
# Table of contents
* [简介](README.md)
-* [第零章-写在前面](ch0/README.md)
+* [写在前面](ch0/README.md)
* [为什么是这本书?](ch0/00-01-why-this-book.md)
- * [来源与版权信息](ch0/00-02-sources-and-license.md)
-* [第一章-静态程序分析简介](ch1/README.md)
-* [第二章-数据流分析——应用](ch2/README.md)
-* [第三章-数据流分析——理论](ch3/README.md)
-* [第四章-过程间分析](ch4/README.md)
- * [过程间分析简介](ch4/04-01-inter-analysis-spa.md)
+ * [资料来源与版权信息](ch0/00-02-sources-and-license.md)
+* [静态程序分析简介与数据流分析](ch1.md)
+* [过程间分析](ch2/README.md)
+ * [过程间分析简介](ch2/02-01-inter-analysis-spa.md)
+ * [指针分析简介](ch2/02-02-pointer-analysis-spa.md)
+ * [指针分析理论一](ch2/02-03-pointer2-analysis-spa.md)
+ * [指针分析理论二](ch2/02-04-pointer3-analysis-spa.md)
diff --git a/ch0/00-01-why-this-book.md b/ch0/00-01-why-this-book.md
index 617c368..3482a10 100644
--- a/ch0/00-01-why-this-book.md
+++ b/ch0/00-01-why-this-book.md
@@ -10,7 +10,7 @@
### 中文社区
-在搜索引擎上搜索相关中文关键词,你会发现结果靠前的答案都是与某南的李老师相关的课程在B站上公开视频的笔记,其中有不少写得很好,**但并非面向一般学习者开发者的教程**。这两者有重要的区别:
+在搜索引擎上搜索相关中文关键词,你会发现结果靠前的答案都是与南京大学相关课程在B站上公开视频的笔记,其中有不少写得很好,**但并非面向一般学习者开发者的教程**。这两者有重要的区别:
* 笔记:**面向自己复习**使用,只要自己回顾时能迅速pick up当时理解到的重点,就是一份好的笔记。
* 教程:**面向他人学习**使用,一份好教程能让学习者迅速把握领域中的重点,并且为学习者的进一步应用打下基础。
@@ -21,18 +21,29 @@
### 理论与实践的结合
-本书将同时涉及理论和实践,这主要是受到了《The Rust Programming Language》的启发。
+本书计划同时涉及理论和实践,这主要是受到了《The Rust Programming Language》的启发。由于老师的实验课程部分尚在设计中,预计会在理论课程结束后自主设计一些简单的实践任务与指南。
### 本书写作的目标
能让大多数有一定编程经历,已经修过本科计算机相关基础课程的大四及以上同学:
-1. 在阅读本书时能较为轻松地理解理论
-2. 能够自主完成一个简单的程序实现
-3. (任何人都)能在阅读过程中接触计算机不同领域的小知识
+1. 在阅读本书时能**较为轻松地理解理论**
+2. 能够**自主完成一个简单的程序实现**
+3. (任何人都)能在阅读过程中接触**计算机不同领域的小知识**
## 为什么要写这本书?
-* 最主要的动力还是老师现场授课时我感受到的passion
-* 这是一个少有人涉足的领域,写这方面的内容很符合我的性格
-* 我从开源社区中获益颇多,找到了合适的机会也希望能为开源社区(尤其是中文社区)作出自己的贡献
\ No newline at end of file
+* **有趣且有用**
+ * 有趣。首先非常**感谢**[**李老师**](https://yuelee.bitbucket.io/)**和**[**谭老师**](https://silverbullettt.bitbucket.io/)的精心准备和深入浅出的精彩课程 :\)
+ * 有用。这门课的**理论内容已经被工业界实践**用于回答一个现代软件领域的重要问题:
+
+ > ❓ 如何自动化地高效保证软件质量
+* **少有人涉足**
+ * 其他领域**已经**有很多优秀前辈**完成了重要的工作**
+ * 这一领域暂时还**不为大多数人所知**
+ * 完善这方面的公开资料**能够帮助到很多人**
+* **知识没有界限**
+ * 无论是[自学日语](https://www.douban.com/group/topic/139681153/),还是各大世界名校的公开课,我都受益颇多。世界已经如此不平等,**知识不应该有界限**
+* **回馈开源社区**
+ * 我从开源社区中获益颇多,找到了合适的机会也希望能为开源社区(尤其是中文社区)作出自己的贡献
+
diff --git a/ch0/00-02-sources-and-license.md b/ch0/00-02-sources-and-license.md
index c60592a..2fa6214 100644
--- a/ch0/00-02-sources-and-license.md
+++ b/ch0/00-02-sources-and-license.md
@@ -1,13 +1,14 @@
-# 来源与版权信息
+# 资料来源与版权信息
## 资料来源
本入门教程主要内容基于南京大学《软件分析》课程。
-[PASCAL研究组主页](https://pascal-group.bitbucket.io/teaching.html)
+[PASCAL研究组主页上的公开课件](https://pascal-group.bitbucket.io/teaching.html)
## 版权信息
教程文字部分遵循CC BY-NC-SA许可协议。
图片部分若无特殊说明则出自课程资料,使用已获作者同意。其他材料会注明出处,侵删。
+
diff --git a/ch0/README.md b/ch0/README.md
index 92d4d65..5a6fbaa 100644
--- a/ch0/README.md
+++ b/ch0/README.md
@@ -1,5 +1,6 @@
-# 第零章简介
+# 写在前面
记录一些你在继续阅读之前可能需要了解的信息。
-如果这是你第一次了解“静态程序分析”,你应该先查看[Github上的简介](https://github.com/RangerNJU/Static-Program-Analysis-Book)。
\ No newline at end of file
+如果这是你第一次了解“静态程序分析”,你应该先查看[Github上的简介](https://github.com/RangerNJU/Static-Program-Analysis-Book)。
+
diff --git a/ch1.md b/ch1.md
new file mode 100644
index 0000000..34e9745
--- /dev/null
+++ b/ch1.md
@@ -0,0 +1,25 @@
+# 静态程序分析简介与数据流分析
+
+在简介中,将介绍:
+
+* 什么是静态程序分析(下简称为静态分析)?
+* 如何设计一个实用的静态程序分析器?
+
+然后将用较长的篇幅介绍静态分析的一个常见应用——数据流分析。
+
+* 首先介绍数据流分析的应用,让学习者有直观感受
+* 然后从理论上深入讲解数据流分析背后的逻辑
+
+**注:这一部分在B站上有相应的视频。在作者腾出时间整理文稿之前,建议读者先到B站观看相应的视频。对应的文字部分暂时移出本仓库。**
+
+对应的视频在这里:
+
+* [第一课-课程简介](https://www.bilibili.com/video/BV1b7411K7P4?from=search&seid=9629980298568702440)
+* [第二课-中间表示\(IR\)](https://www.bilibili.com/video/BV1zE411s77Z)
+* [第三课-数据流分析一](https://www.bilibili.com/video/BV1oE411K79d)
+* [第四课-数据流分析二](https://www.bilibili.com/video/BV19741197zA)
+* [第五课-数据流分析理论一](https://www.bilibili.com/video/BV1A741117it)
+* [第六课-数据流分析理论二](https://www.bilibili.com/video/BV1964y1M7nL)
+
+从[这里](https://ranger-nju.gitbook.io/static-program-analysis-book/ch4)直接跳转到施工完毕区域。
+
diff --git a/ch1/01-01-whats-spa.md b/ch1/01-01-whats-spa.md
deleted file mode 100644
index e69de29..0000000
diff --git a/ch1/01-02-ir.md b/ch1/01-02-ir.md
deleted file mode 100644
index e69de29..0000000
diff --git a/ch1/README.md b/ch1/README.md
deleted file mode 100644
index 8a2b370..0000000
--- a/ch1/README.md
+++ /dev/null
@@ -1,13 +0,0 @@
-# 第一章-静态程序分析简介
-
-在这一部分中,将正式地介绍:
-
-- 什么是静态程序分析(下简称为静态分析)?
-- 如何设计一个实用的静态程序分析器?
-
-**注:第一章到第三章在B站上有相应的视频。在作者腾出时间整理文稿之前,建议读者先到B站观看相应的视频。对应的文字部分暂时移出本仓库。**
-
-对应的视频在这里:
-- [第二课-IR](https://www.bilibili.com/video/BV1zE411s77Z)
-
-从[这里](https://ranger-nju.gitbook.io/static-program-analysis-book/ch4)直接跳转到施工完毕区域(第四章)。
diff --git a/ch2/02-00-dataflow-analysis.md b/ch2/02-00-dataflow-analysis.md
deleted file mode 100644
index 4d9e5c9..0000000
--- a/ch2/02-00-dataflow-analysis.md
+++ /dev/null
@@ -1,4 +0,0 @@
-# 数据流分析
-
-TBD
-
diff --git a/ch2/02-01-inter-analysis-spa.md b/ch2/02-01-inter-analysis-spa.md
new file mode 100644
index 0000000..c918e7f
--- /dev/null
+++ b/ch2/02-01-inter-analysis-spa.md
@@ -0,0 +1,273 @@
+# 过程间分析简介
+
+## 过程间分析简介
+
+本小节通过四个部分介绍过程间分析。
+
+1. Motivation
+ * **为什么** 要引入过程间分析?
+2. Call Graph Construction \(CHA\)
+ * 介绍一个过程间分析 **必要的数据结构Call Graph**
+ * 当前有数种方法来**构建Call Graph**,本节介绍其中**速度最快的一种(Class hierarchy analysis,简称CHA)**
+3. Interprocedural Control-Flow Graph
+ * 之前的章节关注CFG,引入过程间分析后,我们向CFG中**添加相应的元素**,得到过程间的控制流图(ICFG)
+ * 讨论由于添加了新元素而需要**增加的操作**
+4. Interprocedural Data-Flow Analysis
+ * 通过一个例子(也就是实验一中做的常量传播分析)来**总结**过程间分析。
+
+## Motivation
+
+之前的章节中都没有考虑方法调用,然而在实际的程序中方法调用非常常见,那么我们如何分析带方法调用的程序呢?最简单的处理方式是:做最保守的假设,即**为函数调用返回NAC**。而这种情况会**丢失精度**。**引入过程间分析能够提高精度。**如果使用最简单的处理方式,下图中的n和y分析结果都不是常量,尽管我们能够一眼看出他们的运行时值是n=10,y=43。
+
+![](../.gitbook/assets/Ex4-1.png)
+
+## Call Graph Construction \(CHA\)
+
+接下来我们讨论一个必要的数据结构Call Graph,中文可以理解为调用关系图。
+
+### Definition of Call Graph
+
+> A representation of calling relationships in the program.
+
+调用关系图表达调用关系(中文讲起来确实很奇怪),一个简单的例子如下:
+
+![](../.gitbook/assets/Ex4-2.png)
+
+### Call Graph Construction
+
+Call Graph有很多种不同的构造方法,我们接下来会讲解两个极端:最准确的和最快速的。
+
+![](../.gitbook/assets/Ex4-3.png)
+
+#### Call types in Java
+
+本课主要关注Java的调用关系图构建。为此,我们需要先了Java中调用的类型。Java中call可分为三类(不需要理解透彻,之后会详细介绍):
+
+![](../.gitbook/assets/Ex4-4.png)
+
+* Instruction:指Java的**IR中的指令**
+* Receiver objects:方法对应的实例对象(static方法不需要对应实例)。
+* Target methods:表达**方法到IR指令的映射关系**
+* Num of target methods:call可能对应的方法数量。Virtual call与动态绑定和多态实现有关,可以对应多个对象下的重写方法。所以**Virtual call的可能对象可能超过1个**。
+* Determinacy:指什么时候能够确定这个call的对应方法。Virtual call与多态有关,只能在运行时决定调用哪一个具体方法的实现。其他两种call都和多态机制不相关,编译时刻就可以确定。
+
+#### Virtual call and dispatch
+
+Virtual call是几种调用中最为复杂的一种,我们首先重点讨论它。在动态运行时,Virtual call基于两点决定调用哪个具体方法:
+
+1. Type of object
+2. Method signature
+ * Signature = class type + method name + descriptor
+ * Descriptor = return type + parameter types
+
+![](../.gitbook/assets/Ex4-5.png)
+
+Java中Dispatch机制决定具体调用哪个方法:c是一个类的定义,m是一个方法。如果能在本类中找到name和descriptor一致的方法,则调用c的方法,否则到父类中寻找。
+
+> We define function Dispatch\(𝑐, 𝑚\) to simulate the procedure of run-time method dispatch.
+
+![](../.gitbook/assets/Ex4-6.png)
+
+**练习问题**
+
+Q:两次对foo的调用分别调用了哪个类的foo?
+
+![](../.gitbook/assets/image-20201029224401395.png)
+
+A:分别调用A和C中定义的foo方法。
+
+![](../.gitbook/assets/image-20201029224437136.png)
+
+## Class Hierarchy Analysis \(CHA\)
+
+### Definition of CHA
+
+* Require the class **hierarchy information \(inheritance structure\)** of the whole program
+ * 需要首先获得整个程序的继承关系图
+* Resolve a virtual call based on the declared type of receiver variable of the call site
+ * 通过接收变量的声明类型来解析Virtual call
+ * 接收变量的例子:在`a.foo()`中,a就是接收变量
+* Assume the receiver variable a may point to objects of class A or all subclasses of A(Resolve target methods by looking up the class hierarchy of class A)
+ * 假设一个接收变量能够指向A或A的所有子类
+
+### Call Resolution of CHA
+
+#### Algorithm of Resolve
+
+下面介绍解析调用的算法。
+
+![](../.gitbook/assets/image-20201029224506176.png)
+
+* call site\(cs\)就是调用语句,m\(method\)就是对应的函数签名。
+* T集合中保存找到的结果
+* 三个if分支分别对应之前提到的Java中的三种call类型
+ 1. Static call\(所有的静态方法调用\)
+ 2. Special call\(使用super关键字的调用,构造函数调用和Private instance method\)
+ 3. Virtual call\(其他所有调用\)
+
+**Static call**
+
+* 对于不了解OOP中静态方法的同学可以参考[这里](https://www.geeksforgeeks.org/static-methods-vs-instance-methods-java/)。具体来说,静态方法前写的是类名,而非静态方法前写的是变量或指针名。静态方法不需要依赖实例。
+
+![](../.gitbook/assets/image-20201029224736803.png)
+
+**Special call**
+
+* Superclass instance method(super关键字)最为复杂,故优先考虑这种情况
+
+![](../.gitbook/assets/image-20201029224820647.png)
+
+* 为什么处理super调用需要使用Dispatch函数:在下图所示情况中没有Dispatch函数时无法正确解析C类的super.foo调用:
+
+![](../.gitbook/assets/image-20201029224941882.png)
+
+* 而Private instance method和Constructor(一定由类实现或有默认的构造函数)都会在本类的实现中给出,使用Dispatch函数能够将这三种情况都包含,简化代码。
+
+**Virtual call**
+
+* receiver variable在例子中就是c。
+
+![](../.gitbook/assets/image-20201029225106724.png)
+
+* 对receiver c和c的所有直接间接子类都作为call site调用Dispatch
+
+**一个例子**
+
+三个调用都是Virtual call。是上述算法中的第三种情况。
+
+![](../.gitbook/assets/image-20201029225304889.png)
+
+### CHA的特征
+
+1. 只考虑继承结构,所以**很快**
+2. 因为忽略了数据流和控制流的信息,所以**不太准确**
+
+### CHA的应用
+
+常用于IDE中,给用户提供提示。比如写一小段测试代码,看看b.foo\(\)可能会调用哪些函数签名。可以看出CHA分析中认为`b.foo()`可能调用A、C、D中的`foo()`方法。(实际上这并不准确,因为b实际上是B类对象,不会调用子类C、D中的方法,但胜在快速)
+
+![](../.gitbook/assets/image-20201029225350619.png)
+
+### Call Graph Construction
+
+#### Idea
+
+* Build call graph for whole program via CHA
+ * 通过CHA构造整个程序的call graph
+* Start from entry methods \(focus on main method\)
+ * 通常从main函数开始
+* For each reachable method 𝑚, resolve target methods for each call site 𝑐𝑠 in 𝑚 via CHA \(Resolve\(𝑐𝑠\)\)
+ * 递归地处理对每个可达的方法
+* Repeat until no new method is discovered
+ * 当不能拓展新的可达方法时停止
+* 整个过程和计算理论中求闭包的过程很相似
+
+![](../.gitbook/assets/image-20201029230138054.png)
+
+#### Algorithm
+
+![](../.gitbook/assets/image-20201029230224316.png)
+
+* Worklist记录需要处理的methods
+* Call graph是需要构建的目标,是call edges的集合
+* Reachable method是已经处理过的目标,在Worklist中取新目标时,不需要再次处理已经在RM中的目标
+
+#### Example
+
+1. 初始化
+
+![](../.gitbook/assets/image-20201029230504891.png)
+
+2. 处理main后向WL中加入A.foo\(\)
+
+![](../.gitbook/assets/image-20201029230535984.png)
+
+3. 中间省略一些步骤,这里面对C.bar\(\)时,虽然会调用A.foo\(\),但由于A.foo\(\)之前已经处理过(在集合RM中),之后不会再进行处理
+
+![](../.gitbook/assets/image-20201029230622120.png)
+
+4. 这里C.m\(\)是不可达的死代码
+
+![](../.gitbook/assets/image-20201029230909895.png)
+
+_注:忽略new A\(\)对构造函数的调用,这不是例子的重点。_
+
+**这个例子是对本小节的总结,如果不能读懂并独立推导建议重读一遍。如果你理解了第一到第六课的内容但是觉得上面的内容写得不清晰,可以到本书简介中提到的QQ群交流吐槽。**
+
+### Interprocedural Control-Flow Graph
+
+> ICFG = CFG+call & return edges
+
+ICFG可以通过CFG加上两种边构造得到。
+
+1. Call edges: from call sites to the entry nodes of their callees
+2. Return edges: from return statements of the callees to the statements following their call sites \(i.e., return sites\)
+
+例如:
+
+![](../.gitbook/assets/image-20201029231132412.png)
+
+![](../.gitbook/assets/image-20201029231155238.png)
+
+## Interprocedural Data-Flow Analysis
+
+### 定义与比较
+
+目前这一分析领域没有标准方法。首先对过程间和过程内的分析做一个对比,并以常量传播(本校同学第一次实验作业主题,需要一到六课的基础)为例子进行解释。
+
+![](../.gitbook/assets/image-20201029231106891.png)
+
+Edge transfer处理引入的call & return edge。为此,我们需要**在之前章节的CFG基础上增加三种transfer函数。**
+
+* Call edge transfer
+ * 从调用者向被调用者传递参数
+* Return edge transfer
+ * 被调用者向调用者传递返回值
+* Node transfer
+ * 大部分与过程内的常数传播分析一样,不过对于每一个函数调用,都要kill掉LHS(Left hand side)的变量
+
+![](../.gitbook/assets/image-20201029231304304.png)
+
+### Example
+
+![](../.gitbook/assets/image-20201029231706834.png)
+
+#### 小问题
+
+这一段有存在的必要吗?
+
+![](../.gitbook/assets/image-20201029231611608.png)
+
+> Such edge \(from call site to return site\) is named call-to-return edge. It allows the analysis to propagate local data-flow \(a=6 in this case\) on ICFG.
+
+如果没有这一段,那么a就得“出国”去浪费地球资源——在分析被调用函数的全程中都需要记住a的值,这在程序运行时会浪费大量内存。
+
+![](../.gitbook/assets/image-20201029231543567.png)
+
+要记得在调用语句处kill掉表达式左边的值,否则会造成结果的不准确,如:
+
+![](../.gitbook/assets/image-20201029231908883.png)
+
+## 过程间分析有多重要?
+
+讲到这里,我们回到故事的开头,看看过程间分析的引入到底能带来多大的精度提高吧。上述例子应用过程间分析的完整推导如下:
+
+![](../.gitbook/assets/image-20201029231952670.png)
+
+而如果只做过程内分析,则**精度大大下降**:
+
+![](../.gitbook/assets/image-20201029231936719.png)
+
+## Key points
+
+**The X You Need To Understand in This Lecture**
+
+1. How to build call graph via class hierarchy analysis
+ * 如何利用CHA构建调用关系图\(call graph\)
+2. Concept of interprocedural control-flow graph
+ * 过程间控制流图\(CFG\)的概念
+3. Concept of interprocedural data-flow analysis
+ * 过程间数据流分析的概念
+4. Interprocedural constant propagation
+ * 例子——引入过程间分析的常量分析
+
diff --git a/ch2/02-01-reaching-def-analysis.md b/ch2/02-01-reaching-def-analysis.md
deleted file mode 100644
index 2629d9c..0000000
--- a/ch2/02-01-reaching-def-analysis.md
+++ /dev/null
@@ -1,4 +0,0 @@
-# 到达定值分析
-
-TBD
-
diff --git a/ch2/02-02-live-var-analysis.md b/ch2/02-02-live-var-analysis.md
deleted file mode 100644
index 3018285..0000000
--- a/ch2/02-02-live-var-analysis.md
+++ /dev/null
@@ -1,4 +0,0 @@
-# 活跃变量分析
-
-TBD
-
diff --git a/ch2/02-02-pointer-analysis-spa.md b/ch2/02-02-pointer-analysis-spa.md
new file mode 100644
index 0000000..b83a437
--- /dev/null
+++ b/ch2/02-02-pointer-analysis-spa.md
@@ -0,0 +1,198 @@
+# 指针分析简介
+
+## 指针分析简介
+
+**指针分析这一部分相对较难,将会有五节课讲授相关内容。**
+
+**本课主要内容如下:**
+
+1. Motivation
+2. Introduction to Pointer Analysis
+3. Key Factors of Pointer Analysis
+4. Concerned Statements
+
+## Motivation
+
+接下来我们对比基于CHA的分析方法和指针分析的分析方法。首先,回想一下CHA的构造过程。在这个程序中对`get()`的调用,在CHA分析下,应该调用哪几个方法?
+
+![](../.gitbook/assets/image-20201105183618529.png)
+
+### 使用CHA分析
+
+![](../.gitbook/assets/image-20201109140057119.png)
+
+可以看出,由于只关心类的层次结构,分析结果的三个箭头中有两个是false positive。也因此导致了分析结果的不精确。
+
+![](../.gitbook/assets/image-20201109140605829.png)
+
+### 使用指针分析
+
+利用指针分析,我们能知道n指向的对象就是new One\(\)语句所新建出来的对象。所以能精确地知道x一定会取1。
+
+![](../.gitbook/assets/image-20201109154728420.png)
+
+![](../.gitbook/assets/image-20201109154844509.png)
+
+**比较两种分析,可以看出CHA速度快而精度低,接下来我们学习高精度的指针分析。**
+
+## Introduction to Pointer Analysis
+
+程序中保存一个地址的东西都可以视为指针(Pointer/Reference)。
+
+* Regarded as a may-analysis
+ * Computes an over-approximation of the set of objects that a pointer can point to, i.e., we ask “a pointer may point to which objects?”
+
+什么是指针分析呢?举个例子(省略中间过程):
+
+![](../.gitbook/assets/image-20201105184327763.png)
+
+### 区分指针分析与别名分析
+
+Pointer Analysis and Alias Analysis are 2 closely related but different concepts.
+
+* Pointer analysis: **which** objects a pointer can point to?
+* Alias analysis: **can** two pointers point to the same object?
+
+Example-If two pointers, say p and q, refer to the same object, then p and q are aliases.
+
+```cpp
+// p and q are aliases
+p = new C();
+q = p;
+
+// x and y are not aliases
+x = new X();
+y = new Y();
+```
+
+**Alias information can be derived from points-to relations.**
+
+### 指针分析有多重要?
+
+> 业界大佬们说它很重要。
+
+![](../.gitbook/assets/image-20201105184919660.png)
+
+## Key Factors of Pointer Analysis
+
+此处有战术喝水。(现场梗)
+
+* Pointer analysis is a complex system
+* Multiple factors affect the precision and efficiency of the system
+
+![](../.gitbook/assets/image-20201105185230667.png)
+
+### Heap Abstraction
+
+在动态执行中,由于循环和递归的结构,堆上的对象数量可以是无限的。如果不做抽象,面对无限的对象,分析算法可能根本停不下来。
+
+```cpp
+for (…) {
+ A a = new A();
+}
+```
+
+解决方法也很简单,学校里同学太多了就分成班级来管理,我们也可以对堆上的对象进行抽象:
+
+![](../.gitbook/assets/image-20201105185431196.png)
+
+相关的技术有很多,这里只讲一个最常用的分支Allocation-Site Abstraction。而Storeless的方法本课程不涉及。
+
+![](../.gitbook/assets/image-20201105185630758.png)
+
+#### Allocation-Site Abstraction
+
+虽然动态时对象的个数可能是无限的,但是new语句的个数一定是有限的。我们可以按照new语句来进行抽象。
+
+![](../.gitbook/assets/image-20201105185806532.png)
+
+### Context Sensitivity
+
+首先我们需要了解什么是(被调用方法的)**调用上下文(calling contexts)**。调用上下文记录的是函数调用前后相关变量的值。例如,参数和返回值是上下文的一部分。
+
+如果将上下文做区分(进行额外的标记,如记录下图中p指向的目标),对参数不同时的调用做不同的分析,则称为**上下文敏感分析**。
+
+![](../.gitbook/assets/image-20201105190333596.png)
+
+反之,如果不区分上下文,则称为**上下文不敏感分析**。由于忽略了一部分信息,可能会损失分析的精度。
+
+![](../.gitbook/assets/image-20201105190439805.png)
+
+我们首先学习不敏感的分析方法,在之后的课程中介绍上下文敏感分析。
+
+### Flow Sensitivity
+
+> 流敏感分析重视语句执行的顺序,而流不敏感分析则恰恰相反。前者的精度更高,但优势不是特别大;后者的开销则远远小于前者。
+
+之前课程中的所有数据流分析技术都是流敏感的。接下来我们考虑这样一段代码。_前排提示:复习的时候可以把图中箭头右侧挡住自己写一遍。_
+
+```cpp
+c = new C();
+c.f = "x";
+s = c.f;
+c.f = "y";
+```
+
+对于流敏感的分析,会得到如下的mapping。`o1`代表在第一行动态分配的对象。
+
+![](../.gitbook/assets/image-20201105191248594.png)
+
+如果使用流不敏感的分析,会得到如下的mapping。
+
+![](../.gitbook/assets/image-20201105191705757.png)
+
+### Analysis Scope
+
+可以分析整个程序,也可以按需分析(即只分析必要的部分)。
+
+## Concerned Statements
+
+在指针分析中,我们只关注会影响到指针的语句(pointer-affecting statements)。而对于if/switch/loop/break/continue等等语句则可以直接忽略。
+
+### 关注的指针类型
+
+Java中的Pointers有以下几类:
+
+* **Local variable: x**
+* Static field: C.f
+ * Sometimes referred as global variable
+ * 在之后介绍的算法中,**可作为Local variable处理**
+* **Instance field: x.f**
+ * \(pointed by x\) with a field f
+* Array element: array\[i\]
+ * 涉及数组的分析中,我们**忽略下标**,代之以一个域(a single field)。例如,在下图中我们用arr表示。
+* 原因之一:数组下标是变量时难以计算具体值
+ * 在之后介绍的算法中,**可作为Instance field处理**![](../.gitbook/assets/image-20201105194030384.png)
+
+### 关注的语句类型
+
+具体来说,我们关注五种基本类型的语句:
+
+```cpp
+// New
+x = new T()
+
+// Assign
+x = y
+
+// Store
+x.f = y
+
+// Load
+y = x.f
+
+// Call
+r = x.k(a, …)
+```
+
+复杂的Store和Load指令可以解构成简单的,所以我们可以只考虑对上述五种基本类型语句的分析:
+
+![](../.gitbook/assets/image-20201105194707507.png)
+
+## Key points
+
+**The X You Need To Understand in This Lecture**
+
+- **What is pointer analysis?**
+- Understand **the key factors** of pointer analysis
+- Understand **what we analyze** in pointer analysis
\ No newline at end of file
diff --git a/ch2/02-03-available-exp-analysis.md b/ch2/02-03-available-exp-analysis.md
deleted file mode 100644
index 9d0b62f..0000000
--- a/ch2/02-03-available-exp-analysis.md
+++ /dev/null
@@ -1,15 +0,0 @@
-# 可用表达式分析
-
-## 定义
-
-> An expression x op y is available at program point p if \(1\) all paths from the entry to p must pass through the evaluation of x op y, and \(2\) after the last evaluation of x op y, there is no redefinition of x or y.
-
-## 理解定义:一个tricky的例子
-
-1. 按照直觉来说,c处不是,但是按照定义来说是。但是实际上运行时只会走一条分支。
-2. 回顾: must->under-approximation->报出来的全都是真的。不允许误报,但允许漏报 may->不允许漏报,但允许误报 重新理解这个例子。
-
-PS. 如何记住边界条件设置谁?设置是空还是满?对余下所有块的初始化是空还是满(一个巧妙的方法是判断may/must后,如果条件汇合时是交集,一般开始时大多数块初始化为满。)
-
-一个经常迷惑的问题:先gen先kill?根据定义就解决所有问题2
-
diff --git a/ch2/02-03-pointer2-analysis-spa.md b/ch2/02-03-pointer2-analysis-spa.md
new file mode 100644
index 0000000..647835e
--- /dev/null
+++ b/ch2/02-03-pointer2-analysis-spa.md
@@ -0,0 +1,205 @@
+# 指针分析理论基础一
+
+接下来两篇文章将主要介绍以下四点内容。前三点对应线下课程第九课,最后一点对应第十课。
+
+1. Pointer Analysis: Rules
+2. How to Implement Pointer Analysis
+3. Pointer Analysis: Algorithms
+4. Pointer Analysis with Method Calls
+
+我们先关注前三点,暂时不理会函数调用。
+
+## Notations
+
+![](../.gitbook/assets/image-20201105195029800.png)
+
+首先介绍常用数学符号,不会的同学可以复习一下离散数学。
+
+![](../.gitbook/assets/image-20201105195154527.png)
+
+分别定义变量,域,对象(用下标标识是在第几行创建的对象),实例域和指针(是变量和实例对象的并),和指向关系。`X`表示笛卡尔积。
+
+pt\(p\)代表的是指针p可能指向的对象。如在下面的代码块后,pt\(x\)可能指向的目标可以记为$${o_2,o_4}$$(以行号作为object的下标)。
+
+```java
+if(...){
+ x = new A();
+} else {
+ x = new B();
+}
+```
+
+## Pointer Analysis: Rules
+
+_前排提示:与《数理逻辑》/《形式化语义》梦幻联动。没学过的同学也不要着急。_
+
+![](../.gitbook/assets/image-20201105195524932.png)
+
+主要解释Rule一列中的内容。**横线上的内容是前提\(Premises\),横线下的内容是结论\(Conclusion\)。**
+
+用简单易懂的语言描述,看到new语句,我们就将新建的对象加入`pt(x)`。
+
+![](../.gitbook/assets/image-20201105195943007.png)
+
+对于Assign语句,我们将x指向y指向的对象。
+
+![](../.gitbook/assets/image-20201105235312349.png)
+
+对于Store和Load亦然。
+
+![](../.gitbook/assets/image-20201105200112512.png)
+
+![](../.gitbook/assets/image-20201105200123601.png)
+
+### Summary
+
+最后用一图总结。**第一条规则添加指向,而后三条规则传递指向关系。**
+
+![](../.gitbook/assets/image-20201105200412145.png)
+
+## How to Implement Pointer Analysis
+
+_别处的资料都没有全家桶,只介绍某些特殊情况下的分析算法。在这里你能喜提一个完整的指针分析算法全家桶。_
+
+本质上来说,指针分析是在指针间**传递**指向关系。
+
+![](../.gitbook/assets/image-20201105200815104.png)
+
+inclusion constraints的具体解释:在上述表示的结论部分中可以写作两个集合间的包含关系。如Load应该表示为:
+
+* 前提:`y=x.f`和 $$o_i \in pt(x)$$
+* 结论:$$pt(o_i.f) \subset pt(y)$$
+
+> Key to implementation: when 𝑝𝑡\(𝑥\)is **changed**, **propagate** the **changed par**t to the **related pointers** of 𝑥
+
+![](../.gitbook/assets/image-20201105201018655.png)
+
+### Pointer Flow Graph
+
+> Pointer Flow Graph \(PFG\) of a program is a directed graph
+> that expresses how objects flow among the pointers in the program.
+
+为了实现指针分析,我们首先了解与之密切相关的数据结构——指针流图。
+
+图的两大要素是Node和Edge。我们定义:
+
+* `Node: Pointer = V ⋃ (O × F)`
+ * A node n represents **a variable** or **a field of an abstract object**
+* `Edges: Pointer × Pointer`
+ * **An edge 𝑥 -> 𝑦** means that the objects pointed by pointer 𝑥 **may flow to \(and also be pointed to by\)** pointer 𝑦
+
+![](../.gitbook/assets/image-20201105201421501.png)
+
+### Example
+
+假设c和d一开始都指向 $$o_i$$,根据上述规则,我们能够从左侧的程序语句从上到下构建出右侧的指针流图。
+
+![](../.gitbook/assets/image-20201105201746860.png)
+
+因此,所有b所指向的对象更新时,都要传递到e中。这是一个求传递闭包\(transitive closure\)的过程。假如我们考虑j位置的一条新语句`b = new T();`
+
+![](../.gitbook/assets/image-20201105201939088.png)
+
+PFG的整个构造过程,需要在构建PFG和在已有的PFG上传递指向关系这两个步骤间循环往复。这两个步骤是相互依赖的,所以需要精心设计算法来实现分析。
+
+![](../.gitbook/assets/image-20201105202101633.png)
+
+## Pointer Analysis: Algorithms
+
+### Introduction to algorithm
+
+* 由于做流不敏感分析。输入为Set,丢失了语句的顺序关系也没关系。
+* WorkList:保存接下来要处理的指向信息,与BFS中的队列作用类似。
+ * Each worklist entry 𝑛, 𝑝𝑡𝑠 is a pair of pointer 𝑛 and points-to set 𝑝𝑡𝑠, which means that 𝑝𝑡𝑠 should be propagated to 𝑝𝑡\(𝑛\)
+ * E.g., $$[(x,\{o_i\}),(y,\{o_j, o_k\}),(x.f,\{(o_l)\}),\dots]$$
+
+首先,四个红框部分对应之前提到的四种基本语句——New、Assign、Store和Load。接下来做详细讲解。
+
+![](../.gitbook/assets/image-20201127170432941.png)
+
+### Handling of New and Assign
+
+#### Init and adding edges
+
+![](../.gitbook/assets/image-20201112191544354.png)
+
+首先考虑两种简单的语句:New和Assign。
+
+* 前三行代码做初始化的工作,并针对所有的**New**语句,将所有的初始指向关系加入WorkList。
+* 之后的两行代码处理**Assign**语句,添加`y->x`的边到PFG中。添加边的具体算法如下
+
+![](../.gitbook/assets/image-20201112191630283.png)
+
+#### Propagate
+
+![](../.gitbook/assets/image-20201112193329365.png)
+
+传播的具体算法如下,标号为2的语句是整个算法中唯一执行后改变指向关系的语句。
+
+![](../.gitbook/assets/image-20201112193357268.png)
+
+#### Detial-Differential Propagation
+
+在真实的指针分析中,对象的数量非常巨大(上亿),我们通过Differential Propagation来消除冗余。
+
+```cpp
+Solve(𝑆)
+ ...
+ while WL is not empty do
+ remove 𝑛, 𝑝𝑡𝑠 from WL
+ Δ = pts – pt(n) // Differential Propagation
+ Propagate(n, Δ) // Differential Propagation
+```
+
+首先我们考虑不使用Differential Propagation的情况,首先是a->c->d的传递路线。
+
+![](../.gitbook/assets/image-20201112194234928.png)
+
+然后是b->c->d的传递路线,虽然 $$\{o_1, o_3\}$$之前已经在c所指向的集合中了,但依然需要参与传播,这是冗余的。
+
+![](../.gitbook/assets/image-20201112194358502.png)
+
+我们再来看使用Differential Propagation的情况,只需要传播$$\{o_5\}$$一项即可。在实际应用中这能够大大减小开销。
+
+![](../.gitbook/assets/image-20201112194555582.png)
+
+* In practice, Δ is usually small compared with the original set, so propagating only the new points-to information \(Δ\)
+* Besides, Δ is also important for efficiency when handling stores, loads, and method calls, as explained later
+
+### Handling Store and Load
+
+![](../.gitbook/assets/image-20201112195502575.png)
+
+对于AddEdge函数中第二个if的说明:仅在第一次添加s->t到PFG时添加pt\(s\)的信息到t,是因为Propagate中的语句能够处理后续的pt\(s\)变化。
+
+### The Algorithm-Review
+
+至此,我们完整地介绍了为了教学目的设计的指针分析算法。
+
+![](../.gitbook/assets/image-20201123205009821.png)
+
+### Example
+
+**尝试用上述算法,计算以下代码的PFG。**
+
+```java
+b = new C();
+a = b;
+c = new C();
+c.f = a;
+d = c;
+c.f = d;
+e = d.f;
+```
+
+这一例子动态内容很多,所以计划录制一小段视频讲解。先放个答案,能自己推导对的同学就可以跳过视频了。
+
+![](../.gitbook/assets/image-20201126221950557.png)
+
+## Key points
+
+**The X You Need To Understand in This Lecture**
+
+* **Rules** for pointer analysis
+* **PFG**\(Pointer flow graph\)
+* **Algorithm** for pointer analysis
\ No newline at end of file
diff --git a/ch2/02-04-pointer3-analysis-spa.md b/ch2/02-04-pointer3-analysis-spa.md
new file mode 100644
index 0000000..75967c8
--- /dev/null
+++ b/ch2/02-04-pointer3-analysis-spa.md
@@ -0,0 +1,157 @@
+# 指针分析理论基础二
+
+首先回顾一下在上一篇文章中列出的大纲。
+
+1. Pointer Analysis: Rules
+2. How to Implement Pointer Analysis
+3. Pointer Analysis: Algorithms
+4. Pointer Analysis with Method Calls
+
+承接上一篇,本文谈谈包含指针分析如何处理函数调用。接下来用指针分析的方式来构建Call graph,先来对比一下CHA和指针分析两种方法:
+
+* CHA: imprecise, introduce spurious call graph edges and points-to relations
+* Pointer analysis: more precise than CHA, both for call graph and points-to relations\(a.k.a on-the-fly call graph construction\)
+
+## Pointer Analysis with Method Calls
+
+本课将给出一个包含函数间分析的适用于全程序的算法。
+
+考虑下面这样一小段代码,显然,我们必须要有过程间的分析,才能有更准确的分析结果。
+
+```java
+void foo(A a) {
+ …
+ // 𝑝𝑡(𝑎) = ?
+ b = a.bar();
+ // 𝑝𝑡(𝑏) = ?
+ …
+}
+```
+
+### Rule for Call
+
+和过程间分析紧密相关的是过程调用的处理。也就是上节课提到的最后一条与Call有关的规则。
+
+这个规则看起来复杂得多,我们一点一点来解析。首先,请读者们暂停一下,回忆一般语言如何处理过程调用。即过程调用时到底发生了什么。
+
+![](../.gitbook/assets/image-20201126230831572.png)
+
+> 一个参考答案:保存现场,构造调用栈帧,传递参数,跳转到目标函数开始执行……目标函数执行完毕跳转回来,后从预定的位置取返回值(若需要),恢复现场,继续往下执行……
+
+在静态分析中,我们更多地关心数据流,而非控制流。而针对Java,处理函数调用的数据流可以分为以下四个部分:
+
+1. 确定目标方法。用第7课介绍过的Dispatch函数完成。
+2. 传receiver object
+
+![](../.gitbook/assets/image-20201126184745576.png)
+
+3. 传参数
+
+![](../.gitbook/assets/image-20201126185008506.png)
+
+4. 传返回值
+
+![](../.gitbook/assets/image-20201126185233403.png)
+
+因此,我们可以对应规则,在PFG上添加Edge实现过程间信息的传递。完整的规则如下:
+
+![](../.gitbook/assets/image-20201126231116221.png)
+
+#### Detail-1
+
+**Question: Why not add PFG edge 𝑥 →** $$𝑚_{𝑡ℎ𝑖𝑠}$$**?**
+
+通过这两个图可以直观地说明原因:
+
+![](../.gitbook/assets/image-20201126231403264.png)
+
+![](../.gitbook/assets/image-20201126231437769.png)
+
+_在每次算法执行时,_$$o_i$$_是确定的某个(只有一个)对象,然后针对这个对象做Dispatch,能够找到对应的唯一的receiver object._
+
+#### Detail-2
+
+像之前用CHA做过程间分析时一样,我们需要将分析的过程和Call graph构建的过程结合起来。
+
+![](../.gitbook/assets/image-20201126231722298.png)
+
+不同的是,这次我们只分析从main方法(或者一般性地说,程序入口)开始可达的部分。原因有二:
+
+1. 提升分析速度。因为我们能够避免分析不会被执行到的死代码。
+2. 提升分析精度。避免了unreachable部分的代码调用reachable部分方法时可能引起的精度下降。
+
+![](../.gitbook/assets/image-20201126191225969.png)
+
+## Algorithm: PA with Method Calls
+
+接下来介绍一个具体的、易于理解和实现的算法。由于指针分析是静态程序分析的基础,理解了这个看起来枯燥的算法后,更容易在静态程序分析领域触类旁通。~~而且据说后面两节课会学得更加轻松~~
+
+![](../.gitbook/assets/image-20201126191650221.png)
+
+算法整体上来说和上一节课所介绍的大框架相似,黄色标记的部分是这次新加入的部分。绿色部分是对新的全局变量的说明:
+
+* S里的statements就是RM里methods的statements(语句)
+* Call Graph和指针集作为最后的输出。
+
+### Function: AddReachable
+
+AddReachable的作用是:
+
+* **输入参数**m是最新的可达方法。
+* 函数修改维护全局的RM、S和$$S_m$$,并处理新的方法m中的New和Assign语句。
+
+![](../.gitbook/assets/image-20201126194125039.png)
+
+#### Detail-3
+
+**Question: 为什么要检查l->m是否在CG中,即为什么同样的l->m可能不止一次地被处理?**
+
+_l代表call site。可以用行号作为call site的label。_
+
+> Answer: $$o_j, o_k$$同样可能通过Dispatch返回同一个m。
+
+### Function:ProcessCall
+
+ProcessCall的作用是:
+
+* 输入的$$o_i$$是x新指向的目标。
+* 函数在可达的语句集合S中,选择所有与x有关的过程调用,做之前提到的数据流相关四步处理(确定被调用方法、传对象、传参数,传返回值)。
+
+![](../.gitbook/assets/image-20201126195311513.png)
+
+![](../.gitbook/assets/image-20201126195425756.png)
+
+## Example
+
+**利用之前学习的算法分析以下代码,构建Call graph和PFG。**
+
+```java
+class A {
+ static void main() {
+ A a = new A();
+ A b = new B();
+ A c = b.foo(a);
+ }
+ A foo(A x) { … }
+}
+class B extends A {
+ A foo(A y) {
+ A r = new A();
+ return r;
+ }
+}
+```
+
+答案如下:
+
+![](../.gitbook/assets/image-20201126201000426.png)
+
+这个流不敏感的分析算法在分析精度上仍然可以改进。我们将在接下来的课程中学习精度更高的流敏感分析。
+
+## Key points
+
+**The X You Need To Understand in This Lecture**
+
+* Pointer analysis **rule for method call**
+* **Algorithm** for inter-procedural pointer analysis
+* **On-the-fly call graph construction**
diff --git a/ch2/README.md b/ch2/README.md
index 84c06b2..04d22ec 100644
--- a/ch2/README.md
+++ b/ch2/README.md
@@ -1,9 +1,9 @@
-# 第二章-数据流分析的理论与应用
+# 过程间分析
-**注:第一章到第三章在B站上有相应的视频。在作者腾出时间整理文稿之前,建议读者先到B站观看相应的视频。对应的文字部分暂时移出本仓库。**
+**阅读提示:使用屏幕较大的设备能够看到自带的Sticky Table of Contents,更有利于理清阅读思路。**
-对应的视频在这里:
-- [第三课-数据流分析一](https://www.bilibili.com/video/BV1oE411K79d)
-- [第四课-数据流分析二](https://www.bilibili.com/video/BV19741197zA)
+对应视频在:
+
+* [第七课-过程间分析](https://www.bilibili.com/video/BV1GQ4y1T7zm)
+* [第八课-指针分析](https://www.bilibili.com/video/BV1gg4y1z78p)
-从[这里](https://ranger-nju.gitbook.io/static-program-analysis-book/ch4)直接跳转到施工完毕区域(第四章)。
\ No newline at end of file
diff --git a/ch3/README.md b/ch3/README.md
deleted file mode 100644
index 5c524dc..0000000
--- a/ch3/README.md
+++ /dev/null
@@ -1,11 +0,0 @@
-# 第三章-数据流分析——理论
-
-帮助理解之前所数的数据流分析技术,让你在将来review的时候更有效率。忘记了也能自己推导出大概。
-
-**注:第一章到第三章在B站上有相应的视频。在作者腾出时间整理文稿之前,建议读者先到B站观看相应的视频。对应的文字部分暂时移出本仓库。**
-
-对应的课程在这里:
-- [第五课-数据流分析理论一](https://www.bilibili.com/video/BV1A741117it)
-- [第六课-数据流分析理论二](https://www.bilibili.com/video/BV1964y1M7nL)
-
-从[这里](https://ranger-nju.gitbook.io/static-program-analysis-book/ch4)直接跳转到施工完毕区域(第四章)。
\ No newline at end of file
diff --git a/ch4/04-01-inter-analysis-spa.assets/image-20201029224301293.png b/ch4/04-01-inter-analysis-spa.assets/image-20201029224301293.png
deleted file mode 100644
index 8ba6858..0000000
Binary files a/ch4/04-01-inter-analysis-spa.assets/image-20201029224301293.png and /dev/null differ
diff --git a/ch4/04-01-inter-analysis-spa.assets/image-20201029231905890.png b/ch4/04-01-inter-analysis-spa.assets/image-20201029231905890.png
deleted file mode 100644
index b8ea304..0000000
Binary files a/ch4/04-01-inter-analysis-spa.assets/image-20201029231905890.png and /dev/null differ
diff --git a/ch4/04-01-inter-analysis-spa.md b/ch4/04-01-inter-analysis-spa.md
deleted file mode 100644
index d677ad0..0000000
--- a/ch4/04-01-inter-analysis-spa.md
+++ /dev/null
@@ -1,252 +0,0 @@
-**建议使用屏幕较大的设备查看以便纵览全局,在手机上及其他小屏幕设备上查看可能无法查看默认包含的Table of Contents。**
-
-# 过程间分析简介
-
-本小节通过四个部分介绍过程间分析。
-
-1. Motivation
- - **为什么**要引入过程间分析?
-2. Call Graph Construction (CHA)
- - 介绍一个过程间分析**必要的数据结构Call Graph**
- - 当前有数种方法来**构建Call Graph**,本节介绍其中**速度最快的一种(Class hierarchy analysis,简称CHA)**
-3. Interprocedural Control-Flow Graph
- - 之前的章节关注CFG,引入过程间分析后,我们向CFG中**添加相应的元素**,得到过程间的控制流图(ICFG)
- - 讨论由于添加了新元素而需要**增加的操作**
-4. Interprocedural Data-Flow Analysis
- - 通过一个例子(也就是实验一中做的常量传播分析)来**总结**过程间分析。
-
-# Motivation
-
-之前的章节中都没有考虑方法调用,然而在实际的程序中方法调用非常常见,那么我们如何分析带方法调用的程序呢?最简单的处理方式是:做最保守的假设,即**为函数调用返回NAC**。而这种情况会**丢失精度**。**引入过程间分析能够提高精度。**如果使用最简单的处理方式,下图中的n和y分析结果都不是常量,尽管我们能够一眼看出他们的运行时值是n=10,y=43。
-
-
-
-# Call Graph Construction (CHA)
-
-接下来我们讨论一个必要的数据结构Call Graph,中文可以理解为调用关系图。
-
-## Definition of Call Graph
-
-> A representation of calling relationships in the program.
-
-调用关系图表达调用关系(中文讲起来很奇怪!!),一个简单的例子如下:
-
-
-
-## Call Graph Construction
-
-Call Graph有很多种不同的构造方法,我们接下来会讲解两个极端:最准确的和最快速的。
-
-
-
-### Call types in Java
-
-本课主要关注Java的调用关系图构建。为此,我们需要先了Java中调用的类型。Java中call可分为三类(不需要理解透彻,之后会详细介绍):
-
-
-
-- Instruction:指Java的**IR中的指令**
-- Receiver objects:方法对应的实例对象(static方法不需要对应实例)。
-- Target methods:表达**方法到IR指令的映射关系**
-- Num of target methods:call可能对应的方法数量。Virtual call与动态绑定和多态实现有关,可以对应多个对象下的重写方法。所以**Virtual call的可能对象可能超过1个**。
-- Determinacy:指什么时候能够确定这个call的对应方法。Virtual call与多态有关,只能在运行时决定调用哪一个具体方法的实现。其他两种call都和多态机制不相关,编译时刻就可以确定。
-
-### Virtual call and dispatch
-
-Virtual call是几种调用中最为复杂的一种,我们首先重点讨论它。在动态运行时,Virtual call基于两点决定调用哪个具体方法:
-
-1. Type of object
-2. Method signature
- - Signature = class type + method name + descriptor
- - Descriptor = return type + parameter types
-
-
-
-Java中Dispatch机制决定具体调用哪个方法:c是一个类的定义,m是一个方法。如果能在本类中找到name和descriptor一致的方法,则调用c的方法,否则到父类中寻找。
-
-> We define function Dispatch(𝑐, 𝑚) to simulate the procedure of run-time method dispatch.
-
-
-
-**练习问题**
-
-Q:两次对foo的调用分别调用了哪个类的foo?
-
-
-
-A:分别调用A和C中定义的foo方法。
-
-
-
-# Class Hierarchy Analysis (CHA)
-
-## Definition of CHA
-
-- Require the class **hierarchy information (inheritance structure)** of the whole program
- - 需要首先获得整个程序的继承关系图
-- Resolve a virtual call based on the declared type of receiver variable of the call site
- - 通过接收变量的声明类型来解析Virtual call
- - 接收变量的例子:在`a.foo()`中,a就是接收变量
-- Assume the receiver variable a may point to objects of class A or all subclasses of A(Resolve target methods by looking up the class hierarchy of class A)
- - 假设一个接收变量能够指向A或A的所有子类
-
-## Call Resolution of CHA
-
-### Algorithm of Resolve
-
-下面介绍解析调用的算法。
-
-
-
-- call site(cs)就是调用语句,m(method)就是对应的函数签名。
-- T集合中保存找到的结果
-- 三个if分支分别对应之前提到的Java中的三种call类型
- 1. Static call(所有的静态方法调用)
- 2. Special call(使用super关键字的调用,构造函数调用和Private instance method)
- 3. Virtual call(其他所有调用)
-
-**Static call**
-
-- 对于不了解OOP中静态方法的同学可以参考[这里](https://www.geeksforgeeks.org/static-methods-vs-instance-methods-java/)。具体来说,静态方法前写的是类名,而非静态方法前写的是变量或指针名。静态方法不需要依赖实例。
-
-**Special call**
-
-- Superclass instance method(super关键字)最为复杂,故优先考虑这种情况
-
- - 为什么需要Dispatch函数?考虑这种情况:
-
-
-- 而Private instance method和Constructor(一定由类实现或有默认的构造函数)都会在本类的实现中给出,使用Dispatch函数能够将这三种情况都包含,简化代码。
-
-**Virtual call**
-
-- receiver variable在例子中就是c。
-
-- 对receiver c和c的所有直接间接子类都作为call site调用Dispatch
-
-**一个例子**
-
-## CHA的特征
-
-1. 只考虑继承结构,所以**很快**
-2. 因为忽略了数据流和控制流的信息,所以**不太准确**
-
-## CHA的应用
-
-常用于IDE中,给用户提供提示。比如写一小段测试代码,看看b.foo()可能会调用哪些函数签名。可以看出CHA分析中认为`b.foo()`可能调用A、C、D中的`foo()`方法。(实际上这并不准确,因为b实际上是B类对象,不会调用子类C、D中的方法,但胜在快速)
-
-
-
-## Call Graph Construction
-
-### Idea
-
-- Build call graph for whole program via CHA
- - 通过CHA构造整个程序的call graph
-- Start from entry methods (focus on main method)
- - 通常从main函数开始
-- For each reachable method 𝑚, resolve target methods for each call site 𝑐𝑠 in 𝑚 via CHA (Resolve(𝑐𝑠))
- - 递归地处理对每个可达的方法
-- Repeat until no new method is discovered
- - 当不能拓展新的可达方法时停止
-- 整个过程和计算理论中求闭包的过程很相似
-
-
-
-### Algorithm
-
-
-
-- Worklist记录需要处理的methods
-- Call graph是需要构建的目标,是call edges的集合
-- Reachable method是已经处理过的目标,在Worklist中取新目标时,不需要再次处理已经在RM中的目标
-
-### Example
-
-*我也不想当无情的PPT摘抄机器,可是markdown对自己做图的支持太差了啊(x。*
-
-1. 初始化
-2. 处理main后向WL中加入A.foo()
-3. 中间省略一些步骤,这里面对C.bar()时,虽然会调用A.foo(),但由于A.foo()之前已经处理过(在集合RM中),之后不会再进行处理
-4. 这里C.m()是不可达的死代码
-
-*注:忽略new A()对构造函数的调用,这不是例子的重点。*
-
-**这个例子是对本小节的总结,如果不能读懂并独立推导建议重读一遍。如果你理解了第一到第六课的内容但是觉得上面的内容写得不清晰,可以到本书简介中提到的QQ群交流吐槽。**
-
-## Interprocedural Control-Flow Graph
-
-> ICFG = CFG+call & return edges
-
-ICFG可以通过CFG加上两种边构造得到。
-
-1. Call edges: from call sites to the entry nodes of their callees
-2. Return edges: from return statements of the callees to the statements following their call sites (i.e., return sites)
-
-例如:
-
-
-
-
-
-# Interprocedural Data-Flow Analysis
-
-## 定义与比较
-
-目前这一分析领域没有标准方法。首先对过程间和过程内的分析做一个对比,并以常量传播(本校同学第一次实验作业主题,需要一到六课的基础)为例子进行解释。
-
-
-
-Edge transfer处理引入的call & return edge。为此,我们需要**在之前章节的CFG基础上增加三种transfer函数。**
-
-- Call edge transfer
- - 从调用者向被调用者传递参数
-- Return edge transfer
- - 被调用者向调用者传递返回值
-- Node transfer
- - 大部分与过程内的常数传播分析一样,不过对于每一个函数调用,都要kill掉LHS(Left hand side)的变量
-
-## Example
-
-
-
-### 小问题
-
-这一段有存在的必要吗?
-
-
-
-> Such edge (from call site to return site) is named call-to-return edge. It allows the analysis to propagate local data-flow (a=6 in this case) on ICFG.
-
-如果没有这一段,那么a就得“出国”去浪费地球资源——在分析被调用函数的全程中都需要记住a的值,这在程序运行时会浪费大量内存。
-
-
-
-要记得在调用语句处kill掉表达式左边的值,否则会造成结果的不准确,如:
-
-
-
-
-
-# 过程间分析有多重要?
-
-讲到这里,我们回到故事的开头,看看过程间分析的引入到底能带来多大的精度提高吧。上述例子应用过程间分析的完整推导如下:
-
-
-
-而如果只做过程内分析,则**精度大大下降**:
-
-
-
-# Key points
-
-**The X You Need To Understand in This Lecture**
-
-1. How to build call graph via class hierarchy analysis
- - 如何利用CHA构建调用关系图(call graph)
-2. Concept of interprocedural control-flow graph
- - 过程间控制流图(CFG)的概念
-3. Concept of interprocedural data-flow analysis
- - 过程间数据流分析的概念
-4. Interprocedural constant propagation
- - 例子——引入过程间分析的常量分析
\ No newline at end of file
diff --git a/ch4/README.md b/ch4/README.md
deleted file mode 100644
index 5727996..0000000
--- a/ch4/README.md
+++ /dev/null
@@ -1,7 +0,0 @@
-# 过程间分析简介
-
-**建议使用屏幕较大的设备查看以便纵览全局,在手机上及其他小屏幕设备上查看可能无法查看默认包含的Table of Contents。**
-
-即将抵达没有视频辅助的区域,如果想看看视频,请到[第七课](https://www.bilibili.com/video/BV1GQ4y1T7zm)和[第八课](https://www.bilibili.com/video/BV1gg4y1z78p)。
-
-写成gitbook形式力求能够更快地掌握要点(虽然还是因为偷懒留了一部分英文没有翻译),而视频则能动态地呈现内容。欢迎大家提出意见和建议!(方式见[Github repo](https://github.com/RangerNJU/Static-Program-Analysis-Book))。
\ No newline at end of file
diff --git a/src/README.md b/src/README.md
deleted file mode 100644
index f409dc2..0000000
--- a/src/README.md
+++ /dev/null
@@ -1,11 +0,0 @@
-# Static-Program-Analysis-Book
-
-[Gitbook在线阅读地址](https://ranger-nju.gitbook.io/static-program-analysis-book/)
-
-[GitHub项目地址](https://github.com/RangerNJU/Static-Program-Analysis-Book)
-
-----
-
-Getting started with static program analysis. Read this and start writing your first static program analyzer!
-
-静态程序分析入门。阅读此书并着手编写你的第一个静态程序分析器吧!
diff --git a/src/ch3/03-00-dataflow-analysis.md b/src/ch3/03-00-dataflow-analysis.md
deleted file mode 100644
index 70d2b46..0000000
--- a/src/ch3/03-00-dataflow-analysis.md
+++ /dev/null
@@ -1,4 +0,0 @@
-# 数据流分析例一——Reaching Definition
-
-TBD
-
diff --git a/src/ch3/03-03-available-exp-analysis.md b/src/ch3/03-03-available-exp-analysis.md
deleted file mode 100644
index 52d0cd0..0000000
--- a/src/ch3/03-03-available-exp-analysis.md
+++ /dev/null
@@ -1,18 +0,0 @@
-# 可用表达式分析
-
-## 定义
-
-> An expression x op y is available at program point p if (1) all paths from the entry to p must pass through the evaluation of x op y, and (2) after the last evaluation of x op y, there is no redefinition of x or y.
-
-## 理解定义:一个tricky的例子
-
-1. 按照直觉来说,c处不是,但是按照定义来说是。但是实际上运行时只会走一条分支。
-
-2. 回顾:
-must->under-approximation->报出来的全都是真的。不允许误报,但允许漏报
-may->不允许漏报,但允许误报
-重新理解这个例子。
-
-PS. 如何记住边界条件设置谁?设置是空还是满?对余下所有块的初始化是空还是满(一个巧妙的方法是判断may/must后,如果条件汇合时是交集,一般开始时大多数块初始化为满。)
-
-一个经常迷惑的问题:先gen先kill?根据定义就解决所有问题2
\ No newline at end of file
diff --git a/src/ch3/README.md b/src/ch3/README.md
deleted file mode 100644
index 152d806..0000000
--- a/src/ch3/README.md
+++ /dev/null
@@ -1 +0,0 @@
-# 数据流分析的理论与应用