- 浏览: 3015463 次
- 性别:
- 来自: 海外
文章分类
- 全部博客 (430)
- Programming Languages (23)
- Compiler (20)
- Virtual Machine (57)
- Garbage Collection (4)
- HotSpot VM (26)
- Mono (2)
- SSCLI Rotor (1)
- Harmony (0)
- DLR (19)
- Ruby (28)
- C# (38)
- F# (3)
- Haskell (0)
- Scheme (1)
- Regular Expression (5)
- Python (4)
- ECMAScript (2)
- JavaScript (18)
- ActionScript (7)
- Squirrel (2)
- C (6)
- C++ (10)
- D (2)
- .NET (13)
- Java (86)
- Scala (1)
- Groovy (3)
- Optimization (6)
- Data Structure and Algorithm (3)
- Books (4)
- WPF (1)
- Game Engines (7)
- 吉里吉里 (12)
- UML (1)
- Reverse Engineering (11)
- NSIS (4)
- Utilities (3)
- Design Patterns (1)
- Visual Studio (9)
- Windows 7 (3)
- x86 Assembler (1)
- Android (2)
- School Assignment / Test (6)
- Anti-virus (1)
- REST (1)
- Profiling (1)
- misc (39)
- NetOA (12)
- rant (6)
- anime (5)
- Links (12)
- CLR (7)
- GC (1)
- OpenJDK (2)
- JVM (4)
- KVM (0)
- Rhino (1)
- LINQ (2)
- JScript (0)
- Nashorn (0)
- Dalvik (1)
- DTrace (0)
- LLVM (0)
- MSIL (0)
最新评论
-
mldxs:
虽然很多还是看不懂,写的很好!
虚拟机随谈(一):解释器,树遍历解释器,基于栈与基于寄存器,大杂烩 -
HanyuKing:
Java的多维数组 -
funnyone:
Java 8的default method与method resolution -
ljs_nogard:
Xamarin workbook - .Net Core 中不 ...
LINQ的恶搞…… -
txm119161336:
allocatestlye1 顺序为 // Fields o ...
最近做的两次Java/JVM分享的概要
之前有同学在做龙书(第二版)题目,做到8.4的练习,跟我对答案,然后聊起C语言的for循环的代码生成有几种常见的模式。顺道跟大家分享讨论一下。
C语言的for循环大家应该都很熟悉了,C系语言大都有一样或几乎一样的语法结构:一个循环初始化,一个循环条件,一个循环再初始化,然后一个循环体。通常循环初始化在最前面,再初始化的逻辑直接黏在循环体后面,能有变化的就是循环条件的代码生成到什么位置。
举个例子,
把它翻译为龙书第8章所用的三地址指令,可以用许多不同的模式翻译,这里举三种例子:
(注释里标出了基本块的标号、前导基本块、后继基本块,以及基本块的内容等信息。应该很直观吧?)
第一种:循环条件放前面,循环末尾用无条件跳转回到开头:
第二种:循环条件放后面,在进入循环的地方先无条件跳转到位于循环末尾的条件:
第三种:在进入循环的地方先判断是否跳过循环,然后循环条件放在末尾:
顺带一提,这个具体例子中循环条件是拿循环变量与一个编译时常量比较,所以这个版本的代码的(2)可以非常轻易的通过条件常量传播消除掉,等价变换为:
而前两种模式没那么容易消除其中的指令。
有兴趣的同学可以来讨论下这几种模式的异同点
注意三地址指令的条数,基本块的个数与划分,基本块之间控制流边的总个数,代码的静态与动态的情况的关系,等等。
当然这不是啥新问题,早就有很多论文讨论过了。
例如说某篇1978年的小论文⋯名字就先不说了免得剧透。有兴趣的同学自己思考喔。
========================================
下面补充些在实际生活种能看到的例子。
1. Java虚拟机规范,Java SE 7版,3.2小节
这里举了几个Java的for循环翻译为字节码的范例,都符合上面说的“第二种”模式。
例如把这样的代码:
翻译为:
Eclipse Compiler for Java (ecj)就采取了这种模式。但Oracle JDK6里自带的javac实际用的代码生成策略却是前面说的“第一种”,将上面的例子编译为:
好玩吧呵呵厚⋯
C语言的for循环大家应该都很熟悉了,C系语言大都有一样或几乎一样的语法结构:一个循环初始化,一个循环条件,一个循环再初始化,然后一个循环体。通常循环初始化在最前面,再初始化的逻辑直接黏在循环体后面,能有变化的就是循环条件的代码生成到什么位置。
举个例子,
for (int i = 0; i < 100; i++) { foo(); }
把它翻译为龙书第8章所用的三地址指令,可以用许多不同的模式翻译,这里举三种例子:
(注释里标出了基本块的标号、前导基本块、后继基本块,以及基本块的内容等信息。应该很直观吧?)
第一种:循环条件放前面,循环末尾用无条件跳转回到开头:
// B0 -> B1: loop initialize (1) i = 0 // B1 <- { B0, B2 }, -> { B2, B3 }: loop condition (2) if i >= 100 goto (6) // note: inverted condition // B2 <- B1, -> B1: loop body (3) call foo() (4) i = i + 1 (5) goto (2) // B3 <- B1: after loop (6) ...
第二种:循环条件放后面,在进入循环的地方先无条件跳转到位于循环末尾的条件:
// B0 -> B2: loop initialize (1) i = 0 (2) goto (5) // B1 <- B2, -> B2: loop body (3) call foo() (4) i = i + 1 // B2 <- { B0, B1 }, -> { B1, B3 }: loop condition (5) if i < 100 goto (3) // B3 <- B2: after loop (6) ...
第三种:在进入循环的地方先判断是否跳过循环,然后循环条件放在末尾:
// B0 -> { B1, B3 }: loop initialize (1) i = 0 (2) if i >= 100 goto (6) // note: inverted condition // B1 <- { B0, B2 }, -> B2: loop body (3) call foo() (4) i = i + 1 // B2 <- B1, -> { B1, B3 }: loop condition (5) if i < 100 goto (3) // B3 <- { B0, B2 }: after loop (6) ...
顺带一提,这个具体例子中循环条件是拿循环变量与一个编译时常量比较,所以这个版本的代码的(2)可以非常轻易的通过条件常量传播消除掉,等价变换为:
// B0 -> B1: loop initialize (1) i = 0 // B1 <- { B0, B2 }, -> B2: loop body (2) call foo() (3) i = i + 1 // B2 <- B1, -> { B1, B3 }: loop condition (4) if i < 100 goto (2) // B3 <- { B0, B2 }: after loop (5) ...
而前两种模式没那么容易消除其中的指令。
有兴趣的同学可以来讨论下这几种模式的异同点
注意三地址指令的条数,基本块的个数与划分,基本块之间控制流边的总个数,代码的静态与动态的情况的关系,等等。
当然这不是啥新问题,早就有很多论文讨论过了。
例如说某篇1978年的小论文⋯名字就先不说了免得剧透。有兴趣的同学自己思考喔。
========================================
下面补充些在实际生活种能看到的例子。
1. Java虚拟机规范,Java SE 7版,3.2小节
这里举了几个Java的for循环翻译为字节码的范例,都符合上面说的“第二种”模式。
例如把这样的代码:
void spin() { int i; for (i = 0; i < 100; i++) { ; // Loop body is empty } }
翻译为:
0: iconst_0 // Push int constant 0 1: istore_1 // Store into local variable 1 (i=0) 2: goto 8 // First time through don't increment 5: iinc 1, 1 // Increment local variable 1 by 1 (i++) 8: iload_1 // Push local variable 1 (i) 9: bipush 100 // Push int constant 100 11: if_icmplt 5 // Compare and loop if less than (i < 100) 14: return // Return void when done
Eclipse Compiler for Java (ecj)就采取了这种模式。但Oracle JDK6里自带的javac实际用的代码生成策略却是前面说的“第一种”,将上面的例子编译为:
0: iconst_0 1: istore_1 2: iload_1 3: bipush 100 5: if_icmpge 14 8: iinc 1, 1 11: goto 2 14: return
好玩吧呵呵厚⋯
发表评论
-
The Prehistory of Java, HotSpot and Train
2014-06-02 08:18 0http://cs.gmu.edu/cne/itcore/vi ... -
MSJVM and Sun 1.0.x/1.1.x
2014-05-20 18:50 0当年的survey paper: http://www.sym ... -
Sun JDK1.4.2_28有TieredCompilation
2014-05-12 08:48 0原来以前Sun的JDK 1.4.2 update 28就已经有 ... -
IBM JVM notes (2014 ver)
2014-05-11 07:16 0Sovereign JIT http://publib.bou ... -
class data sharing by Apple
2014-03-28 05:17 0class data sharing is implement ... -
Java 8与静态工具类
2014-03-19 08:43 16137以前要在Java里实现所谓“静态工具类”(static uti ... -
Java 8的default method与method resolution
2014-03-19 02:23 10332先看看下面这个代码例子, interface IFoo { ... -
HotSpot Server VM与Server Class Machine
2014-02-18 13:21 0HotSpot VM历来有Client VM与Server V ... -
Java 8的lambda表达式在OpenJDK8中的实现
2014-02-04 12:08 0三月份JDK8就要发布首发了,现在JDK8 release c ... -
GC stack map与deopt stack map的异同
2014-01-08 09:56 0两者之间不并存在包含关系。它们有交集,但也各自有特别的地方。 ... -
HotSpot Server Compiler与data-flow analysis
2014-01-07 17:41 0http://en.wikipedia.org/wiki/Da ... -
基于LLVM实现VM的JIT的一些痛点
2014-01-07 17:25 0同事Philip Reames Sanjoy Das http ... -
《自制编程语言》的一些笔记
2013-11-24 00:20 0http://kmaebashi.com/programmer ... -
字符串的一般封装方式的内存布局 (1): 元数据与字符串内容,整体还是分离?
2013-11-07 17:44 22250(Disclaimer:未经许可请 ... -
字符串的一般封装方式的内存布局
2013-11-01 12:55 0(Disclaimer:未经许可请 ... -
关于string,内存布局,C++ std::string,CoW
2013-10-30 20:45 0(Disclaimer:未经许可请 ... -
Java的instanceof是如何实现的
2013-09-22 16:57 0Java语言规范,Java SE 7版 http://docs ... -
struct做参数不能从寄存器传?
2013-08-28 23:33 0test test test struct Foo { i ... -
oop、klass、handle的关系
2013-07-30 17:34 0oopDesc及其子类的实例 oop : oopDesc* ... -
Nashorn各种笔记
2013-07-15 17:03 0http://bits.netbeans.org/netbea ...
相关推荐
一个简单的编辑器 编译原理课设 对简单的程序进行语义分析并将中间代码生成
实验课上写的编译原理的语义分析和四元式代码的生成。
编译原理实验 语义分析与中间代码生成 Sample语言的语义和代码生成规则,熟悉Sample语言的语义分析和代码生成过
编译原理语义分析和中间代码生成实验报告,基于VS2010开发的纯C#的程序,附程序执行截图
语义分析及目标代码生成c++源码.zip编译原理OJ-语义分析及目标代码生成c++源码.zip编译原理OJ-语义分析及目标代码生成c++源码.zip编译原理OJ-语义分析及目标代码生成c++源码.zip编译原理OJ-语义分析及目标代码生成...
C# 语义分析 中间代码 大学课程设计 C# 语义分析 中间代码 大学课程设计
详细探讨了语义分析和中间代码生成凭证的设计方式
语义分析及中间代码生成程序设计原理与实现技术
第五章_语义分析和中间代码生成_(编译原理)......
华中科技大学 编译原理 面向过程的C语言的编译器设计 功能包括:词法分析和语法分析、语义分析、中间代码生成的 源码 题目:c--语言编译器设计与实现(请为自己的编译器命名) 源语言定义:或采用教材中Decaf语言,...
词法分析,递归下降的语法分析及四元式代码生成的C语言代码
1. 分析PL/0程序的Block子程序,...要求从自己的源程序中选择一条语句,结合这条语句写出语义分析和代码生成过程。在描述这个过程中,要说清楚每个功能有哪个子程序的哪条语句来完成,说清楚语句和参数的含义和功能。
编译原理 课程设计编译原理 课程设计编译原理 课程设计编译原理 课程设计编译原理 课程设计
编译原理实验 语义分析 源代码 C语言实现
编译 原理 第四章 语义分析 中间代码 生成 课后 答案 好东西来下载
Java编写的一个类C语言编译器(词法分析,语法分析,语义分析和目标代码生成) 编写一个完整的类C语言编译器是一个复杂的编程项目,涉及多个阶段,包括词法分析、语法分析、语义分析和目标代码生成。以下是一个简化...
语义分析与中间代码生成天津理工大学编译原理实验3
TINY+词法分析,语法分析,语义分析,代码生成。包含实验报告。
语义分析和中间代码生成实用教案.pptx
华中科技大学 编译原理 面向过程的C--语言的编译器设计 功能包括:词法分析和语法分析、语义分析、中间代码生成的 源码.zip