[K/Wasm] Add Binaryen sizes to Wasm size tests
This commit is contained in:
+2
@@ -1,7 +1,9 @@
|
||||
// TARGET_BACKEND: WASM
|
||||
|
||||
// RUN_THIRD_PARTY_OPTIMIZER
|
||||
// WASM_DCE_EXPECTED_OUTPUT_SIZE: wasm 12_559
|
||||
// WASM_DCE_EXPECTED_OUTPUT_SIZE: mjs 4_526
|
||||
// WASM_OPT_EXPECTED_OUTPUT_SIZE: 2_640
|
||||
|
||||
// FILE: test.kt
|
||||
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
// TARGET_BACKEND: WASM
|
||||
|
||||
// RUN_THIRD_PARTY_OPTIMIZER
|
||||
// WASM_DCE_EXPECTED_OUTPUT_SIZE: wasm 38_992
|
||||
// WASM_DCE_EXPECTED_OUTPUT_SIZE: mjs 4_552
|
||||
// WASM_OPT_EXPECTED_OUTPUT_SIZE: 9_847
|
||||
|
||||
fun box(): String {
|
||||
println("Hello, World!")
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
// TARGET_BACKEND: WASM
|
||||
|
||||
// RUN_THIRD_PARTY_OPTIMIZER
|
||||
// WASM_DCE_EXPECTED_OUTPUT_SIZE: wasm 13_922
|
||||
// WASM_DCE_EXPECTED_OUTPUT_SIZE: mjs 5_081
|
||||
// WASM_OPT_EXPECTED_OUTPUT_SIZE: 4_317
|
||||
|
||||
// FILE: test.kt
|
||||
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
// TARGET_BACKEND: WASM
|
||||
|
||||
// RUN_THIRD_PARTY_OPTIMIZER
|
||||
// WASM_DCE_EXPECTED_OUTPUT_SIZE: wasm 17_619
|
||||
// WASM_DCE_EXPECTED_OUTPUT_SIZE: mjs 4_398
|
||||
// WASM_OPT_EXPECTED_OUTPUT_SIZE: 5_841
|
||||
|
||||
object Simple
|
||||
|
||||
|
||||
+2
@@ -1,6 +1,8 @@
|
||||
// TARGET_BACKEND: WASM
|
||||
|
||||
// RUN_THIRD_PARTY_OPTIMIZER
|
||||
// WASM_DCE_EXPECTED_OUTPUT_SIZE: wasm 12_601
|
||||
// WASM_DCE_EXPECTED_OUTPUT_SIZE: mjs 4_398
|
||||
// WASM_OPT_EXPECTED_OUTPUT_SIZE: 3_743
|
||||
|
||||
fun box() = "OK"
|
||||
@@ -1,7 +1,9 @@
|
||||
// TARGET_BACKEND: JS_IR
|
||||
// TARGET_BACKEND: WASM
|
||||
|
||||
// RUN_THIRD_PARTY_OPTIMIZER
|
||||
// WASM_DCE_EXPECTED_OUTPUT_SIZE: wasm 13_109
|
||||
// WASM_OPT_EXPECTED_OUTPUT_SIZE: 3_900
|
||||
|
||||
interface I {
|
||||
fun foo() = "OK"
|
||||
|
||||
+4
@@ -39,4 +39,8 @@ object WasmEnvironmentConfigurationDirectives : SimpleDirectivesContainer() {
|
||||
description = "Enables generation of source map",
|
||||
applicability = DirectiveApplicability.Global
|
||||
)
|
||||
|
||||
val RUN_THIRD_PARTY_OPTIMIZER by directive(
|
||||
description = "Also run third-party optimizer (for now, only binaryen is supported) after the main compilation",
|
||||
)
|
||||
}
|
||||
|
||||
@@ -54,6 +54,7 @@ object BinaryArtifacts {
|
||||
class Wasm(
|
||||
val compilerResult: WasmCompilerResult,
|
||||
val compilerResultWithDCE: WasmCompilerResult,
|
||||
val compilerResultWithOptimizer: WasmCompilerResult?,
|
||||
) : ResultingArtifact.Binary<Wasm>() {
|
||||
override val kind: BinaryKind<Wasm>
|
||||
get() = ArtifactKinds.Wasm
|
||||
|
||||
+2
-33
@@ -13,6 +13,7 @@ import org.gradle.work.NormalizeLineEndings
|
||||
import org.jetbrains.kotlin.gradle.targets.js.ir.KotlinJsIrCompilation
|
||||
import org.jetbrains.kotlin.gradle.tasks.registerTask
|
||||
import org.jetbrains.kotlin.gradle.utils.newFileProperty
|
||||
import org.jetbrains.kotlin.platform.wasm.BinaryenConfig
|
||||
import javax.inject.Inject
|
||||
|
||||
@DisableCachingByDefault
|
||||
@@ -33,39 +34,7 @@ constructor() : AbstractExecTask<BinaryenExec>(BinaryenExec::class.java) {
|
||||
}
|
||||
|
||||
@Input
|
||||
var binaryenArgs: MutableList<String> = mutableListOf(
|
||||
// Proposals
|
||||
"--enable-gc",
|
||||
"--enable-reference-types",
|
||||
"--enable-exception-handling",
|
||||
"--enable-bulk-memory", // For array initialization from data sections
|
||||
|
||||
// Other options
|
||||
"--enable-nontrapping-float-to-int",
|
||||
// It's turned out that it's not safe
|
||||
// "--closed-world",
|
||||
|
||||
// Optimizations:
|
||||
// Note the order and repetition of the next options matter.
|
||||
//
|
||||
// About Binaryen optimizations:
|
||||
// GC Optimization Guidebook -- https://github.com/WebAssembly/binaryen/wiki/GC-Optimization-Guidebook
|
||||
// Optimizer Cookbook -- https://github.com/WebAssembly/binaryen/wiki/Optimizer-Cookbook
|
||||
//
|
||||
"--inline-functions-with-loops",
|
||||
"--traps-never-happen",
|
||||
"--fast-math",
|
||||
// without "--type-merging" it produces increases the size
|
||||
// "--type-ssa",
|
||||
"-O3",
|
||||
"-O3",
|
||||
"--gufa",
|
||||
"-O3",
|
||||
// requires --closed-world
|
||||
// "--type-merging",
|
||||
"-O3",
|
||||
"-Oz",
|
||||
)
|
||||
var binaryenArgs: MutableList<String> = BinaryenConfig.binaryenArgs.toMutableList()
|
||||
|
||||
@PathSensitive(PathSensitivity.RELATIVE)
|
||||
@InputFile
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.tasks.testing.Test
|
||||
import org.jetbrains.kotlin.gradle.targets.js.binaryen.BinaryenRootExtension
|
||||
import org.jetbrains.kotlin.gradle.targets.js.binaryen.BinaryenRootPlugin
|
||||
|
||||
private object BinaryenUtils {
|
||||
lateinit var binaryenPlugin: BinaryenRootExtension
|
||||
|
||||
fun useBinaryenPlugin(project: Project) {
|
||||
binaryenPlugin = BinaryenRootPlugin.apply(project.rootProject)
|
||||
}
|
||||
}
|
||||
|
||||
fun Project.useBinaryenPlugin() {
|
||||
BinaryenUtils.useBinaryenPlugin(this)
|
||||
}
|
||||
|
||||
fun Test.setupBinaryen() {
|
||||
dependsOn(BinaryenUtils.binaryenPlugin.setupTaskProvider)
|
||||
val binaryenExecutablePath = project.provider {
|
||||
BinaryenUtils.binaryenPlugin.requireConfigured().executablePath.absolutePath
|
||||
}
|
||||
doFirst {
|
||||
systemProperty("binaryen.path", binaryenExecutablePath.get())
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.platform.wasm
|
||||
|
||||
object BinaryenConfig {
|
||||
val binaryenArgs = listOf(
|
||||
// Proposals
|
||||
"--enable-gc",
|
||||
"--enable-reference-types",
|
||||
"--enable-exception-handling",
|
||||
"--enable-bulk-memory", // For array initialization from data sections
|
||||
|
||||
// Other options
|
||||
"--enable-nontrapping-float-to-int",
|
||||
// It's turned out that it's not safe
|
||||
// "--closed-world",
|
||||
|
||||
// Optimizations:
|
||||
// Note the order and repetition of the next options matter.
|
||||
//
|
||||
// About Binaryen optimizations:
|
||||
// GC Optimization Guidebook -- https://github.com/WebAssembly/binaryen/wiki/GC-Optimization-Guidebook
|
||||
// Optimizer Cookbook -- https://github.com/WebAssembly/binaryen/wiki/Optimizer-Cookbook
|
||||
//
|
||||
"--inline-functions-with-loops",
|
||||
"--traps-never-happen",
|
||||
"--fast-math",
|
||||
// without "--type-merging" it produces increases the size
|
||||
// "--type-ssa",
|
||||
"-O3",
|
||||
"-O3",
|
||||
"--gufa",
|
||||
"-O3",
|
||||
// requires --closed-world
|
||||
// "--type-merging",
|
||||
"-O3",
|
||||
"-Oz",
|
||||
)
|
||||
}
|
||||
@@ -79,6 +79,7 @@ val generationRoot = projectDir.resolve("tests-gen")
|
||||
|
||||
useD8Plugin()
|
||||
useNodeJsPlugin()
|
||||
useBinaryenPlugin()
|
||||
optInToExperimentalCompilerApi()
|
||||
|
||||
sourceSets {
|
||||
@@ -147,6 +148,7 @@ fun Project.wasmProjectTest(
|
||||
workingDir = rootDir
|
||||
setupV8()
|
||||
setupNodeJs()
|
||||
setupBinaryen()
|
||||
setupSpiderMonkey()
|
||||
useJUnitPlatform()
|
||||
setupWasmStdlib("js")
|
||||
|
||||
+19
-1
@@ -7,6 +7,7 @@ package org.jetbrains.kotlin.wasm.test.converters
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.phaser.PhaseConfig
|
||||
import org.jetbrains.kotlin.backend.common.phaser.toPhaseMap
|
||||
import org.jetbrains.kotlin.backend.wasm.WasmCompilerResult
|
||||
import org.jetbrains.kotlin.backend.wasm.compileToLoweredIr
|
||||
import org.jetbrains.kotlin.backend.wasm.compileWasm
|
||||
import org.jetbrains.kotlin.backend.wasm.dce.eliminateDeadDeclarations
|
||||
@@ -32,12 +33,15 @@ import org.jetbrains.kotlin.test.model.BinaryArtifacts
|
||||
import org.jetbrains.kotlin.test.model.TestModule
|
||||
import org.jetbrains.kotlin.test.services.*
|
||||
import org.jetbrains.kotlin.test.services.configuration.WasmEnvironmentConfigurator
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.runIf
|
||||
import org.jetbrains.kotlin.wasm.test.handlers.getWasmTestOutputDirectory
|
||||
import org.jetbrains.kotlin.wasm.test.tools.WasmOptimizer
|
||||
import java.io.File
|
||||
|
||||
class WasmBackendFacade(
|
||||
private val testServices: TestServices
|
||||
) : AbstractTestFacade<BinaryArtifacts.KLib, BinaryArtifacts.Wasm>() {
|
||||
private val supportedOptimizer: WasmOptimizer = WasmOptimizer.Binaryen
|
||||
|
||||
override val inputKind = ArtifactKinds.KLib
|
||||
override val outputKind = ArtifactKinds.Wasm
|
||||
@@ -126,13 +130,27 @@ class WasmBackendFacade(
|
||||
|
||||
return BinaryArtifacts.Wasm(
|
||||
compilerResult,
|
||||
compilerResultWithDCE
|
||||
compilerResultWithDCE,
|
||||
runIf(WasmEnvironmentConfigurationDirectives.RUN_THIRD_PARTY_OPTIMIZER in testServices.moduleStructure.allDirectives) {
|
||||
compilerResultWithDCE.runThirdPartyOptimizer()
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
override fun shouldRunAnalysis(module: TestModule): Boolean {
|
||||
return WasmEnvironmentConfigurator.isMainModule(module, testServices)
|
||||
}
|
||||
|
||||
private fun WasmCompilerResult.runThirdPartyOptimizer(): WasmCompilerResult {
|
||||
val (newWasm, newWat) = supportedOptimizer.run(wasm, withText = wat != null)
|
||||
return WasmCompilerResult(
|
||||
wat = newWat,
|
||||
jsUninstantiatedWrapper = jsUninstantiatedWrapper,
|
||||
jsWrapper = jsWrapper,
|
||||
sourceMap = null,
|
||||
wasm = newWasm
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun extractTestPackage(testServices: TestServices): String? {
|
||||
|
||||
@@ -7,12 +7,9 @@ package org.jetbrains.kotlin.wasm.test.handlers
|
||||
|
||||
import org.jetbrains.kotlin.backend.wasm.WasmCompilerResult
|
||||
import org.jetbrains.kotlin.backend.wasm.writeCompilationResult
|
||||
import org.jetbrains.kotlin.js.JavaScript
|
||||
import org.jetbrains.kotlin.test.DebugMode
|
||||
import org.jetbrains.kotlin.test.InTextDirectivesUtils
|
||||
import org.jetbrains.kotlin.test.directives.WasmEnvironmentConfigurationDirectives
|
||||
import org.jetbrains.kotlin.test.directives.WasmEnvironmentConfigurationDirectives.RUN_UNIT_TESTS
|
||||
import org.jetbrains.kotlin.test.model.TestFile
|
||||
import org.jetbrains.kotlin.test.services.TestServices
|
||||
import org.jetbrains.kotlin.test.services.moduleStructure
|
||||
import org.jetbrains.kotlin.wasm.test.tools.WasmVM
|
||||
@@ -21,6 +18,8 @@ import java.io.File
|
||||
class WasiBoxRunner(
|
||||
testServices: TestServices
|
||||
) : AbstractWasmArtifactsCollector(testServices) {
|
||||
private val vmsToCheck: List<WasmVM> = listOf(WasmVM.NodeJs)
|
||||
|
||||
override fun processAfterAllModules(someAssertionWasFailed: Boolean) {
|
||||
if (!someAssertionWasFailed) {
|
||||
runWasmCode()
|
||||
@@ -66,6 +65,7 @@ class WasiBoxRunner(
|
||||
dir.mkdirs()
|
||||
|
||||
writeCompilationResult(res, dir, baseFileName)
|
||||
|
||||
File(dir, "test.mjs").writeText(testWasi)
|
||||
|
||||
if (debugMode >= DebugMode.DEBUG) {
|
||||
@@ -79,25 +79,27 @@ class WasiBoxRunner(
|
||||
val testFileText = originalFile.readText()
|
||||
val failsIn: List<String> = InTextDirectivesUtils.findListWithPrefixes(testFileText, "// WASM_FAILS_IN: ")
|
||||
|
||||
val exception = WasmVM.NodeJs.runWithCathedExceptions(
|
||||
debugMode = debugMode,
|
||||
disableExceptions = false,
|
||||
failsIn = failsIn,
|
||||
entryMjs = "test.mjs",
|
||||
jsFilePaths = emptyList(),
|
||||
workingDirectory = dir
|
||||
)
|
||||
|
||||
if (exception != null) {
|
||||
throw exception
|
||||
val exceptions = vmsToCheck.mapNotNull { vm ->
|
||||
vm.runWithCathedExceptions(
|
||||
debugMode = debugMode,
|
||||
disableExceptions = false,
|
||||
failsIn = failsIn,
|
||||
entryMjs = "test.mjs",
|
||||
jsFilePaths = emptyList(),
|
||||
workingDirectory = dir
|
||||
)
|
||||
}
|
||||
|
||||
if (mode == "dce") {
|
||||
checkExpectedOutputSize(debugMode, testFileText, dir)
|
||||
processExceptions(exceptions)
|
||||
|
||||
when (mode) {
|
||||
"dce" -> checkExpectedDceOutputSize(debugMode, testFileText, dir)
|
||||
"optimized" -> checkExpectedOptimizedOutputSize(debugMode, testFileText, dir)
|
||||
}
|
||||
}
|
||||
|
||||
writeToFilesAndRunTest("dev", artifacts.compilerResult)
|
||||
writeToFilesAndRunTest("dce", artifacts.compilerResultWithDCE)
|
||||
artifacts.compilerResultWithOptimizer?.let { writeToFilesAndRunTest("optimized", it) }
|
||||
}
|
||||
}
|
||||
@@ -7,13 +7,10 @@ package org.jetbrains.kotlin.wasm.test.handlers
|
||||
|
||||
import org.jetbrains.kotlin.backend.wasm.WasmCompilerResult
|
||||
import org.jetbrains.kotlin.backend.wasm.writeCompilationResult
|
||||
import org.jetbrains.kotlin.js.JavaScript
|
||||
import org.jetbrains.kotlin.test.DebugMode
|
||||
import org.jetbrains.kotlin.test.InTextDirectivesUtils
|
||||
import org.jetbrains.kotlin.test.directives.WasmEnvironmentConfigurationDirectives
|
||||
import org.jetbrains.kotlin.test.directives.WasmEnvironmentConfigurationDirectives.DISABLE_WASM_EXCEPTION_HANDLING
|
||||
import org.jetbrains.kotlin.test.directives.WasmEnvironmentConfigurationDirectives.RUN_UNIT_TESTS
|
||||
import org.jetbrains.kotlin.test.model.TestFile
|
||||
import org.jetbrains.kotlin.test.services.TestServices
|
||||
import org.jetbrains.kotlin.test.services.moduleStructure
|
||||
import org.jetbrains.kotlin.wasm.test.tools.WasmVM
|
||||
@@ -22,6 +19,8 @@ import java.io.File
|
||||
class WasmBoxRunner(
|
||||
testServices: TestServices
|
||||
) : AbstractWasmArtifactsCollector(testServices) {
|
||||
private val vmsToCheck: List<WasmVM> = listOf(WasmVM.V8, WasmVM.SpiderMonkey)
|
||||
|
||||
override fun processAfterAllModules(someAssertionWasFailed: Boolean) {
|
||||
if (!someAssertionWasFailed) {
|
||||
runWasmCode()
|
||||
@@ -71,6 +70,7 @@ class WasmBoxRunner(
|
||||
dir.mkdirs()
|
||||
|
||||
writeCompilationResult(res, dir, baseFileName)
|
||||
|
||||
File(dir, "test.mjs").writeText(testJs)
|
||||
|
||||
val (jsFilePaths) = collectedJsArtifacts.saveJsArtifacts(dir)
|
||||
@@ -117,7 +117,7 @@ class WasmBoxRunner(
|
||||
|
||||
val disableExceptions = DISABLE_WASM_EXCEPTION_HANDLING in testServices.moduleStructure.allDirectives
|
||||
|
||||
val exceptions = listOf(WasmVM.V8, WasmVM.SpiderMonkey).mapNotNull { vm ->
|
||||
val exceptions = vmsToCheck.mapNotNull { vm ->
|
||||
vm.runWithCathedExceptions(
|
||||
debugMode = debugMode,
|
||||
disableExceptions = disableExceptions,
|
||||
@@ -130,13 +130,15 @@ class WasmBoxRunner(
|
||||
|
||||
processExceptions(exceptions)
|
||||
|
||||
if (mode == "dce") {
|
||||
checkExpectedOutputSize(debugMode, testFileText, dir)
|
||||
when (mode) {
|
||||
"dce" -> checkExpectedDceOutputSize(debugMode, testFileText, dir)
|
||||
"optimized" -> checkExpectedOptimizedOutputSize(debugMode, testFileText, dir)
|
||||
}
|
||||
}
|
||||
|
||||
writeToFilesAndRunTest("dev", artifacts.compilerResult)
|
||||
writeToFilesAndRunTest("dce", artifacts.compilerResultWithDCE)
|
||||
artifacts.compilerResultWithOptimizer?.let { writeToFilesAndRunTest("optimized", it) }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -169,8 +171,8 @@ internal fun WasmVM.runWithCathedExceptions(
|
||||
return null
|
||||
}
|
||||
|
||||
fun checkExpectedOutputSize(debugMode: DebugMode, testFileContent: String, testDir: File) {
|
||||
val expectedSizes =
|
||||
fun checkExpectedDceOutputSize(debugMode: DebugMode, testFileContent: String, testDir: File) {
|
||||
val expectedDceSizes =
|
||||
InTextDirectivesUtils.findListWithPrefixes(testFileContent, "// WASM_DCE_EXPECTED_OUTPUT_SIZE: ")
|
||||
.map {
|
||||
val i = it.indexOf(' ')
|
||||
@@ -178,10 +180,27 @@ fun checkExpectedOutputSize(debugMode: DebugMode, testFileContent: String, testD
|
||||
val size = it.substring(i + 1)
|
||||
extension.trim().lowercase() to size.filter(Char::isDigit).toInt()
|
||||
}
|
||||
assertExpectedSizesMatchActual(debugMode, testDir, expectedDceSizes)
|
||||
}
|
||||
|
||||
fun checkExpectedOptimizedOutputSize(debugMode: DebugMode, testFileContent: String, testDir: File) {
|
||||
val expectedOptimizeSizes = InTextDirectivesUtils
|
||||
.findListWithPrefixes(testFileContent, "// WASM_OPT_EXPECTED_OUTPUT_SIZE: ")
|
||||
.lastOrNull()
|
||||
?.filter(Char::isDigit)
|
||||
?.toInt() ?: return
|
||||
|
||||
assertExpectedSizesMatchActual(debugMode, testDir, listOf("wasm" to expectedOptimizeSizes))
|
||||
}
|
||||
|
||||
private fun assertExpectedSizesMatchActual(
|
||||
debugMode: DebugMode,
|
||||
testDir: File,
|
||||
fileExtensionToItsExpectedSize: Iterable<Pair<String, Int>>
|
||||
) {
|
||||
val filesByExtension = testDir.listFiles()?.groupBy { it.extension }.orEmpty()
|
||||
|
||||
val errors = expectedSizes.mapNotNull { (extension, expectedSize) ->
|
||||
val errors = fileExtensionToItsExpectedSize.mapNotNull { (extension, expectedSize) ->
|
||||
val totalSize = filesByExtension[extension].orEmpty().sumOf { it.length() }
|
||||
|
||||
val thresholdPercent = 1
|
||||
@@ -204,4 +223,4 @@ fun checkExpectedOutputSize(debugMode: DebugMode, testFileContent: String, testD
|
||||
}
|
||||
|
||||
if (errors.isNotEmpty()) throw AssertionError(errors.joinToString("\n"))
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.wasm.test.tools
|
||||
|
||||
import org.jetbrains.kotlin.platform.wasm.BinaryenConfig
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.runIf
|
||||
import java.io.ByteArrayOutputStream
|
||||
import java.io.File
|
||||
import kotlin.test.fail
|
||||
|
||||
sealed interface WasmOptimizer {
|
||||
fun run(wasmInput: ByteArray, withText: Boolean = false): OptimizationResult
|
||||
|
||||
data class OptimizationResult(val wasm: ByteArray, val wat: String?)
|
||||
|
||||
object Binaryen : WasmOptimizer {
|
||||
private val binaryenPath = System.getProperty("binaryen.path")
|
||||
|
||||
override fun run(wasmInput: ByteArray, withText: Boolean): OptimizationResult {
|
||||
val command = arrayOf(binaryenPath, *BinaryenConfig.binaryenArgs.toTypedArray())
|
||||
return OptimizationResult(
|
||||
exec(command, wasmInput),
|
||||
runIf(withText) { exec(command + "-S", wasmInput).toString(Charsets.UTF_8) }
|
||||
)
|
||||
}
|
||||
|
||||
private fun exec(command: Array<String>, input: ByteArray): ByteArray {
|
||||
val timestamp = System.currentTimeMillis()
|
||||
val savedInput = File
|
||||
.createTempFile("binaryen_input_$timestamp", ".wasm")
|
||||
.apply { writeBytes(input) }
|
||||
val savedOutput = File
|
||||
.createTempFile("binaryen_output_$timestamp", ".wasm")
|
||||
|
||||
val processBuilder = ProcessBuilder(*(command + listOf("-o", savedOutput.absolutePath, savedInput.absolutePath)))
|
||||
.redirectErrorStream(true)
|
||||
|
||||
val exitValue = processBuilder.start().waitFor()
|
||||
|
||||
if (exitValue != 0) {
|
||||
val commandString = command.joinToString(" ") { escapeShellArgument(it) }
|
||||
fail("Command \"$commandString\" terminated with exit code $exitValue")
|
||||
}
|
||||
|
||||
return savedOutput.readBytes()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -119,5 +119,5 @@ internal class ExternalTool(val path: String) {
|
||||
}
|
||||
}
|
||||
|
||||
private fun escapeShellArgument(arg: String): String =
|
||||
internal fun escapeShellArgument(arg: String): String =
|
||||
"'${arg.replace("'", "'\\''")}'"
|
||||
|
||||
Reference in New Issue
Block a user