Skip to content

Commit

Permalink
Add "Kotlin consumers only" settings and fix highlighting
Browse files Browse the repository at this point in the history
- Kotlin consumers only sets several compiler flags to eliminate
  null checks. This was always set before this change.
- Fix highlithing of ranges.
- Fix highlithing of annotations (FQNs are now supported).
  • Loading branch information
romainguy committed Oct 14, 2024
1 parent 686131d commit 8ad5175
Show file tree
Hide file tree
Showing 8 changed files with 3,995 additions and 3,932 deletions.
19 changes: 17 additions & 2 deletions src/jvmMain/kotlin/dev/romainguy/kotlin/explorer/Disassembly.kt
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ private val oatDumpParser = OatDumpParser()

suspend fun buildAndRun(
toolPaths: ToolPaths,
kotlinOnlyConsumers: Boolean,
compilerFlags: String,
source: String,
onLogs: (AnnotatedString) -> Unit,
Expand All @@ -63,7 +64,7 @@ suspend fun buildAndRun(
Files.writeString(path, source)
writeSupportFiles(directory)

val kotlinc = KotlinCompiler(toolPaths, directory).compile(compilerFlags, path)
val kotlinc = KotlinCompiler(toolPaths, directory).compile(kotlinOnlyConsumers, compilerFlags, path)

if (kotlinc.exitCode != 0) {
withContext(ui) {
Expand Down Expand Up @@ -96,6 +97,7 @@ suspend fun buildAndRun(
suspend fun buildAndDisassemble(
toolPaths: ToolPaths,
source: String,
kotlinOnlyConsumers: Boolean,
compilerFlags: String,
r8rules: String,
minApi: Int,
Expand Down Expand Up @@ -124,7 +126,7 @@ suspend fun buildAndDisassemble(
Files.writeString(path, source)
writeSupportFiles(directory)

val kotlinc = KotlinCompiler(toolPaths, directory).compile(compilerFlags, path)
val kotlinc = KotlinCompiler(toolPaths, directory).compile(kotlinOnlyConsumers, compilerFlags, path)

if (kotlinc.exitCode != 0) {
updater.addJob(launch(ui) {
Expand Down Expand Up @@ -278,6 +280,19 @@ private fun cleanupClasses(directory: Path) {
}

private fun writeSupportFiles(directory: Path) {
Files.writeString(
directory.resolve("NeverInline.kt"),
"""
@file:OptIn(ExperimentalMultiplatform::class)
package dalvik.annotation.optimization
@Retention(AnnotationRetention.BINARY)
@Target(AnnotationTarget.CONSTRUCTOR, AnnotationTarget.FUNCTION)
public annotation class NeverInline()
""".trimIndent()
)

Files.writeString(
directory.resolve("Keep.kt"),
"""
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -526,6 +526,7 @@ private fun FrameWindowScope.MainMenu(
buildAndDisassemble(
explorerState.toolPaths,
sourceTextArea.text,
explorerState.kotlinOnlyConsumers,
explorerState.compilerFlags,
explorerState.r8Rules,
explorerState.minApi,
Expand All @@ -544,6 +545,7 @@ private fun FrameWindowScope.MainMenu(
scope.launch {
buildAndRun(
explorerState.toolPaths,
explorerState.kotlinOnlyConsumers,
explorerState.compilerFlags,
sourceTextArea.text,
onLogsUpdate,
Expand Down
15 changes: 14 additions & 1 deletion src/jvmMain/kotlin/dev/romainguy/kotlin/explorer/Settings.kt
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@

package dev.romainguy.kotlin.explorer

import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.onClick
import androidx.compose.foundation.text.input.InputTransformation
import androidx.compose.foundation.text.input.TextFieldLineLimits
import androidx.compose.foundation.text.input.TextFieldState
Expand All @@ -39,6 +41,7 @@ fun Settings(
) {
val androidHome = rememberTextFieldState(state.androidHome)
val kotlinHome = rememberTextFieldState(state.kotlinHome)
val kotlinOnlyConsumers = remember { mutableStateOf(state.kotlinOnlyConsumers) }
val compilerFlags = rememberTextFieldState(state.compilerFlags)
val r8rules = rememberTextFieldState(state.r8Rules)
val minApi = rememberTextFieldState(state.minApi.toString())
Expand All @@ -49,6 +52,7 @@ fun Settings(
state.saveState(
androidHome.text.toString(),
kotlinHome.text.toString(),
kotlinOnlyConsumers.value,
compilerFlags.text.toString(),
r8rules.text.toString(),
minApi.text.toString(),
Expand All @@ -68,6 +72,7 @@ fun Settings(
StringSetting("Kotlin compiler flags: ", compilerFlags)
MultiLineStringSetting("R8 rules: ", r8rules)
IntSetting("Min API: ", minApi, minValue = 1)
BooleanSetting("Kotlin only consumers", kotlinOnlyConsumers)
BooleanSetting("Decompile hidden instruction sets", decompileHiddenIsa)
Spacer(modifier = Modifier.height(8.dp))
Buttons(saveEnabled = toolPaths.isValid, onSaveClick, onDismissRequest)
Expand All @@ -93,6 +98,7 @@ private fun ColumnScope.Buttons(
private fun ExplorerState.saveState(
androidHome: String,
kotlinHome: String,
kotlinOnlyConsumers: Boolean,
compilerFlags: String,
r8Rules: String,
minApi: String,
Expand All @@ -102,6 +108,7 @@ private fun ExplorerState.saveState(
) {
this.androidHome = androidHome
this.kotlinHome = kotlinHome
this.kotlinOnlyConsumers = kotlinOnlyConsumers
this.compilerFlags = compilerFlags
this.r8Rules = r8Rules
this.minApi = minApi.toIntOrNull() ?: 21
Expand Down Expand Up @@ -149,13 +156,19 @@ private fun IntSetting(title: String, state: TextFieldState, minValue: Int) {
})
}

@OptIn(ExperimentalFoundationApi::class)
@Composable
private fun BooleanSetting(@Suppress("SameParameterValue") title: String, state: MutableState<Boolean>) {
Row {
Checkbox(state.value, onCheckedChange = { state.value = it })
Text(
title,
modifier = Modifier.align(Alignment.CenterVertically)
modifier = Modifier
.align(Alignment.CenterVertically)
.padding(start = 2.dp)
.onClick {
state.value = !state.value
}
)
}
}
Expand Down
2 changes: 2 additions & 0 deletions src/jvmMain/kotlin/dev/romainguy/kotlin/explorer/State.kt
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ private const val AndroidHome = "ANDROID_HOME"
private const val KotlinHome = "KOTLIN_HOME"
private const val Optimize = "OPTIMIZE"
private const val KeepEverything = "KEEP_EVERYTHING"
private const val KotlinOnlyConsumers = "KOTLIN_ONLY_CONSUMERS"
private const val CompilerFlags = "COMPILER_FLAGS"
private const val R8Rules = "R8_RULES"
private const val MinApi = "MIN_API"
Expand Down Expand Up @@ -59,6 +60,7 @@ class ExplorerState {
var toolPaths by mutableStateOf(createToolPaths())
var optimize by BooleanState(Optimize, true)
var keepEverything by BooleanState(KeepEverything, true)
var kotlinOnlyConsumers by BooleanState(KotlinOnlyConsumers, true)
var compilerFlags by StringState(CompilerFlags, "")
var r8Rules by StringState(R8Rules, "")
var minApi by IntState(MinApi, 21)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,26 +20,36 @@ import dev.romainguy.kotlin.explorer.ToolPaths
import dev.romainguy.kotlin.explorer.process
import java.nio.file.Path

private val BuiltInFiles = listOf(
"Keep.kt",
"NeverInline.kt"
)

class KotlinCompiler(private val toolPaths: ToolPaths, private val outputDirectory: Path) {
suspend fun compile(compilerFlags: String, source: Path) =
process(*buildCompileCommand(compilerFlags, source), directory = outputDirectory)
suspend fun compile(kotlinOnlyConsumers: Boolean, compilerFlags: String, source: Path) =
process(*buildCompileCommand(kotlinOnlyConsumers, compilerFlags, source), directory = outputDirectory)

private fun buildCompileCommand(compilerFlags: String, file: Path): Array<String> {
private fun buildCompileCommand(kotlinOnlyConsumers: Boolean, compilerFlags: String, file: Path): Array<String> {
val command = mutableListOf(
toolPaths.kotlinc.toString(),
"-Xmulti-platform",
"-Xno-param-assertions",
"-Xno-call-assertions",
"-Xno-receiver-assertions",
"-classpath",
(toolPaths.kotlinLibs + listOf(toolPaths.platform)).joinToString(":") { jar -> jar.toString() },
file.toString(),
file.parent.resolve("Keep.kt").toString()
(toolPaths.kotlinLibs + listOf(toolPaths.platform)).joinToString(":") { jar -> jar.toString() }
).apply {
if (kotlinOnlyConsumers) {
this += "-Xno-param-assertions"
this += "-Xno-call-assertions"
this += "-Xno-receiver-assertions"
}
if (compilerFlags.isNotEmpty() || compilerFlags.isNotBlank()) {
// TODO: Do something smarter in case a flag looks like -foo="something with space"
addAll(compilerFlags.split(' '))
}
// Source code to compile
this += file.toString()
for (fileName in BuiltInFiles) {
this += file.parent.resolve(fileName).toString()
}
}

return command.toTypedArray()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ class LocalBuilder(private val outputDirectory: Path) : Builder {
}

private suspend fun kotlinCompile(path: Path) {
val result = kotlinCompiler.compile("", path)
val result = kotlinCompiler.compile(kotlinOnlyConsumers, "", path)
if (result.exitCode != 0) {
System.err.println(result.output)
fail("kotlinc error")
Expand Down
Loading

0 comments on commit 8ad5175

Please sign in to comment.