Skip to content

Commit

Permalink
Wasm init
Browse files Browse the repository at this point in the history
  • Loading branch information
ilgonmic authored and woainikk committed Jun 19, 2023
1 parent 6483d9e commit 2d87c39
Show file tree
Hide file tree
Showing 11 changed files with 133 additions and 32 deletions.
22 changes: 22 additions & 0 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,19 @@ val kotlinJsDependency: Configuration by configurations.creating {
)
}
}

val kotlinWasmDependency: Configuration by configurations.creating {
isTransitive = false
attributes {
attribute(
KotlinPlatformType.attribute,
KotlinPlatformType.wasm
)
}
}

val libJSFolder = "$kotlinVersion-js"
val libWasmFolder = "$kotlinVersion-wasm"
val libJVMFolder = kotlinVersion
val propertyFile = "application.properties"
val jacksonVersionKotlinDependencyJar = "2.14.0" // don't forget to update version in `executor.policy` file.
Expand All @@ -44,6 +56,11 @@ val copyJSDependencies by tasks.creating(Copy::class) {
into(libJSFolder)
}

val copyWasmDependencies by tasks.creating(Copy::class) {
from(files(Callable { kotlinWasmDependency.map { zipTree(it) } }))
into(libWasmFolder)
}

plugins {
id("org.springframework.boot") version "2.7.10"
id("io.spring.dependency-management") version "1.1.0"
Expand Down Expand Up @@ -89,6 +106,7 @@ dependencies {
kotlinDependency("org.jetbrains.kotlin:kotlin-test:$kotlinVersion")
kotlinDependency("org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.7.1")
kotlinJsDependency("org.jetbrains.kotlin:kotlin-stdlib-js:$kotlinVersion")
kotlinWasmDependency("org.jetbrains.kotlin:kotlin-stdlib-wasm:$kotlinVersion")

annotationProcessor("org.springframework:spring-context-indexer")
implementation("com.google.code.gson:gson")
Expand Down Expand Up @@ -134,7 +152,10 @@ fun generateProperties(prefix: String = "") = """
indexesJs.file=${prefix + indexesJs}
libraries.folder.jvm=${prefix + libJVMFolder}
libraries.folder.js=${prefix + libJSFolder}
libraries.folder.wasm=${prefix + libWasmFolder}
spring.mvc.pathmatch.matching-strategy=ant_path_matcher
server.compression.enabled=true
server.compression.mime-types=application/json
""".trimIndent()

java {
Expand All @@ -150,6 +171,7 @@ tasks.withType<KotlinCompile> {
}
dependsOn(copyDependencies)
dependsOn(copyJSDependencies)
dependsOn(copyWasmDependencies)
dependsOn(":executors:jar")
dependsOn(":indexation:run")
buildPropertyFile()
Expand Down
11 changes: 10 additions & 1 deletion common/src/main/kotlin/component/KotlinEnvironment.kt
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@ import java.io.File

class KotlinEnvironment(
val classpath: List<File>,
additionalJsClasspath: List<File>
additionalJsClasspath: List<File>,
additionalWasmClasspath: List<File>,
) {
companion object {
/**
Expand Down Expand Up @@ -59,6 +60,7 @@ class KotlinEnvironment(
}

val JS_LIBRARIES = additionalJsClasspath.map { it.absolutePath }
val WASM_LIBRARIES = additionalWasmClasspath.map { it.absolutePath }

@Synchronized
fun <T> environment(f: (KotlinCoreEnvironment) -> T): T {
Expand All @@ -72,6 +74,13 @@ class KotlinEnvironment(
put(JSConfigurationKeys.LIBRARIES, JS_LIBRARIES)
}

val wasmConfiguration: CompilerConfiguration = configuration.copy().apply {
put(CommonConfigurationKeys.MODULE_NAME, "moduleId")
put(JSConfigurationKeys.LIBRARIES, WASM_LIBRARIES)
put(JSConfigurationKeys.WASM_ENABLE_ARRAY_RANGE_CHECKS, false)
put(JSConfigurationKeys.WASM_ENABLE_ASSERTS, false)
}

private val messageCollector = object : MessageCollector {
override fun clear() {}
override fun hasErrors(): Boolean {
Expand Down
3 changes: 2 additions & 1 deletion indexation/src/main/kotlin/KotlinEnvironmentConfiguration.kt
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ class KotlinEnvironmentConfiguration(fileName: String) {
val kotlinEnvironment = run {
val jvmFile = File(fileName)
val jsFile = File("$fileName-js")
val wasmFile = File("$fileName-wasm")
val classPath =
listOfNotNull(jvmFile)
.flatMap {
Expand All @@ -15,6 +16,6 @@ class KotlinEnvironmentConfiguration(fileName: String) {
}

val additionalJsClasspath = listOfNotNull(jsFile)
KotlinEnvironment(classPath, additionalJsClasspath)
KotlinEnvironment(classPath, additionalJsClasspath, listOfNotNull(wasmFile))
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,6 @@ class KotlinEnvironmentConfiguration(val librariesFile: LibrariesFile) {
}

val additionalJsClasspath = listOfNotNull(librariesFile.js)
return KotlinEnvironment(classPath, additionalJsClasspath)
return KotlinEnvironment(classPath, additionalJsClasspath, listOfNotNull(librariesFile.wasm))
}
}
Original file line number Diff line number Diff line change
@@ -1,23 +1,25 @@
package com.compiler.server.compiler.components

import com.compiler.server.model.ErrorDescriptor
import com.compiler.server.model.TranslationJSResult
import com.compiler.server.model.toExceptionDescriptor
import com.compiler.server.model.*
import component.KotlinEnvironment
import org.jetbrains.kotlin.backend.common.phaser.PhaseConfig
import org.jetbrains.kotlin.backend.wasm.compileToLoweredIr
import org.jetbrains.kotlin.backend.wasm.compileWasm
import org.jetbrains.kotlin.backend.wasm.dce.eliminateDeadDeclarations
import org.jetbrains.kotlin.backend.wasm.wasmPhases
import org.jetbrains.kotlin.cli.common.messages.AnalyzerWithCompilerReport
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
import org.jetbrains.kotlin.ir.backend.js.CompilerResult
import org.jetbrains.kotlin.ir.backend.js.WholeWorldStageController
import org.jetbrains.kotlin.ir.backend.js.compile
import org.jetbrains.kotlin.ir.backend.js.prepareAnalyzedSourceModule
import org.jetbrains.kotlin.ir.backend.js.*
import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.IrModuleToJsTransformer
import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.TranslationMode
import org.jetbrains.kotlin.ir.declarations.impl.IrFactoryImpl
import org.jetbrains.kotlin.ir.declarations.impl.IrFactoryImplForJsIC
import org.jetbrains.kotlin.js.config.JsConfig
import org.jetbrains.kotlin.js.facade.K2JSTranslator
import org.jetbrains.kotlin.js.facade.MainCallParameters
import org.jetbrains.kotlin.js.facade.TranslationResult
import org.jetbrains.kotlin.js.facade.exceptions.TranslationException
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.resolve.CompilerEnvironment
import org.springframework.stereotype.Service
Expand Down Expand Up @@ -47,8 +49,8 @@ class KotlinToJSTranslator(
files: List<KtFile>,
arguments: List<String>,
coreEnvironment: KotlinCoreEnvironment,
translate: (List<KtFile>, List<String>, KotlinCoreEnvironment) -> TranslationJSResult
): TranslationJSResult {
translate: (List<KtFile>, List<String>, KotlinCoreEnvironment) -> TranslationResultWithJsCode
): TranslationResultWithJsCode {
val (errors, _) = errorAnalyzer.errorsFrom(files, coreEnvironment, isJs = true)
return try {
if (errorAnalyzer.isOnlyWarnings(errors)) {
Expand Down Expand Up @@ -143,6 +145,44 @@ class KotlinToJSTranslator(
return TranslationJSResult(listLines.joinToString("\n"))
}

fun doTranslateWithWasm(
files: List<KtFile>,
arguments: List<String>,
coreEnvironment: KotlinCoreEnvironment
): TranslationWasmResult {
val currentProject = coreEnvironment.project

val sourceModule = prepareAnalyzedSourceModule(
currentProject,
files,
kotlinEnvironment.wasmConfiguration,
kotlinEnvironment.WASM_LIBRARIES,
friendDependencies = emptyList(),
analyzer = AnalyzerWithCompilerReport(kotlinEnvironment.wasmConfiguration),
)

val (allModules, backendContext) = compileToLoweredIr(
depsDescriptors = sourceModule,
phaseConfig = PhaseConfig(wasmPhases),
irFactory = IrFactoryImpl,
exportedDeclarations = setOf(FqName("main")),
propertyLazyInitialization = true,
)
eliminateDeadDeclarations(allModules, backendContext)

val res = compileWasm(
allModules = allModules,
backendContext = backendContext,
baseFileName = "moduleId",
emitNameSection = false,
allowIncompleteImplementations = true,
generateWat = false,
generateSourceMaps = false
)

return TranslationWasmResult(res.jsUninstantiatedWrapper, res.wasm)
}

private fun getJsCodeFromModule(compiledModule: CompilerResult): String {
val jsCodeObject = compiledModule.outputs.values.single()

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,14 @@ class ApplicationConfiguration(
@Bean
fun librariesFiles() = LibrariesFile(
File(librariesFolderProperties.jvm),
File(librariesFolderProperties.js)
File(librariesFolderProperties.js),
File(librariesFolderProperties.wasm)
)
}

@ConfigurationProperties(prefix = "libraries.folder")
class LibrariesFolderProperties {
lateinit var jvm: String
lateinit var js: String
lateinit var wasm: String
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
package com.compiler.server.controllers

import com.compiler.server.model.ErrorDescriptor
import com.compiler.server.model.ExecutionResult
import com.compiler.server.model.Project
import com.compiler.server.model.TranslationJSResult
import com.compiler.server.model.*
import com.compiler.server.model.bean.VersionInfo
import com.compiler.server.service.KotlinProjectExecutor
import org.springframework.web.bind.annotation.*
Expand All @@ -24,10 +21,16 @@ class CompilerRestController(private val kotlinProjectExecutor: KotlinProjectExe
@PostMapping("/translate")
fun translateKotlinProjectEndpoint(
@RequestBody project: Project,
@RequestParam(defaultValue = "false") ir: Boolean
): TranslationJSResult {
return if (ir) kotlinProjectExecutor.convertToJsIr(project)
else kotlinProjectExecutor.convertToJs(project)
@RequestParam(defaultValue = "false") ir: Boolean,
@RequestParam(defaultValue = "js") compiler: String
): TranslationResultWithJsCode {
if (!ir) {
return kotlinProjectExecutor.convertToJs(project)
}
return when (KotlinTranslatableCompiler.valueOf(compiler.uppercase())) {
KotlinTranslatableCompiler.JS -> kotlinProjectExecutor.convertToJsIr(project)
KotlinTranslatableCompiler.WASM -> kotlinProjectExecutor.convertToWasm(project)
}
}

@PostMapping("/complete")
Expand Down
17 changes: 15 additions & 2 deletions src/main/kotlin/com/compiler/server/model/ExecutionResult.kt
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,24 @@ open class ExecutionResult(
private fun textWithError() = text.startsWith(ERROR_STREAM_START)
}

abstract class TranslationResultWithJsCode(
open val jsCode: String?,
errors: Map<String, List<ErrorDescriptor>>,
exception: ExceptionDescriptor?
) : ExecutionResult(errors, exception)

data class TranslationJSResult(
val jsCode: String? = null,
override val jsCode: String? = null,
override var exception: ExceptionDescriptor? = null,
override var errors: Map<String, List<ErrorDescriptor>> = emptyMap()
) : ExecutionResult(errors, exception)
) : TranslationResultWithJsCode(jsCode, errors, exception)

data class TranslationWasmResult(
override val jsCode: String? = null,
val wasm: ByteArray,
override var exception: ExceptionDescriptor? = null,
override var errors: Map<String, List<ErrorDescriptor>> = emptyMap()
) : TranslationResultWithJsCode(jsCode, errors, exception)

@JsonInclude(JsonInclude.Include.NON_EMPTY)
class JunitExecutionResult(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package com.compiler.server.model

enum class KotlinTranslatableCompiler {
JS,
WASM
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,8 @@ package com.compiler.server.model.bean

import java.io.File

class LibrariesFile(val jvm: File, val js: File)
class LibrariesFile(
val jvm: File,
val js: File,
val wasm: File
)
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,7 @@ package com.compiler.server.service

import com.compiler.server.compiler.KotlinFile
import com.compiler.server.compiler.components.*
import com.compiler.server.model.ErrorDescriptor
import com.compiler.server.model.ExecutionResult
import com.compiler.server.model.Project
import com.compiler.server.model.TranslationJSResult
import com.compiler.server.model.*
import com.compiler.server.model.bean.VersionInfo
import component.KotlinEnvironment
import model.Completion
Expand Down Expand Up @@ -41,14 +38,18 @@ class KotlinProjectExecutor(
}.also { logExecutionResult(project, it) }
}

fun convertToJs(project: Project): TranslationJSResult {
fun convertToJs(project: Project): TranslationResultWithJsCode {
return convertJsWithConverter(project, kotlinToJSTranslator::doTranslate)
}

fun convertToJsIr(project: Project): TranslationJSResult {
fun convertToJsIr(project: Project): TranslationResultWithJsCode {
return convertJsWithConverter(project, kotlinToJSTranslator::doTranslateWithIr)
}

fun convertToWasm(project: Project): TranslationResultWithJsCode {
return convertJsWithConverter(project, kotlinToJSTranslator::doTranslateWithWasm)
}

fun complete(project: Project, line: Int, character: Int): List<Completion> {
return kotlinEnvironment.environment {
val file = getFilesFrom(project, it).first()
Expand Down Expand Up @@ -83,8 +84,8 @@ class KotlinProjectExecutor(

private fun convertJsWithConverter(
project: Project,
converter: (List<KtFile>, List<String>, KotlinCoreEnvironment) -> TranslationJSResult
): TranslationJSResult {
converter: (List<KtFile>, List<String>, KotlinCoreEnvironment) -> TranslationResultWithJsCode
): TranslationResultWithJsCode {
return kotlinEnvironment.environment { environment ->
val files = getFilesFrom(project, environment).map { it.kotlinFile }
kotlinToJSTranslator.translate(
Expand Down

0 comments on commit 2d87c39

Please sign in to comment.