标签:ini frame tar iad class ack 位置 项目 属性
项目的完整代码在 C2j-Compiler
第十一篇,终于要进入代码生成部分了,但是但是在此之前,因为我们要做的是C语言到字节码的编译,所以自然要了解一些字节码,但是由于C语言比较简单,所以只需要了解一些字节码基础
JVM有一个执行环境叫做stack frame
这个环境有两个基本数据结构
还有一个PC指针,它指向下一条要执行的指令。
int f(int a, int b) {
return a+b;
}
f(1,2);
JVM的执行环境是这样变化的
stack:
localarray:1,2
pc:把a从localarray取出放到stack
stack:1
localarray:2
pc:把b从localarray取出放到stack
stack:1,2
localarray:
pc:把a,b弹出堆栈并且相加压入堆栈
.class public CSourceToJava
.super java/lang/Object
.method public static main([Ljava/lang/String;)V
getstatic java/lang/System/out Ljava/io/PrintStream;
ldc "Hello World!"
invokevirtual java/io/PrintStream/println(Ljava/lang/String;)V
return
.end method
.end class
getstatic、ldc和invokevirtual都相当于JVM提供的指令
getstatic和ldc相当于压入堆栈操作。invokevirtual则是从堆栈弹出参数,然后调用方法
stack: out "Hello World!"
JVM的运行基本都是围绕着堆栈来进行,所以指令也都是和堆栈相关,比如进行一个乘法1 * 2:
bipush 1
bipush 2
imul
可以看到JVM的指令操作时带数据的类型,b代表byte,也就是只能操作-128 ~ 128之间的数,而i代表是整形操作,所以相应也会有sipush等等了
下面加入要把1 * 2打印用prinft打印在控制台上,就需要把out对象压入堆栈,此时的堆栈:
stack: 2 out
但是调用out的参数需要在堆栈顶部,所以这时候就需要两个指令iload、istore
istore 0把2放到局部变量队列,再把out压入堆栈,再用iload 0把2放入堆栈中
stack: out 2
在字节码里,局部变量和函数参数都会存储在队列上
int func() {
int a;
int b;
a = 1;
b = 2;
return a + b;
}
看一下这个方法执行的时候堆栈的变化情况
// 执行a = 1,把1压到stack上,再把1放入到队列里
stack:
array:1
// 执行b = 1,也同理
stack:
array:1, 2
最后的return也有相应的return指令,所以完整的指令如下
sipush 1
istore 0
sipush 2
istore 1
iload 0
iload 1
iadd
ireturn
int func(int a, int b, int c, int d){}
在调用这个函数的适合,函数参数就会按照顺序被压入堆栈中,然后拷贝到队列上
stack: a b c d
array:
stack:
array: d c b a
所以在之后的代码生成部分就需要一个来找到局部变量的位置的函数
下面这段指令的作用是创建一个大小为100的整形数组
sipush 100
newarray int
astore 0
下面这段指令是读取数组的第66个元素
aload 0
sipush 66
iaload
aload 0
sipush 7
sipush 10
iastore
C语言里的结构体其实就相当于没有方法只有属性的类,所以可以把结构体编译成一个类
new MyClass //创建一个名字为MyClass的类
invokespecial ClassName/<init>() V //调用类的无参构造函数
public class MyClass {
public int a;
public char c;
public MyClass () {
this.a = 0;
this.c = 0;
}
}
public class MyClass生成下面的代码,都是对应生成一个类的特殊指令
.class public MyClass
.super java/lang/Object
下面的则是对应属性的声明
.field public c C
.field public a I
声明完属性,就是构造函数了,首先是先把类的实例加载到堆栈,再调用它的父类构造函数,对属性的赋值:
aload 0
invokespecial java/lang/Object/<init>()V
aload 0
sipush 0
putfield MyClass/c C
aload 0
sipush 0
putfield MyClass/a I
return
完整的对应的Java字节码如下:
.class public MyClass
.super java/lang/Object
.field public c C
.field public a I
.method public <init>()V
aload 0
invokespecial java/lang/Object/<init>()V
aload 0
sipush 0
putfield MyClass/c C
aload 0
sipush 0
putfield MyClass/a I
return
.end method
.end class
aload 3 ;假设类实例位于局部变量队列第3个位置
putfield ClassName/x I
这一篇主要就是了解一下Java基本的字节码,因为C语言的语法比较简单,所以只需要知道一点就足够生成代码了。下一篇就可以正式进入代码生成部分
另外,欢迎Star这个项目!
标签:ini frame tar iad class ack 位置 项目 属性
原文地址:https://www.cnblogs.com/secoding/p/11384619.html