Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update the KotlinUnsafeCastOperatorFilter for Kotlin 1.6.0 #6

Closed
wants to merge 2 commits into from

Conversation

poseidon-mysugr
Copy link
Collaborator

@poseidon-mysugr poseidon-mysugr commented Nov 18, 2021

The Kotlin 1.6.0 compiler changed how "unsafe casts" are compiled. Consider the following Kotlin class:

class Cast {
    fun cast(any: Any?): String {
        return any as String
    }
}

The Kotlin 1.5.32 compiler compiles the cast function to

  public final java.lang.String cast(java.lang.Object);
    descriptor: (Ljava/lang/Object;)Ljava/lang/String;
    flags: (0x0011) ACC_PUBLIC, ACC_FINAL
    Code:
      stack=3, locals=2, args_size=2
         0: aload_1
         1: ifnonnull     14
         4: new           #16                 // class java/lang/NullPointerException
         7: dup
         8: ldc           #18                 // String null cannot be cast to non-null type kotlin.String
        10: invokespecial #21                 // Method java/lang/NullPointerException."<init>":(Ljava/lang/String;)V
        13: athrow
        14: aload_1
        15: checkcast     #23                 // class java/lang/String
        18: areturn
      StackMapTable: number_of_entries = 1
        frame_type = 14 /* same */
      LineNumberTable:
        line 5: 0
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0      19     0  this   Lcom/mysugr/Cast;
            0      19     1   any   Ljava/lang/Object;
    RuntimeInvisibleAnnotations:
      0: #13()
        org.jetbrains.annotations.NotNull
    RuntimeInvisibleParameterAnnotations:
      parameter 0:
        0: #14()
          org.jetbrains.annotations.Nullable

while the Kotlin 1.6.0 compiler produces:

  public final java.lang.String cast(java.lang.Object);
    descriptor: (Ljava/lang/Object;)Ljava/lang/String;
    flags: (0x0011) ACC_PUBLIC, ACC_FINAL
    Code:
      stack=3, locals=2, args_size=2
         0: aload_1
         1: dup
         2: ifnonnull     16
         5: pop
         6: new           #16                 // class java/lang/NullPointerException
         9: dup
        10: ldc           #18                 // String null cannot be cast to non-null type kotlin.String
        12: invokespecial #21                 // Method java/lang/NullPointerException."<init>":(Ljava/lang/String;)V
        15: athrow
        16: checkcast     #23                 // class java/lang/String
        19: areturn
      StackMapTable: number_of_entries = 1
        frame_type = 80 /* same_locals_1_stack_item */
          stack = [ class java/lang/Object ]
      LineNumberTable:
        line 5: 0
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0      20     0  this   Lcom/mysugr/Cast;
            0      20     1   any   Ljava/lang/Object;
    RuntimeInvisibleAnnotations:
      0: #13()
        org.jetbrains.annotations.NotNull
    RuntimeInvisibleParameterAnnotations:
      parameter 0:
        0: #14()
          org.jetbrains.annotations.Nullable

The 1.6.0 compiler duplicates the variable that's being casted before checking whether it's null, and pops the extra copy from the stack in case it is null; previous compilers instead loaded the variable a second time if it wasn't null.

This change makes the KotlinUnsafeCastOperatorFilter not detect the unsafe cast anymore because of the extra POP instruction; allowing this instruction to be there but not requiring it makes the filter compatible with both variants.

@poseidon-mysugr
Copy link
Collaborator Author

was already merged upstream, should be released in 0.8.8

@poseidon-mysugr
Copy link
Collaborator Author

@ChristopherKoellner after updating from 0.8.8, this PR is obsolete, I'm closing it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
2 participants