1. 程式人生 > >《自己動手寫java虛擬機器》學習筆記(七)-----執行緒私有執行時資料區(go)

《自己動手寫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虛擬機器》