六、类与对象
创建jvmgo tdaheap文件夹
将rtdaobject.go移到heap文件夹中,并修改包名,并修改solt.go、local_vars.go、operand_stack.go文件,经过了前面的努力,现在终于开始对类和对象进行编写。
一、方法区
1、类信息
在heap文件夹下创建class.go文件,在里面定义Class结构体
1 package heap 2 3 import "strings" 4 import "jvmgo/classfile" 5 6 // name, superClassName and interfaceNames are all binary names(jvms8-4.2.1) 7 type Class struct { 8 accessFlags uint16 //类的访问标识,总共16比特 9 name string // thisClassName 10 superClassName string //超类名 11 interfaceNames []string //继承的接口名 12 constantPool *ConstantPool //存放运行是的常量池指针 13 fields []*Field //字段表 14 methods []*Method //方法表 15 loader *ClassLoader 16 superClass *Class 17 interfaces []*Class 18 instanceSlotCount uint 19 staticSlotCount uint 20 staticVars Slots 21 } 22 23 func newClass(cf *classfile.ClassFile) *Class { //把ClassFile结构体定义成Class结构体 24 class := &Class{} 25 class.accessFlags = cf.AccessFlags() 26 class.name = cf.ClassName() 27 class.superClassName = cf.SuperClassName() 28 class.interfaceNames = cf.InterfaceNames() 29 class.constantPool = newConstantPool(class, cf.ConstantPool()) 30 class.fields = newFields(class, cf.Fields()) 31 class.methods = newMethods(class, cf.Methods()) 32 return class 33 } 34 35 func (self *Class) IsPublic() bool {//判断类的类型 36 return 0 != self.accessFlags&ACC_PUBLIC 37 } 38 func (self *Class) IsFinal() bool { 39 return 0 != self.accessFlags&ACC_FINAL 40 } 41 func (self *Class) IsSuper() bool { 42 return 0 != self.accessFlags&ACC_SUPER 43 } 44 func (self *Class) IsInterface() bool { 45 return 0 != self.accessFlags&ACC_INTERFACE 46 } 47 func (self *Class) IsAbstract() bool { 48 return 0 != self.accessFlags&ACC_ABSTRACT 49 } 50 func (self *Class) IsSynthetic() bool { 51 return 0 != self.accessFlags&ACC_SYNTHETIC 52 } 53 func (self *Class) IsAnnotation() bool { 54 return 0 != self.accessFlags&ACC_ANNOTATION 55 } 56 func (self *Class) IsEnum() bool { 57 return 0 != self.accessFlags&ACC_ENUM 58 } 59 60 // getters 61 func (self *Class) ConstantPool() *ConstantPool { 62 return self.constantPool 63 } 64 func (self *Class) StaticVars() Slots { 65 return self.staticVars 66 } 67 68 // jvms 5.4.4 69 func (self *Class) isAccessibleTo(other *Class) bool {//是否可用 70 return self.IsPublic() || 71 self.getPackageName() == other.getPackageName() 72 } 73 74 func (self *Class) getPackageName() string { 75 if i := strings.LastIndex(self.name, "/"); i >= 0 { 76 return self.name[:i] 77 } 78 return "" 79 } 80 81 func (self *Class) GetMainMethod() *Method { 82 return self.getStaticMethod("main", "([Ljava/lang/String;)V") 83 } 84 85 func (self *Class) getStaticMethod(name, descriptor string) *Method { 86 for _, method := range self.methods { 87 if method.IsStatic() && 88 method.name == name && 89 method.descriptor == descriptor { 90 91 return method 92 } 93 } 94 return nil 95 } 96 97 func (self *Class) NewObject() *Object { //使用new创建对象 98 return newObject(self) 99 }
2、字段信息
字段和方法都属于类的成员,他们都有一些相同的信息,创建一个结构体存放重复信息,创建class_mwember.go文件,其中有ClassMember结构体
1 package heap 2 3 import "jvmgo/classfile" 4 5 type ClassMember struct { 6 accessFlags uint16 //访问标识 7 name string //字段或方法名 8 descriptor string // 9 class *Class //指向包含的类对象 10 } 11 12 func (self *ClassMember) copyMemberInfo(memberInfo *classfile.MemberInfo) { //从class文件中复制信息 13 self.accessFlags = memberInfo.AccessFlags() 14 self.name = memberInfo.Name() 15 self.descriptor = memberInfo.Descriptor() 16 } 17 18 func (self *ClassMember) IsPublic() bool { 19 return 0 != self.accessFlags&ACC_PUBLIC 20 } 21 func (self *ClassMember) IsPrivate() bool { 22 return 0 != self.accessFlags&ACC_PRIVATE 23 } 24 func (self *ClassMember) IsProtected() bool { 25 return 0 != self.accessFlags&ACC_PROTECTED 26 } 27 func (self *ClassMember) IsStatic() bool { 28 return 0 != self.accessFlags&ACC_STATIC 29 } 30 func (self *ClassMember) IsFinal() bool { 31 return 0 != self.accessFlags&ACC_FINAL 32 } 33 func (self *ClassMember) IsSynthetic() bool { 34 return 0 != self.accessFlags&ACC_SYNTHETIC 35 } 36 37 // getters 38 func (self *ClassMember) Name() string { 39 return self.name 40 } 41 func (self *ClassMember) Descriptor() string { 42 return self.descriptor 43 } 44 func (self *ClassMember) Class() *Class { 45 return self.class 46 } 47 48 // jvms 5.4.4 49 func (self *ClassMember) isAccessibleTo(d *Class) bool { 50 if self.IsPublic() { 51 return true 52 } 53 c := self.class 54 if self.IsProtected() { 55 return d == c || d.isSubClassOf(c) || 56 c.getPackageName() == d.getPackageName() 57 } 58 if !self.IsPrivate() { 59 return c.getPackageName() == d.getPackageName() 60 } 61 return d == c 62 }
接下来在heap文件夹下创建field.go文件,定义Field结构体
1 package heap 2 3 import "jvmgo/classfile" 4 5 type Field struct { 6 ClassMember 7 constValueIndex uint 8 slotId uint 9 } 10 11 func newFields(class *Class, cfFields []*classfile.MemberInfo) []*Field { //根据class字段创建字段表 12 fields := make([]*Field, len(cfFields)) 13 for i, cfField := range cfFields { 14 fields[i] = &Field{} 15 fields[i].class = class 16 fields[i].copyMemberInfo(cfField) 17 fields[i].copyAttributes(cfField) 18 } 19 return fields 20 } 21 func (self *Field) copyAttributes(cfField *classfile.MemberInfo) { 22 if valAttr := cfField.ConstantValueAttribute(); valAttr != nil { 23 self.constValueIndex = uint(valAttr.ConstantValueIndex()) 24 } 25 } 26 27 func (self *Field) IsVolatile() bool { 28 return 0 != self.accessFlags&ACC_VOLATILE 29 } 30 func (self *Field) IsTransient() bool { 31 return 0 != self.accessFlags&ACC_TRANSIENT 32 } 33 func (self *Field) IsEnum() bool { 34 return 0 != self.accessFlags&ACC_ENUM 35 } 36 37 func (self *Field) ConstValueIndex() uint { 38 return self.constValueIndex 39 } 40 func (self *Field) SlotId() uint { 41 return self.slotId 42 } 43 func (self *Field) isLongOrDouble() bool { 44 return self.descriptor == "J" || self.descriptor == "D" 45 }
classfilemember_info.go文件中添加
func (self *MemberInfo) ConstantValueAttribute() *ConstantValueAttribute { for _, attrInfo := range self.attributes { switch attrInfo.(type) { case *ConstantValueAttribute: return attrInfo.(*ConstantValueAttribute) } } return nil }
3、方法信息
方法比字段要复杂,因为字段有字节码,在heap文件夹下创建method.go文件,定义Method结构体。
1 package heap 2 3 import "jvmgo/classfile" 4 5 type Method struct { 6 ClassMember 7 maxStack uint //操作数栈的大小 8 maxLocals uint //局部变量表的大小 9 code []byte //存放字节码 10 } 11 12 func newMethods(class *Class, cfMethods []*classfile.MemberInfo) []*Method { //根据class中的信息创建Method表 13 methods := make([]*Method, len(cfMethods)) 14 for i, cfMethod := range cfMethods { 15 methods[i] = &Method{} 16 methods[i].class = class 17 methods[i].copyMemberInfo(cfMethod) 18 methods[i].copyAttributes(cfMethod) 19 } 20 return methods 21 } 22 23 func (self *Method) copyAttributes(cfMethod *classfile.MemberInfo) { //从method_info中提取信息 24 if codeAttr := cfMethod.CodeAttribute(); codeAttr != nil { 25 self.maxStack = codeAttr.MaxStack() 26 self.maxLocals = codeAttr.MaxLocals() 27 self.code = codeAttr.Code() 28 } 29 } 30 31 func (self *Method) IsSynchronized() bool { 32 return 0 != self.accessFlags&ACC_SYNCHRONIZED 33 } 34 func (self *Method) IsBridge() bool { 35 return 0 != self.accessFlags&ACC_BRIDGE 36 } 37 func (self *Method) IsVarargs() bool { 38 return 0 != self.accessFlags&ACC_VARARGS 39 } 40 func (self *Method) IsNative() bool { 41 return 0 != self.accessFlags&ACC_NATIVE 42 } 43 func (self *Method) IsAbstract() bool { 44 return 0 != self.accessFlags&ACC_ABSTRACT 45 } 46 func (self *Method) IsStrict() bool { 47 return 0 != self.accessFlags&ACC_STRICT 48 } 49 50 // getters 51 func (self *Method) MaxStack() uint { 52 return self.maxStack 53 } 54 func (self *Method) MaxLocals() uint { 55 return self.maxLocals 56 } 57 func (self *Method) Code() []byte { 58 return self.code 59 }
二、运行时常量池
运行时常量池主要存放两种信息:字面量和富符号引用。在heap下创建constant_pool.go文件,定义Constant和ConstantPool结构体。
1 package heap 2 3 import "fmt" 4 import "jvmgo/classfile" 5 6 type Constant interface{} 7 8 type ConstantPool struct { 9 class *Class 10 consts []Constant 11 } 12 13 func newConstantPool(class *Class, cfCp classfile.ConstantPool) *ConstantPool {//把class中的常量池转化为运行时常量池 14 cpCount := len(cfCp) 15 consts := make([]Constant, cpCount) 16 rtCp := &ConstantPool{class, consts} 17 18 for i := 1; i < cpCount; i++ { 19 cpInfo := cfCp[i] 20 switch cpInfo.(type) { 21 case *classfile.ConstantIntegerInfo: 22 intInfo := cpInfo.(*classfile.ConstantIntegerInfo) 23 consts[i] = intInfo.Value() 24 case *classfile.ConstantFloatInfo: 25 floatInfo := cpInfo.(*classfile.ConstantFloatInfo) 26 consts[i] = floatInfo.Value() 27 case *classfile.ConstantLongInfo: 28 longInfo := cpInfo.(*classfile.ConstantLongInfo) 29 consts[i] = longInfo.Value() 30 i++ 31 case *classfile.ConstantDoubleInfo: 32 doubleInfo := cpInfo.(*classfile.ConstantDoubleInfo) 33 consts[i] = doubleInfo.Value() 34 i++ 35 case *classfile.ConstantStringInfo: 36 stringInfo := cpInfo.(*classfile.ConstantStringInfo) 37 consts[i] = stringInfo.String() 38 case *classfile.ConstantClassInfo: 39 classInfo := cpInfo.(*classfile.ConstantClassInfo) 40 consts[i] = newClassRef(rtCp, classInfo) 41 case *classfile.ConstantFieldrefInfo: 42 fieldrefInfo := cpInfo.(*classfile.ConstantFieldrefInfo) 43 consts[i] = newFieldRef(rtCp, fieldrefInfo) 44 case *classfile.ConstantMethodrefInfo: 45 methodrefInfo := cpInfo.(*classfile.ConstantMethodrefInfo) 46 consts[i] = newMethodRef(rtCp, methodrefInfo) 47 case *classfile.ConstantInterfaceMethodrefInfo: 48 methodrefInfo := cpInfo.(*classfile.ConstantInterfaceMethodrefInfo) 49 consts[i] = newInterfaceMethodRef(rtCp, methodrefInfo) 50 default: 51 // todo 52 } 53 } 54 55 return rtCp 56 } 57 58 func (self *ConstantPool) GetConstant(index uint) Constant { 59 if c := self.consts[index]; c != nil { 60 return c 61 } 62 panic(fmt.Sprintf("No constants at index %d", index)) 63 }
1、类符号引用
在heap下创建cp_symref.go文件,定义SymRef结构体
1 package heap 2 3 // symbolic reference 4 type SymRef struct { 5 cp *ConstantPool //运行时常量池指针
6 className string //类名 7 class *Class //解析后的类结构体指针 8 } 9 10 func (self *SymRef) ResolvedClass() *Class { 11 if self.class == nil { 12 self.resolveClassRef() 13 } 14 return self.class 15 } 16 17 // jvms8 5.4.3.1 18 func (self *SymRef) resolveClassRef() { 19 d := self.cp.class 20 c := d.loader.LoadClass(self.className) 21 if !c.isAccessibleTo(d) { 22 panic("java.lang.IllegalAccessError") 23 } 24 25 self.class = c 26 }
在heap下创建cp_classref.go文件,定义ClassRef结构体
1 package heap 2 3 import "jvmgo/classfile" 4 5 type ClassRef struct { 6 SymRef 7 } 8 9 func newClassRef(cp *ConstantPool, classInfo *classfile.ConstantClassInfo) *ClassRef {//根据类信息创建ClassRef实例 10 ref := &ClassRef{} 11 ref.cp = cp 12 ref.className = classInfo.Name() 13 return ref 14 }
ClassRef结构体继承了SymRef结构体,未添加任何字段。
2、字段符号引用
定义MemberRef结构体,在heap下创建cp_memberref.go文件
1 package heap 2 3 import "jvmgo/classfile" 4 5 type MemberRef struct { 6 SymRef 7 name string 8 descriptor string 9 } 10 11 func (self *MemberRef) copyMemberRefInfo(refInfo *classfile.ConstantMemberrefInfo) { 12 self.className = refInfo.ClassName() 13 self.name, self.descriptor = refInfo.NameAndDescriptor() 14 } 15 16 func (self *MemberRef) Name() string { 17 return self.name 18 } 19 func (self *MemberRef) Descriptor() string { 20 return self.descriptor 21 }
接下来是FieldRef结构体,创建cp_fieldref.go文件
package heap import "jvmgo/classfile" type FieldRef struct { MemberRef field *Field } func newFieldRef(cp *ConstantPool, refInfo *classfile.ConstantFieldrefInfo) *FieldRef { ref := &FieldRef{} ref.cp = cp ref.copyMemberRefInfo(&refInfo.ConstantMemberrefInfo) return ref } func (self *FieldRef) ResolvedField() *Field { if self.field == nil { self.resolveFieldRef() } return self.field } // jvms 5.4.3.2 func (self *FieldRef) resolveFieldRef() { d := self.cp.class c := self.ResolvedClass() field := lookupField(c, self.name, self.descriptor) if field == nil { panic("java.lang.NoSuchFieldError") } if !field.isAccessibleTo(d) { panic("java.lang.IllegalAccessError") } self.field = field } func lookupField(c *Class, name, descriptor string) *Field { for _, field := range c.fields { if field.name == name && field.descriptor == descriptor { return field } } for _, iface := range c.interfaces { if field := lookupField(iface, name, descriptor); field != nil { return field } } if c.superClass != nil { return lookupField(c.superClass, name, descriptor) } return nil }
3、方法符号引用
在heap下创建cp_methodref.go文件
1 package heap 2 3 import "jvmgo/classfile" 4 5 type MethodRef struct { 6 MemberRef 7 method *Method 8 } 9 10 func newMethodRef(cp *ConstantPool, refInfo *classfile.ConstantMethodrefInfo) *MethodRef { 11 ref := &MethodRef{} 12 ref.cp = cp 13 ref.copyMemberRefInfo(&refInfo.ConstantMemberrefInfo) 14 return ref 15 } 16 17 func (self *MethodRef) ResolvedMethod() *Method { 18 if self.method == nil { 19 self.resolveMethodRef() 20 } 21 return self.method 22 } 23 24 // jvms8 5.4.3.3 25 func (self *MethodRef) resolveMethodRef() { 26 //class := self.Class() 27 // todo 28 }
4、接口方法符号引用
heap下创建cp_interface_methodref.go文件,定义InterfaceMethodRef结构体
1 package heap 2 3 import "jvmgo/classfile" 4 5 type InterfaceMethodRef struct { 6 MemberRef 7 method *Method 8 } 9 10 func newInterfaceMethodRef(cp *ConstantPool, refInfo *classfile.ConstantInterfaceMethodrefInfo) *InterfaceMethodRef { 11 ref := &InterfaceMethodRef{} 12 ref.cp = cp 13 ref.copyMemberRefInfo(&refInfo.ConstantMemberrefInfo) 14 return ref 15 } 16 17 func (self *InterfaceMethodRef) ResolvedInterfaceMethod() *Method { 18 if self.method == nil { 19 self.resolveInterfaceMethodRef() 20 } 21 return self.method 22 } 23 24 // jvms8 5.4.3.4 25 func (self *InterfaceMethodRef) resolveInterfaceMethodRef() { 26 //class := self.ResolveClass() 27 // todo 28 }
三、类加载器
实现一个简化的类加载器,在heap下创建class_loader.go文件,定义ClassLoader结构体
1 package heap 2 3 import "fmt" 4 import "jvmgo/classfile" 5 import "jvmgo/classpath" 6 7 /* 8 class names: 9 - primitive types: boolean, byte, int ... 10 - primitive arrays: [Z, [B, [I ... 11 - non-array classes: java/lang/Object ... 12 - array classes: [Ljava/lang/Object; ... 13 */ 14 type ClassLoader struct { //依赖Classpath搜索和读取class文件 15 cp *classpath.Classpath //保存Classpath指针 16 classMap map[string]*Class // loaded classes,key是类的完全限定名 17 } 18 19 func NewClassLoader(cp *classpath.Classpath) *ClassLoader { 20 return &ClassLoader{ 21 cp: cp, 22 classMap: make(map[string]*Class), 23 } 24 } 25 26 func (self *ClassLoader) LoadClass(name string) *Class {//把类数据加载到方法区 27 if class, ok := self.classMap[name]; ok { 28 // already loaded 29 return class 30 } 31 32 return self.loadNonArrayClass(name) 33 } 34 35 func (self *ClassLoader) loadNonArrayClass(name string) *Class { 36 data, entry := self.readClass(name) 37 class := self.defineClass(data) 38 link(class) 39 fmt.Printf("[Loaded %s from %s] ", name, entry) 40 return class 41 } 42 43 func (self *ClassLoader) readClass(name string) ([]byte, classpath.Entry) {//调用Classpath的ReadClass(),并进行错误处理 44 data, entry, err := self.cp.ReadClass(name) 45 if err != nil { 46 panic("java.lang.ClassNotFoundException: " + name) 47 } 48 return data, entry 49 } 50 51 // jvms 5.3.5 52 func (self *ClassLoader) defineClass(data []byte) *Class {// 53 class := parseClass(data)//转化成类对象 54 class.loader = self 55 resolveSuperClass(class)//解析类符号 56 resolveInterfaces(class) 57 self.classMap[class.name] = class//加入map 58 return class 59 } 60 61 func parseClass(data []byte) *Class { 62 cf, err := classfile.Parse(data) 63 if err != nil { 64 //panic("java.lang.ClassFormatError") 65 panic(err) 66 } 67 return newClass(cf) 68 } 69 70 // jvms 5.4.3.1 71 func resolveSuperClass(class *Class) { 72 if class.name != "java/lang/Object" { 73 class.superClass = class.loader.LoadClass(class.superClassName) 74 } 75 } 76 func resolveInterfaces(class *Class) { 77 interfaceCount := len(class.interfaceNames) 78 if interfaceCount > 0 { 79 class.interfaces = make([]*Class, interfaceCount) 80 for i, interfaceName := range class.interfaceNames { 81 class.interfaces[i] = class.loader.LoadClass(interfaceName) 82 } 83 } 84 } 85 86 func link(class *Class) {//分为验证的准备两个阶段 87 verify(class) 88 prepare(class) 89 } 90 91 func verify(class *Class) { 92 // todo 93 } 94 95 // jvms 5.4.2 96 func prepare(class *Class) { 97 calcInstanceFieldSlotIds(class) 98 calcStaticFieldSlotIds(class) 99 allocAndInitStaticVars(class) 100 } 101 102 func calcInstanceFieldSlotIds(class *Class) {//计算实例字段的个数 103 slotId := uint(0) 104 if class.superClass != nil { 105 slotId = class.superClass.instanceSlotCount 106 } 107 for _, field := range class.fields { 108 if !field.IsStatic() { 109 field.slotId = slotId 110 slotId++ 111 if field.isLongOrDouble() { 112 slotId++ 113 } 114 } 115 } 116 class.instanceSlotCount = slotId 117 } 118 119 func calcStaticFieldSlotIds(class *Class) {//计算静态字段的个数 120 slotId := uint(0) 121 for _, field := range class.fields { 122 if field.IsStatic() { 123 field.slotId = slotId 124 slotId++ 125 if field.isLongOrDouble() { 126 slotId++ 127 } 128 } 129 } 130 class.staticSlotCount = slotId 131 } 132 133 func allocAndInitStaticVars(class *Class) {给类变量分配空间 134 class.staticVars = newSlots(class.staticSlotCount) 135 for _, field := range class.fields { 136 if field.IsStatic() && field.IsFinal() { 137 initStaticFinalVar(class, field) 138 } 139 } 140 } 141 142 func initStaticFinalVar(class *Class, field *Field) {//从常量池加载常量值 143 vars := class.staticVars 144 cp := class.constantPool 145 cpIndex := field.ConstValueIndex() 146 slotId := field.SlotId() 147 148 if cpIndex > 0 { 149 switch field.Descriptor() { 150 case "Z", "B", "C", "S", "I": 151 val := cp.GetConstant(cpIndex).(int32) 152 vars.SetInt(slotId, val) 153 case "J": 154 val := cp.GetConstant(cpIndex).(int64) 155 vars.SetLong(slotId, val) 156 case "F": 157 val := cp.GetConstant(cpIndex).(float32) 158 vars.SetFloat(slotId, val) 159 case "D": 160 val := cp.GetConstant(cpIndex).(float64) 161 vars.SetDouble(slotId, val) 162 case "Ljava/lang/String;": 163 panic("todo") 164 } 165 } 166 }
四、对象、实例变量和类变量
在heap下创建slots.go文件,代码如下
1 package heap 2 3 import "math" 4 5 type Slot struct { 6 num int32 7 ref *Object 8 } 9 10 type Slots []Slot 11 12 func newSlots(slotCount uint) Slots { 13 if slotCount > 0 { 14 return make([]Slot, slotCount) 15 } 16 return nil 17 } 18 19 func (self Slots) SetInt(index uint, val int32) { 20 self[index].num = val 21 } 22 func (self Slots) GetInt(index uint) int32 { 23 return self[index].num 24 } 25 26 func (self Slots) SetFloat(index uint, val float32) { 27 bits := math.Float32bits(val) 28 self[index].num = int32(bits) 29 } 30 func (self Slots) GetFloat(index uint) float32 { 31 bits := uint32(self[index].num) 32 return math.Float32frombits(bits) 33 } 34 35 // long consumes two slots 36 func (self Slots) SetLong(index uint, val int64) { 37 self[index].num = int32(val) 38 self[index+1].num = int32(val >> 32) 39 } 40 func (self Slots) GetLong(index uint) int64 { 41 low := uint32(self[index].num) 42 high := uint32(self[index+1].num) 43 return int64(high)<<32 | int64(low) 44 } 45 46 // double consumes two slots 47 func (self Slots) SetDouble(index uint, val float64) { 48 bits := math.Float64bits(val) 49 self.SetLong(index, int64(bits)) 50 } 51 func (self Slots) GetDouble(index uint) float64 { 52 bits := uint64(self.GetLong(index)) 53 return math.Float64frombits(bits) 54 } 55 56 func (self Slots) SetRef(index uint, ref *Object) { 57 self[index].ref = ref 58 } 59 func (self Slots) GetRef(index uint) *Object { 60 return self[index].ref 61 }
五、类和对象相关指令
在这里我们将实现十条类和对象相关的指令,new指令用来创建类实例,putstatic和getstatic用于存取静态变量,putfield和getfield用于存取实例变量,instanceof和checkcast指令用于判断对象是否属于某种类型,ldc指令把运行时常量池的常量推到操作数栈顶。
在jvmgoinstructions下创建references文件夹。
1、new指令
1 package references 2 3 import "jvmgo/instructions/base" 4 import "jvmgo/rtda" 5 import "jvmgo/rtda/heap" 6 7 // Create new object 8 type NEW struct{ base.Index16Instruction } 9 10 func (self *NEW) Execute(frame *rtda.Frame) { 11 cp := frame.Method().Class().ConstantPool() 12 classRef := cp.GetConstant(self.Index).(*heap.ClassRef) 13 class := classRef.ResolvedClass() 14 // todo: init class 15 16 if class.IsInterface() || class.IsAbstract() { 17 panic("java.lang.InstantiationError") 18 } 19 20 ref := class.NewObject() 21 frame.OperandStack().PushRef(ref) 22 }
2、putstatic和getstatic指令
创建putstatic.go文件
1 package references 2 3 import "jvmgo/instructions/base" 4 import "jvmgo/rtda" 5 import "jvmgo/rtda/heap" 6 7 // Set static field in class 8 type PUT_STATIC struct{ base.Index16Instruction } 9 10 func (self *PUT_STATIC) Execute(frame *rtda.Frame) { 11 currentMethod := frame.Method() 12 currentClass := currentMethod.Class() 13 cp := currentClass.ConstantPool() 14 fieldRef := cp.GetConstant(self.Index).(*heap.FieldRef) 15 field := fieldRef.ResolvedField() 16 class := field.Class() 17 // todo: init class 18 19 if !field.IsStatic() { 20 panic("java.lang.IncompatibleClassChangeError") 21 } 22 if field.IsFinal() { 23 if currentClass != class || currentMethod.Name() != "<clinit>" { 24 panic("java.lang.IllegalAccessError") 25 } 26 } 27 28 descriptor := field.Descriptor() 29 slotId := field.SlotId() 30 slots := class.StaticVars() 31 stack := frame.OperandStack() 32 33 switch descriptor[0] { 34 case 'Z', 'B', 'C', 'S', 'I': 35 slots.SetInt(slotId, stack.PopInt()) 36 case 'F': 37 slots.SetFloat(slotId, stack.PopFloat()) 38 case 'J': 39 slots.SetLong(slotId, stack.PopLong()) 40 case 'D': 41 slots.SetDouble(slotId, stack.PopDouble()) 42 case 'L', '[': 43 slots.SetRef(slotId, stack.PopRef()) 44 default: 45 // todo 46 } 47 }
创建getstatic.go文件
1 package references 2 3 import "jvmgo/instructions/base" 4 import "jvmgo/rtda" 5 import "jvmgo/rtda/heap" 6 7 // Get static field from class 8 type GET_STATIC struct{ base.Index16Instruction } 9 10 func (self *GET_STATIC) Execute(frame *rtda.Frame) { 11 cp := frame.Method().Class().ConstantPool() 12 fieldRef := cp.GetConstant(self.Index).(*heap.FieldRef) 13 field := fieldRef.ResolvedField() 14 class := field.Class() 15 // todo: init class 16 17 if !field.IsStatic() { 18 panic("java.lang.IncompatibleClassChangeError") 19 } 20 21 descriptor := field.Descriptor() 22 slotId := field.SlotId() 23 slots := class.StaticVars() 24 stack := frame.OperandStack() 25 26 switch descriptor[0] { 27 case 'Z', 'B', 'C', 'S', 'I': 28 stack.PushInt(slots.GetInt(slotId)) 29 case 'F': 30 stack.PushFloat(slots.GetFloat(slotId)) 31 case 'J': 32 stack.PushLong(slots.GetLong(slotId)) 33 case 'D': 34 stack.PushDouble(slots.GetDouble(slotId)) 35 case 'L', '[': 36 stack.PushRef(slots.GetRef(slotId)) 37 default: 38 // todo 39 } 40 }
3、putfield和getfield指令
创建putfield.go文件
1 package references 2 3 import "jvmgo/instructions/base" 4 import "jvmgo/rtda" 5 import "jvmgo/rtda/heap" 6 7 // Set field in object 8 type PUT_FIELD struct{ base.Index16Instruction } 9 10 func (self *PUT_FIELD) Execute(frame *rtda.Frame) { 11 currentMethod := frame.Method() 12 currentClass := currentMethod.Class() 13 cp := currentClass.ConstantPool() 14 fieldRef := cp.GetConstant(self.Index).(*heap.FieldRef) 15 field := fieldRef.ResolvedField() 16 17 if field.IsStatic() { 18 panic("java.lang.IncompatibleClassChangeError") 19 } 20 if field.IsFinal() { 21 if currentClass != field.Class() || currentMethod.Name() != "<init>" { 22 panic("java.lang.IllegalAccessError") 23 } 24 } 25 26 descriptor := field.Descriptor() 27 slotId := field.SlotId() 28 stack := frame.OperandStack() 29 30 switch descriptor[0] { 31 case 'Z', 'B', 'C', 'S', 'I': 32 val := stack.PopInt() 33 ref := stack.PopRef() 34 if ref == nil { 35 panic("java.lang.NullPointerException") 36 } 37 ref.Fields().SetInt(slotId, val) 38 case 'F': 39 val := stack.PopFloat() 40 ref := stack.PopRef() 41 if ref == nil { 42 panic("java.lang.NullPointerException") 43 } 44 ref.Fields().SetFloat(slotId, val) 45 case 'J': 46 val := stack.PopLong() 47 ref := stack.PopRef() 48 if ref == nil { 49 panic("java.lang.NullPointerException") 50 } 51 ref.Fields().SetLong(slotId, val) 52 case 'D': 53 val := stack.PopDouble() 54 ref := stack.PopRef() 55 if ref == nil { 56 panic("java.lang.NullPointerException") 57 } 58 ref.Fields().SetDouble(slotId, val) 59 case 'L', '[': 60 val := stack.PopRef() 61 ref := stack.PopRef() 62 if ref == nil { 63 panic("java.lang.NullPointerException") 64 } 65 ref.Fields().SetRef(slotId, val) 66 default: 67 // todo 68 } 69 }
创建getfield.go文件
1 package references 2 3 import "jvmgo/instructions/base" 4 import "jvmgo/rtda" 5 import "jvmgo/rtda/heap" 6 7 // Fetch field from object 8 type GET_FIELD struct{ base.Index16Instruction } 9 10 func (self *GET_FIELD) Execute(frame *rtda.Frame) { 11 cp := frame.Method().Class().ConstantPool() 12 fieldRef := cp.GetConstant(self.Index).(*heap.FieldRef) 13 field := fieldRef.ResolvedField() 14 15 if field.IsStatic() { 16 panic("java.lang.IncompatibleClassChangeError") 17 } 18 19 stack := frame.OperandStack() 20 ref := stack.PopRef() 21 if ref == nil { 22 panic("java.lang.NullPointerException") 23 } 24 25 descriptor := field.Descriptor() 26 slotId := field.SlotId() 27 slots := ref.Fields() 28 29 switch descriptor[0] { 30 case 'Z', 'B', 'C', 'S', 'I': 31 stack.PushInt(slots.GetInt(slotId)) 32 case 'F': 33 stack.PushFloat(slots.GetFloat(slotId)) 34 case 'J': 35 stack.PushLong(slots.GetLong(slotId)) 36 case 'D': 37 stack.PushDouble(slots.GetDouble(slotId)) 38 case 'L', '[': 39 stack.PushRef(slots.GetRef(slotId)) 40 default: 41 // todo 42 } 43 }
4、instanceof和checkcast指令
创建instanceof.go文件
1 package references 2 3 import "jvmgo/instructions/base" 4 import "jvmgo/rtda" 5 import "jvmgo/rtda/heap" 6 7 // Determine if object is of given type 8 type INSTANCE_OF struct{ base.Index16Instruction } 9 10 func (self *INSTANCE_OF) Execute(frame *rtda.Frame) { 11 stack := frame.OperandStack() 12 ref := stack.PopRef() 13 if ref == nil { 14 stack.PushInt(0) 15 return 16 } 17 18 cp := frame.Method().Class().ConstantPool() 19 classRef := cp.GetConstant(self.Index).(*heap.ClassRef) 20 class := classRef.ResolvedClass() 21 if ref.IsInstanceOf(class) { 22 stack.PushInt(1) 23 } else { 24 stack.PushInt(0) 25 } 26 }
创建checkcast.go文件
1 package references 2 3 import "jvmgo/instructions/base" 4 import "jvmgo/rtda" 5 import "jvmgo/rtda/heap" 6 7 // Check whether object is of given type 8 type CHECK_CAST struct{ base.Index16Instruction } 9 10 func (self *CHECK_CAST) Execute(frame *rtda.Frame) { 11 stack := frame.OperandStack() 12 ref := stack.PopRef() 13 stack.PushRef(ref) 14 if ref == nil { 15 return 16 } 17 18 cp := frame.Method().Class().ConstantPool() 19 classRef := cp.GetConstant(self.Index).(*heap.ClassRef) 20 class := classRef.ResolvedClass() 21 if !ref.IsInstanceOf(class) { 22 panic("java.lang.ClassCastException") 23 } 24 }
5、ldc指令
在instructionsconstants下创建ldc.go文件
1 package constants 2 3 import "jvmgo/instructions/base" 4 import "jvmgo/rtda" 5 6 // Push item from run-time constant pool 7 type LDC struct{ base.Index8Instruction } 8 9 func (self *LDC) Execute(frame *rtda.Frame) { 10 _ldc(frame, self.Index) 11 } 12 13 // Push item from run-time constant pool (wide index) 14 type LDC_W struct{ base.Index16Instruction } 15 16 func (self *LDC_W) Execute(frame *rtda.Frame) { 17 _ldc(frame, self.Index) 18 } 19 20 func _ldc(frame *rtda.Frame, index uint) { 21 stack := frame.OperandStack() 22 cp := frame.Method().Class().ConstantPool() 23 c := cp.GetConstant(index) 24 25 switch c.(type) { 26 case int32: 27 stack.PushInt(c.(int32)) 28 case float32: 29 stack.PushFloat(c.(float32)) 30 // case string: 31 // case *heap.ClassRef: 32 // case MethodType, MethodHandle 33 default: 34 panic("todo: ldc!") 35 } 36 } 37 38 // Push long or double from run-time constant pool (wide index) 39 type LDC2_W struct{ base.Index16Instruction } 40 41 func (self *LDC2_W) Execute(frame *rtda.Frame) { 42 stack := frame.OperandStack() 43 cp := frame.Method().Class().ConstantPool() 44 c := cp.GetConstant(self.Index) 45 46 switch c.(type) { 47 case int64: 48 stack.PushLong(c.(int64)) 49 case float64: 50 stack.PushDouble(c.(float64)) 51 default: 52 panic("java.lang.ClassFormatError") 53 } 54 }
六、测试
修改main.go文件
1 package main 2 3 import "fmt" 4 import "strings" 5 import "jvmgo/classpath" 6 import _ "jvmgo/classfile" 7 import "jvmgo/rtda/heap" 8 9 func main() { 10 cmd := parseCmd() 11 12 if cmd.versionFlag { 13 fmt.Println("version 0.0.1") 14 } else if cmd.helpFlag || cmd.class == "" { 15 printUsage() 16 } else { 17 startJVM(cmd) 18 } 19 } 20 21 func startJVM(cmd *Cmd) { 22 cp := classpath.Parse(cmd.XjreOption, cmd.cpOption) 23 classLoader := heap.NewClassLoader(cp) 24 25 className := strings.Replace(cmd.class, ".", "/", -1) 26 mainClass := classLoader.LoadClass(className) 27 mainMethod := mainClass.GetMainMethod() 28 if mainMethod != nil { 29 interpret(mainMethod) 30 } else { 31 fmt.Printf("Main method not found in class %s ", cmd.class) 32 } 33 }
再修改interpreter.go文件
只修改interpret()函数
func interpret(method *heap.Method) { thread := rtda.NewThread() frame := thread.NewFrame(method) thread.PushFrame(frame) defer catchErr(frame) loop(thread, method.Code()) }
rtda hread.go文件中NewFrame()方法修改为
func (self *Thread) NewFrame(method *heap.Method) *Frame {
return newFrame(self, method)
}
rtdaframe.go文件中NewFrame()修改为
func newFrame(thread *Thread, method *heap.Method) *Frame { return &Frame{ thread: thread, method: method, localVars: newLocalVars(method.MaxLocals()), operandStack: newOperandStack(method.MaxStack()), } }
另外在instructions eferences目录下创建invokespecial.go文件
1 package references 2 3 import "jvmgo/instructions/base" 4 import "jvmgo/rtda" 5 6 // Invoke instance method; 7 // special handling for superclass, private, and instance initialization method invocations 8 type INVOKE_SPECIAL struct{ base.Index16Instruction } 9 10 // hack! 11 func (self *INVOKE_SPECIAL) Execute(frame *rtda.Frame) { 12 frame.OperandStack().PopRef() 13 }
创建invokevirtual.go文件
1 package references 2 3 import "fmt" 4 import "jvmgo/instructions/base" 5 import "jvmgo/rtda" 6 import "jvmgo/rtda/heap" 7 8 // Invoke instance method; dispatch based on class 9 type INVOKE_VIRTUAL struct{ base.Index16Instruction } 10 11 // hack! 12 func (self *INVOKE_VIRTUAL) Execute(frame *rtda.Frame) { 13 cp := frame.Method().Class().ConstantPool() 14 methodRef := cp.GetConstant(self.Index).(*heap.MethodRef) 15 if methodRef.Name() == "println" { 16 stack := frame.OperandStack() 17 switch methodRef.Descriptor() { 18 case "(Z)V": 19 fmt.Printf("%v ", stack.PopInt() != 0) 20 case "(C)V": 21 fmt.Printf("%c ", stack.PopInt()) 22 case "(I)V", "(B)V", "(S)V": 23 fmt.Printf("%v ", stack.PopInt()) 24 case "(F)V": 25 fmt.Printf("%v ", stack.PopFloat()) 26 case "(J)V": 27 fmt.Printf("%v ", stack.PopLong()) 28 case "(D)V": 29 fmt.Printf("%v ", stack.PopDouble()) 30 default: 31 panic("println: " + methodRef.Descriptor()) 32 } 33 stack.PopRef() 34 } 35 }
使用MyObject.java为例子进行测试
1 public class MyObject { 2 3 public static int staticVar; 4 public int instanceVar; 5 6 public static void main(String[] args) { 7 int x = 32768; // ldc 8 MyObject myObj = new MyObject(); // new 9 MyObject.staticVar = x; // putstatic 10 x = MyObject.staticVar; // getstatic 11 myObj.instanceVar = x; // putfield 12 x = myObj.instanceVar; // getfield 13 Object obj = myObj; 14 if (obj instanceof MyObject) { // instanceof 15 myObj = (MyObject) obj; // checkcast 16 System.out.println(myObj.instanceVar); 17 } 18 } 19 20 }
在命令行窗口编译本程序
go install jvmgo
PS D:Program_Filesgoin> .jvmgo.exe -Xjre "D:APPjavajava1.8jdk1.8.0_171jre" MyObject [Loaded java/lang/Object from D:APPjavajava1.8jdk1.8.0_171jrelib t.jar] [Loaded MyObject from D:Program_Filesgoin] pc: 0 inst:*constants.LDC &{{2}} pc: 2 inst:*stores.ISTORE_1 &{{}} pc: 3 inst:*references.NEW &{{3}} pc: 6 inst:*stack.DUP &{{}} pc: 7 inst:*references.INVOKE_SPECIAL &{{4}} pc:10 inst:*stores.ASTORE_2 &{{}} pc:11 inst:*loads.ILOAD_1 &{{}} pc:12 inst:*references.PUT_STATIC &{{5}} pc:15 inst:*references.GET_STATIC &{{5}} pc:18 inst:*stores.ISTORE_1 &{{}} pc:19 inst:*loads.ALOAD_2 &{{}} pc:20 inst:*loads.ILOAD_1 &{{}} pc:21 inst:*references.PUT_FIELD &{{6}} pc:24 inst:*loads.ALOAD_2 &{{}} pc:25 inst:*references.GET_FIELD &{{6}} pc:28 inst:*stores.ISTORE_1 &{{}} pc:29 inst:*loads.ALOAD_2 &{{}} pc:30 inst:*stores.ASTORE_3 &{{}} pc:31 inst:*loads.ALOAD_3 &{{}} pc:32 inst:*references.INSTANCE_OF &{{3}} pc:35 inst:*comparisons.IFEQ &{{18}} pc:38 inst:*loads.ALOAD_3 &{{}} pc:39 inst:*references.CHECK_CAST &{{3}} pc:42 inst:*stores.ASTORE_2 &{{}} pc:43 inst:*references.GET_STATIC &{{7}} [Loaded java/lang/System from D:APPjavajava1.8jdk1.8.0_171jrelib t.jar] pc:46 inst:*loads.ALOAD_2 &{{}} pc:47 inst:*references.GET_FIELD &{{6}} pc:50 inst:*references.INVOKE_VIRTUAL &{{8}} 32768