Objektreferenz wird bei Lambda Funktionen fälschlicherweise auf den Stack gelegt #297

Open
opened 2024-03-17 21:13:29 +00:00 by i21023 · 2 comments
Collaborator

Das Problem scheint ein ähnliches wir bei #296 zu sein, auch wenn es hier im Zusammenhang von Lambda Fuktionen auftritt.

Beispiel Code

import java.lang.Integer;

public class Foo{
    public static operation(func, a, b){
        return func.apply(a, b);
    }

    public exec(){
        return Foo.operation((x,y) -> x+y, 10, 10);
    }
}

Datei Foo.jav

public java.lang.Object exec();
    descriptor: ()Ljava/lang/Object;
    flags: (0x0001) ACC_PUBLIC
    Code:
      stack=3, locals=1, args_size=1
         0: aload_0
         1: invokedynamic #46,  0             // InvokeDynamic #0:apply:(LFoo;)LFun2$$Ljava$lang$Integer$_$Ljava$lang$Integer$_$Ljava$lang$Object$_$;
         6: ldc           #47                 // int 10
         8: invokestatic  #21                 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
        11: ldc           #47                 // int 10
        13: invokestatic  #21                 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
        16: invokestatic  #49                 // Method operation:(LFun2$$Ljava$lang$Integer$_$Ljava$lang$Integer$_$Ljava$lang$Object$_$;Ljava/lang/Integer;Ljava/lang/Integer;)Ljava/lang/Object;
        19: areturn
    Signature: #29                          // ()Ljava/lang/Object;
      JavaTXSignature: length = 0x2 (unknown attribute)
       00 38

Bytecode der Methode exec()

Wie bei #296 scheint auch hier fälschlicherweise die Referenz auf das aktuelle Objekt auf den Stack geladen (hier ist die Methode zwar nicht static, aber mMn besteht trotzdem kein Grund die Referenz auf den Stack zu laden).
Wenn man statt return Foo.operation((x,y) -> x+y, 10, 10);, return operation((x,y) -> x+y, 10, 10); schreibt, wird aload_0 am Anfang der Methode sogar 2x aufgerufen. Ich denke das ist das Problem aus #296, dennoch scheint es hier noch im Zusammenhang mit Lambda Funktionen ein Ähnliches Problem zu ergeben.
Auch hier kommt es beim ausführen mittels einer mit javac kompilierten Klasse mit Main Methode zu einem Fehler zur Laufzeit.

$ java Main

Exception in thread "main" java.lang.VerifyError: Bad type on operand stack
Exception Details:
  Location:
    Foo.lambda$0(Ljava/lang/Integer;Ljava/lang/Integer;)Ljava/lang/Object; @9: areturn
  Reason:
    Type integer (current frame, stack[0]) is not assignable to reference type
  Current Frame:
    bci: @9
    flags: { }
    locals: { 'Foo', 'java/lang/Integer', 'java/lang/Integer' }
    stack: { integer }
  Bytecode:
    0000000: 2bb6 0011 2cb6 0011 60b0               

        at Main.main(Main.java:3)
Das Problem scheint ein ähnliches wir bei #296 zu sein, auch wenn es hier im Zusammenhang von Lambda Fuktionen auftritt. **Beispiel Code** ```java import java.lang.Integer; public class Foo{ public static operation(func, a, b){ return func.apply(a, b); } public exec(){ return Foo.operation((x,y) -> x+y, 10, 10); } } ``` *Datei Foo.jav* ``` public java.lang.Object exec(); descriptor: ()Ljava/lang/Object; flags: (0x0001) ACC_PUBLIC Code: stack=3, locals=1, args_size=1 0: aload_0 1: invokedynamic #46, 0 // InvokeDynamic #0:apply:(LFoo;)LFun2$$Ljava$lang$Integer$_$Ljava$lang$Integer$_$Ljava$lang$Object$_$; 6: ldc #47 // int 10 8: invokestatic #21 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer; 11: ldc #47 // int 10 13: invokestatic #21 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer; 16: invokestatic #49 // Method operation:(LFun2$$Ljava$lang$Integer$_$Ljava$lang$Integer$_$Ljava$lang$Object$_$;Ljava/lang/Integer;Ljava/lang/Integer;)Ljava/lang/Object; 19: areturn Signature: #29 // ()Ljava/lang/Object; JavaTXSignature: length = 0x2 (unknown attribute) 00 38 ``` *Bytecode der Methode `exec()`* Wie bei #296 scheint auch hier fälschlicherweise die Referenz auf das aktuelle Objekt auf den Stack geladen (hier ist die Methode zwar nicht static, aber mMn besteht trotzdem kein Grund die Referenz auf den Stack zu laden). Wenn man statt `return Foo.operation((x,y) -> x+y, 10, 10);`, `return operation((x,y) -> x+y, 10, 10);` schreibt, wird aload_0 am Anfang der Methode sogar 2x aufgerufen. Ich denke das ist das Problem aus #296, dennoch scheint es hier noch im Zusammenhang mit Lambda Funktionen ein Ähnliches Problem zu ergeben. Auch hier kommt es beim ausführen mittels einer mit javac kompilierten Klasse mit Main Methode zu einem Fehler zur Laufzeit. ``` $ java Main Exception in thread "main" java.lang.VerifyError: Bad type on operand stack Exception Details: Location: Foo.lambda$0(Ljava/lang/Integer;Ljava/lang/Integer;)Ljava/lang/Object; @9: areturn Reason: Type integer (current frame, stack[0]) is not assignable to reference type Current Frame: bci: @9 flags: { } locals: { 'Foo', 'java/lang/Integer', 'java/lang/Integer' } stack: { integer } Bytecode: 0000000: 2bb6 0011 2cb6 0011 60b0 at Main.main(Main.java:3) ```
Owner

Die Lambdafunktion selber ist auch falsch, es müsste Integer zurückgegeben werden und nicht Object.

Die Lambdafunktion selber ist auch falsch, es müsste Integer zurückgegeben werden und nicht Object.
Owner

Wenn ich hier:

constraintsSet.addUndConstraint(new Pair(returnExpr.getType(), info.getCurrentTypeScope().getReturnType(), PairOperator.SMALLERDOT, loc(returnExpr.getOffset())));

SMALLERDOT durch EQUALSDOT ersetze bekommt der Lambdaausruck den Rückgabetyp Integer.
Vielleicht muss man das machen falls es ein Lambdausdruck ist weil hier der Typ ja direkt vom Rückgabewert abhängt.

Wenn ich hier: https://gitea.hb.dhbw-stuttgart.de/JavaTX/JavaCompilerCore/src/commit/01e374eadd5cfaac5dbddc9e7ef5730ba482bb30/src/main/java/de/dhbwstuttgart/typeinference/typeAlgo/TYPEStmt.java#L482 `SMALLERDOT` durch `EQUALSDOT` ersetze bekommt der Lambdaausruck den Rückgabetyp Integer. Vielleicht muss man das machen falls es ein Lambdausdruck ist weil hier der Typ ja direkt vom Rückgabewert abhängt.
dholle added the
Codegen
confirmed
in progress
labels 2024-03-18 12:56:09 +00:00
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#297
No description provided.