六、类与对象

创建jvmgo\rtda\heap文件夹

将rtda\object.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 }

 classfile\member_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]\n", 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指令把运行时常量池的常量推到操作数栈顶。

在jvmgo\instructions下创建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指令

在instructions\constants下创建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\n", 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\thread.go文件中NewFrame()方法修改为

func (self *Thread) NewFrame(method *heap.Method) *Frame {
return newFrame(self, method) }

rtda\frame.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\references目录下创建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\n", stack.PopInt() != 0)
20         case "(C)V":
21             fmt.Printf("%c\n", stack.PopInt())
22         case "(I)V", "(B)V", "(S)V":
23             fmt.Printf("%v\n", stack.PopInt())
24         case "(F)V":
25             fmt.Printf("%v\n", stack.PopFloat())
26         case "(J)V":
27             fmt.Printf("%v\n", stack.PopLong())
28         case "(D)V":
29             fmt.Printf("%v\n", 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_Files\go\bin> .\jvmgo.exe -Xjre "D:\APP\java\java1.8\jdk1.8.0_171\jre" MyObject
[Loaded java/lang/Object from D:\APP\java\java1.8\jdk1.8.0_171\jre\lib\rt.jar]
[Loaded MyObject from D:\Program_Files\go\bin]
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:\APP\java\java1.8\jdk1.8.0_171\jre\lib\rt.jar]
pc:46 inst:*loads.ALOAD_2 &{{}}
pc:47 inst:*references.GET_FIELD &{{6}}
pc:50 inst:*references.INVOKE_VIRTUAL &{{8}}
32768

猜你喜欢

转载自www.cnblogs.com/pingxin/p/p00085.html