Skip to content

Commit 2ea0f60

Browse files
committed
Add IC for Compose Wasm
1 parent ff8f0c0 commit 2ea0f60

File tree

13 files changed

+248
-55
lines changed

13 files changed

+248
-55
lines changed

build.gradle.kts

+12-3
Original file line numberDiff line numberDiff line change
@@ -41,9 +41,17 @@ allprojects {
4141
maven("https://maven.pkg.jetbrains.space/kotlin/p/wasm/experimental")
4242
maven("https://maven.pkg.jetbrains.space/public/p/compose/dev")
4343
}
44-
afterEvaluate {
45-
dependencies {
46-
dependencies {
44+
}
45+
46+
setOf(
47+
rootProject,
48+
project(":common"),
49+
project(":executors"),
50+
project(":indexation"),
51+
).forEach { project ->
52+
project.afterEvaluate {
53+
project.dependencies {
54+
project.dependencies {
4755
implementation("com.fasterxml.jackson.module:jackson-module-kotlin:2.15.2")
4856
implementation(libs.kotlin.idea) {
4957
isTransitive = false
@@ -109,6 +117,7 @@ fun generateProperties(prefix: String = "") = """
109117
libraries.folder.compose-wasm=${prefix + libComposeWasm}
110118
libraries.folder.compose-wasm-compiler-plugins=${prefix + libComposeWasmCompilerPlugins}
111119
libraries.folder.compiler-plugins=${prefix + compilerPluginsForJVM}
120+
caches.folder.compose-wasm=${prefix + cachesComposeWasm}
112121
spring.mvc.pathmatch.matching-strategy=ant_path_matcher
113122
server.compression.enabled=true
114123
server.compression.mime-types=application/json,text/javascript,application/wasm

buildSrc/src/main/kotlin/properties.kt

+7-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1+
import org.gradle.accessors.dm.LibrariesForLibs
12
import org.gradle.api.Project
23
import org.gradle.kotlin.dsl.provideDelegate
3-
import org.gradle.accessors.dm.LibrariesForLibs
44
import org.gradle.kotlin.dsl.the
55

66
val indexes: String by System.getProperties()
@@ -25,6 +25,8 @@ val Project.libComposeWasm
2525
get() = "$kotlinVersion-compose-wasm"
2626
val Project.libComposeWasmCompilerPlugins
2727
get() = "$kotlinVersion-compose-wasm-compiler-plugins"
28+
val Project.cachesComposeWasm
29+
get() = "$kotlinVersion-caches-compose-wasm"
2830

2931
val Project.libJVMFolder
3032
get() = rootProject.layout.projectDirectory.dir(libJVM)
@@ -42,4 +44,7 @@ val Project.libComposeWasmFolder
4244
get() = rootProject.layout.projectDirectory.dir(libComposeWasm)
4345

4446
val Project.libComposeWasmCompilerPluginsFolder
45-
get() = rootProject.layout.projectDirectory.dir(libComposeWasmCompilerPlugins)
47+
get() = rootProject.layout.projectDirectory.dir(libComposeWasmCompilerPlugins)
48+
49+
val Project.cachesComposeWasmFolder
50+
get() = rootProject.layout.projectDirectory.dir(cachesComposeWasm)

common/src/main/kotlin/component/KotlinEnvironment.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package component
22

33
import com.intellij.openapi.util.Disposer
4-
import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys
54
import org.jetbrains.kotlin.cli.common.arguments.K2JVMCompilerArguments
65
import org.jetbrains.kotlin.cli.common.arguments.parseCommandLineArguments
76
import org.jetbrains.kotlin.cli.common.messages.MessageCollector
@@ -33,6 +32,7 @@ class KotlinEnvironment(
3332
composeWasmCompilerPlugins: List<File>,
3433
val compilerPlugins: List<File> = emptyList(),
3534
composeWasmCompilerPluginsOptions: List<CompilerPluginOption>,
35+
val composeWasmCache: File,
3636
) {
3737
companion object {
3838
/**

gradle/libs.versions.toml

+2-2
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,11 @@ kotlinx-coroutines-test = "1.6.4"
1414
kotlinx-datetime = "0.6.0-RC.2"
1515
kotlinx-io = "0.5.3"
1616
kotlinx-serialization = "1.7.1"
17-
skiko = "0.7.90"
17+
skiko = "0.8.15"
1818
# don't forget to update jackson version in `executor.policy` file.
1919
jackson = "2.14.0"
2020
hamcrest = "2.2"
21-
compose = "1.6.0"
21+
compose = "1.7.0-rc01"
2222

2323
[libraries]
2424
kotlin-reflect = { group = "org.jetbrains.kotlin", name = "kotlin-reflect", version.ref = "kotlin" }

indexation/src/main/kotlin/KotlinEnvironmentConfiguration.kt

+3-1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ class KotlinEnvironmentConfiguration(
1414
val wasmFile = File("$fileName-wasm")
1515
val composeWasmFile = File("$fileName-compose-wasm")
1616
val composeWasmCompilerPluginsFile = File("$fileName-compose-wasm-compiler-plugins")
17+
val composeWasmCachesFile = File("$fileName-caches-compose-wasm")
1718
val classPath =
1819
listOfNotNull(jvmFile)
1920
.flatMap {
@@ -44,7 +45,8 @@ class KotlinEnvironmentConfiguration(
4445
"suppressKotlinVersionCompatibilityCheck",
4546
version
4647
),
47-
)
48+
),
49+
composeWasmCachesFile
4850
)
4951
}
5052
}

src/main/kotlin/com/compiler/server/compiler/components/KotlinEnvironment.kt

+5-3
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,16 @@
11
package com.compiler.server.compiler.components
22

3+
import com.compiler.server.model.bean.CachesFile
34
import com.compiler.server.model.bean.LibrariesFile
4-
import com.compiler.server.model.bean.VersionInfo
55
import component.CompilerPluginOption
66
import component.KotlinEnvironment
77
import org.springframework.context.annotation.Bean
88
import org.springframework.context.annotation.Configuration
99

1010
@Configuration
1111
class KotlinEnvironmentConfiguration(
12-
val librariesFile: LibrariesFile
12+
val librariesFile: LibrariesFile,
13+
val cachesFile: CachesFile,
1314
) {
1415
@Bean
1516
fun kotlinEnvironment(): KotlinEnvironment {
@@ -39,7 +40,8 @@ class KotlinEnvironmentConfiguration(
3940
"generateDecoys",
4041
"false"
4142
),
42-
)
43+
),
44+
cachesFile.composeWasm
4345
)
4446
}
4547
}

src/main/kotlin/com/compiler/server/compiler/components/KotlinToJSTranslator.kt

+90-40
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,11 @@ import component.KotlinEnvironment
66
import org.jetbrains.kotlin.cli.js.K2JSCompiler
77
import org.jetbrains.kotlin.psi.KtFile
88
import org.springframework.stereotype.Service
9-
import kotlin.io.path.div
10-
import kotlin.io.path.readBytes
11-
import kotlin.io.path.readText
9+
import java.io.File
10+
import java.nio.file.Path
11+
import kotlin.contracts.ExperimentalContracts
12+
import kotlin.contracts.contract
13+
import kotlin.io.path.*
1214

1315
@Service
1416
class KotlinToJSTranslator(
@@ -46,28 +48,42 @@ class KotlinToJSTranslator(
4648
fun translateWasm(
4749
files: List<KtFile>,
4850
debugInfo: Boolean,
51+
generateIncrementalCache: Boolean,
4952
projectType: ProjectType,
50-
translate: (List<KtFile>, List<String>, List<String>, List<String>) -> CompilationResult<WasmTranslationSuccessfulOutput>
53+
translate: (
54+
List<KtFile>,
55+
List<String>,
56+
List<String>,
57+
List<String>,
58+
Boolean,
59+
File?,
60+
Boolean,
61+
) -> CompilationResult<WasmTranslationSuccessfulOutput>
5162
): TranslationResultWithJsCode {
5263
return try {
53-
val (dependencies, compilerPlugins, compilerPluginOptions) = when (projectType) {
54-
ProjectType.WASM -> listOf(
64+
val parameters: WasmParameters = when (projectType) {
65+
ProjectType.WASM -> WasmParameters(
5566
kotlinEnvironment.WASM_LIBRARIES,
5667
emptyList(),
57-
emptyList()
68+
emptyList(),
69+
null
5870
)
59-
ProjectType.COMPOSE_WASM -> listOf(
71+
ProjectType.COMPOSE_WASM -> WasmParameters(
6072
kotlinEnvironment.COMPOSE_WASM_LIBRARIES,
6173
kotlinEnvironment.COMPOSE_WASM_COMPILER_PLUGINS,
62-
kotlinEnvironment.composeWasmCompilerPluginOptions
74+
kotlinEnvironment.composeWasmCompilerPluginOptions,
75+
kotlinEnvironment.composeWasmCache,
6376
)
6477
else -> throw IllegalStateException("Wasm should have wasm or compose-wasm project type")
6578
}
6679
val compilationResult = translate(
6780
files,
68-
dependencies,
69-
compilerPlugins,
70-
compilerPluginOptions
81+
parameters.dependencies,
82+
parameters.plugins,
83+
parameters.pluginOptions,
84+
generateIncrementalCache,
85+
parameters.cacheDir,
86+
debugInfo,
7187
)
7288
val wasmCompilationOutput = when (compilationResult) {
7389
is Compiled<WasmTranslationSuccessfulOutput> -> compilationResult.result
@@ -136,6 +152,9 @@ class KotlinToJSTranslator(
136152
dependencies: List<String>,
137153
compilerPlugins: List<String>,
138154
compilerPluginOptions: List<String>,
155+
generateIncrementalCache: Boolean,
156+
cacheDir: File?,
157+
debugInfo: Boolean,
139158
): CompilationResult<WasmTranslationSuccessfulOutput> =
140159
usingTempDirectory { inputDir ->
141160
val moduleName = "moduleId"
@@ -156,40 +175,71 @@ class KotlinToJSTranslator(
156175
val additionalCompilerArgumentsForKLib: List<String> = listOf(
157176
"-Xreport-all-warnings",
158177
"-Wextra",
159-
"-Xwasm",
160-
"-Xir-produce-klib-dir",
161-
"-libraries=${dependencies.joinToString(PATH_SEPARATOR)}",
162-
"-ir-output-dir=$klibPath",
163-
"-ir-output-name=$moduleName",
164-
) + compilerPluginsArgs
178+
"-Xwasm",
179+
"-Xir-produce-klib-dir",
180+
"-libraries=${dependencies.joinToString(PATH_SEPARATOR)}",
181+
"-ir-output-dir=$klibPath",
182+
"-ir-output-name=$moduleName",
183+
) + compilerPluginsArgs
165184

166-
k2JSCompiler.tryCompilation(inputDir, ioFiles, filePaths + additionalCompilerArgumentsForKLib)
167-
.flatMap {
168-
k2JSCompiler.tryCompilation(inputDir, ioFiles, listOf(
169-
"-Xreport-all-warnings",
170-
"-Wextra",
171-
"-Xwasm",
172-
"-Xwasm-generate-wat",
173-
"-Xir-produce-js",
174-
"-Xir-dce",
175-
"-Xinclude=$klibPath",
176-
"-libraries=${dependencies.joinToString(PATH_SEPARATOR)}",
177-
"-ir-output-dir=${(outputDir / "wasm").toFile().canonicalPath}",
178-
"-ir-output-name=$moduleName",
179-
))
180-
}
181-
.map {
182-
WasmTranslationSuccessfulOutput(
183-
jsCode = (outputDir / "wasm" / "$moduleName.uninstantiated.mjs").readText(),
184-
jsInstantiated = (outputDir / "wasm" / "$moduleName.mjs").readText(),
185-
wasm = (outputDir / "wasm" / "$moduleName.wasm").readBytes(),
186-
wat = (outputDir / "wasm" / "$moduleName.wat").readText(),
187-
)
185+
val compileAction: (icDir: Path?) -> CompilationResult<WasmTranslationSuccessfulOutput> = { icDir ->
186+
k2JSCompiler.tryCompilation(inputDir, ioFiles, filePaths + additionalCompilerArgumentsForKLib)
187+
.flatMap {
188+
k2JSCompiler.tryCompilation(
189+
inputDir, ioFiles, mutableListOf(
190+
"-Xreport-all-warnings",
191+
"-Wextra",
192+
"-Xwasm",
193+
"-Xir-produce-js",
194+
"-Xinclude=$klibPath",
195+
"-libraries=${dependencies.joinToString(PATH_SEPARATOR)}",
196+
"-ir-output-dir=${(outputDir / "wasm").toFile().canonicalPath}",
197+
"-ir-output-name=$moduleName",).also {
198+
if (debugInfo) it.add("-Xwasm-generate-wat")
199+
if (compileWithCacheDir(generateIncrementalCache, icDir)) {
200+
it.add("-Xcache-directory=${icDir.normalize().absolutePathString()}")
201+
} else {
202+
it.add("-Xir-dce")
203+
}
204+
}
205+
)
206+
}
207+
.map {
208+
WasmTranslationSuccessfulOutput(
209+
jsCode = (outputDir / "wasm" / "$moduleName.uninstantiated.mjs").readText(),
210+
jsInstantiated = (outputDir / "wasm" / "$moduleName.mjs").readText(),
211+
wasm = (outputDir / "wasm" / "$moduleName.wasm").readBytes(),
212+
wat = if (debugInfo) (outputDir / "wasm" / "$moduleName.wat").readText() else null,
213+
)
214+
}
215+
}
216+
217+
if (generateIncrementalCache) {
218+
compileAction(cacheDir!!.toPath())
219+
} else {
220+
val cacheDirPath = cacheDir?.toPath()
221+
if (compileWithCacheDir(generateIncrementalCache = false, cacheDirPath)) {
222+
usingTempDirectory { tmpDir ->
223+
val cachesDir = tmpDir.resolve("caches").normalize()
224+
cacheDirPath.toFile().copyRecursively(cachesDir.toFile())
225+
compileAction(cachesDir)
226+
}
227+
} else {
228+
compileAction(null)
188229
}
230+
}
189231
}
190232
}
191233
}
192234

235+
@OptIn(ExperimentalContracts::class)
236+
private fun compileWithCacheDir(generateIncrementalCache: Boolean, cacheDir: Path?): Boolean {
237+
contract {
238+
returns() implies (cacheDir != null)
239+
}
240+
return cacheDir != null && (generateIncrementalCache || cacheDir.exists())
241+
}
242+
193243
private fun String.withMainArgumentsIr(arguments: List<String>): String {
194244
val mainIrFunction = """
195245
| function mainWrapper() {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package com.compiler.server.compiler.components
2+
3+
import java.io.File
4+
5+
data class WasmParameters(
6+
val dependencies: List<String>,
7+
val plugins: List<String>,
8+
val pluginOptions: List<String>,
9+
val cacheDir: File?
10+
)

src/main/kotlin/com/compiler/server/configuration/ApplicationConfiguration.kt

+14-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package com.compiler.server.configuration
22

3+
import com.compiler.server.model.bean.CachesFile
34
import com.compiler.server.model.bean.LibrariesFile
45
import com.compiler.server.model.bean.VersionInfo
56
import org.springframework.beans.factory.annotation.Value
@@ -12,10 +13,11 @@ import org.springframework.web.servlet.config.annotation.WebMvcConfigurer
1213
import java.io.File
1314

1415
@Configuration
15-
@EnableConfigurationProperties(value = [LibrariesFolderProperties::class])
16+
@EnableConfigurationProperties(value = [LibrariesFolderProperties::class, CachesFolderProperties::class])
1617
class ApplicationConfiguration(
1718
@Value("\${kotlin.version}") private val version: String,
18-
private val librariesFolderProperties: LibrariesFolderProperties
19+
private val librariesFolderProperties: LibrariesFolderProperties,
20+
private val cachesFolderProperties: CachesFolderProperties,
1921
) : WebMvcConfigurer {
2022
override fun addFormatters(registry: FormatterRegistry) {
2123
registry.addConverter(ProjectConverter())
@@ -36,6 +38,11 @@ class ApplicationConfiguration(
3638
File(librariesFolderProperties.composeWasmCompilerPlugins),
3739
File(librariesFolderProperties.compilerPlugins)
3840
)
41+
42+
@Bean
43+
fun cachesFiles() = CachesFile(
44+
File(cachesFolderProperties.composeWasm)
45+
)
3946
}
4047

4148
@ConfigurationProperties(prefix = "libraries.folder")
@@ -46,4 +53,9 @@ class LibrariesFolderProperties {
4653
lateinit var composeWasm: String
4754
lateinit var composeWasmCompilerPlugins: String
4855
lateinit var compilerPlugins: String
56+
}
57+
58+
@ConfigurationProperties(prefix = "caches.folder")
59+
class CachesFolderProperties {
60+
lateinit var composeWasm: String
4961
}

src/main/kotlin/com/compiler/server/controllers/CompilerRestController.kt

+10
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,16 @@ class CompilerRestController(private val kotlinProjectExecutor: KotlinProjectExe
3737
}
3838
}
3939

40+
@PostMapping("/generate-cache")
41+
fun generateKotlinIncrementalCacheEndpoint(
42+
@RequestParam(defaultValue = "compose-wasm") compiler: String
43+
): TranslationResultWithJsCode? {
44+
return when (KotlinTranslatableCompiler.valueOf(compiler.uppercase().replace("-", "_"))) {
45+
KotlinTranslatableCompiler.COMPOSE_WASM -> kotlinProjectExecutor.generateWasmIncrementalCache(ProjectType.COMPOSE_WASM)
46+
else -> null
47+
}
48+
}
49+
4050
@PostMapping("/complete")
4151
fun getKotlinCompleteEndpoint(
4252
@RequestBody project: Project,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
package com.compiler.server.model.bean
2+
3+
import java.io.File
4+
5+
class CachesFile(val composeWasm: File)

0 commit comments

Comments
 (0)