《自己动手写java虚拟机》学习笔记(七)-----线程私有运行时数据区(go)

     项目地址:https://github.com/gongxianshengjiadexiaohuihui

     在运行java程序时,Java虚拟机需要使用内存来存放各种各样的数据,Java虚拟机规范把这些内存的区域叫做运行时数据区。运行时数据区可以分为两类:一类是多个线程共享的,另一类是线程私有的。多线程共享的运行时数据区需要在java虚拟机启动时创建,在java虚拟机退出时销毁。线程私有的运行时数据区则在创建线程时才创建,线程退出时销毁。

    多线程共享的内存区域主要存放两类数据:类数据和类实例对象。对象数据放在堆中,类数据放在方法区中。堆由垃圾回收器定期清理,所以程序员不需要关心对象空间的释放。类数据包括字段信息和方法信息,方法的字节码,运行时常量池。从逻辑上讲,方法区也是堆的一部分。

     线程私有的运行时数据区用于辅助执行java字节码,每个线程都有自己的pc寄存器,和java虚拟机栈。java虚拟机栈又有栈帧构成,帧中保存方法执行的状态。包括局部变量表和操作数栈。在某一时刻,某一线程肯定是在执行某个方法。这个方法叫做当前方法,执行该方法的帧,叫做线程的当前帧。

java虚拟机支持的数据类型

我们来根据这个图实现线程私有的运行时数据区

首先是Thread

package rtda

type Thread struct {
	pc   int
	stack *Stack
}
//构造函数
func  NewThread() *Thread{
	return &Thread{
		stack: newStack(1024),
	}
}
//setter&getter
func (self *Thread)PC() int{
	return self.pc
}
func (self *Thread)SetPC(pc int){
	self.pc = pc
}
//操作栈帧
func (self *Thread)PushFrame(frame *Frame){
	self.stack.push(frame)
}
func (self *Thread)PopFrame() *Frame{
	return self.stack.pop()
}
func (self *Thread)CurrentFrame() *Frame{
	return self.stack.top()
}

从上层往下层,接下来构造jvm_stack

package rtda

type Stack struct {
//最大容量
maxSize uint
//当前数量
size    uint
//这是一个链表结构,_top相当于头指针
_top    *Frame
}
//构造函数
func newStack(maxSize uint) *Stack {
return &Stack{
maxSize: maxSize,

  }
 }
//出栈进栈操作
func (self *Stack) push(frame *Frame) {
if self.size >= self.maxSize {
panic("java.lang.StackOverflowError")
 }

if self._top != nil {
frame.lower = self._top
}

self._top = frame
self.size++
}

func (self *Stack) pop() *Frame {
if self._top == nil {

panic("jvm stack is empty!")

 }

top := self._top
self._top = top.lower
top.lower = nil
self.size--

return top
}

func (self *Stack) top() *Frame {
if self._top == nil {
panic("jvm stack is empty!")
}

return self._top
}

接下来一层是我们的栈帧

package rtda

type Frame struct {
	lower *Frame
	localVars LocalVars
	operandStack *OperandStack
}
func NewFrame(maxLocals, maxStack uint)*Frame{
	return &Frame{
		localVars : newLocalVars(maxLocals),
		operandStack : newOperandStack(maxStack),
	}
}
//getter
func (self *Frame)LocalVars()LocalVars{
	return self.localVars
}
func (self *Frame)OperandStack()*OperandStack{
	return self.operandStack
}

在构造局部变量表和操作数栈之前,我们要准备两样东西

一个是object,因为我们操作的数据不仅有基本类型,还有引用,因为具体object我们会在后面实现,在次先创建一个内容为空的object

package rtda

type Object struct {

}

局部变量表是按索引访问的,类似于按照数组下标访问的,这个数组的每个元素至少可以容纳一个int值或引用值。我们想到可以用一个结构体去表示一个int值和一个引用,需要什么值,取什么值即可。

package rtda

type Slot struct {
	num int32
	ref *Object
}

局部变量表

因为局部变量表存放的是int32,所以存放float,double,long的时候,需要我们进行转换

package rtda

import "math"

type LocalVars []Slot

func newLocalVars(maxlocals uint) LocalVars{
	if maxlocals > 0{
		return make([]Slot,maxlocals)
	}
	return nil
}
func (self LocalVars) SetInt(index uint, val int32){
	self[index].num = val
}
func (self LocalVars) GetInt(index uint) int32{
	return self[index].num
}
func (self LocalVars) SetFloat(index uint, val float32){
	bits := math.Float32bits(val)
	self[index].num = int32(bits)
}
func (self LocalVars)GetFloat(index uint) float32{
	bits := uint32(self[index].num)
	return math.Float32frombits(bits)
}
func (self LocalVars)SetLong(index uint, val int64){
	self[index].num = int32(val)
	self[index+1].num = int32(val >> 32)
}
func (self LocalVars)GetLong(index uint) int64{
	low := uint32(self[index].num)
	high := uint32(self[index+1].num)
	return int64(high)<<32 |int64(low)
}
func (self LocalVars)SetDouble(index uint, val float64){
	bits := math.Float64bits(val)
	self.SetLong(index,int64(bits))
}
func (self LocalVars)GetDouble(index uint)float64{
	bits := (uint64)(self.GetLong(index))
	return math.Float64frombits(bits)
}
func (self LocalVars)SetRef(index uint, ref *Object){
	self[index].ref = ref
}
func (self LocalVars)GetRef(index uint)*Object{
	return self[index].ref
}

操作数栈

package rtda

import "math"
//操作数栈 属于栈帧 一个方法执行就对应一个

//操作数栈大小是编译器编译时就确定的 在class文件的方法信息的code属性里面有写这项
type OperandStack struct {
	size uint
	slots []Slot
}

func newOperandStack(maxStack uint)*OperandStack{
	if maxStack > 0{
		return &OperandStack{
			slots : make([]Slot,maxStack),
		}
	}
	return nil
}

func (self *OperandStack)PushInt(val int32){
	self.slots[self.size].num = val
	self.size ++
}
func (self *OperandStack)PopInt() int32{
	self.size --
	return  self.slots[self.size].num
}

func (self *OperandStack)PushFloat(val float32){
	bits := math.Float32bits(val)
	self.slots[self.size].num = int32(bits)
	self.size ++
}
func (self *OperandStack)PopFloat()float32  {
	self.size --
	bits := uint32(self.slots[self.size].num)
	return math.Float32frombits(bits)
}

func (self *OperandStack)PushLong(val int64){
	self.slots[self.size].num = int32(val)
	self.slots[self.size+1].num = int32(val >> 32)
	self.size += 2
}
func (self *OperandStack)PopLong()int64{
	self.size -= 2
	low := uint32(self.slots[self.size].num)
	high := uint32(self.slots[self.size+1].num)
	return int64(high) << 32 | int64(low)
}

func (self *OperandStack)PushDouble(val float64){
	bits := math.Float64bits(val)
	self.PushLong(int64(bits))

}
func (self *OperandStack)PopDouble()float64{
	bits := uint64(self.PopLong())
	return math.Float64frombits(bits)
}

func (self *OperandStack)PushRef(ref *Object){
	self.slots[self.size].ref = ref
	self.size ++
}
func(self *OperandStack)PopRef() *Object{
	self.size --
	return self.slots[self.size].ref
}

最后改造我们的main函数

package main

import "fmt"
import "jvmgo/rtda"


func main(){
	//调用解析命令行的行数,接受解析结果
    cmd:=parseCmd()
    if cmd.versionFlag{
    	fmt.Println("version 0.0.1")
    }else if cmd.helpFlag||cmd.class==""{
    	printUsage()
    }else{
    	startJVM(cmd)
    }
}

func startJVM(cmd *Cmd){
    frame := rtda.NewFrame(100,100)
    testLocalVars(frame.LocalVars());
    testOperandStack(frame.OperandStack());
}
func testLocalVars(vars rtda.LocalVars) {
	vars.SetInt(0, 100)
	vars.SetInt(1, -100)
	vars.SetLong(2, 2997924580)
	vars.SetLong(4, -2997924580)
	vars.SetFloat(6, 3.1415926)
	vars.SetDouble(7, 2.71828182845)
	vars.SetRef(9, nil)
	println(vars.GetInt(0))
	println(vars.GetInt(1))
	println(vars.GetLong(2))
	println(vars.GetLong(4))
	println(vars.GetFloat(6))
	println(vars.GetDouble(7))
	println(vars.GetRef(9))
}

func testOperandStack(ops *rtda.OperandStack) {
	ops.PushInt(100)
	ops.PushInt(-100)
	ops.PushLong(2997924580)
	ops.PushLong(-2997924580)
	ops.PushFloat(3.1415926)
	ops.PushDouble(2.71828182845)
	ops.PushRef(nil)
	println(ops.PopRef())
	println(ops.PopDouble())
	println(ops.PopFloat())
	println(ops.PopLong())
	println(ops.PopLong())
	println(ops.PopInt())
	println(ops.PopInt())
}

运行结果

参考资料:《自己动手写Java虚拟机》

猜你喜欢

转载自blog.csdn.net/qq_33543634/article/details/84708853