0
点赞
收藏
分享

微信扫一扫

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 
 * @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 项

34 新增的 miranda 方法 & 新增的常量池 entry_java

这里面的处理不光包含 miranda 方法的处理, 还包含 一些默认方法的处理 

我们这里主要关注的是 这个 actionPerformed 的 miranda 方法, 可以看到 是创建了一个方法的数据结构(Method) 

34 新增的 miranda 方法 & 新增的常量池 entry_java_02

那么方法的代码主要是什么呢? 

根据给定的 message 新建了一个 errorName 的异常, 然后 抛出去了 

34 新增的 miranda 方法 & 新增的常量池 entry_ide_03

我们再来看一下 这个 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 的方法列表中 

34 新增的 miranda 方法 & 新增的常量池 entry_ide_04

 merge 常量池部分的代码 

34 新增的 miranda 方法 & 新增的常量池 entry_ide_05

如果 你细心的话, 你会发现这个 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 的数据

举报

相关推荐

0 条评论