Static Funktionen lädt Objektreferenz auf Stack, wenn nicht mit <Klassenname>.<Methodenname> aufgerufen #296

Closed
opened 2024-03-17 20:47:49 +00:00 by jschmidt · 0 comments
Collaborator

Beispiel-Code

public class Test {
    static exec(){
        return foo();
    }

    static foo(){
        return 10;
    }
}

Datei Test.jav

public class Main {
    public static void main(String[] args) {
        System.out.println(Test.exec());
    }
}

Datei Main.java

Wenn Test.jav entsprechend mit javatx und Main.java mit javac kompiliert wird, schlägt die Ausführung in der JVM fehl.

$ java Main
Exception in thread "main" java.lang.VerifyError: Bad local variable type
Exception Details:
  Location:
    Test.exec()Ljava/lang/Integer; @0: aload_0
  Reason:
    Type top (current frame, locals[0]) is not assignable to reference type
  Current Frame:
    bci: @0
    flags: { }
    locals: { }
    stack: { }
  Bytecode:
    0000000: 2ab8 000e b600 14b8 0018 b0            

        at Main.main(Main.java:3)

Das Problem scheint falsch generierter Bytecode zu sein.

static java.lang.Integer exec();
   descriptor: ()Ljava/lang/Integer;
   flags: (0x0008) ACC_STATIC
   Code:
     stack=2, locals=1, args_size=0
        0: aload_0
        1: invokestatic  #14                 // Method foo:()Ljava/lang/Integer;
        4: invokevirtual #20                 // Method java/lang/Integer.intValue:()I
        7: invokestatic  #24                 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
       10: areturn
   Signature: #11                          // ()Ljava/lang/Integer;
     JavaTXSignature: length = 0x2 (unknown attribute)
      00 1F

Bytecode für Methode exec()

Die statische Methode führt aload_0 aus, sie hat aber weder Parameter, noch eine Referenz auf das aktuelle Objekt (da static).

Wenn der Quellcode der Klasse Test insofern angepasst wird, dass die statische Methode foo() explizit mit dem Klassenname aufgerufen wird, scheint das Problem (warum auch immer) nicht aufzutreten.

public class Test {
    static exec(){
        return Test.foo();
    }

    static foo(){
        return 10;
    }
}

Datei Test.jav mit explizitem Aufruf der statischen Methode foo()

static java.lang.Integer exec();
    descriptor: ()Ljava/lang/Integer;
    flags: (0x0008) ACC_STATIC
    Code:
      stack=1, locals=0, args_size=0
         0: invokestatic  #14                 // Method foo:()Ljava/lang/Integer;
         3: invokevirtual #20                 // Method java/lang/Integer.intValue:()I
         6: invokestatic  #24                 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
         9: areturn
    Signature: #11                          // ()Ljava/lang/Integer;
      JavaTXSignature: length = 0x2 (unknown attribute)
       00 1F

Bytecode für Methode exec() für neuen Quellcode

Dann lässt sich der Code auch korrekt auf der JVM ausführen.

**Beispiel-Code** ```java public class Test { static exec(){ return foo(); } static foo(){ return 10; } } ``` *Datei `Test.jav`* ```java public class Main { public static void main(String[] args) { System.out.println(Test.exec()); } } ``` *Datei `Main.java`* Wenn Test.jav entsprechend mit javatx und Main.java mit javac kompiliert wird, schlägt die Ausführung in der JVM fehl. ``` $ java Main Exception in thread "main" java.lang.VerifyError: Bad local variable type Exception Details: Location: Test.exec()Ljava/lang/Integer; @0: aload_0 Reason: Type top (current frame, locals[0]) is not assignable to reference type Current Frame: bci: @0 flags: { } locals: { } stack: { } Bytecode: 0000000: 2ab8 000e b600 14b8 0018 b0 at Main.main(Main.java:3) ``` Das Problem scheint falsch generierter Bytecode zu sein. ``` static java.lang.Integer exec(); descriptor: ()Ljava/lang/Integer; flags: (0x0008) ACC_STATIC Code: stack=2, locals=1, args_size=0 0: aload_0 1: invokestatic #14 // Method foo:()Ljava/lang/Integer; 4: invokevirtual #20 // Method java/lang/Integer.intValue:()I 7: invokestatic #24 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer; 10: areturn Signature: #11 // ()Ljava/lang/Integer; JavaTXSignature: length = 0x2 (unknown attribute) 00 1F ``` *Bytecode für Methode `exec()`* Die statische Methode führt aload_0 aus, sie hat aber weder Parameter, noch eine Referenz auf das aktuelle Objekt (da static). Wenn der Quellcode der Klasse Test insofern angepasst wird, dass die statische Methode `foo()` explizit mit dem Klassenname aufgerufen wird, scheint das Problem (warum auch immer) nicht aufzutreten. ```java public class Test { static exec(){ return Test.foo(); } static foo(){ return 10; } } ``` *Datei `Test.jav` mit explizitem Aufruf der statischen Methode `foo()`* ``` static java.lang.Integer exec(); descriptor: ()Ljava/lang/Integer; flags: (0x0008) ACC_STATIC Code: stack=1, locals=0, args_size=0 0: invokestatic #14 // Method foo:()Ljava/lang/Integer; 3: invokevirtual #20 // Method java/lang/Integer.intValue:()I 6: invokestatic #24 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer; 9: areturn Signature: #11 // ()Ljava/lang/Integer; JavaTXSignature: length = 0x2 (unknown attribute) 00 1F ``` *Bytecode für Methode `exec()` für neuen Quellcode* Dann lässt sich der Code auch korrekt auf der JVM ausführen.
dholle referenced this issue from a commit 2024-03-18 09:17:16 +00:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: JavaTX/JavaCompilerCore#296
No description provided.