8

super()コンストラクターのバイトコードを分析して、コードがどこで終わるかを判断するための明白で迅速な方法があるかどうか疑問に思いました。

より具体的には、コンストラクターメソッドへのコンストラクターの呼び出しがオプションである(または、存在しない場合は暗黙的に)Javaとは対照的にsuper()、バイトコードの世界では常に必要です。

黒魔術の目的のために、私はバイトコード分析と利用可能な最も単純な方法によってINVOKESPECIAL、Javaの世界のsuper()呼び出しに対応する呼び出しが何であるかを知る必要があります。

難しい例をここに残しておきます。

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)));
    }
}

対応するバイトコードで: ここに画像の説明を入力してください

4

4 に答える 4

4

実際、バイトコード コンストラクターの規則は、Java の規則よりもはるかに緩いものです。

唯一のルールは、正常に戻るすべてのパスでコンストラクターを 1 つだけ呼び出す必要があり、コンストラクター呼び出しで例外がスローされた場合は、例外もスローする必要があるということです。

とりわけ、これは、コンストラクターが他のコンストラクターへの複数の呼び出しを含むか、まったく含まない可能性があることを意味します。

とにかく、特定のinvokespecial呼び出しが現在のオブジェクトを初期化しているかどうかを判断する唯一の保証された方法は、データフロー分析を行うことです。これは、単純な検出器を混乱させる同じクラスの他のオブジェクトを初期化する可能性があるためです。

編集: これは、(Krakatau アセンブラー構文を使用した) 完全に有効なクラスの例であり、遭遇する可能性のある問題のいくつかを示しています。とりわけ、同じクラス内の他のコンストラクターへの呼び出し、コンストラクターの再帰呼び出し、およびコンストラクター内の同じクラスの他のオブジェクトの構築があります。

.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
于 2013-01-31T19:02:41.643 に答える
2

簡単な解決策は、new Aオブジェクトの数と、スーパー コンストラクターを呼び出した数A.<init> より多い場合initの数を数えることです。andが呼び出された場合に備えnewて、同じチェックを行う必要があります。new BB.<init>this(...)

于 2013-01-31T19:22:59.893 に答える
1

thisオペランドスタックが最初の引数として使用される参照を含む呼び出しオペコードを見つける必要があります。このためには、さまざまなオペコードが持つオペランド スタックへの影響について知っておく必要があります。あなたの例aload_0では、(this参照である)から始めて、その参照の上でかなりの魔法を行います(常にオペランドスタックを更新します)。しばらくすると、探している呼び出しオペコードがそこにあり、this参照 (および引数のいくつかの参照) を消費します。これがsuper呼び出しです。

于 2013-01-31T19:22:56.337 に答える
0

The answer to super() invocation is line no. 31.

I found it easy via eclipse's Class File editor. Have a look at the snap attached below.

One thing to remember here is, The prefix 'a' means that the opcode is manipulating an object reference. The prefix 'i' means the opcode is manipulating an integer.

So, the line by line explanation is as follows,

12  new java.lang.Integer //Create a new java.lang.Integer 
15  dup //Make a extra reference to the same Integer
16  iconst_2 // this means opcode is manipulating Integer as Integer(2)
17  invokespecial java.lang.Integer(int) //Integer(2) is invoked
20  invokespecial A(java.lang.Object, java.lang.Object) //new A(new Object(), new Integer(2) is invoked
23  new java.lang.Integer //Create a new java.lang.Integer
26  dup //Make a extra reference to the same Integer
27  iconst_1 // this means opcode is manipulating Integer as Integer(1)
28  invokespecial java.lang.Integer(int) //Integer(1) is invoked
31  invokespecial A(java.lang.Object, java.lang.Object) **//super(new A(new Object(), new Integer(2)), new Integer(1)) is invoked**

I hope the later is easy to comprehend. :)

56 - this invoke is for the sysout related A(object,object) invocation.

enter image description here

于 2013-01-31T20:07:45.733 に答える