美文网首页
18、异常处理

18、异常处理

作者: 陈桐Caliburn | 来源:发表于2020-05-24 21:15 被阅读0次

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"

相关文章

网友评论

      本文标题:18、异常处理

      本文链接:https://www.haomeiwen.com/subject/eqmlahtx.html