35 根据 InstanceKlass 查找 itable 的数据
Posted 蓝风9
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了35 根据 InstanceKlass 查找 itable 的数据相关的知识,希望对你有一定的参考价值。
前言
// 呵呵 昨天陷入了没有流量的窘迫境地
vtable 的相关数据结构介绍 可以参见 根据 InstanceKlass 查找 vtable 的数据
itable 的数据结构的组合, 这里会介绍
理解 vtable, itable 对于理解 invokevirtual, invokeinterface 是有帮助的, 进而对于 java 里面多态的具体实现方式, 也是一个基础
以下调试 vm 部分基于 jdk9, HSDB 部分这里就不在赘述了, 参考 根据 InstanceKlass 查找 vtable 的数据
测试用例
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 的调试
我们先来看一下 itable 的元数据信息
table_offset 为 80, 看过 根据 InstanceKlass 查找 vtable 的数据 应该知道 vtable 中的 table_offset 为 448, 并且 vtable 有 24 个元素
那么和这里的 80 有什么关系呢?, 这两个 offset 的单位是不一样的, itable 的单位为字, vtable的单位为字节
448(InstanceKlass of Test02LoopUpVTable) + 24 * 8(vtable 24个Method*) = 640(字节)
80 * 8 = 640 (字节), itable 是跟在 vtable 后面的
我们再来看一下 itable 的开始区域 和 结束区域的计算方式
itable 的开始于 vtable 结束的地方, itable 的长度为 itable_len(这里为31, 计算的方式我们待会儿再看)
itable 里面的 table_offset 是这么计算出来的(单位是 intptr_t*, 8字节)
另外从下面的逻辑可以看到, 在 itable 的区域, itableOffsetEntry(4个(三个接口 + 一个dummy)) 在前面, methodEntry(23个) 在后面
从这里也可以大致的推导出 itable_len 的计算为 4*2 + 23 = 31(字)
我们再来看一下 initialize
处理的业务主要是在当前 InstanceKlass 的 itable 上面记录, 给定接口的方法, 如果重写了 则吧 Method 记录在 itable 上面
我这里 Test02LoopUpVTable 总共实现了三个接口 : "java.util.Iterable", "java.util.Collection", ", "java.awt.event.ActionListener"
并且 顺序和上面一致
其中 java.util.Iterable 有三个方法, iterator, forEach, spliterator, 后两个是默认接口方法
其中 java.util.Collection 有十九个方法
其中 java.awt.event.ActionListener 有一个方法, actionPerformed
这上述的一些方法, iterator, actionPerformed 这两个很明显 Test02LoopUpVTable 是没有实现的
forEach, spliterator 有对应的 默认方法实现
那么我们来看一下 Test02LoopUpVTable 的 itable 的一些数据
(lldb) x 0x7c008fc30 -c 0x400
# InstanceKlass of Test02LoopUpVTable
0x7c008fc30: 30 27 a3 0f 01 00 00 00 00 00 00 00 29 00 00 00 0'..........)...
0x7c008fc40: 40 00 00 00 00 00 00 00 f0 e9 b1 33 85 7f 00 00 @..........3....
0x7c008fc50: 18 6b 01 c0 07 00 00 00 90 c1 7d 13 01 00 00 00 .k.............
0x7c008fc60: 70 0f 00 c0 07 00 00 00 f8 6e 01 c0 07 00 00 00 p........n......
0x7c008fc70: 30 fc 08 c0 07 00 00 00 00 00 00 00 00 00 00 00 0...............
0x7c008fc80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x7c008fc90: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x7c008fca0: 18 8b b7 bf 07 00 00 00 f8 6e 01 c0 07 00 00 00 .........n......
0x7c008fcb0: 00 00 00 00 00 00 00 00 00 77 07 c0 07 00 00 00 .........w......
0x7c008fcc0: 00 00 00 00 00 00 00 00 60 2c 43 32 85 7f 00 00 ........`,C2....
0x7c008fcd0: 01 04 00 00 21 04 20 10 00 00 00 00 00 00 00 00 ....!. .........
0x7c008fce0: 01 00 00 00 00 00 00 00 00 00 00 00 18 00 00 00 ................
0x7c008fcf0: 01 00 ff ff 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x7c008fd00: f0 da 59 32 85 7f 00 00 00 00 00 00 00 00 00 00 ..Y2............
0x7c008fd10: b0 c2 7d 13 01 00 00 00 60 e0 2e 13 01 00 00 00 .......`.......
0x7c008fd20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x7c008fd30: 06 00 00 00 00 00 00 00 26 00 28 00 00 00 06 00 ........&.(.....
0x7c008fd40: 01 00 00 00 1f 00 00 00 00 00 9c 00 00 00 34 00 ..............4.
0x7c008fd50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x7c008fd60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x7c008fd70: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x7c008fd80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x7c008fd90: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x7c008fda0: 04 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x7c008fdb0: 00 00 00 00 00 00 00 00 60 c5 7d 13 01 00 00 00 ........`......
0x7c008fdc0: 88 c5 7d 13 01 00 00 00 e0 be 7d 13 01 00 00 00 ..............
0x7c008fdd0: 90 c1 7d 13 01 00 00 00 48 e0 2e 13 01 00 00 00 .......H.......
0x7c008fde0: 00 c7 7d 13 01 00 00 00 f8 be 7d 13 01 00 00 00 ..............
# vtable of Test02LoopUpVTable
0x7c008fdf0: 38 ee 2e 13 01 00 00 00 28 e8 2e 13 01 00 00 00 8.......(.......
0x7c008fe00: 60 15 41 13 01 00 00 00 40 e7 2e 13 01 00 00 00 `.A.....@.......
0x7c008fe10: c8 e8 2e 13 01 00 00 00 50 0e 41 13 01 00 00 00 ........P.A.....
0x7c008fe20: 58 0f 41 13 01 00 00 00 30 14 41 13 01 00 00 00 X.A.....0.A.....
0x7c008fe30: f0 07 41 13 01 00 00 00 f0 08 41 13 01 00 00 00 ..A.......A.....
0x7c008fe40: 38 c1 7d 13 01 00 00 00 90 0b 41 13 01 00 00 00 8........A.....
0x7c008fe50: 08 0a 41 13 01 00 00 00 b0 06 41 13 01 00 00 00 ..A.......A.....
0x7c008fe60: 48 11 41 13 01 00 00 00 48 10 41 13 01 00 00 00 H.A.....H.A.....
0x7c008fe70: 58 13 41 13 01 00 00 00 50 12 41 13 01 00 00 00 X.A.....P.A.....
0x7c008fe80: c0 c9 40 13 01 00 00 00 70 ca 40 13 01 00 00 00 ..@.....p.@.....
0x7c008fe90: f8 bd 40 13 01 00 00 00 c8 c6 40 13 01 00 00 00 ..@.......@.....
0x7c008fea0: 20 cb 40 13 01 00 00 00 00 c2 7d 13 01 00 00 00 .@............
# itable of Test02LoopUpVTable
0x7c008feb0: 28 69 01 c0 07 00 00 00 c0 02 00 00 00 00 00 00 (i..............
0x7c008fec0: 18 6b 01 c0 07 00 00 00 d8 02 00 00 00 00 00 00 .k..............
0x7c008fed0: e0 d3 08 c0 07 00 00 00 70 03 00 00 00 00 00 00 ........p.......
0x7c008fee0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x7c008fef0: 00 00 00 00 00 00 00 00 c0 c9 40 13 01 00 00 00 ..........@.....
0x7c008ff00: f8 bd 40 13 01 00 00 00 50 0e 41 13 01 00 00 00 ..@.....P.A.....
0x7c008ff10: 58 0f 41 13 01 00 00 00 30 14 41 13 01 00 00 00 X.A.....0.A.....
0x7c008ff20: f0 07 41 13 01 00 00 00 f0 08 41 13 01 00 00 00 ..A.......A.....
0x7c008ff30: 38 c1 7d 13 01 00 00 00 90 0b 41 13 01 00 00 00 8........A.....
0x7c008ff40: 08 0a 41 13 01 00 00 00 00 00 00 00 00 00 00 00 ..A.............
0x7c008ff50: c0 c9 40 13 01 00 00 00 48 11 41 13 01 00 00 00 ..@.....H.A.....
0x7c008ff60: 70 ca 40 13 01 00 00 00 48 10 41 13 01 00 00 00 p.@.....H.A.....
0x7c008ff70: 58 13 41 13 01 00 00 00 50 12 41 13 01 00 00 00 X.A.....P.A.....
0x7c008ff80: c8 c6 40 13 01 00 00 00 20 cb 40 13 01 00 00 00 ..@..... .@.....
0x7c008ff90: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x7c008ffa0: 00 c2 7d 13 01 00 00 00 20 00 00 00 01 00 00 00 ....... .......
0x7c008ffb0: f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 ................
0x7c008ffc0: f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 ................
0x7c008ffd0: f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 ................
0x7c008ffe0: f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 ................
0x7c008fff0: f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 ................
0x7c0090000: f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 ................
0x7c0090010: f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 ................
0x7c0090020: f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 ................
itable 的前面 8 个字为 itableOffsetEntry
然后 之后的 23 个字为 methodEntry
我们先来看一下前面 8 个字
0x7c008feb0: 28 69 01 c0 07 00 00 00 c0 02 00 00 00 00 00 00 (i..............
0x7c008fec0: 18 6b 01 c0 07 00 00 00 d8 02 00 00 00 00 00 00 .k..............
0x7c008fed0: e0 d3 08 c0 07 00 00 00 70 03 00 00 00 00 00 00 ........p.......
0x7c008fee0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
然后 运行时查看一下 这几个 itableOffsetEntry
(lldb) po offset_entry(0)->interface_klass()
0x00000007c0016928
(lldb) po offset_entry(0)->offset()
704
(lldb) po offset_entry(1)->interface_klass()
0x00000007c0016b18
(lldb) po offset_entry(1)->offset()
728
(lldb) po offset_entry(2)->interface_klass()
0x00000007c008d3e0
(lldb) po offset_entry(2)->offset()
880
(lldb) po offset_entry(3)->interface_klass()
<nil>
(lldb) po offset_entry(3)->offset()
<nil>
offset_entry(3) 是 dummy 节点
然后我们再来看一下 这些 methodEntry 的的信息
0x7c008fef0: 00 00 00 00 00 00 00 00 c0 c9 40 13 01 00 00 00 ..........@.....
0x7c008ff00: f8 bd 40 13 01 00 00 00 50 0e 41 13 01 00 00 00 ..@.....P.A.....
0x7c008ff10: 58 0f 41 13 01 00 00 00 30 14 41 13 01 00 00 00 X.A.....0.A.....
0x7c008ff20: f0 07 41 13 01 00 00 00 f0 08 41 13 01 00 00 00 ..A.......A.....
0x7c008ff30: 38 c1 7d 13 01 00 00 00 90 0b 41 13 01 00 00 00 8........A.....
0x7c008ff40: 08 0a 41 13 01 00 00 00 00 00 00 00 00 00 00 00 ..A.............
0x7c008ff50: c0 c9 40 13 01 00 00 00 48 11 41 13 01 00 00 00 ..@.....H.A.....
0x7c008ff60: 70 ca 40 13 01 00 00 00 48 10 41 13 01 00 00 00 p.@.....H.A.....
0x7c008ff70: 58 13 41 13 01 00 00 00 50 12 41 13 01 00 00 00 X.A.....P.A.....
0x7c008ff80: c8 c6 40 13 01 00 00 00 20 cb 40 13 01 00 00 00 ..@..... .@.....
0x7c008ff90: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x7c008ffa0: 00 c2 7d 13 01 00 00 00 20 00 00 00 01 00 00 00 ....... .......
然后 我们再来看一下 这几个 methodEntry 对应的数据
(lldb) po ((Method*)0x011340c9c0)->name_and_sig_as_C_string()
"java.util.Collection.spliterator()Ljava/util/Spliterator;"
(lldb) po ((Method*)0x011340bdf8)->name_and_sig_as_C_string()
"java.lang.Iterable.forEach(Ljava/util/function/Consumer;)V"
(lldb) po ((Method*)(0x01137dc200))->name_and_sig_as_C_string()
"com.hx.test07.Test02LoopUpVTable.actionPerformed(Ljava/awt/event/ActionEvent;)V"
Iterable.iterator 方法 Test02LoopUpVTable 没有实现, 因此 对应的是 NULL
Iterable.spliterator 被 Collection.spliterator 重写, 因此记录的是 Collection.spliterator
Iterable.forEach 记录的是默认方法 Iterable.forEach
... 省略中间 N 个 Collection 的方法
ActionListener.actionPerformed 记录的是类加载之后, 创建 instanceKlass 的时候 miranda 方法处理增加的一个 Method, 参见 新增的 miranda 方法 & 新增的常量池 entry
vtable_len 是怎么计算的呢?
可以看到 Test02LoopUpVTable 总共实现了 四个接口, 但是 上面我们只提到了三个 ?
另外就是 这里的四个接口 和 上面的 四个itableOffsetEntry 是对应的吗 ?
那是因为 EventListener 接口是一个标记接口, 没有方法, 因此处理的时候 就把它过滤掉了
计算 itable_len 的计算方式为 itableOffsetEntry 的数量(加上一个 dummy) * itableOffsetEntry 占用的空间(2个字), methodEntry 的数量 * methodEntry 占用的空间(1个字)
参考
根据 InstanceKlass 查找 vtable 的数据
创作打卡挑战赛 赢取流量/现金/CSDN周边激励大奖以上是关于35 根据 InstanceKlass 查找 itable 的数据的主要内容,如果未能解决你的问题,请参考以下文章
33 根据 InstanceKlass 查找 vtable 的数据
33 根据 InstanceKlass 查找 vtable 的数据
51 java.lang.Class/java.lang.ClassLoader/InstanceKlass/ClassloaderData 的卸载
51 java.lang.Class/java.lang.ClassLoader/InstanceKlass/ClassloaderData 的卸载