I am currently suffering from a JVM crash in produ...
# compose-desktop
m
I am currently suffering from a JVM crash in production code. In general my Compose desktop app works fine until I perform a specific action. Then I get the following error:
Copy code
Inconsistent stackmap frames at branch target 1938
Exception Details:
  Location:
    net/sf/geographiclib/Geodesic.InverseInt(DDDDI)Lnet/sf/geographiclib/Geodesic$InverseData; @1938: iconst_0
  Reason:
    Type top (current frame, locals[67]) is not assignable to double (stack map, locals[67])
...
More details in the thread.
The problem only occurs when I create a release build of the app and not when I just run it in the IDE. It happens on both Mac and Windows (haven’t tested Linux). The relevant code where the crash happens is from a numerical Java library which I have converted to Kotlin but I doubt that anything is wrong with the code because it works perfectly from the IDE. It’s just pure Kotlin number-crunshing. Does anybody have an idea how I could track that down and fix it?
c
are you using proguard in the release build? how does your code for
net/sf/geographiclib/Geodesic.InverseInt(DDDDI)
look like? seems like there is a
0
(iconst_0) on top of the stack but a
double
is expected.
m
I better put that into a ZIP because it is too long to post it as text here.
c
and proguard? enabled or not?
m
Copy code
buildTypes.release {
    proguard {
        version.set("7.6.0")
        isEnabled.set(true)
        optimize.set(false)
        obfuscate.set(false)
        configurationFiles.from(project.file("compose-desktop.pro"))
    }
}
c
not sure what
optimize.set(false)
but there are options for proguard that could affect you. see https://www.guardsquare.com/manual/configuration/optimizations
code/merging
code/simplification/*
esp.
code/simplification/math
I’d try to manually disable them in your
.pro
file. also not sure if applying a configurations file will override your
optimize.set(false)
and
obfuscate.set(false)
m
As far as I understand it optimize=false means that the optimizations which you have mentioned are not attempted.
c
also not sure if applying a configurations file will override your
optimize.set(false)
and
obfuscate.set(false)
🤷
m
No, unless I explicitly override these settings which I don’t. I have just some keep and don-warn and so on statements in there.
c
still, I’d try to disable them manually. its 2 lines in the pro file. If it works when runnning the non-release version it could only be something with proguard.
or, the JVM you are running on. are they the same - Is your IDE using the same JVM as when you run the
jar
?
m
I just made a release build with ProGuard switched off (in the config shown above) and the error is gone. So it’s definitely a ProGuard issue. The JVMs are the same in this case.
👍 1
c
then good look and toi toi toi with finding the “issue” - those might be nerve-racking. Been there, done that 😅 🤞
🤨 2
😪 2
m
While I was trying to track this down, I stumbled over another ProGuard issue which may be related and indicate a more general problem. https://github.com/Guardsquare/proguard/issues/441
c
Did you try a different Kotlin version? Maybe the generated bytecode that Proguard consumes has some weird code paths.
m
I have only tried Kotlin 2.0.20 and 2.0.21. Going back to older versions just because of ProGuard is not an option for me.
c
I would still try it to narrow it down. At least in that MCVE you created.
p
I had such kind of problems with Proguard. I gave up trying to find solution. So i switched to R8 and have no problems now.
m
Is there any documentation on how to use R8 with Compose desktop and how to replace ProGuard? I have to admit that I am not a Gradle Guru 😉.
p
I don't know how to make it work with Compose Desktop Gradle scripts, I'm using Fat Jar + R8 to have single obfuscated/optimized jar as output. First step is to configure fat jar to take all runtime dependencies and produce single jar. Second is to create JavaExec task to run R8 and provide that single jar to it. Then you can package resulting jar using any packaging tool you need. JavaExec task for R8 is pretty simple. Here is a part extracted from my scripts:
Copy code
project.tasks.register("<task name>", JavaExec::class.java) {
            val singleJarFile = singleJarTask.get().archiveFile // getting jar from FatJar output
            val outFile: RegularFile = <here specify location of resulting jar file>
            inputs.file(singleJarFile)
            outputs.file(outFile)
            classpath(r8Config) // as classpath you need to provide configuration where R8 jar is located. You can create new Configuration and add dependency of "com.android.tools:r8:<r8 version>" there  
            mainClass.set("com.android.tools.r8.R8")
            //
            args(
                "--release",
                "--classfile",
                "--output", outFile.asFile.absolutePath,
                "--lib", javaLauncher.get().metadata.installationPath,
                singleJarFile.get().asFile.absolutePath
            )
        }
R8 automatically search for rules at META-INF/com.android.tools/r8/*.pro in provided jar for obfuscation/optimization