Skip to content

Commit 2b7c4f7

Browse files
JSMonkSpace Team
authored and
Space Team
committed
[K/Wasm] Don't add mappings into source-maps for unavailable sources
IDEA JavaScript debugger gets stuck if many files are listed inside source maps (^FL-27262). To help the debugger, we filter sources from modules not in the user project. It's a temporary solution until the third-party libraries debugging is supported (it depends on the issue with file absolute path in KLIB by default ^KT-58406)
1 parent e35e9ae commit 2b7c4f7

File tree

16 files changed

+105
-21
lines changed

16 files changed

+105
-21
lines changed

compiler/cli/cli-common/gen/org/jetbrains/kotlin/cli/common/arguments/K2JSCompilerArgumentsCopyGenerated.kt

+1
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ fun copyK2JSCompilerArguments(from: K2JSCompilerArguments, to: K2JSCompilerArgum
1919
to.friendModulesDisabled = from.friendModulesDisabled
2020
to.generateDts = from.generateDts
2121
to.generatePolyfills = from.generatePolyfills
22+
to.includeUnavailableSourcesIntoSourceMap = from.includeUnavailableSourcesIntoSourceMap
2223
to.includes = from.includes
2324
to.irBaseClassInMetadata = from.irBaseClassInMetadata
2425
to.irBuildCache = from.irBuildCache

compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/K2JSCompilerArguments.kt

+10
Original file line numberDiff line numberDiff line change
@@ -274,6 +274,16 @@ In combination with '-meta-info', this generates both IR and pre-IR versions of
274274
field = value
275275
}
276276

277+
@Argument(
278+
value = "-Xwasm-source-map-include-mappings-from-unavailable-sources",
279+
description = "Insert source mappings from libraries even if their sources are unavailable on the end-user machine."
280+
)
281+
var includeUnavailableSourcesIntoSourceMap = false
282+
set(value) {
283+
checkFrozen()
284+
field = value
285+
}
286+
277287
@Argument(
278288
value = "-Xir-dce-dump-reachability-info-to-file",
279289
valueDescription = "<path>",

compiler/cli/cli-js/src/org/jetbrains/kotlin/cli/js/K2JsIrCompiler.kt

+2
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,7 @@ class K2JsIrCompiler : CLICompiler<K2JSCompilerArguments>() {
209209
configuration.put(WasmConfigurationKeys.WASM_GENERATE_WAT, arguments.wasmGenerateWat)
210210
configuration.put(WasmConfigurationKeys.WASM_USE_TRAPS_INSTEAD_OF_EXCEPTIONS, arguments.wasmUseTrapsInsteadOfExceptions)
211211
configuration.put(WasmConfigurationKeys.WASM_USE_NEW_EXCEPTION_PROPOSAL, arguments.wasmUseNewExceptionProposal)
212+
212213
configuration.putIfNotNull(WasmConfigurationKeys.WASM_TARGET, arguments.wasmTarget?.let(WasmTarget::fromName))
213214

214215
configuration.put(JSConfigurationKeys.OPTIMIZE_GENERATED_JS, arguments.optimizeGeneratedJs)
@@ -839,6 +840,7 @@ class K2JsIrCompiler : CLICompiler<K2JSCompilerArguments>() {
839840
sourceMapContentEmbedding = SourceMapSourceEmbedding.INLINING
840841
}
841842
configuration.put(JSConfigurationKeys.SOURCE_MAP_EMBED_SOURCES, sourceMapContentEmbedding)
843+
configuration.put(JSConfigurationKeys.SOURCE_MAP_INCLUDE_MAPPINGS_FROM_UNAVAILABLE_FILES, arguments.includeUnavailableSourcesIntoSourceMap)
842844

843845
if (!arguments.sourceMap && sourceMapEmbedContentString != null) {
844846
messageCollector.report(WARNING, "source-map-embed-sources argument has no effect without source map", null)

compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/SourceMapsInfo.kt

+3-1
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ data class SourceMapsInfo(
1717
val outputDir: File?,
1818
val sourceMapContentEmbedding: SourceMapSourceEmbedding,
1919
val namesPolicy: SourceMapNamesPolicy,
20+
val includeUnavailableSourcesIntoSourceMap: Boolean = false
2021
) {
2122
companion object {
2223
fun from(configuration: CompilerConfiguration): SourceMapsInfo? =
@@ -26,7 +27,8 @@ data class SourceMapsInfo(
2627
configuration.get(JSConfigurationKeys.SOURCE_MAP_SOURCE_ROOTS, emptyList()),
2728
configuration.get(JSConfigurationKeys.OUTPUT_DIR),
2829
configuration.get(JSConfigurationKeys.SOURCE_MAP_EMBED_SOURCES, SourceMapSourceEmbedding.INLINING),
29-
configuration.get(JSConfigurationKeys.SOURCEMAP_NAMES_POLICY, SourceMapNamesPolicy.SIMPLE_NAMES)
30+
configuration.get(JSConfigurationKeys.SOURCEMAP_NAMES_POLICY, SourceMapNamesPolicy.SIMPLE_NAMES),
31+
configuration.getBoolean(JSConfigurationKeys.SOURCE_MAP_INCLUDE_MAPPINGS_FROM_UNAVAILABLE_FILES),
3032
)
3133
} else {
3234
null

compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/ir2wasm/locationUtils.kt

+16-5
Original file line numberDiff line numberDiff line change
@@ -46,12 +46,23 @@ fun IrElement.getSourceLocation(file: IrFile?, type: LocationType = LocationType
4646

4747
if (line < 0 || column < 0) return SourceLocation.NoLocation("startLine or startColumn < 0")
4848

49-
if (file.isIgnoredFile) {
50-
return SourceLocation.IgnoredLocation(path, line, column)
51-
}
52-
49+
val module = file.module.name.asString()
5350

54-
return SourceLocation.Location(path, line, column)
51+
return if (file.isIgnoredFile) {
52+
SourceLocation.IgnoredLocation(
53+
module,
54+
path,
55+
line,
56+
column
57+
)
58+
} else {
59+
SourceLocation.Location(
60+
module,
61+
path,
62+
line,
63+
column
64+
)
65+
}
5566
}
5667

5768
fun WasmExpressionBuilder.buildUnreachableForVerifier() {

compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/utils/SourceMapGenerator.kt

+21-8
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,12 @@ class SourceMapGenerator(
3939
val sourceMapBuilder =
4040
SourceMap3Builder(null, { error("This should not be called for Kotlin/Wasm") }, sourceMapsInfo.sourceMapPrefix)
4141

42-
val pathResolver =
43-
SourceFilePathResolver.create(sourceMapsInfo.sourceRoots, sourceMapsInfo.sourceMapPrefix, sourceMapsInfo.outputDir)
42+
val pathResolver = SourceFilePathResolver.create(
43+
sourceMapsInfo.sourceRoots,
44+
sourceMapsInfo.sourceMapPrefix,
45+
sourceMapsInfo.outputDir,
46+
sourceMapsInfo.includeUnavailableSourcesIntoSourceMap
47+
)
4448

4549
var prev: SourceLocation.Location? = null
4650
var prevGeneratedLine = 0
@@ -62,12 +66,21 @@ class SourceMapGenerator(
6266
// TODO: add the ignored location into "ignoreList" in future
6367
is SourceLocation.NoLocation, is SourceLocation.IgnoredLocation -> sourceMapBuilder.addEmptyMapping(generatedLocation.column)
6468
is SourceLocation.Location -> {
65-
sourceLocation.apply {
66-
// TODO resulting path goes too deep since temporary directory we compiled first is deeper than final destination.
67-
val relativePath = pathResolver.getPathRelativeToSourceRoots(File(file)).replace(Regex("^\\.\\./"), "")
68-
sourceMapBuilder.addMapping(relativePath, null, { null }, line, column, null, generatedLocation.column)
69-
prev = this
70-
}
69+
// TODO resulting path goes too deep since temporary directory we compiled first is deeper than final destination.
70+
val relativePath = pathResolver
71+
.getPathRelativeToSourceRootsIfExists(sourceLocation.module, File(sourceLocation.file))
72+
?.replace(Regex("^\\.\\./"), "") ?: continue
73+
74+
sourceMapBuilder.addMapping(
75+
relativePath,
76+
null,
77+
{ null },
78+
sourceLocation.line,
79+
sourceLocation.column,
80+
null,
81+
generatedLocation.column
82+
)
83+
prev = sourceLocation
7184
}
7285
}
7386

compiler/testData/cli/js/jsExtraHelp.out

+2
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ where advanced options include:
1010
-Xfriend-modules-disabled Disable internal declaration export.
1111
-Xgenerate-dts Generate a TypeScript declaration .d.ts file alongside the JS file. This is available only in the IR backend.
1212
-Xgenerate-polyfills Generate polyfills for features from the ES6+ standards.
13+
-Xwasm-source-map-include-mappings-from-unavailable-sources
14+
Insert source mappings from libraries even if their sources are unavailable on the end-user machine.
1315
-Xinclude=<path> Path to an intermediate library that should be processed in the same manner as source files.
1416
-Xir-base-class-in-metadata Write base classes into metadata.
1517
-Xir-build-cache Use the compiler to build the cache.

compiler/tests-common-new/tests/org/jetbrains/kotlin/test/directives/WasmEnvironmentConfigurationDirectives.kt

+5
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,11 @@ object WasmEnvironmentConfigurationDirectives : SimpleDirectivesContainer() {
4444
applicability = DirectiveApplicability.Global
4545
)
4646

47+
val SOURCE_MAP_INCLUDE_MAPPINGS_FROM_UNAVAILABLE_FILES by directive(
48+
description = "Insert source mappings from libraries even if their sources are unavailable on the end-user machine",
49+
applicability = DirectiveApplicability.Global
50+
)
51+
4752
val RUN_THIRD_PARTY_OPTIMIZER by directive(
4853
description = "Also run third-party optimizer (for now, only binaryen is supported) after the main compilation",
4954
)

compiler/tests-common-new/tests/org/jetbrains/kotlin/test/services/configuration/WasmEnvironmentConfigurator.kt

+3
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import org.jetbrains.kotlin.test.directives.JsEnvironmentConfigurationDirectives
1919
import org.jetbrains.kotlin.test.directives.JsEnvironmentConfigurationDirectives.SOURCE_MAP_EMBED_SOURCES
2020
import org.jetbrains.kotlin.test.directives.WasmEnvironmentConfigurationDirectives
2121
import org.jetbrains.kotlin.test.directives.WasmEnvironmentConfigurationDirectives.DISABLE_WASM_EXCEPTION_HANDLING
22+
import org.jetbrains.kotlin.test.directives.WasmEnvironmentConfigurationDirectives.SOURCE_MAP_INCLUDE_MAPPINGS_FROM_UNAVAILABLE_FILES
2223
import org.jetbrains.kotlin.test.directives.WasmEnvironmentConfigurationDirectives.USE_NEW_EXCEPTION_HANDLING_PROPOSAL
2324
import org.jetbrains.kotlin.test.directives.model.DirectivesContainer
2425
import org.jetbrains.kotlin.test.directives.model.RegisteredDirectives
@@ -93,11 +94,13 @@ abstract class WasmEnvironmentConfigurator(testServices: TestServices) : Environ
9394
val sourceDirs = module.files.map { it.originalFile.parent }.distinct()
9495
configuration.put(JSConfigurationKeys.SOURCE_MAP_SOURCE_ROOTS, sourceDirs)
9596
configuration.put(JSConfigurationKeys.SOURCE_MAP, true)
97+
configuration.put(JSConfigurationKeys.SOURCE_MAP_INCLUDE_MAPPINGS_FROM_UNAVAILABLE_FILES, SOURCE_MAP_INCLUDE_MAPPINGS_FROM_UNAVAILABLE_FILES in registeredDirectives)
9698

9799
val sourceMapSourceEmbedding = registeredDirectives[SOURCE_MAP_EMBED_SOURCES].singleOrNull() ?: SourceMapSourceEmbedding.NEVER
98100
configuration.put(JSConfigurationKeys.SOURCE_MAP_EMBED_SOURCES, sourceMapSourceEmbedding)
99101

100102
configuration.put(WasmConfigurationKeys.WASM_USE_TRAPS_INSTEAD_OF_EXCEPTIONS, DISABLE_WASM_EXCEPTION_HANDLING in registeredDirectives)
101103
configuration.put(WasmConfigurationKeys.WASM_USE_NEW_EXCEPTION_PROPOSAL, USE_NEW_EXCEPTION_HANDLING_PROPOSAL in registeredDirectives)
104+
102105
}
103106
}

js/js.frontend/src/org/jetbrains/kotlin/js/config/JSConfigurationKeys.java

+3
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,9 @@ public class JSConfigurationKeys {
4141
public static final CompilerConfigurationKey<SourceMapNamesPolicy> SOURCEMAP_NAMES_POLICY = CompilerConfigurationKey.create(
4242
"a policy to generate a mapping from generated identifiers to their corresponding original names");
4343

44+
public static final CompilerConfigurationKey<Boolean> SOURCE_MAP_INCLUDE_MAPPINGS_FROM_UNAVAILABLE_FILES = CompilerConfigurationKey.create(
45+
"insert source mappings from libraries even if their sources are unavailable on the end-user machine");
46+
4447
public static final CompilerConfigurationKey<Boolean> META_INFO =
4548
CompilerConfigurationKey.create("generate .meta.js and .kjsm files");
4649

js/js.sourcemap/src/org/jetbrains/kotlin/js/sourceMap/SourceFilePathResolver.kt

+23-4
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,19 @@ package org.jetbrains.kotlin.js.sourceMap
77
import org.jetbrains.kotlin.config.CompilerConfiguration
88
import org.jetbrains.kotlin.js.config.JSConfigurationKeys
99
import org.jetbrains.kotlin.js.config.JsConfig
10+
import org.jetbrains.kotlin.utils.addToStdlib.runIf
1011
import java.io.File
1112
import java.io.IOException
1213

13-
class SourceFilePathResolver(sourceRoots: List<File>, outputDir: File? = null) {
14+
class SourceFilePathResolver(
15+
sourceRoots: List<File>,
16+
outputDir: File? = null,
17+
private val includeUnavailableSourcesIntoSourceMap: Boolean = false
18+
) {
1419
private val sourceRoots = sourceRoots.mapTo(mutableSetOf<File>()) { it.absoluteFile }
1520
private val outputDirPathResolver = outputDir?.let(::RelativePathCalculator)
1621
private val cache = mutableMapOf<File, String>()
22+
private val modulesAndTheirSourcesStatus = hashMapOf<String, Boolean>()
1723

1824
@Throws(IOException::class)
1925
fun getPathRelativeToSourceRoots(file: File): String {
@@ -25,6 +31,12 @@ class SourceFilePathResolver(sourceRoots: List<File>, outputDir: File? = null) {
2531
return path
2632
}
2733

34+
@Throws(IOException::class)
35+
fun getPathRelativeToSourceRootsIfExists(moduleId: String, file: File): String? {
36+
val moduleSourcesShouldBeAdded = includeUnavailableSourcesIntoSourceMap || modulesAndTheirSourcesStatus.getOrPut(moduleId) { file.exists() }
37+
return runIf(moduleSourcesShouldBeAdded) { getPathRelativeToSourceRoots(file) }
38+
}
39+
2840
@Throws(IOException::class)
2941
private fun calculatePathRelativeToSourceRoots(file: File): String {
3042
val pathRelativeToOutput = calculatePathRelativeToOutput(file)
@@ -57,15 +69,22 @@ class SourceFilePathResolver(sourceRoots: List<File>, outputDir: File? = null) {
5769
fun create(configuration: CompilerConfiguration) = create(
5870
sourceRoots = configuration.get(JSConfigurationKeys.SOURCE_MAP_SOURCE_ROOTS, emptyList()),
5971
sourceMapPrefix = configuration.get(JSConfigurationKeys.SOURCE_MAP_PREFIX, ""),
60-
outputDir = configuration.get(JSConfigurationKeys.OUTPUT_DIR)
72+
outputDir = configuration.get(JSConfigurationKeys.OUTPUT_DIR),
73+
includeUnavailableSourcesIntoSourceMap = configuration.getBoolean(JSConfigurationKeys.SOURCE_MAP_INCLUDE_MAPPINGS_FROM_UNAVAILABLE_FILES)
6174
)
6275

6376
@JvmStatic
64-
fun create(sourceRoots: List<String>, sourceMapPrefix: String, outputDir: File?): SourceFilePathResolver {
77+
fun create(
78+
sourceRoots: List<String>,
79+
sourceMapPrefix: String,
80+
outputDir: File?,
81+
includeUnavailableSourcesIntoSourceMap: Boolean = false,
82+
): SourceFilePathResolver {
6583
val generateRelativePathsInSourceMap = sourceMapPrefix.isEmpty() && sourceRoots.isEmpty()
6684
return SourceFilePathResolver(
6785
sourceRoots.map(::File),
68-
outputDir.takeIf { generateRelativePathsInSourceMap }
86+
outputDir.takeIf { generateRelativePathsInSourceMap },
87+
includeUnavailableSourcesIntoSourceMap
6988
)
7089
}
7190
}

wasm/wasm.ir/src/org/jetbrains/kotlin/wasm/ir/convertors/WasmIrToBinary.kt

+1
Original file line numberDiff line numberDiff line change
@@ -737,6 +737,7 @@ private class SourceLocationMappingToBinary(
737737
) : SourceLocationMapping() {
738738
override val generatedLocation: SourceLocation.Location by lazy {
739739
SourceLocation.Location(
740+
module = "",
740741
file = "",
741742
line = 0,
742743
column = offsets.sumOf {

wasm/wasm.ir/src/org/jetbrains/kotlin/wasm/ir/convertors/WasmIrToText.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ class WasmIrToText(
8383
debugInformationGenerator?.addSourceLocation(
8484
SourceLocationMappingToText(
8585
it,
86-
SourceLocation.Location("", stringBuilder.lineNumber, stringBuilder.columnNumber),
86+
SourceLocation.Location("", "", stringBuilder.lineNumber, stringBuilder.columnNumber),
8787
)
8888
)
8989
}

wasm/wasm.ir/src/org/jetbrains/kotlin/wasm/ir/source/location/SourceLocation.kt

+12-2
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,19 @@ sealed class SourceLocation {
99
object NoLocation : SourceLocation()
1010

1111
// Both line and column are zero-based
12-
data class Location(val file: String, val line: Int, val column: Int) : SourceLocation()
12+
data class Location(
13+
val module: String,
14+
val file: String,
15+
val line: Int,
16+
val column: Int
17+
) : SourceLocation()
1318

14-
data class IgnoredLocation(val file: String, val line: Int, val column: Int) : SourceLocation()
19+
data class IgnoredLocation(
20+
val module: String,
21+
val file: String,
22+
val line: Int,
23+
val column: Int
24+
) : SourceLocation()
1525

1626
companion object {
1727
@Suppress("FunctionName", "UNUSED_PARAMETER")

wasm/wasm.tests/test/org/jetbrains/kotlin/wasm/test/AbstractFirWasmTest.kt

+1
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,7 @@ open class AbstractFirWasmJsSteppingTest : AbstractFirWasmJsTest(
132132
commonConfigurationForWasmBlackBoxCodegenTest()
133133
defaultDirectives {
134134
+WasmEnvironmentConfigurationDirectives.GENERATE_SOURCE_MAP
135+
+WasmEnvironmentConfigurationDirectives.SOURCE_MAP_INCLUDE_MAPPINGS_FROM_UNAVAILABLE_FILES
135136
}
136137
}
137138
}

wasm/wasm.tests/test/org/jetbrains/kotlin/wasm/test/AbstractK1WasmTest.kt

+1
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ open class AbstractK1WasmSteppingTest : AbstractK1WasmTest(
8080
commonConfigurationForWasmBlackBoxCodegenTest()
8181
defaultDirectives {
8282
+WasmEnvironmentConfigurationDirectives.GENERATE_SOURCE_MAP
83+
+WasmEnvironmentConfigurationDirectives.SOURCE_MAP_INCLUDE_MAPPINGS_FROM_UNAVAILABLE_FILES
8384
}
8485
}
8586
}

0 commit comments

Comments
 (0)