14、jvm支持数组

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

实战项目地址

https://github.com/yinlingchaoliu/jvmgo.git

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 160,026评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,655评论 1 296
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,726评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,204评论 0 213
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,558评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,731评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,944评论 2 314
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,698评论 0 203
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,438评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,633评论 2 247
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,125评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,444评论 3 255
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,137评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,103评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,888评论 0 197
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,772评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,669评论 2 271