[JS IR] Support IR dump in JS tests

This commit is contained in:
Sergej Jaskiewicz
2021-12-14 16:42:24 +03:00
committed by Space
parent 2436ca3d8b
commit 3fb1096c18
4 changed files with 79 additions and 12 deletions
+25
View File
@@ -337,6 +337,31 @@ abstract class MyAnotherAbstractTestRunner : MyAbstractTestRunner() {
} }
``` ```
# Debugging tests (JS and WASM only):
Kotlin/JS and Kotlin/WASM tests support the following system properties to make debugging them more convenient:
- `kotlin.js.debugMode` for setting a debug mode for Kotlin/JS tests
- `kotlin.wasm.debugMode` for setting a debug mode for Kotlin/WASM tests
- `org.jetbrains.kotlin.compiler.ir.dump.strategy` for the IR dump strategy to use. Set it to `"KotlinLike"`
if you want the IR dump to be more human-readable.
Note that to pass a system property from gradle task invocation, its name should be prefixed with `fd.`.
For example, to debug Kotlin/JS tests, run:
```
./gradlew :js:js.tests:jsIrTest -Pfd.kotlin.js.debugMode=2
```
To debug WASM tests, run:
```
./gradlew :js:js.tests:wasmTest -Pfd.kotlin.wasm.debugMode=2
```
Values of the debug mode: `0` (or `false`), `1` (or `true`), `2`.
Debug mode `2` will ensure that IR is dumped to a file after each lowering phase.
The IR dumps will appear next to the generated `.js` or `.wat` file.
# Code style # Code style
Please keep your abstract test runners as simple as possible. Ideally each abstract test runner should contain **only** test configuration with DSL and nothing else. All services implementations should be declared in separate files. Please keep your abstract test runners as simple as possible. Ideally each abstract test runner should contain **only** test configuration with DSL and nothing else. All services implementations should be declared in separate files.
@@ -0,0 +1,30 @@
/*
* Copyright 2010-2021 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.test
/**
* Represents a mode fore debugging tests. Depending on what is tested, can represent different things.
* For example, in JS IR and WASM tests the selected mode will determine if the test output should include IR dumps.
*/
enum class DebugMode {
NONE,
DEBUG,
SUPER_DEBUG;
companion object {
/**
* Obtains a [DebugMode] from the system property with the given [key].
* If the property is not defined, returns [NONE].
*/
fun fromSystemProperty(key: String): DebugMode = when (System.getProperty(key)) {
"2", "super_debug" -> SUPER_DEBUG
"1", "true", "debug" -> DEBUG
"0", "false", "", null -> NONE
else -> NONE
}
}
}
@@ -6,6 +6,7 @@
package org.jetbrains.kotlin.js.test.converters package org.jetbrains.kotlin.js.test.converters
import org.jetbrains.kotlin.backend.common.phaser.PhaseConfig import org.jetbrains.kotlin.backend.common.phaser.PhaseConfig
import org.jetbrains.kotlin.backend.common.phaser.toPhaseMap
import org.jetbrains.kotlin.backend.common.serialization.signature.IdSignatureDescriptor import org.jetbrains.kotlin.backend.common.serialization.signature.IdSignatureDescriptor
import org.jetbrains.kotlin.config.CommonConfigurationKeys import org.jetbrains.kotlin.config.CommonConfigurationKeys
import org.jetbrains.kotlin.config.CompilerConfiguration import org.jetbrains.kotlin.config.CompilerConfiguration
@@ -34,6 +35,7 @@ import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.psi2ir.Psi2IrConfiguration import org.jetbrains.kotlin.psi2ir.Psi2IrConfiguration
import org.jetbrains.kotlin.psi2ir.Psi2IrTranslator import org.jetbrains.kotlin.psi2ir.Psi2IrTranslator
import org.jetbrains.kotlin.serialization.js.ModuleKind import org.jetbrains.kotlin.serialization.js.ModuleKind
import org.jetbrains.kotlin.test.DebugMode
import org.jetbrains.kotlin.test.directives.JsEnvironmentConfigurationDirectives import org.jetbrains.kotlin.test.directives.JsEnvironmentConfigurationDirectives
import org.jetbrains.kotlin.test.frontend.classic.ClassicFrontendOutputArtifact import org.jetbrains.kotlin.test.frontend.classic.ClassicFrontendOutputArtifact
import org.jetbrains.kotlin.test.frontend.classic.moduleDescriptorProvider import org.jetbrains.kotlin.test.frontend.classic.moduleDescriptorProvider
@@ -105,6 +107,21 @@ class JsIrBackendFacade(
).dump(module, firstTimeCompilation) ).dump(module, firstTimeCompilation)
} }
val debugMode = DebugMode.fromSystemProperty("kotlin.js.debugMode")
val phaseConfig = if (debugMode >= DebugMode.SUPER_DEBUG) {
val dumpOutputDir = File(
JsEnvironmentConfigurator.getJsArtifactsOutputDir(testServices),
JsEnvironmentConfigurator.getJsArtifactSimpleName(testServices, module.name) + "-irdump"
)
PhaseConfig(
jsPhases,
dumpToDirectory = dumpOutputDir.path,
toDumpStateAfter = jsPhases.toPhaseMap().values.toSet()
)
} else {
PhaseConfig(jsPhases)
}
val loweredIr = compileIr( val loweredIr = compileIr(
irModuleFragment, irModuleFragment,
MainModule.Klib(inputArtifact.outputFile.absolutePath), MainModule.Klib(inputArtifact.outputFile.absolutePath),
@@ -113,7 +130,7 @@ class JsIrBackendFacade(
irModuleFragment.irBuiltins, irModuleFragment.irBuiltins,
symbolTable, symbolTable,
deserializer, deserializer,
PhaseConfig(jsPhases), // TODO debug mode phaseConfig,
exportedDeclarations = setOf(FqName.fromSegments(listOfNotNull(testPackage, TEST_FUNCTION))), exportedDeclarations = setOf(FqName.fromSegments(listOfNotNull(testPackage, TEST_FUNCTION))),
dceDriven = false, dceDriven = false,
dceRuntimeDiagnostic = null, dceRuntimeDiagnostic = null,
@@ -341,4 +358,4 @@ fun String.augmentWithModuleName(moduleName: String): String {
return removeSuffix("_v5.js") + "-${moduleName}_v5.js" return removeSuffix("_v5.js") + "-${moduleName}_v5.js"
} }
fun File.augmentWithModuleName(moduleName: String): File = File(absolutePath.augmentWithModuleName(moduleName)) fun File.augmentWithModuleName(moduleName: String): File = File(absolutePath.augmentWithModuleName(moduleName))
@@ -32,6 +32,7 @@ import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.psi.KtNamedFunction import org.jetbrains.kotlin.psi.KtNamedFunction
import org.jetbrains.kotlin.psi.KtPsiFactory import org.jetbrains.kotlin.psi.KtPsiFactory
import org.jetbrains.kotlin.resolve.CompilerEnvironment import org.jetbrains.kotlin.resolve.CompilerEnvironment
import org.jetbrains.kotlin.test.DebugMode
import org.jetbrains.kotlin.test.Directives import org.jetbrains.kotlin.test.Directives
import org.jetbrains.kotlin.test.KotlinTestWithEnvironment import org.jetbrains.kotlin.test.KotlinTestWithEnvironment
import org.jetbrains.kotlin.test.TestFiles import org.jetbrains.kotlin.test.TestFiles
@@ -147,15 +148,9 @@ abstract class BasicWasmBoxTest(
testFunction: String testFunction: String
) { ) {
val filesToCompile = units.map { (it as TranslationUnit.SourceFile).file } val filesToCompile = units.map { (it as TranslationUnit.SourceFile).file }
val debugMode: Int = when (System.getProperty("kotlin.wasm.debugMode")) { val debugMode = DebugMode.fromSystemProperty("kotlin.wasm.debugMode")
"2", "super_debug" -> 2 val phaseConfig = if (debugMode >= DebugMode.DEBUG) {
"1", "true", "debug" -> 1 val allPhasesSet = if (debugMode >= DebugMode.SUPER_DEBUG) wasmPhases.toPhaseMap().values.toSet() else emptySet()
"0", "false", "", null -> 0
else -> 0
}
val phaseConfig = if (debugMode >= 1) {
val allPhasesSet = if (debugMode >= 2) wasmPhases.toPhaseMap().values.toSet() else emptySet()
val dumpOutputDir = File(outputWatFile.parent, outputWatFile.nameWithoutExtension + "-irdump") val dumpOutputDir = File(outputWatFile.parent, outputWatFile.nameWithoutExtension + "-irdump")
println("\n ------ Dumping phases to file://$dumpOutputDir") println("\n ------ Dumping phases to file://$dumpOutputDir")
println("\n ------ KT file://${testFile.absolutePath}") println("\n ------ KT file://${testFile.absolutePath}")
@@ -211,7 +206,7 @@ abstract class BasicWasmBoxTest(
outputJsFile.write(compilerResult.js + "\n" + testRunner) outputJsFile.write(compilerResult.js + "\n" + testRunner)
if (debugMode >= 2) { if (debugMode >= DebugMode.SUPER_DEBUG) {
createDirectoryToRunInBrowser(outputBrowserDir, compilerResult) createDirectoryToRunInBrowser(outputBrowserDir, compilerResult)
} }
} }