JVM 指令

  • 1、Demo
  • 2、Class 文件说明
    • 2.1 Class文件结构
    • 2.2 jvm type, method signature
    • 2.3 泛型表示
  • 3、方法说明
    • 3.1 方法结构

      • 3.1.1 Thread Stack Model
      • 3.1.2 指令
      • 3.1.3 Stack Map Frames
  • 4、字节码工具库
  • 5、JVM 指令集

在java程序开发过程中,没有源码是很常见的事,我们可以通过IDE(Eclipse需要配置jad.exe、IDEA)自动的将class文件反编译为java文件。或者我们借助于其他工具(jd-gui, luyten)来直接的对整个jar包进行反编译。反编译工具是如何做到代码反编译的呢?如果是在生产环境下帮助用户解决问题时,是没有这些工具的,该怎么办呢?

在开发apm,jprofiler这样的工具时,spring团队在实现aop (例如interceptor),通常都会通过字节码 技术对已有代码进行改造,以达到对代码进行监控,改造工作。那么又是如何将字节码指令嵌入的呢?

要想了解这些东西,不学习class文件如何看,不了解相关字节码指令是很难解决上面的问题的。

1、Demo

在了解class文件之前,先来看一个例子:这是一个真实的需求。不同的机器时间没有使用NTP服务进行时间同步。在这样的一个环境下,各个机器的数据都以入库(如果的数据是机器自身的时间),现在要查看某个机器当前时间的数据,或者最近20分钟的数据。为了解决该问题,做了一个机器时间计算工具:

实现的源码如下:

public class RelativeTime
{
    private String machineId;
    private long delta;

    public RelativeTime() {
    }

    public RelativeTime(final String machineId, final long time) {
        this.machineId = machineId;
        final long now = System.currentTimeMillis();
        this.delta = now - time;
    }

    public String getMachineId() {
        return this.machineId;
    }

    public void setMachineId(final String machineId) {
        this.machineId = machineId;
    }

    public long getDelta() {
        return this.delta;
    }

    public void setDelta(final long delta) {
        this.delta = delta;
    }
}

import java.util.concurrent.*;

public class RelativeTimeManager
{
    private final ConcurrentHashMap<String, RelativeTime> cache;

    public RelativeTimeManager() {
        this.cache = new ConcurrentHashMap<String, RelativeTime>();
    }

    public void add(final String machineId, final long machineTime) {
        if (machineId != null) {
            final RelativeTime t = new RelativeTime(machineId, machineTime);
            this.add(t);
        }
    }

    public void add(final RelativeTime time) {
        if (time != null) {
            this.cache.put(time.getMachineId(), time);
        }
    }

    public void addIfAbsent(final String machineId, final long machineTime) {
        if (machineId != null && machineTime > 0L) {
            final RelativeTime t = new RelativeTime(machineId, machineTime);
            this.addIfAbsent(t);
        }
    }

    public void addIfAbsent(final RelativeTime time) {
        this.cache.putIfAbsent(time.getMachineId(), time);
    }

    public void remove(final String machineId) {
        if (machineId != null) {
            this.cache.remove(machineId);
        }
    }

    public boolean hasMachine(final String machineId) {
        return machineId != null && this.cache.get(machineId) != null;
    }

    public long getDeltaTime(final String machineId) {
        return this.cache.get(machineId).getDelta();
    }

    public long getMachineCurrentTime(final String machineId) {
        return this.getMachineRelativeTime(machineId, System.currentTimeMillis());
    }

    public long getMachineRelativeTime(final String machineId, final long time) {
        if (this.hasMachine(machineId)) {
            final long delta = this.getDeltaTime(machineId);
            return time - delta;
        }
        return time;
    }
}

先来解决上面提出的第一个问题,没有反编译工具的情况下如何查看java类:

在java_home/bin目录下,有这样一个工具:javap,使用它即可查看class文件内容。

对上述两个类分别执行 javap -l -v -p RelativeTime.class (javap -l -v -p RelativeTimeManager.class) 命令后如下:

RelativeTime:

Classfile /C:/Users/User/Desktop/webgate-commons/com/bes/webgate/common/clock/RelativeTime.class
  Last modified 2017-11-10; size 1005 bytes
  MD5 checksum eff96db3a12a575b2a4ebc1272b896e4
  Compiled from "RelativeTime.java"
public class com.bes.webgate.common.clock.RelativeTime
  SourceFile: "RelativeTime.java"
  minor version: 0
  major version: 50
  flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
   #1 = Methodref          #6.#31         //  java/lang/Object."<init>":()V
   #2 = Fieldref           #5.#32         //  com/bes/webgate/common/clock/RelativeTime.machineId:Ljava/lang/String;
   #3 = Methodref          #33.#34        //  java/lang/System.currentTimeMillis:()J
   #4 = Fieldref           #5.#35         //  com/bes/webgate/common/clock/RelativeTime.delta:J
   #5 = Class              #36            //  com/bes/webgate/common/clock/RelativeTime
   #6 = Class              #37            //  java/lang/Object
   #7 = Utf8               machineId
   #8 = Utf8               Ljava/lang/String;
   #9 = Utf8               delta
  #10 = Utf8               J
  #11 = Utf8               <init>
  #12 = Utf8               ()V
  #13 = Utf8               Code
  #14 = Utf8               LineNumberTable
  #15 = Utf8               LocalVariableTable
  #16 = Utf8               this
  #17 = Utf8               Lcom/bes/webgate/common/clock/RelativeTime;
  #18 = Utf8               (Ljava/lang/String;J)V
  #19 = Utf8               time
  #20 = Utf8               now
  #21 = Utf8               getMachineId
  #22 = Utf8               ()Ljava/lang/String;
  #23 = Utf8               setMachineId
  #24 = Utf8               (Ljava/lang/String;)V
  #25 = Utf8               getDelta
  #26 = Utf8               ()J
  #27 = Utf8               setDelta
  #28 = Utf8               (J)V
  #29 = Utf8               SourceFile
  #30 = Utf8               RelativeTime.java
  #31 = NameAndType        #11:#12        //  "<init>":()V
  #32 = NameAndType        #7:#8          //  machineId:Ljava/lang/String;
  #33 = Class              #38            //  java/lang/System
  #34 = NameAndType        #39:#26        //  currentTimeMillis:()J
  #35 = NameAndType        #9:#10         //  delta:J
  #36 = Utf8               com/bes/webgate/common/clock/RelativeTime
  #37 = Utf8               java/lang/Object
  #38 = Utf8               java/lang/System
  #39 = Utf8               currentTimeMillis
{
  private java.lang.String machineId;
    flags: ACC_PRIVATE 

  private long delta;
    flags: ACC_PRIVATE 

  public com.bes.webgate.common.clock.RelativeTime();
    flags: ACC_PUBLIC
    LineNumberTable:
      line 20: 0
      line 22: 4
    LocalVariableTable:
      Start  Length  Slot  Name   Signature
             0       5     0  this   Lcom/bes/webgate/common/clock/RelativeTime;
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0
         1: invokespecial #1                  // Method java/lang/Object."<init>":()V
         4: return
      LineNumberTable:
        line 20: 0
        line 22: 4
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
               0       5     0  this   Lcom/bes/webgate/common/clock/RelativeTime;

  public com.bes.webgate.common.clock.RelativeTime(java.lang.String, long);
    flags: ACC_PUBLIC
    LineNumberTable:
      line 24: 0
      line 25: 4
      line 26: 9
      line 27: 14
      line 28: 22
    LocalVariableTable:
      Start  Length  Slot  Name   Signature
             0      23     0  this   Lcom/bes/webgate/common/clock/RelativeTime;
             0      23     1 machineId   Ljava/lang/String;
             0      23     2  time   J
            14       9     4   now   J
    Code:
      stack=5, locals=6, args_size=3
         0: aload_0
         1: invokespecial #1                  // Method java/lang/Object."<init>":()V
         4: aload_0
         5: aload_1
         6: putfield      #2                  // Field machineId:Ljava/lang/String;
         9: invokestatic  #3                  // Method java/lang/System.currentTimeMillis:()J
        12: lstore        4
        14: aload_0
        15: lload         4
        17: lload_2
        18: lsub
        19: putfield      #4                  // Field delta:J
        22: return
      LineNumberTable:
        line 24: 0
        line 25: 4
        line 26: 9
        line 27: 14
        line 28: 22
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
               0      23     0  this   Lcom/bes/webgate/common/clock/RelativeTime;
               0      23     1 machineId   Ljava/lang/String;
               0      23     2  time   J
              14       9     4   now   J

  public java.lang.String getMachineId();
    flags: ACC_PUBLIC
    LineNumberTable:
      line 31: 0
    LocalVariableTable:
      Start  Length  Slot  Name   Signature
             0       5     0  this   Lcom/bes/webgate/common/clock/RelativeTime;
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0
         1: getfield      #2                  // Field machineId:Ljava/lang/String;
         4: areturn
      LineNumberTable:
        line 31: 0
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
               0       5     0  this   Lcom/bes/webgate/common/clock/RelativeTime;

  public void setMachineId(java.lang.String);
    flags: ACC_PUBLIC
    LineNumberTable:
      line 35: 0
      line 36: 5
    LocalVariableTable:
      Start  Length  Slot  Name   Signature
             0       6     0  this   Lcom/bes/webgate/common/clock/RelativeTime;
             0       6     1 machineId   Ljava/lang/String;
    Code:
      stack=2, locals=2, args_size=2
         0: aload_0
         1: aload_1
         2: putfield      #2                  // Field machineId:Ljava/lang/String;
         5: return
      LineNumberTable:
        line 35: 0
        line 36: 5
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
               0       6     0  this   Lcom/bes/webgate/common/clock/RelativeTime;
               0       6     1 machineId   Ljava/lang/String;

  public long getDelta();
    flags: ACC_PUBLIC
    LineNumberTable:
      line 39: 0
    LocalVariableTable:
      Start  Length  Slot  Name   Signature
             0       5     0  this   Lcom/bes/webgate/common/clock/RelativeTime;
    Code:
      stack=2, locals=1, args_size=1
         0: aload_0
         1: getfield      #4                  // Field delta:J
         4: lreturn
      LineNumberTable:
        line 39: 0
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
               0       5     0  this   Lcom/bes/webgate/common/clock/RelativeTime;

  public void setDelta(long);
    flags: ACC_PUBLIC
    LineNumberTable:
      line 43: 0
      line 44: 5
    LocalVariableTable:
      Start  Length  Slot  Name   Signature
             0       6     0  this   Lcom/bes/webgate/common/clock/RelativeTime;
             0       6     1 delta   J
    Code:
      stack=3, locals=3, args_size=2
         0: aload_0
         1: lload_1
         2: putfield      #4                  // Field delta:J
         5: return
      LineNumberTable:
        line 43: 0
        line 44: 5
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
               0       6     0  this   Lcom/bes/webgate/common/clock/RelativeTime;
               0       6     1 delta   J
}

RelativeTimeManager:

Classfile /C:/Users/User/Desktop/webgate-commons/com/bes/webgate/common/clock/RelativeTimeManager.class
  Last modified 2017-11-10; size 2352 bytes
  MD5 checksum 3475ce705b7622e212b5630a59413264
  Compiled from "RelativeTimeManager.java"
public class com.bes.webgate.common.clock.RelativeTimeManager
  SourceFile: "RelativeTimeManager.java"
  minor version: 0
  major version: 50
  flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
   #1 = Methodref          #20.#56        //  java/lang/Object."<init>":()V
   #2 = Class              #57            //  java/util/concurrent/ConcurrentHashMap
   #3 = Methodref          #2.#56         //  java/util/concurrent/ConcurrentHashMap."<init>":()V
   #4 = Fieldref           #19.#58        //  com/bes/webgate/common/clock/RelativeTimeManager.cache:Ljava/util/concurrent/ConcurrentHashMap;
   #5 = Class              #59            //  com/bes/webgate/common/clock/RelativeTime
   #6 = Methodref          #5.#60         //  com/bes/webgate/common/clock/RelativeTime."<init>":(Ljava/lang/String;J)V
   #7 = Methodref          #19.#61        //  com/bes/webgate/common/clock/RelativeTimeManager.add:(Lcom/bes/webgate/common/clock/RelativeTime;)V
   #8 = Methodref          #5.#62         //  com/bes/webgate/common/clock/RelativeTime.getMachineId:()Ljava/lang/String;
   #9 = Methodref          #2.#63         //  java/util/concurrent/ConcurrentHashMap.put:(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
  #10 = Methodref          #19.#64        //  com/bes/webgate/common/clock/RelativeTimeManager.addIfAbsent:(Lcom/bes/webgate/common/clock/RelativeTime;)V
  #11 = Methodref          #2.#65         //  java/util/concurrent/ConcurrentHashMap.putIfAbsent:(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
  #12 = Methodref          #2.#66         //  java/util/concurrent/ConcurrentHashMap.remove:(Ljava/lang/Object;)Ljava/lang/Object;
  #13 = Methodref          #2.#67         //  java/util/concurrent/ConcurrentHashMap.get:(Ljava/lang/Object;)Ljava/lang/Object;
  #14 = Methodref          #5.#68         //  com/bes/webgate/common/clock/RelativeTime.getDelta:()J
  #15 = Methodref          #69.#70        //  java/lang/System.currentTimeMillis:()J
  #16 = Methodref          #19.#71        //  com/bes/webgate/common/clock/RelativeTimeManager.getMachineRelativeTime:(Ljava/lang/String;J)J
  #17 = Methodref          #19.#72        //  com/bes/webgate/common/clock/RelativeTimeManager.hasMachine:(Ljava/lang/String;)Z
  #18 = Methodref          #19.#73        //  com/bes/webgate/common/clock/RelativeTimeManager.getDeltaTime:(Ljava/lang/String;)J
  #19 = Class              #74            //  com/bes/webgate/common/clock/RelativeTimeManager
  #20 = Class              #75            //  java/lang/Object
  #21 = Utf8               cache
  #22 = Utf8               Ljava/util/concurrent/ConcurrentHashMap;
  #23 = Utf8               Signature
  #24 = Utf8               Ljava/util/concurrent/ConcurrentHashMap<Ljava/lang/String;Lcom/bes/webgate/common/clock/RelativeTime;>;
  #25 = Utf8               <init>
  #26 = Utf8               ()V
  #27 = Utf8               Code
  #28 = Utf8               LineNumberTable
  #29 = Utf8               LocalVariableTable
  #30 = Utf8               this
  #31 = Utf8               Lcom/bes/webgate/common/clock/RelativeTimeManager;
  #32 = Utf8               add
  #33 = Utf8               (Ljava/lang/String;J)V
  #34 = Utf8               t
  #35 = Utf8               Lcom/bes/webgate/common/clock/RelativeTime;
  #36 = Utf8               machineId
  #37 = Utf8               Ljava/lang/String;
  #38 = Utf8               machineTime
  #39 = Utf8               J
  #40 = Utf8               StackMapTable
  #41 = Utf8               (Lcom/bes/webgate/common/clock/RelativeTime;)V
  #42 = Utf8               time
  #43 = Utf8               addIfAbsent
  #44 = Utf8               remove
  #45 = Utf8               (Ljava/lang/String;)V
  #46 = Utf8               hasMachine
  #47 = Utf8               (Ljava/lang/String;)Z
  #48 = Utf8               getDeltaTime
  #49 = Utf8               (Ljava/lang/String;)J
  #50 = Utf8               getMachineCurrentTime
  #51 = Utf8               getMachineRelativeTime
  #52 = Utf8               (Ljava/lang/String;J)J
  #53 = Utf8               delta
  #54 = Utf8               SourceFile
  #55 = Utf8               RelativeTimeManager.java
  #56 = NameAndType        #25:#26        //  "<init>":()V
  #57 = Utf8               java/util/concurrent/ConcurrentHashMap
  #58 = NameAndType        #21:#22        //  cache:Ljava/util/concurrent/ConcurrentHashMap;
  #59 = Utf8               com/bes/webgate/common/clock/RelativeTime
  #60 = NameAndType        #25:#33        //  "<init>":(Ljava/lang/String;J)V
  #61 = NameAndType        #32:#41        //  add:(Lcom/bes/webgate/common/clock/RelativeTime;)V
  #62 = NameAndType        #76:#77        //  getMachineId:()Ljava/lang/String;
  #63 = NameAndType        #78:#79        //  put:(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
  #64 = NameAndType        #43:#41        //  addIfAbsent:(Lcom/bes/webgate/common/clock/RelativeTime;)V
  #65 = NameAndType        #80:#79        //  putIfAbsent:(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
  #66 = NameAndType        #44:#81        //  remove:(Ljava/lang/Object;)Ljava/lang/Object;
  #67 = NameAndType        #82:#81        //  get:(Ljava/lang/Object;)Ljava/lang/Object;
  #68 = NameAndType        #83:#84        //  getDelta:()J
  #69 = Class              #85            //  java/lang/System
  #70 = NameAndType        #86:#84        //  currentTimeMillis:()J
  #71 = NameAndType        #51:#52        //  getMachineRelativeTime:(Ljava/lang/String;J)J
  #72 = NameAndType        #46:#47        //  hasMachine:(Ljava/lang/String;)Z
  #73 = NameAndType        #48:#49        //  getDeltaTime:(Ljava/lang/String;)J
  #74 = Utf8               com/bes/webgate/common/clock/RelativeTimeManager
  #75 = Utf8               java/lang/Object
  #76 = Utf8               getMachineId
  #77 = Utf8               ()Ljava/lang/String;
  #78 = Utf8               put
  #79 = Utf8               (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
  #80 = Utf8               putIfAbsent
  #81 = Utf8               (Ljava/lang/Object;)Ljava/lang/Object;
  #82 = Utf8               get
  #83 = Utf8               getDelta
  #84 = Utf8               ()J
  #85 = Utf8               java/lang/System
  #86 = Utf8               currentTimeMillis
{
  private final java.util.concurrent.ConcurrentHashMap<java.lang.String, com.bes.webgate.common.clock.RelativeTime> cache;
    flags: ACC_PRIVATE, ACC_FINAL
    Signature: #24                          // Ljava/util/concurrent/ConcurrentHashMap<Ljava/lang/String;Lcom/bes/webgate/common/clock/RelativeTime;>;

  public com.bes.webgate.common.clock.RelativeTimeManager();
    flags: ACC_PUBLIC
    LineNumberTable:
      line 22: 0
      line 20: 4
      line 24: 15
    LocalVariableTable:
      Start  Length  Slot  Name   Signature
             0      16     0  this   Lcom/bes/webgate/common/clock/RelativeTimeManager;
    Code:
      stack=3, locals=1, args_size=1
         0: aload_0
         1: invokespecial #1                  // Method java/lang/Object."<init>":()V
         4: aload_0
         5: new           #2                  // class java/util/concurrent/ConcurrentHashMap
         8: dup
         9: invokespecial #3                  // Method java/util/concurrent/ConcurrentHashMap."<init>":()V
        12: putfield      #4                  // Field cache:Ljava/util/concurrent/ConcurrentHashMap;
        15: return
      LineNumberTable:
        line 22: 0
        line 20: 4
        line 24: 15
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
               0      16     0  this   Lcom/bes/webgate/common/clock/RelativeTimeManager;

  public void add(java.lang.String, long);
    flags: ACC_PUBLIC
    LineNumberTable:
      line 27: 0
      line 28: 4
      line 29: 15
      line 31: 21
    LocalVariableTable:
      Start  Length  Slot  Name   Signature
            15       6     4     t   Lcom/bes/webgate/common/clock/RelativeTime;
             0      22     0  this   Lcom/bes/webgate/common/clock/RelativeTimeManager;
             0      22     1 machineId   Ljava/lang/String;
             0      22     2 machineTime   J
    Code:
      stack=5, locals=5, args_size=3
         0: aload_1
         1: ifnull        21
         4: new           #5                  // class com/bes/webgate/common/clock/RelativeTime
         7: dup
         8: aload_1
         9: lload_2
        10: invokespecial #6                  // Method com/bes/webgate/common/clock/RelativeTime."<init>":(Ljava/lang/String;J)V
        13: astore        4
        15: aload_0
        16: aload         4
        18: invokevirtual #7                  // Method add:(Lcom/bes/webgate/common/clock/RelativeTime;)V
        21: return
      LineNumberTable:
        line 27: 0
        line 28: 4
        line 29: 15
        line 31: 21
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
              15       6     4     t   Lcom/bes/webgate/common/clock/RelativeTime;
               0      22     0  this   Lcom/bes/webgate/common/clock/RelativeTimeManager;
               0      22     1 machineId   Ljava/lang/String;
               0      22     2 machineTime   J
      StackMapTable: number_of_entries = 1
           frame_type = 21 /* same */

  public void add(com.bes.webgate.common.clock.RelativeTime);
    flags: ACC_PUBLIC
    LineNumberTable:
      line 34: 0
      line 35: 4
      line 37: 17
    LocalVariableTable:
      Start  Length  Slot  Name   Signature
             0      18     0  this   Lcom/bes/webgate/common/clock/RelativeTimeManager;
             0      18     1  time   Lcom/bes/webgate/common/clock/RelativeTime;
    Code:
      stack=3, locals=2, args_size=2
         0: aload_1
         1: ifnull        17
         4: aload_0
         5: getfield      #4                  // Field cache:Ljava/util/concurrent/ConcurrentHashMap;
         8: aload_1
         9: invokevirtual #8                  // Method com/bes/webgate/common/clock/RelativeTime.getMachineId:()Ljava/lang/String;
        12: aload_1
        13: invokevirtual #9                  // Method java/util/concurrent/ConcurrentHashMap.put:(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
        16: pop
        17: return
      LineNumberTable:
        line 34: 0
        line 35: 4
        line 37: 17
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
               0      18     0  this   Lcom/bes/webgate/common/clock/RelativeTimeManager;
               0      18     1  time   Lcom/bes/webgate/common/clock/RelativeTime;
      StackMapTable: number_of_entries = 1
           frame_type = 17 /* same */

  public void addIfAbsent(java.lang.String, long);
    flags: ACC_PUBLIC
    LineNumberTable:
      line 40: 0
      line 41: 10
      line 42: 21
      line 44: 27
    LocalVariableTable:
      Start  Length  Slot  Name   Signature
            21       6     4     t   Lcom/bes/webgate/common/clock/RelativeTime;
             0      28     0  this   Lcom/bes/webgate/common/clock/RelativeTimeManager;
             0      28     1 machineId   Ljava/lang/String;
             0      28     2 machineTime   J
    Code:
      stack=5, locals=5, args_size=3
         0: aload_1
         1: ifnull        27
         4: lload_2
         5: lconst_0
         6: lcmp
         7: ifle          27
        10: new           #5                  // class com/bes/webgate/common/clock/RelativeTime
        13: dup
        14: aload_1
        15: lload_2
        16: invokespecial #6                  // Method com/bes/webgate/common/clock/RelativeTime."<init>":(Ljava/lang/String;J)V
        19: astore        4
        21: aload_0
        22: aload         4
        24: invokevirtual #10                 // Method addIfAbsent:(Lcom/bes/webgate/common/clock/RelativeTime;)V
        27: return
      LineNumberTable:
        line 40: 0
        line 41: 10
        line 42: 21
        line 44: 27
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
              21       6     4     t   Lcom/bes/webgate/common/clock/RelativeTime;
               0      28     0  this   Lcom/bes/webgate/common/clock/RelativeTimeManager;
               0      28     1 machineId   Ljava/lang/String;
               0      28     2 machineTime   J
      StackMapTable: number_of_entries = 1
           frame_type = 27 /* same */

  public void addIfAbsent(com.bes.webgate.common.clock.RelativeTime);
    flags: ACC_PUBLIC
    LineNumberTable:
      line 47: 0
      line 48: 13
    LocalVariableTable:
      Start  Length  Slot  Name   Signature
             0      14     0  this   Lcom/bes/webgate/common/clock/RelativeTimeManager;
             0      14     1  time   Lcom/bes/webgate/common/clock/RelativeTime;
    Code:
      stack=3, locals=2, args_size=2
         0: aload_0
         1: getfield      #4                  // Field cache:Ljava/util/concurrent/ConcurrentHashMap;
         4: aload_1
         5: invokevirtual #8                  // Method com/bes/webgate/common/clock/RelativeTime.getMachineId:()Ljava/lang/String;
         8: aload_1
         9: invokevirtual #11                 // Method java/util/concurrent/ConcurrentHashMap.putIfAbsent:(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
        12: pop
        13: return
      LineNumberTable:
        line 47: 0
        line 48: 13
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
               0      14     0  this   Lcom/bes/webgate/common/clock/RelativeTimeManager;
               0      14     1  time   Lcom/bes/webgate/common/clock/RelativeTime;

  public void remove(java.lang.String);
    flags: ACC_PUBLIC
    LineNumberTable:
      line 51: 0
      line 52: 4
      line 54: 13
    LocalVariableTable:
      Start  Length  Slot  Name   Signature
             0      14     0  this   Lcom/bes/webgate/common/clock/RelativeTimeManager;
             0      14     1 machineId   Ljava/lang/String;
    Code:
      stack=2, locals=2, args_size=2
         0: aload_1
         1: ifnull        13
         4: aload_0
         5: getfield      #4                  // Field cache:Ljava/util/concurrent/ConcurrentHashMap;
         8: aload_1
         9: invokevirtual #12                 // Method java/util/concurrent/ConcurrentHashMap.remove:(Ljava/lang/Object;)Ljava/lang/Object;
        12: pop
        13: return
      LineNumberTable:
        line 51: 0
        line 52: 4
        line 54: 13
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
               0      14     0  this   Lcom/bes/webgate/common/clock/RelativeTimeManager;
               0      14     1 machineId   Ljava/lang/String;
      StackMapTable: number_of_entries = 1
           frame_type = 13 /* same */

  public boolean hasMachine(java.lang.String);
    flags: ACC_PUBLIC
    LineNumberTable:
      line 57: 0
      line 58: 4
      line 60: 6
    LocalVariableTable:
      Start  Length  Slot  Name   Signature
             0      23     0  this   Lcom/bes/webgate/common/clock/RelativeTimeManager;
             0      23     1 machineId   Ljava/lang/String;
    Code:
      stack=2, locals=2, args_size=2
         0: aload_1
         1: ifnonnull     6
         4: iconst_0
         5: ireturn
         6: aload_0
         7: getfield      #4                  // Field cache:Ljava/util/concurrent/ConcurrentHashMap;
        10: aload_1
        11: invokevirtual #13                 // Method java/util/concurrent/ConcurrentHashMap.get:(Ljava/lang/Object;)Ljava/lang/Object;
        14: ifnull        21
        17: iconst_1
        18: goto          22
        21: iconst_0
        22: ireturn
      LineNumberTable:
        line 57: 0
        line 58: 4
        line 60: 6
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
               0      23     0  this   Lcom/bes/webgate/common/clock/RelativeTimeManager;
               0      23     1 machineId   Ljava/lang/String;
      StackMapTable: number_of_entries = 3
           frame_type = 6 /* same */
           frame_type = 14 /* same */
           frame_type = 64 /* same_locals_1_stack_item */
          stack = [ int ]

  public long getDeltaTime(java.lang.String);
    flags: ACC_PUBLIC
    LineNumberTable:
      line 64: 0
    LocalVariableTable:
      Start  Length  Slot  Name   Signature
             0      15     0  this   Lcom/bes/webgate/common/clock/RelativeTimeManager;
             0      15     1 machineId   Ljava/lang/String;
    Code:
      stack=2, locals=2, args_size=2
         0: aload_0
         1: getfield      #4                  // Field cache:Ljava/util/concurrent/ConcurrentHashMap;
         4: aload_1
         5: invokevirtual #13                 // Method java/util/concurrent/ConcurrentHashMap.get:(Ljava/lang/Object;)Ljava/lang/Object;
         8: checkcast     #5                  // class com/bes/webgate/common/clock/RelativeTime
        11: invokevirtual #14                 // Method com/bes/webgate/common/clock/RelativeTime.getDelta:()J
        14: lreturn
      LineNumberTable:
        line 64: 0
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
               0      15     0  this   Lcom/bes/webgate/common/clock/RelativeTimeManager;
               0      15     1 machineId   Ljava/lang/String;

  public long getMachineCurrentTime(java.lang.String);
    flags: ACC_PUBLIC
    LineNumberTable:
      line 68: 0
    LocalVariableTable:
      Start  Length  Slot  Name   Signature
             0       9     0  this   Lcom/bes/webgate/common/clock/RelativeTimeManager;
             0       9     1 machineId   Ljava/lang/String;
    Code:
      stack=4, locals=2, args_size=2
         0: aload_0
         1: aload_1
         2: invokestatic  #15                 // Method java/lang/System.currentTimeMillis:()J
         5: invokevirtual #16                 // Method getMachineRelativeTime:(Ljava/lang/String;J)J
         8: lreturn
      LineNumberTable:
        line 68: 0
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
               0       9     0  this   Lcom/bes/webgate/common/clock/RelativeTimeManager;
               0       9     1 machineId   Ljava/lang/String;

  public long getMachineRelativeTime(java.lang.String, long);
    flags: ACC_PUBLIC
    LineNumberTable:
      line 72: 0
      line 73: 8
      line 74: 15
      line 76: 20
    LocalVariableTable:
      Start  Length  Slot  Name   Signature
            15       5     4 delta   J
             0      22     0  this   Lcom/bes/webgate/common/clock/RelativeTimeManager;
             0      22     1 machineId   Ljava/lang/String;
             0      22     2  time   J
    Code:
      stack=4, locals=6, args_size=3
         0: aload_0
         1: aload_1
         2: invokevirtual #17                 // Method hasMachine:(Ljava/lang/String;)Z
         5: ifeq          20
         8: aload_0
         9: aload_1
        10: invokevirtual #18                 // Method getDeltaTime:(Ljava/lang/String;)J
        13: lstore        4
        15: lload_2
        16: lload         4
        18: lsub
        19: lreturn
        20: lload_2
        21: lreturn
      LineNumberTable:
        line 72: 0
        line 73: 8
        line 74: 15
        line 76: 20
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
              15       5     4 delta   J
               0      22     0  this   Lcom/bes/webgate/common/clock/RelativeTimeManager;
               0      22     1 machineId   Ljava/lang/String;
               0      22     2  time   J
      StackMapTable: number_of_entries = 1
           frame_type = 20 /* same */

}

2、Class 文件说明

2.1 Class 文件结构

从上面的class文件中,我们就可以看出个大概结构:

从这两个文件的结构中,我们可以轻松的看出一个class文件的结构:

需要注意的是,class文件中,是不会保留代码注释的。如果以非debug模式编译的话,连行号都不会有的。开发过程中的class,都是有行号的,不然都没办法调试了。

2.2 jvm type 、method signature

从上面demo的常量池(Constant pool),可以看到包含了一个类的类型,方法描述,字段描述等。

同时也可以看出类名,方法名,字段名就是和源码一样的,但是字段的类型,方法的类型,和真是的java类型还是有区别的。例如machineId的java类型java.lang.String,而class文件表示的则是 Ljava/lang/String; long表示为J

看来JVM中是有一套自己的表示方式的:

jvm type signature:

于此同时,我编写了一个java类向jvm type signature转换的工具:

Jvm中也有自己的一套method signature:

(paramTypeSignatures)returnTypeSignature

例如:

有了上面的类型签名的转换工具,想必实现方法前面的转换也就不成问题的了。

2.3 泛型表示

Java类型,方法在jvm都有一套自己的表示方式,Java5中引入的泛型,也自然有一套表示方式的,感兴趣的话,可以自己了解一下。

下面是一些简单的例子:

3、方法说明

了解了class文件结构,类型,方法的表示后,下面就进入重头戏了——查看方法。

3.1 方法结构

从上面的字节码,也能看出一个方法会有一堆的指令组成。每一个方法,大概有这些描述区域:

1) modifier(flags:)

2) LineNumberTable (debug模式编译的class文件才会有,反编译工具反编译处理的代码行号之所以对应,你之所以可以调试代码,就是依赖于此)

3) LocalVariableTable (局部变量表,包含三部分内容: this, 方法的所有参数,方法体中声明的所有局部变量)

4) Code (指令序列,运行是就是按照该序列执行的)

5)StackMapTable(stack map frames table,用于jvm在加载类时,verify阶段对code中指令序列里,在所有的跳转指令处,进行execute method stack frame状态校验。目前可能对这句话不理解,不要急,看了后面的内容,就理解了)

3.1.1 Thread Stack Model

如果你稍有Java开发经验,应该都会调试过代码,或者用jstack打过运行时调用栈,或者是看过exception stack。也就是,在运行时采用stack结构各个方法的调串成一条调用链的。在jvm内部,将运行时stack中的每一个元素(方法调用)看作是一个execute frame。

每一个execute frame由两部分组成:一个local variables table,一个operand stack。

Local variables table用于放局部变量,this等。

Operand stack 是执行指令时涉及的操作数存放的地方。

3.1.2 指令

Java运行时的最小单位就是指令的执行。一条完整的指令包括两部分,一个是操作码(opcode),一个是操作数(operand)。

例如:IADD a,b ,这条指令是执行a + b, IADD是 opcode, a,b 是operand。

也就是说operand可以理解为opcode的参数。

指令执行时,通常是对三个地方的数据 进行操作1)local variables table, 2) operand stack, 3) constant pool 。

Jvm 提供了很多指令,这些指令大概可以分为两类:

1) 从local variables table 或者 constants pool 将值load到 operand stack,或者反过来将 operand stack 中的值 store 给local variables table。

2) 基于stack 进行操作,例如 IADD, 就从 stack 顶取2个值进行 加法运算后,将结果push到stack。

到此,相信可以大概猜测出运行过程 :执行一个方法时:

1) 构建 execute frame (初始化 local variables table, operand stack)

2) 将execute frame 放到 thread stack。

在构建local variables table时,第一个(也就是index 为0的)是this, 后面紧接的是方法的参数列表。

在执行方法内的指令序列时,遇见 load类指令时,就load数据到operand stack,遇见运算类指令时,就从 operand stack 中取值运行,遇见 store类指令时,就从stack顶取值放到local variables table中。

3.1.3 Stack Map Frames

从Java 6起,引入了使用stack map frames进行字节码校验机制。那么stack map frames到底是怎样一回事呢?

假设你的类,被人篡改了,加入了一些不可描述的指令。通过jvm 的stack map frames检验,是可以帮你查出来问题的。

上面已经说明了operand stack,也了解了指令执行过程,可以说大多数指令,都是要与operand stack打交道的。这个检验就是基于operand stack在执行指令前后的状态来的。

例如:

上面 就是一个stack map。也就是说记录了指令执行前后,operand stack 与 指令的映射关系的表,就是 stack map frames。

一个方法可以很简单,也可以很复杂。对于一个复杂的方法,指令会非常多,那么它的stack map frames 会非常长。如果类加载过程中,要校验这么长的stack map,那性能可想而知。

所以JVM设计者呢,采取了一个折中的方案。只在stack map frames 里只保留跳转指令的状态。至于跳转指令,例如:if,else,try,catch等。

4、字节码工具库

目前常用的字节码操作的工具有:javaassist,asm,bcel

基于asm的库有bytebuddy,cglib

5、指令集

在上面说了,指令主要针对local variables table, operand stack, constants进行操作。如果详细对指令进行归类的话,大概可以归类如下:

1)   Local variables

2)    stack

3)    Constants

4)    Arithmetic and logic

5)    Object,field,method

6)    Array

7)    Jump

8)    Return

原文地址:https://www.cnblogs.com/f1194361820/p/8524666.html

时间: 2024-11-01 11:43:26

JVM 指令的相关文章

[转]JVM指令详解(上)

作者:禅楼望月(http://www.cnblogs.com/yaoyinglong) 本文主要记录一些JVM指令,便于记忆与查阅. 一.未归类系列A 此系列暂未归类. 指令码    助记符                            说明 0x00         nop                                什么都不做 0x01        aconst_null                   将null推送至栈顶 二.const系列 该系列命令主要

JVM指令助记符

以下只是JVM指令助记符,关于JVM指令的详细内容请阅读<JVM指令详解> 变量到操作数栈:iload,iload_,lload,lload_,fload,fload_,dload,dload_,aload,aload_ 操作数栈到变量:istore,istore_,lstore,lstore_,fstore,fstore_,dstore,dstore_,astore,astore_ 常数到操作数栈:bipush,sipush,ldc,ldc_w,ldc2_w,aconst_null,icon

Java并发编程(五)JVM指令重排

引言:在Java中看似顺序的代码在JVM中,可能会出现编译器或者CPU对这些操作指令进行了重新排序:在特定情况下,指令重排将会给我们的程序带来不确定的结果..... 如下代码可能的结果有哪些? public class PossibleReordering { static int x = 0, y = 0; static int a = 0, b = 0; public static void main(String[] args) throws InterruptedException {

jvm指令

栈和局部变量操作 将常量压入栈的指令 aconst_null 将null对象引用压入栈 iconst_m1 将int类型常量-1压入栈 iconst_0 iconst_1 将int类型常量1压入栈 iconst_2 将int类型常量2压入栈 iconst_3 将int类型常量3压入栈 iconst_4 将int类型常量4压入栈 iconst_5 将int类型常量5压入栈 lconst_0 将long类型常量0压入栈 lconst_1 将long类型常量1压入栈 fconst_0 将float类型

Javap与JVM指令

一.javap命令简述 javap是jdk自带的反解析工具.它的作用就是根据class字节码文件,反解析出当前类对应的code区(汇编指令).本地变量表.异常表和代码行偏移量映射表.常量池等等信息.当然这些信息中,有些信息(如本地变量表.指令和代码行偏移量映射表.常量池中方法的参数名称等等)需要在使用javac编译成class文件时,指定参数才能输出,比如,你直接javac xx.java,就不会在生成对应的局部变量表等信息,如果你使用javac -g xx.java就可以生成所有相关信息了.如

jvm 指令重排

引言:在Java中看似顺序的代码在JVM中,可能会出现编译器或者CPU对这些操作指令进行了重新排序:在特定情况下,指令重排将会给我们的程序带来不确定的结果..... 1.  什么是指令重排? 在计算机执行指令的顺序在经过程序编译器编译之后形成的指令序列,一般而言,这个指令序列是会输出确定的结果:以确保每一次的执行都有确定的结果.但是,一般情况下,CPU和编译器为了提升程序执行的效率,会按照一定的规则允许进行指令优化,在某些情况下,这种优化会带来一些执行的逻辑问题,主要的原因是代码逻辑之间是存在一

JVM 指令集合

1 指令码 助记符 说明 2 0x00 nop 什么都不做 3 0x01 aconst_null 将null推送至栈顶 4 0x02 iconst_m1 将int型-1推送至栈顶 5 0x03 iconst_0 将int型0推送至栈顶 6 0x04 iconst_1 将int型1推送至栈顶 7 0x05 iconst_2 将int型2推送至栈顶 8 0x06 iconst_3 将int型3推送至栈顶 9 0x07 iconst_4 将int型4推送至栈顶 10 0x08 iconst_5 将in

JVM指令重排

指令重排的基本原则: a.程序顺序原则:一个线程内保证语义的串行性 b.volatile规则:volatile变量的写,先发生于读 c.锁规则:解锁(unlock)必然发生在随后的加锁(lock)前 d.传递性:A先于B,B先于C 那么A必然先于C e.线程的start方法先于它的每一个动作 f.线程的所有操作先于线程的终结(Thread.join()) g.线程的中断(interrupt())先于被中断线程的代码 h.对象的构造函数执行结束先于finalize()方法 写后读 a = 1;b

JVM指令详解(上)

一.未归类系列A 此系列暂未归类. 指令码    助记符                            说明 0x00         nop                                什么都不做 0x01        aconst_null                   将null推送至栈顶 二.const系列 该系列命令主要负责把简单的数值类型送到栈顶.该系列命令不带参数.注意只把简单的数值类型送到栈顶时,才使用如下的命令. 比如对应int型才该方式只能把