本文系 Creating JVM language 翻译的第 14 篇。
原文中的代码和原文有不一致的地方均在新的代码仓库中更正过,建议参考新的代码仓库。

源码

Github

支持新的类型

目前为止 Enkel 仅支持了整数类型和字符串类型。是时候支持其他的原始类型了。这也是为创建面向对象特性做准备。

指令集的抽象

字节码指令中有很多指令仅仅是在数据类型上有区别,以 return 指令举例:

  • return - 方法返回
  • ireturn - 返回interger
  • freturn - 返回float
  • dreturn - 返回double
  • lreturn - 返回long
  • areturn - 返回引用

字节码生成的时候,我们多写一点 case 语句可以实现,但是很丑陋。因此我用 TypeSpecificOpcodes 枚举存储了所有类型对应的字节码指令:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public enum TypeSpecificOpcodes { 

INT (ILOAD, ISTORE, IRETURN,IADD,ISUB,IMUL,IDIV), //values (-127,127) - one byte.
LONG (LLOAD, LSTORE, LRETURN,LADD,LSUB,LMUL,LDIV),
FLOAT (FLOAD, FSTORE, FRETURN,FADD,FSUB,FMUL,FDIV),
DOUBLE (DLOAD, DSTORE, DRETURN,DADD,DSUB,DMUL,DDIV),
VOID(ALOAD, ASTORE, RETURN,0,0,0,0),
OBJECT (ALOAD,ASTORE,ARETURN,0,0,0,0);

TypeSpecificOpcodes(int load, int store, int ret, int add, int sub, int mul, int div) {
//assign each parameter to the field
}

//getters

类型相关的字节码指令,目前我们用到了:

  • load - 从局部变量表中加载变量
  • store - 存储至局部变量表
  • ret - 返回
  • add - 操作数栈中两个数相加
  • sub - 栈中操作数相减
  • mul - 栈中操作数相乘
  • div - 栈中操作数相除

TypeSpecificOpcodes 是在 BultInType 类中:

1
2
3
4
5
6
7
8
9
10
11
12
13
public enum BultInType implements Type {
BOOLEAN("bool",boolean.class,"Z", TypeSpecificOpcodes.INT),

//other members

BultInType(String name, Class<?> typeClass, String descriptor, TypeSpecificOpcodes opcodes) {
//assign to fields
}

@Override
public int getMultiplyOpcode() {
return opcodes.getMultiply();
}

无论何时,两个数相乘,只要知道类型就可以了,再也不用查找类型对应的字节码指令:

1
2
3
4
5
public void generate(Multiplication expression) {
evaluateArthimeticComponents(expression);
Type type = expression.getType();
methodVisitor.visitInsn(type.getMultiplyOpcode());
}

示例

如下 Enkel 代码:

1
2
3
4
5
6
7
main(string[] args) {
var stringVar = "str"
var booleanVar = true
var integerVar = 2745 + 33
var doubleVar = 2343.05
var sumOfDoubleVars = 23.0 + doubleVar
}

编译后的字节码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class AllPrimitiveTypes {
public static void main(java.lang.String[]);
Code:
0: ldc #8 // String str
2: astore_1 //store it variable
3: ldc #9 // int 1 - bool values are represented as ints in JVM
5: istore_2 //store as int
6: ldc #10 // int 2745
8: ldc #11 // int 33
10: iadd // iadd - add integers
11: istore_3 //store result in integer varaible
12: ldc #12 // float 2343.05f
14: fstore 4 //store in float variable
16: ldc #13 // float 23.0f
18: fload 4 //load integer varaible (from index 4)
20: fadd //add float variables
21: fstore 5 //store float result
23: return
}