zoukankan      html  css  js  c++  java
  • 六、类与对象

    创建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
  • 相关阅读:
    取模和取余详解
    如何上传图片到博客园的文章中?
    Java并发关键字Volatile 详解
    MySQL查询基础
    MySQL基础
    Access denied for user 'root'@'localhost' Could not obtain connection
    获取和设置select的option值
    如何将long类型的时间变量转变为标准时间
    【Java】对文件或文件夹进行重命名
    安装GlassFish4 报错:unsupported major.minor version 51.0
  • 原文地址:https://www.cnblogs.com/pingxin/p/p00085.html
Copyright © 2011-2022 走看看