34 新增的 miranda 方法 & 新增的常量池 entry
Posted 蓝风9
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了34 新增的 miranda 方法 & 新增的常量池 entry相关的知识,希望对你有一定的参考价值。
前言
接着上一篇 根据 InstanceKlass 查找 vtable 的数据, 其中留下了一些 存在疑问的地方, 呵呵 本文主要就是探讨这几点疑问的地方
同样适用上面的方式, 可以很轻松的定位到 vtable 的最后一个元素 对应的类是 Test02LoopUpVTable
方法名称的 常量池索引是 74??, 参照最上面 我们的字节码中的信息, 我们发现 class 文件中常量池只有 65 个元素呀?
那这是 怎么回事呢?, 仅限于篇幅, 就不在这里介绍了
另外就是 如果你够细心的话, 你会发现 上面运行时介绍的时候, Test02LoopUpVTable 里面出现了四个方法, 其中有一个 actionPerformed??, 这个方法 并没有在原文件中体现阿? 这是怎么又回事呢 ?!!
以下调试 vm 部分基于 jdk9
测试用例
package com.hx.test07;
import java.awt.event.ActionListener;
import java.util.AbstractCollection;
/**
* LookUpVTable
*
* @author Jerry.X.He <970655147@qq.com>
* @version 1.0
* @date 2020-06-26 11:09
*/
public abstract class Test02LoopUpVTable extends AbstractCollection<String> implements ActionListener
// identStr
private String identStr = "identStr";
int f01;
int f02;
int f03;
int f04;
int f05;
// Test02LoopUpVTable
public static void main(String[] args)
// Test02LoopUpVTable instance = new Test02LoopUpVTable();
//
// int sz = instance.size();
int sz = 222;
System.out.println(" szie : " + sz);
// @Override
// public String get(int index)
// return null;
//
@Override
public int size()
return 222;
对应的字节码信息如下, 下面参照可能需要使用到
master:test07 jerry$ javap -c -v Test02LoopUpVTable.class
Classfile /Users/jerry/IdeaProjects/HelloWorld/target/classes/com/hx/test07/Test02LoopUpVTable.class
Last modified Jun 26, 2020; size 1171 bytes
MD5 checksum e3b1a319ed8ec01458c1bc5d08937f60
Compiled from "Test02LoopUpVTable.java"
public abstract class com.hx.test07.Test02LoopUpVTable extends java.util.AbstractCollection<java.lang.String> implements java.awt.event.ActionListener
minor version: 0
major version: 52
flags: ACC_PUBLIC, ACC_SUPER, ACC_ABSTRACT
Constant pool:
#1 = Methodref #13.#41 // java/util/AbstractCollection."<init>":()V
#2 = String #15 // identStr
#3 = Fieldref #12.#42 // com/hx/test07/Test02LoopUpVTable.identStr:Ljava/lang/String;
#4 = Fieldref #43.#44 // java/lang/System.out:Ljava/io/PrintStream;
#5 = Class #45 // java/lang/StringBuilder
#6 = Methodref #5.#41 // java/lang/StringBuilder."<init>":()V
#7 = String #46 // szie :
#8 = Methodref #5.#47 // java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
#9 = Methodref #5.#48 // java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
#10 = Methodref #5.#49 // java/lang/StringBuilder.toString:()Ljava/lang/String;
#11 = Methodref #50.#51 // java/io/PrintStream.println:(Ljava/lang/String;)V
#12 = Class #52 // com/hx/test07/Test02LoopUpVTable
#13 = Class #53 // java/util/AbstractCollection
#14 = Class #54 // java/awt/event/ActionListener
#15 = Utf8 identStr
#16 = Utf8 Ljava/lang/String;
#17 = Utf8 f01
#18 = Utf8 I
#19 = Utf8 f02
#20 = Utf8 f03
#21 = Utf8 f04
#22 = Utf8 f05
#23 = Utf8 <init>
#24 = Utf8 ()V
#25 = Utf8 Code
#26 = Utf8 LineNumberTable
#27 = Utf8 LocalVariableTable
#28 = Utf8 this
#29 = Utf8 Lcom/hx/test07/Test02LoopUpVTable;
#30 = Utf8 main
#31 = Utf8 ([Ljava/lang/String;)V
#32 = Utf8 args
#33 = Utf8 [Ljava/lang/String;
#34 = Utf8 sz
#35 = Utf8 size
#36 = Utf8 ()I
#37 = Utf8 Signature
#38 = Utf8 Ljava/util/AbstractCollection<Ljava/lang/String;>;Ljava/awt/event/ActionListener;
#39 = Utf8 SourceFile
#40 = Utf8 Test02LoopUpVTable.java
#41 = NameAndType #23:#24 // "<init>":()V
#42 = NameAndType #15:#16 // identStr:Ljava/lang/String;
#43 = Class #55 // java/lang/System
#44 = NameAndType #56:#57 // out:Ljava/io/PrintStream;
#45 = Utf8 java/lang/StringBuilder
#46 = Utf8 szie :
#47 = NameAndType #58:#59 // append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
#48 = NameAndType #58:#60 // append:(I)Ljava/lang/StringBuilder;
#49 = NameAndType #61:#62 // toString:()Ljava/lang/String;
#50 = Class #63 // java/io/PrintStream
#51 = NameAndType #64:#65 // println:(Ljava/lang/String;)V
#52 = Utf8 com/hx/test07/Test02LoopUpVTable
#53 = Utf8 java/util/AbstractCollection
#54 = Utf8 java/awt/event/ActionListener
#55 = Utf8 java/lang/System
#56 = Utf8 out
#57 = Utf8 Ljava/io/PrintStream;
#58 = Utf8 append
#59 = Utf8 (Ljava/lang/String;)Ljava/lang/StringBuilder;
#60 = Utf8 (I)Ljava/lang/StringBuilder;
#61 = Utf8 toString
#62 = Utf8 ()Ljava/lang/String;
#63 = Utf8 java/io/PrintStream
#64 = Utf8 println
#65 = Utf8 (Ljava/lang/String;)V
int f01;
descriptor: I
flags:
int f02;
descriptor: I
flags:
int f03;
descriptor: I
flags:
int f04;
descriptor: I
flags:
int f05;
descriptor: I
flags:
public com.hx.test07.Test02LoopUpVTable();
descriptor: ()V
flags: ACC_PUBLIC
Code:
stack=2, locals=1, args_size=1
0: aload_0
1: invokespecial #1 // Method java/util/AbstractCollection."<init>":()V
4: aload_0
5: ldc #2 // String identStr
7: putfield #3 // Field identStr:Ljava/lang/String;
10: return
LineNumberTable:
line 13: 0
line 16: 4
LocalVariableTable:
Start Length Slot Name Signature
0 11 0 this Lcom/hx/test07/Test02LoopUpVTable;
public static void main(java.lang.String[]);
descriptor: ([Ljava/lang/String;)V
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=3, locals=2, args_size=1
0: sipush 222
3: istore_1
4: getstatic #4 // Field java/lang/System.out:Ljava/io/PrintStream;
7: new #5 // class java/lang/StringBuilder
10: dup
11: invokespecial #6 // Method java/lang/StringBuilder."<init>":()V
14: ldc #7 // String szie :
16: invokevirtual #8 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
19: iload_1
20: invokevirtual #9 // Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
23: invokevirtual #10 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
26: invokevirtual #11 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
29: return
LineNumberTable:
line 29: 0
line 30: 4
line 32: 29
LocalVariableTable:
Start Length Slot Name Signature
0 30 0 args [Ljava/lang/String;
4 26 1 sz I
public int size();
descriptor: ()I
flags: ACC_PUBLIC
Code:
stack=1, locals=1, args_size=1
0: sipush 222
3: ireturn
LineNumberTable:
line 42: 0
LocalVariableTable:
Start Length Slot Name Signature
0 4 0 this Lcom/hx/test07/Test02LoopUpVTable;
Signature: #38 // Ljava/util/AbstractCollection<Ljava/lang/String;>;Ljava/awt/event/ActionListener;
SourceFile: "Test02LoopUpVTable.java"
基于vm的调试
通过调试, 发现 在 generate_default_methods 之后, 方法增加了一个, 并且常量池的数据 也发生了改变, 增加到了 75 项
这里面的处理不光包含 miranda 方法的处理, 还包含 一些默认方法的处理
我们这里主要关注的是 这个 actionPerformed 的 miranda 方法, 可以看到 是创建了一个方法的数据结构(Method)
那么方法的代码主要是什么呢?
根据给定的 message 新建了一个 errorName 的异常, 然后 抛出去了
我们再来看一下 这个 Method 的 code 对应的信息
bb 00 43 59 12 45 b7 00 49 bf
new 00 43
dup
ldc 45
invokespecial 00 49
athrow
贴一下 Test02LoopUpVTable的运行时常量池信息 作为参照
这样就可以看到 上面这段代码 到底做了什么事情, 具体是什么异常, 错误消息是什么
constant pool
- holder: 0x00000007c008fc30
- cache: 0x0000000114a6d5b8
- resolved_references: 0x00000007bfb78d60
- reference_map: 0x0000000114a6d6e8
- 1 : Method : klass_index=13 name_and_type_index=41
- 2 : String : 'identStr'
- 3 : Field : klass_index=12 name_and_type_index=42
- 4 : Field : klass_index=43 name_and_type_index=44
- 5 : Unresolved Class : 'java/lang/StringBuilder'
- 6 : Method : klass_index=5 name_and_type_index=41
- 7 : String : ' szie : '
- 8 : Method : klass_index=5 name_and_type_index=47
- 9 : Method : klass_index=5 name_and_type_index=48
- 10 : Method : klass_index=5 name_and_type_index=49
- 11 : Method : klass_index=50 name_and_type_index=51
- 12 : Unresolved Class : 'com/hx/test07/Test02LoopUpVTable'
- 13 : Unresolved Class : 'java/util/AbstractCollection'
- 14 : Unresolved Class : 'java/awt/event/ActionListener'
- 15 : Utf8 : 'identStr'
- 16 : Utf8 : 'Ljava/lang/String;'
- 17 : Utf8 : 'f01'
- 18 : Utf8 : 'I'
- 19 : Utf8 : 'f02'
- 20 : Utf8 : 'f03'
- 21 : Utf8 : 'f04'
- 22 : Utf8 : 'f05'
- 23 : Utf8 : '<init>'
- 24 : Utf8 : '()V'
- 25 : Utf8 : 'Code'
- 26 : Utf8 : 'LineNumberTable'
- 27 : Utf8 : 'LocalVariableTable'
- 28 : Utf8 : 'this'
- 29 : Utf8 : 'Lcom/hx/test07/Test02LoopUpVTable;'
- 30 : Utf8 : 'main'
- 31 : Utf8 : '([Ljava/lang/String;)V'
- 32 : Utf8 : 'args'
- 33 : Utf8 : '[Ljava/lang/String;'
- 34 : Utf8 : 'sz'
- 35 : Utf8 : 'size'
- 36 : Utf8 : '()I'
- 37 : Utf8 : 'Signature'
- 38 : Utf8 : 'Ljava/util/AbstractCollection<Ljava/lang/String;>;Ljava/awt/event/ActionListener;'
- 39 : Utf8 : 'SourceFile'
- 40 : Utf8 : 'Test02LoopUpVTable.java'
- 41 : NameAndType : name_index=23 signature_index=24
- 42 : NameAndType : name_index=15 signature_index=16
- 43 : Unresolved Class : 'java/lang/System'
- 44 : NameAndType : name_index=56 signature_index=57
- 45 : Utf8 : 'java/lang/StringBuilder'
- 46 : Utf8 : ' szie : '
- 47 : NameAndType : name_index=58 signature_index=59
- 48 : NameAndType : name_index=58 signature_index=60
- 49 : NameAndType : name_index=61 signature_index=62
- 50 : Unresolved Class : 'java/io/PrintStream'
- 51 : NameAndType : name_index=64 signature_index=65
- 52 : Utf8 : 'com/hx/test07/Test02LoopUpVTable'
- 53 : Utf8 : 'java/util/AbstractCollection'
- 54 : Utf8 : 'java/awt/event/ActionListener'
- 55 : Utf8 : 'java/lang/System'
- 56 : Utf8 : 'out'
- 57 : Utf8 : 'Ljava/io/PrintStream;'
- 58 : Utf8 : 'append'
- 59 : Utf8 : '(Ljava/lang/String;)Ljava/lang/StringBuilder;'
- 60 : Utf8 : '(I)Ljava/lang/StringBuilder;'
- 61 : Utf8 : 'toString'
- 62 : Utf8 : '()Ljava/lang/String;'
- 63 : Utf8 : 'java/io/PrintStream'
- 64 : Utf8 : 'println'
- 65 : Utf8 : '(Ljava/lang/String;)V'
- 66 : Utf8 : 'java/lang/AbstractMethodError'
- 67 : Unresolved Class : 'java/lang/AbstractMethodError'
- 68 : Utf8 : 'Method com/hx/test07/Test02LoopUpVTable.actionPerformed(Ljava/awt/event/ActionEvent;)V is abstract'
- 69 : String : 'Method com/hx/test07/Test02LoopUpVTable.actionPerformed(Ljava/awt/event/ActionEvent;)V is abstract'
- 70 : Utf8 : '<init>'
- 71 : Utf8 : '(Ljava/lang/String;)V'
- 72 : NameAndType : name_index=70 signature_index=71
- 73 : Method : klass_index=67 name_and_type_index=72
- 74 : Utf8 : 'actionPerformed'
- 75 : Utf8 : '(Ljava/awt/event/ActionEvent;)V'
然后 之后的处理, 就是 merge 新增的方法的常量池的信息, 以及 吧新增的方法 merge 到 klass 的方法列表中
merge 常量池部分的代码
如果 你细心的话, 你会发现这个 bpool 在上面生成 actionPerformed 的代码的时候使用过, 这就是为什么其中能够记录 新增的方法相关的这部分新的 entry
什么是 miranda 方法?
// Check if a method is a miranda method, given a class's methods array,
// its default_method table and its super class.
// "Miranda" means an abstract non-private method that would not be
// overridden for the local class.
// A "miranda" method should only include non-private interface
// instance methods, i.e. not private methods, not static methods,
// not default methods (concrete interface methods), not overpass methods.
// If a given class already has a local (including overpass) method, a
// default method, or any of its superclasses has the same which would have
// overridden an abstract method, then this is not a miranda method.
完
参考
根据 InstanceKlass 查找 vtable 的数据
以上是关于34 新增的 miranda 方法 & 新增的常量池 entry的主要内容,如果未能解决你的问题,请参考以下文章