在字节码中确定哪里是super()方法调用,所有构造函数必须在JVM上执行 [英] Determining in the bytecode where is the super() method call all constructors must do on the JVM

查看:139
本文介绍了在字节码中确定哪里是super()方法调用,所有构造函数必须在JVM上执行的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想知道在分析构造函数的字节码时是否有一种明显而快速的方法,以确定 super()代码的结束位置。

I was wondering if there's an obvious and quick way of when analyzing a constructor's bytecode, to determine where the super() code ends in.

更具体地说,与Java形成鲜明对比的是,构造函数中对任何 super()构造函数方法的调用是可选的(或者更确切地说) ,当不存在时 - 隐式),在字节码世界中总是需要它。

More concretely, and in sharp contrast to Java, where a call in the constructor to any super() constructor method is optional (or rather, when not present -- implicit), in the bytecode world it is always needed.

出于黑魔法的目的,我需要通过字节码分析和最简单的方法知道, INVOKESPECIAL 调用对应于Java世界的 super()调用。

For black magic purposes I'm in need of knowing just by bytecode analysis and by the simplest method available, what's the INVOKESPECIAL call that corresponds to the Java world's super() call.

我会留下你的一个简单的例子:

I'll leave you here with a hard example:

public static class A {
    public A(Object o, Object b) {
    }
}

public static class B extends A {
    public B() {
        //the below super is in bold just to signal that's the one
        //I'm looking for
        SUPER(new A(new Object(), new Integer(2)), new Integer(1));
        System.out.println(new A(new Object(), new Integer(2)));
    }
}

带有相应的字节码:

with the corresponding bytecode:

推荐答案

实际上,字节码构造函数的规则比Java的规则要宽松得多。

Actually, the rules for bytecode constructors are much more lax than Java's rules.

唯一的规则是必须在任何正常返回的路径上调用一个构造函数如果构造函数调用抛出异常,那么你也必须抛出异常。

The only rule is that exactly one constructor must be called on any path that returns normally and if a constructor call throws an exception, then you must throw an exception too.

除此之外,这意味着构造函数可能包含对其他构造函数的多次调用或者没有

Among other things, this means that a constructor may contain multiple calls to other constructors or none at all.

无论如何,确定给定调用特殊调用是否正在初始化当前对象的唯一保证方法是进行数据流分析,因为可以初始化同一类的其他对象,这会混淆一个天真的探测器。

Anyway, the only guaranteed way to determine whether a given invokespecial call is initializing the current object is to do a dataflow analysis, since it's possible to initialize other objects of the same class, which would confuse a naive detector.

编辑:这是一个完全有效的类(使用Krakatau汇编语法)的示例,显示了您可能遇到的一些问题。除此之外,它还调用了同一个类中的其他构造函数,构造函数的递归调用,以及在构造函数中构造同一个类的其他对象。

Here is an example of a perfectly valid class (using the Krakatau assembler syntax), showing some of the issues you could run into. Among other things, it has calls to other constructors in the same class, recursive invocation of constructors, and constructing other objects of the same class inside the constructor.

.class public ctors
.super java/lang/Object

; A normal constructor
.method public <init> : ()V
    .limit locals 1
    .limit stack 1

    aload_0
    invokespecial java/lang/Object <init> ()V
    return
.end method

; A weird constructor
.method public <init> : (I)V
    .limit locals 2
    .limit stack 5

    iload_1
    ifne LREST
        aload_0
        invokespecial ctors <init> ()V
        return

LREST:
    aload_0
    new ctors
    iinc 1 -1
    iload_1
LFAKE_START:
    invokespecial ctors <init> (I)V
LFAKE_END:
    iconst_0
    invokespecial ctors <init> (I)V
    return

.catch [0] from LFAKE_START to LFAKE_END using LCATCH
LCATCH:
    aload_0
    invokespecial java/lang/Object <init> ()V
    return
.end method

.method public static main : ([Ljava/lang/String;)V
    .limit locals 1
    .limit stack 2

    new ctors
    iconst_5
    invokespecial ctors <init> (I)V
    return
.end method

这篇关于在字节码中确定哪里是super()方法调用,所有构造函数必须在JVM上执行的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆