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
异常处理
unchecked 异常 : java.lang.RuntimeException、java.lang.Error
checked异常:其他
异常父类:java.lang.Throwable
异常指令 athrow
需要实现Throwable native方法
private native Throwable fillInStackTrace(int dummy)
1、注册native方法
const jlThrowable = "java/lang/Throwable"
type StackTraceElement struct {
fileName string
className string
methodName string
lineNumber int
}
func (self *StackTraceElement) String() string {
return fmt.Sprintf("%s.%s(%s:%d)",
self.className, self.methodName, self.fileName, self.lineNumber)
}
func init() {
native.Register(jlThrowable, "fillInStackTrace", "(I)Ljava/lang/Throwable;", fillInStackTrace)
}
// private native Throwable fillInStackTrace(int dummy);
// (I)Ljava/lang/Throwable;
func fillInStackTrace(frame *rtda.Frame) {
this := frame.LocalVars().GetThis()
frame.OperandStack().PushRef(this)
stes := createStackTraceElements(this, frame.Thread())
this.SetExtra(stes)
}
java代码
void catchOne(){
try{
tryItOut()
}catch(TestExc e){
handleExc(e)
}
}
异常处理表
type ExceptionHandler struct {
startPc int //try代码段
endPc int //try代码段
handlerPc int //处理句柄
catchType *ClassRef //异常类
}
Method
type Method struct {
exceptionTable ExceptionTable //异常处理表
lineNumberTable * classfile.LineNumberTableAttribute
}
func (self *Method) copyAttributes(cfMethod *classfile.MemberInfo) {
if codeAttr := cfMethod.CodeAttribute(); codeAttr != nil {
self.maxStack = codeAttr.MaxStack()
self.maxLocals = codeAttr.MaxLocals()
self.code = codeAttr.Code()
//todo exception 增加异常处理
self.exceptionTable = newExceptionTable(codeAttr.ExceptionTable(),self.class.constantPool)
// todo 代码行号
self.lineNumberTable = codeAttr.LineNumberTableAttribute()
}
}
func (self *Method) FindExceptionHandler(exClass *Class, pc int) int {
handler := self.exceptionTable.findExceptionHandler(exClass, pc)
if handler != nil {
return handler.handlerPc
}
return -1
}
func (self *Method) GetLineNumber(pc int) int {
if self.IsNative() {
return -2
}
if self.lineNumberTable == nil {
return -1
}
return self.lineNumberTable.GetLineNumber(pc)
}
newExceptionTable
//todo exception 异常处理
type ExceptionTable []*ExceptionHandler
type ExceptionHandler struct {
startPc int //try代码段
endPc int //try代码段
handlerPc int //处理句柄
catchType *ClassRef //异常类
}
//从classfile生成异常处理
func newExceptionTable(entries []*classfile.ExceptionTableEntry, cp *ConstantPool) ExceptionTable {
table := make([]*ExceptionHandler, len(entries))
for i, entry := range entries {
table[i] = &ExceptionHandler{
startPc: int(entry.StartPc()),
endPc: int(entry.EndPc()),
handlerPc: int(entry.HandlerPc()),
catchType: getCatchType(uint(entry.CatchType()), cp),
}
}
return table
}
//获得异常类
func getCatchType(index uint, cp *ConstantPool) *ClassRef {
if index == 0 {
return nil // catch all
}
return cp.GetConstant(index).(*ClassRef)
}
func (self ExceptionTable) findExceptionHandler(exClass *Class, pc int) *ExceptionHandler {
for _, handler := range self {
// jvms: The start_pc is inclusive and end_pc is exclusive
if pc >= handler.startPc && pc < handler.endPc {
if handler.catchType == nil {
return handler //catch-all
}
catchClass := handler.catchType.ResolvedClass()
if catchClass == exClass || catchClass.IsSuperClassOf(exClass) {
return handler
}
}
}
return nil
}
异常代码行数
func (self *CodeAttribute) LineNumberTableAttribute() *LineNumberTableAttribute {
for _, attrInfo := range self.attributes {
switch attrInfo.(type) {
case *LineNumberTableAttribute:
return attrInfo.(*LineNumberTableAttribute)
}
}
return nil
}
异常指令athrow
func (self *ATHROW) Execute(frame *rtda.Frame) {
ex := frame.OperandStack().PopRef()
if ex == nil {
panic("java.lang.NullPointerException")
}
thread := frame.Thread()
//未找异常处理方法
if !findAndGotoExceptionHandler(thread, ex) {
//抛出uncaught异常
handleUncaughtException(thread, ex)
}
}
func findAndGotoExceptionHandler(thread *rtda.Thread, ex *heap.Object) bool {
for {
frame := thread.CurrentFrame()
pc := frame.NextPC() - 1
handlerPC := frame.Method().FindExceptionHandler(ex.Class(), pc)
if handlerPC > 0 {
stack := frame.OperandStack()
stack.Clear()
stack.PushRef(ex)
frame.SetNextPC(handlerPC)
return true
}
thread.PopFrame()
if thread.IsStackEmpty() {
break
}
}
return false
}
// todo
func handleUncaughtException(thread *rtda.Thread, ex *heap.Object) {
thread.ClearStack()
jMsg := ex.GetRefVar("detailMessage", "Ljava/lang/String;")
goMsg := heap.GoString(jMsg)
println(ex.Class().JavaName() + ": " + goMsg)
stes := reflect.ValueOf(ex.Extra())
for i := 0; i < stes.Len(); i++ {
ste := stes.Index(i).Interface().(interface {
String() string
})
println("\tat " + ste.String())
}
}
异常测试
#exception 异常处理
go run main -cp test/lib/example.jar jvmgo.book.ch10.ParseIntTest 123
go run main -cp test/lib/example.jar jvmgo.book.ch10.ParseIntTest abc
go run main -cp test/lib/example.jar jvmgo.book.ch10.ParseIntTest
实战项目地址
https://github.com/yinlingchaoliu/jvmgo.git
提交标签 "exception"
网友评论