本节继续学习异常处理。
实现athrow指令
athrow属于引用类指令,在/instructions/references包下创建athrow.go文件,在其中定义athrow指令:
|
|
athrow指令的实现中有三个方法还没给出,下面列举下:
修改/rtdata/operand_stack.go文件,添加清空操作数栈的方法:
123456func (self *OperandStack) Clear() {self.size = 0for i := range self.slots {self.slots[i].ref = nil}}修改/rtdata/jvm_stack.go文件,添加清空JVM虚拟机栈的方法:
12345func (self *Stack) clear() {for !self.isEmpty() {self.pop()}}
3.修改/rtdata/thread.go文件,添加清空JVM虚拟机栈的方法:
最后,修改下/instructions/factory.go文件,放开athrow指令的注释。
Java虚拟机栈信息
再回到/native/java/lang/Throwable.go文件,在其中定义StackTraceElement结构体:
在真正完成fillInStackTrace()方法之前,有些准备工作要坐下:
在/rtdata/jvm_stack.go文件中添加构造栈帧完整的栈帧的方法:
1234567func (self *Stack) getFrames() []*Frame {frames := make([]*Frame, 0, self.size)for frame := self._top; frame != nil; frame = frame.lower {frames = append(frames, frame)}return frames}在/rtdata/thread中添加上述调用:
1234// 获取完整的Java虚拟机栈func (self *Thread) GetFrames() []*Frame {return self.stack.getFrames()}修改/rtdata/heap/class.go文件:
12345678910111213141516171819202122type Class struct {...// 类所在的文件名sourceFile string}func (self *Class) SourceFile() string {return self.sourceFile}func newClass(cf *classfile.ClassFile) *Class {...class.sourceFile = getSourceFile(cf)}// 要注意的是,并不是每个class文件都有源文件信息func getSourceFile(cf *classfile.ClassFile) string {if sfAttr := cf.SourceFileAttribute(); sfAttr != nil {return sfAttr.FileName()}return "Unknown" // todo}修改/classfile/class_file.go文件,添加获取SourceFileAttribute的方法:
123456789func (self *ClassFile) SourceFileAttribute() *SourceFileAttribute {for _, attrInfo := range self.attributes {switch attrInfo.(type) {case *SourceFileAttribute:return attrInfo.(*SourceFileAttribute)}}return nil}修改/rtdata/heap/method.go文件:
12345678910111213141516171819202122232425type Method struct {...// 行号表信息lineNumberTable *classfile.LineNumberTableAttribute}func (self *Method) copyAttributes(cfMethod *classfile.MemberInfo) {if codeAttr := cfMethod.CodeAttribute(); codeAttr != nil {...self.lineNumberTable = codeAttr.LineNumberTableAttribute()}}// 和源文件一样,并不是每个方法都有行号表。func (self *Method) GetLineNumber(pc int) int {// 本地方法没有字节码,自然就没有行号表,返回-2if self.IsNative() {return -2}// 没有行号表,返回-1if self.lineNumberTable == nil {return -1}return self.lineNumberTable.GetLineNumber(pc)}修改/classfile/attr_code.go文件,添加如下方法:
123456789func (self *CodeAttribute) LineNumberTableAttribute() *LineNumberTableAttribute {for _, attrInfo := range self.attributes {switch attrInfo.(type) {case *LineNumberTableAttribute:return attrInfo.(*LineNumberTableAttribute)}}return nil}
最后可以来完成在真正完成fillInStackTrace()方法了:
|
|
测试
在java项目中新建ParseIntTest.java,代码就不贴出来了,参照项目源码,下面给出测试结果:
写在最后
本系列的学习就到此为止了。首先要感谢原作者不遗余力地写出本书供后来者学习,书中的知识对本人的提升很有帮助,建议有兴趣的Java从业者去买一本看看,支持正版。学到现在,最多也就只敢说是Java小学生,或许还够不上,学无止境,加油!