在本节,我们将实现线程共享的运行时数据区,包括方法区和运行时常量池
方法区
它是运行时数据区的一块逻辑区域,由多个线程共享,主要存放从class文件获取的类信息,另外类变量也存放在方法区中。
class相关结构体
我们首先实现类结构体和类成员结构体,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| type Class struct { accessFlags uint16 name string superClassName string interfaceNames []string constantPool *classfile.ConstantPool fields []*Field methods []*Method loader *ClassLoader superClass *Class interfaces []*Class instanceSlotCount uint staticSlotCount uint staticVars Slots }
type ClassMember struct { accessFlags uint16 name string descriptor string class *Class }
type Field struct { ClassMember }
type Method struct { ClassMember maxStack uint maxLocals uint code []byte }
|
运行时常量池
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64
| type ConstantPool struct { class *Class consts []Constant }
func newConstantPool(class *Class, cfCp classfile.ConstantPool) *ConstantPool { cpCount := len(cfCp) consts := make([]Constant, cpCount) rtCp := &ConstantPool{class, consts}
for i := 0; i < cpCount; i++ { cpInfo := cfCp[i] switch cpInfo.(type) { case *classfile.ConstantIntegerInfo: intInfo := cpInfo.(*classfile.ConstantIntegerInfo) consts[i] = intInfo.Value() case *classfile.ConstantFloatInfo: floatInfo := cpInfo.(*classfile.ConstantFloatInfo) consts[i] = floatInfo.Value() case *classfile.ConstantLongInfo: longInfo := cpInfo.(*classfile.ConstantLongInfo) consts[i] = longInfo.Value() i++ case *classfile.ConstantDoubleInfo: doubleInfo := cpInfo.(*classfile.ConstantDoubleInfo) consts[i] = doubleInfo.Value() i++ case *classfile.ConstantStringInfo: stringInfo := cpInfo.(*classfile.ConstantStringInfo) consts[i] = stringInfo.Name() case *classfile.ConstantClassInfo: classInfo := cpInfo.(*classfile.ConstantClassInfo) consts[i] = newClassRef(rtCp, classInfo) case *classfile.ConstantFieldrefInfo: fieldrefInfo := cpInfo.(*classfile.ConstantFieldrefInfo) consts[i] = newFieldRef(rtCp, fieldrefInfo) case *classfile.ConstantMethodrefInfo: methodrefInfo := cpInfo.(*classfile.ConstantMethodrefInfo) consts[i] = newMethodRef(rtCp, methodrefInfo) case *classfile.ConstantInterfaceMethodrefInfo: methodrefInfo := cpInfo.(*classfile.ConstantInterfaceMethodrefInfo) consts[i] = newInterfaceMethodRef(rtCp, methodrefInfo) } }
return rtCp }
|
对应classFile中的常量池中元素类型,我们转换其相应的类型,
分为字面量和引用,字面量包括整数、浮点数、长整数、双精度浮点数、字符串字面量,引用包括类符号引用、字段符号引用、方法符号引用、接口方法符号引用。
举例如方法符号引用:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| type SymRef struct { cp *ConstantPool className string class *Class }
type MemberRef struct { SymRef name string descriptor string }
func (self *MemberRef) copyMemberRefInfo(memberInfo *classfile.ConstantMemberrefInfo) { self.className = memberInfo.ClassName() self.name, self.descriptor = memberInfo.NameAndDescriptor() }
type MethodRef struct { MemberRef method *Method }
func newMethodRef(cp *ConstantPool, refInfo *classfile.ConstantMethodrefInfo) *MethodRef { ref := &MethodRef{} ref.cp = cp ref.copyMemberRefInfo(&refInfo.ConstantMemberrefInfo) return ref }
|
类加载器
类加载器,用来读取class文件、解析class、验证和准备class,
分别使用classpath,classfile,相当于再次走一遍过程即可。
重点说一下验证和准备class:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106
|
func link(class *Class) { verify(class) prepare(class) }
func verify(class *Class) { }
func prepare(class *Class) { calcInstanceFieldSlotIds(class) calcStaticFieldSlotIds(class) allocAndInitStaticVars(class) }
func calcInstanceFieldSlotIds(class *Class) { slotId := uint(0) if class.superClass != nil { slotId = class.superClass.instanceSlotCount } for _, field := range class.fields { if !field.IsStatic() { field.slotId = slotId slotId++ if field.isLongOrDouble() { field.slotId++ } } } class.instanceSlotCount = slotId }
func calcStaticFieldSlotIds(class *Class) { slotId := uint(0) for _, field := range class.fields { if field.IsStatic() { field.slotId = slotId slotId++ if field.isLongOrDouble() { slotId++ } } } class.staticSlotCount = slotId }
func allocAndInitStaticVars(class *Class) { class.staticVars = newSlots(class.staticSlotCount) for _, field := range class.fields { if field.IsStatic() && field.IsFinal() { initStaticFinalVar(class, field) } } }
func initStaticFinalVar(class *Class, field *Field) { vars := class.staticVars cp := class.constantPool cpIndex := field.ConstValueIndex() slotId := field.SlotId()
if cpIndex > 0 { switch field.descriptor { case "Z", "B", "C", "S", "I": val := cp.GetConstant(cpIndex).(int32) vars.SetInt(slotId, val) case "J": val := cp.GetConstant(cpIndex).(int64) vars.SetLong(slotId, val) case "F": val := cp.GetConstant(cpIndex).(float32) vars.SetFloat(slotId, val) case "D": val := cp.GetConstant(cpIndex).(float64) vars.SetDouble(slotId, val) case "Ljava/lang/String;": panic("todo") } } }
|
类和类成员引用
实现ResolvedClass和ResolvedMemberRef接口,用来表示类和类成员引用。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| func (self *SymRef) ResolvedClass() *Class { if self.class == nil { self.resolveClassRef() } return self.class }
func (self *SymRef) resolveClassRef() { d := self.cp.class c := d.loader.LoadClass(self.className) if !c.isAccessibleTo(d) { panic("java.lang.IllegalAccessError") } self.class = c }
|
如果类已经解析过了,就不解析了。解析类时,应进行类的访问控制规则判断,只有符合规则的类才能被访问。
类似,我们实现字段引用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71
| type FieldRef struct { MemberRef field *Field }
func (self *FieldRef) ResolvedField() *Field { if self.field == nil { self.resolvedFieldRef() } return self.field }
func (self *FieldRef) resolvedFieldRef() { 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") } }
func lookupField(class *Class, name, descriptor string) *Field { for _, field := range class.fields { if field.name == name && field.descriptor == descriptor { return field } } for _, iface := range class.interfaces { if field := lookupField(iface, name, descriptor); field != nil { return field } } if class.superClass != nil { return lookupField(class.superClass, name, descriptor) } return nil }
func (self *Field) isAccessibleTo(d *Class) bool { if self.IsPublic() { return true } c := self.class
if self.IsProtected() { return d == c || d.isSubClassOf(c) || c.getPackageName() == d.getPackageName() }
if self.IsPrivate() { return d == c }
return c.getPackageName() == d.getPackageName() }
|
如果字段已经解析了,就不解析了。
解析字段的时候,先进行查找字段,查询字段所属类是否存在字段,然后查询其父类和接口是否存在字段。
最后进行字段的访问控制规则判断,只有符合规则的字段才能被访问。
总结
在本篇,我们实现了类的结构体,以及其相关的属性。
常量池将class文件的常量池转换而来,常量池存储常量数值和符号引用。
方法表与字段表存储对应的类成员信息,静态变量存储静态变量。
当然我们也做了classLoader的实现,实现了类的加载,解析,初始化。