14、jvm支持数组
2020-05-22 本文已影响0人
陈桐Caliburn
gojvm目录
1、搭建go环境
2、cmd命令行参数解析
3、搜索class文件
4、添加testOption 便于单元测试
5、解析classfile文件
6、运行时数据区
7、指令集
8、解释器
9、创建Class
10、类加载器
11、对象实例化new object
12、方法调用和返回
13 类初始化
14、jvm支持数组
15、jvm支持字符串-数组扩展
16、本地方法调用
17、ClassLoader原理
18、异常处理
19、 启动jvm
知识扩展
基本型数组 一维数组
引用型数组 多维数组
数组类 | 普通类 |
---|---|
java虚拟机运行时生成 | class文件加载 |
newarray/anewarray | new创建 |
存放aload/astore | 存放putfield/getfield |
arraylength读取长度
([)+数组元素类型描述符 eg:
int[] -> [I
int[][] ->[[I
Object -> [Ljava/lang/Object;
关键函数
type Object struct{
class *Class
data interface{} //void *
}
// 新创建的实例对象需要赋初值,go默认赋了
func newObject(class *Class) *Object {
return &Object{
class: class,
data: newSlots(class.instanceSlotCount),
}
}
以int数组为例
array_object.go
func (self *Object) Ints() []int32 {
return self.data.([]int32)
}
//arraylength
func (self *Object) ArrayLength() int32 {
switch self.data.(type) {
case []int32:
return int32(len(self.data.([]int32)))
default:
panic("Not array!")
}
}
array_class.go
func (self *Class) NewArray(count uint) *Object {
if !self.IsArray() {
panic("Not array class: " + self.name)
}
switch self.Name() {
case "[I": //int
return &Object{self, make([]int32, count)}
default:
return &Object{self, make([]*Object, count)}
}
}
类加载器支持数组
class_loader.go
// 把类数据加载到方法区
func (self *ClassLoader) LoadClass(name string) *Class {
if class, ok := self.classMap[name]; ok {
return class // 类已经加载
}
//数组类型
if name[0] == '['{
return self.loadArrayClass(name)
}
//非数组类型
return self.loadNonArrayClass(name) // 普通类的数据来自于class文件,数组类的数据是jvm在运行期间动态生成的
}
func (self *ClassLoader) loadArrayClass(name string) *Class {
class := &Class{
accessFlags: ACC_PUBLIC, // todo
name: name,
loader: self,
initStarted: true,
superClass: self.LoadClass("java/lang/Object"),
interfaces: []*Class{
self.LoadClass("java/lang/Cloneable"),
self.LoadClass("java/io/Serializable"),
},
}
self.classMap[name] = class
return class
}
newarray指令
func (self *NEW_ARRAY) Execute(frame *rtda.Frame) {
stack := frame.OperandStack()
count := stack.PopInt()
if count < 0 {
panic("java.lang.NegativeArraySizeException")
}
classLoader := frame.Method().Class().Loader()
arrClass := getPrimitiveArrayClass(classLoader, self.atype)
arr := arrClass.NewArray(uint(count))
stack.PushRef(arr)
}
func getPrimitiveArrayClass(loader *heap.ClassLoader, atype uint8) *heap.Class {
switch atype {
case AT_BOOLEAN:
return loader.LoadClass("[Z")
case AT_BYTE:
return loader.LoadClass("[B")
case AT_CHAR:
return loader.LoadClass("[C")
case AT_SHORT:
return loader.LoadClass("[S")
case AT_INT:
return loader.LoadClass("[I")
case AT_LONG:
return loader.LoadClass("[J")
case AT_FLOAT:
return loader.LoadClass("[F")
case AT_DOUBLE:
return loader.LoadClass("[D")
default:
panic("Invalid atype!")
}
}
符号表转换
class_name_helper.go
var primitiveTypes = map[string]string{
"void": "V",
"boolean": "Z",
"byte": "B",
"short": "S",
"int": "I",
"long": "J",
"char": "C",
"float": "F",
"double": "D",
}
// [XXX -> [[XXX
// int -> [I
// XXX -> [LXXX;
func getArrayClassName(className string) string {
return "[" + toDescriptor(className)
}
// [[XXX -> [XXX
// [LXXX; -> XXX
// [I -> int
func getComponentClassName(className string) string {
if className[0] == '[' {
componentTypeDescriptor := className[1:]
return toClassName(componentTypeDescriptor)
}
panic("Not array: " + className)
}
// [XXX => [XXX
// int => I
// XXX => LXXX;
func toDescriptor(className string) string {
if className[0] == '[' {
// array
return className
}
if d, ok := primitiveTypes[className]; ok {
// primitive
return d
}
// object
return "L" + className + ";"
}
// [XXX => [XXX
// LXXX; => XXX
// I => int
func toClassName(descriptor string) string {
if descriptor[0] == '[' {
// array
return descriptor
}
if descriptor[0] == 'L' {
// object
return descriptor[1 : len(descriptor)-1]
}
for className, d := range primitiveTypes {
if d == descriptor {
// primitive
return className
}
}
panic("Invalid descriptor: " + descriptor)
}
aload/astore指令
func (self *AALOAD) Execute(frame *rtda.Frame) {
stack := frame.OperandStack()
index := stack.PopInt()
arrRef := stack.PopRef()
checkNotNil(arrRef)
refs := arrRef.Refs()
checkIndex(len(refs), index)
stack.PushRef(refs[index])
}
func (self *AASTORE) Execute(frame *rtda.Frame) {
stack := frame.OperandStack()
ref := stack.PopRef()
index := stack.PopInt()
arrRef := stack.PopRef()
checkNotNil(arrRef)
refs := arrRef.Refs()
checkIndex(len(refs), index)
refs[index] = ref
}
测试数组
go run main -verbose:class -verbose:inst -test "array" -cp test/lib/example.jar jvmgo.book.ch08.BubbleSortTest