From 3fb1096c18f2f1be82823ab7c997c8e6e9a8393b Mon Sep 17 00:00:00 2001 From: Sergej Jaskiewicz Date: Tue, 14 Dec 2021 16:42:24 +0300 Subject: [PATCH] [JS IR] Support IR dump in JS tests --- compiler/test-infrastructure/ReadMe.md | 25 ++++++++++++++++ .../org/jetbrains/kotlin/test/DebugMode.kt | 30 +++++++++++++++++++ .../js/test/converters/JsIrBackendFacade.kt | 21 +++++++++++-- .../kotlin/js/testOld/BasicWasmBoxTest.kt | 15 ++++------ 4 files changed, 79 insertions(+), 12 deletions(-) create mode 100644 compiler/tests-common/tests/org/jetbrains/kotlin/test/DebugMode.kt diff --git a/compiler/test-infrastructure/ReadMe.md b/compiler/test-infrastructure/ReadMe.md index 0a97b14ad50..a16549e89e7 100644 --- a/compiler/test-infrastructure/ReadMe.md +++ b/compiler/test-infrastructure/ReadMe.md @@ -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 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. diff --git a/compiler/tests-common/tests/org/jetbrains/kotlin/test/DebugMode.kt b/compiler/tests-common/tests/org/jetbrains/kotlin/test/DebugMode.kt new file mode 100644 index 00000000000..3117af89ef3 --- /dev/null +++ b/compiler/tests-common/tests/org/jetbrains/kotlin/test/DebugMode.kt @@ -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 + } + } +} diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/converters/JsIrBackendFacade.kt b/js/js.tests/test/org/jetbrains/kotlin/js/test/converters/JsIrBackendFacade.kt index 9cf5fe05f33..7acd17f513b 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/converters/JsIrBackendFacade.kt +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/converters/JsIrBackendFacade.kt @@ -6,6 +6,7 @@ package org.jetbrains.kotlin.js.test.converters 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.config.CommonConfigurationKeys 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.Psi2IrTranslator 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.frontend.classic.ClassicFrontendOutputArtifact import org.jetbrains.kotlin.test.frontend.classic.moduleDescriptorProvider @@ -105,6 +107,21 @@ class JsIrBackendFacade( ).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( irModuleFragment, MainModule.Klib(inputArtifact.outputFile.absolutePath), @@ -113,7 +130,7 @@ class JsIrBackendFacade( irModuleFragment.irBuiltins, symbolTable, deserializer, - PhaseConfig(jsPhases), // TODO debug mode + phaseConfig, exportedDeclarations = setOf(FqName.fromSegments(listOfNotNull(testPackage, TEST_FUNCTION))), dceDriven = false, dceRuntimeDiagnostic = null, @@ -341,4 +358,4 @@ fun String.augmentWithModuleName(moduleName: String): String { return removeSuffix("_v5.js") + "-${moduleName}_v5.js" } -fun File.augmentWithModuleName(moduleName: String): File = File(absolutePath.augmentWithModuleName(moduleName)) \ No newline at end of file +fun File.augmentWithModuleName(moduleName: String): File = File(absolutePath.augmentWithModuleName(moduleName)) diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/testOld/BasicWasmBoxTest.kt b/js/js.tests/test/org/jetbrains/kotlin/js/testOld/BasicWasmBoxTest.kt index 8e0680d0f0e..ddd35fa86a7 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/testOld/BasicWasmBoxTest.kt +++ b/js/js.tests/test/org/jetbrains/kotlin/js/testOld/BasicWasmBoxTest.kt @@ -32,6 +32,7 @@ import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.psi.KtNamedFunction import org.jetbrains.kotlin.psi.KtPsiFactory import org.jetbrains.kotlin.resolve.CompilerEnvironment +import org.jetbrains.kotlin.test.DebugMode import org.jetbrains.kotlin.test.Directives import org.jetbrains.kotlin.test.KotlinTestWithEnvironment import org.jetbrains.kotlin.test.TestFiles @@ -147,15 +148,9 @@ abstract class BasicWasmBoxTest( testFunction: String ) { val filesToCompile = units.map { (it as TranslationUnit.SourceFile).file } - val debugMode: Int = when (System.getProperty("kotlin.wasm.debugMode")) { - "2", "super_debug" -> 2 - "1", "true", "debug" -> 1 - "0", "false", "", null -> 0 - else -> 0 - } - - val phaseConfig = if (debugMode >= 1) { - val allPhasesSet = if (debugMode >= 2) wasmPhases.toPhaseMap().values.toSet() else emptySet() + val debugMode = DebugMode.fromSystemProperty("kotlin.wasm.debugMode") + val phaseConfig = if (debugMode >= DebugMode.DEBUG) { + val allPhasesSet = if (debugMode >= DebugMode.SUPER_DEBUG) wasmPhases.toPhaseMap().values.toSet() else emptySet() val dumpOutputDir = File(outputWatFile.parent, outputWatFile.nameWithoutExtension + "-irdump") println("\n ------ Dumping phases to file://$dumpOutputDir") println("\n ------ KT file://${testFile.absolutePath}") @@ -211,7 +206,7 @@ abstract class BasicWasmBoxTest( outputJsFile.write(compilerResult.js + "\n" + testRunner) - if (debugMode >= 2) { + if (debugMode >= DebugMode.SUPER_DEBUG) { createDirectoryToRunInBrowser(outputBrowserDir, compilerResult) } }