Falscher Bytecode bei Konstruktoraufruf mit Subtyp #329

Open
opened 2024-05-02 21:48:39 +00:00 by i21023 · 1 comment
Collaborator

Wenn man den eigenen Konstruktor mit this(...) aufruft und ein Subtyp des erwarteten Parameters als Parameter angibt, stimmt er Bytecode nicht. Allerdings stimmt der Bytecode für einen super()- oder einen normalen Methodenaufruf.

Beispiel

import java.lang.Number;
import java.lang.Integer;
import java.lang.Boolean;

class Foo{
    Number x;
    public Foo(a){
        x = a;
    }
    public Foo(){
        this(new Integer(10));
    }
}

In diesem Fall wird folgendes inferiert:

class Foo{
    Number x;
    public Foo(Number a){
        x = a;
    }
    public Foo(){
        this(new Integer(10));
    }
}

Allerdings sieht der Aufruf des überladenen Konstruktors im Standardkonstruktor im Bytecode folgendermaßen aus:

  public Foo();
    descriptor: ()V
    flags: (0x0001) ACC_PUBLIC
    Code:
      stack=4, locals=1, args_size=1
         0: aload_0
         1: new           #18                 // class java/lang/Integer
         4: dup
         5: ldc           #19                 // int 10
         7: invokestatic  #23                 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
        10: invokespecial #26                 // Method java/lang/Integer."<init>":(I)V
        13: invokestatic  #23                 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
        16: invokespecial #29                 // Method "<init>":(Ljava/lang/Integer;)V
        19: return
        20: athrow

Es wird also versucht den überladenen Konstruktor mit Integer aufzurufen, richtig wäre aber Number.

Wie gesagt ist der generierte Bytecode bei normalen Methodenaufrufen und super aufrufen korrekt, i.e.

import java.lang.Number;
import java.lang.Integer;
import java.lang.Boolean;

class Foo{
    Number x;
    public goo(a){
        x = a;
    }
    public goo(){
        goo(new Integer(10));
    }
}
  public void goo();
    descriptor: ()V
    flags: (0x0001) ACC_PUBLIC
    Code:
      stack=4, locals=1, args_size=1
         0: aload_0
         1: new           #19                 // class java/lang/Integer
         4: dup
         5: ldc           #20                 // int 10
         7: invokestatic  #24                 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
        10: invokespecial #27                 // Method java/lang/Integer."<init>":(I)V
        13: invokestatic  #24                 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
        16: invokevirtual #29                 // Method goo:(Ljava/lang/Number;)V
        19: return
        20: athrow
Wenn man den eigenen Konstruktor mit this(...) aufruft und ein Subtyp des erwarteten Parameters als Parameter angibt, stimmt er Bytecode nicht. Allerdings stimmt der Bytecode für einen super()- oder einen normalen Methodenaufruf. ### Beispiel ```java import java.lang.Number; import java.lang.Integer; import java.lang.Boolean; class Foo{ Number x; public Foo(a){ x = a; } public Foo(){ this(new Integer(10)); } } ``` In diesem Fall wird folgendes inferiert: ```java class Foo{ Number x; public Foo(Number a){ x = a; } public Foo(){ this(new Integer(10)); } } ``` Allerdings sieht der Aufruf des überladenen Konstruktors im Standardkonstruktor im Bytecode folgendermaßen aus: ``` public Foo(); descriptor: ()V flags: (0x0001) ACC_PUBLIC Code: stack=4, locals=1, args_size=1 0: aload_0 1: new #18 // class java/lang/Integer 4: dup 5: ldc #19 // int 10 7: invokestatic #23 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer; 10: invokespecial #26 // Method java/lang/Integer."<init>":(I)V 13: invokestatic #23 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer; 16: invokespecial #29 // Method "<init>":(Ljava/lang/Integer;)V 19: return 20: athrow ``` Es wird also versucht den überladenen Konstruktor mit Integer aufzurufen, richtig wäre aber Number. Wie gesagt ist der generierte Bytecode bei normalen Methodenaufrufen und super aufrufen korrekt, i.e. ```java import java.lang.Number; import java.lang.Integer; import java.lang.Boolean; class Foo{ Number x; public goo(a){ x = a; } public goo(){ goo(new Integer(10)); } } ``` ``` public void goo(); descriptor: ()V flags: (0x0001) ACC_PUBLIC Code: stack=4, locals=1, args_size=1 0: aload_0 1: new #19 // class java/lang/Integer 4: dup 5: ldc #20 // int 10 7: invokestatic #24 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer; 10: invokespecial #27 // Method java/lang/Integer."<init>":(I)V 13: invokestatic #24 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer; 16: invokevirtual #29 // Method goo:(Ljava/lang/Number;)V 19: return 20: athrow ```
Owner

Die Signatur ist immernoch falsch, selbes Problem wie #332

Die Signatur ist immernoch falsch, selbes Problem wie #332
Sign in to join this conversation.
No Milestone
No project
No Assignees
2 Participants
Notifications
Due Date
The due date is invalid or out of range. Please use the format 'yyyy-mm-dd'.

No due date set.

Dependencies

No dependencies set.

Reference: JavaTX/JavaCompilerCore#329
No description provided.