JVM: add a language feature to omit *E between SMAP strata

Fixes #KT-37704
This commit is contained in:
pyos
2020-03-23 19:13:27 +01:00
committed by max-kammerer
parent 923a71f676
commit 4558d48481
18 changed files with 236 additions and 45 deletions
@@ -21,6 +21,7 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.codegen.inline.FileMapping;
import org.jetbrains.kotlin.codegen.inline.SMAPBuilder;
import org.jetbrains.kotlin.codegen.inline.SourceMapper;
import org.jetbrains.kotlin.codegen.serialization.JvmSerializationBindings;
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin;
import org.jetbrains.org.objectweb.asm.*;
@@ -38,8 +39,6 @@ public abstract class AbstractClassBuilder implements ClassBuilder {
private final JvmSerializationBindings serializationBindings = new JvmSerializationBindings();
private final List<FileMapping> fileMappings = new ArrayList<>();
private String sourceName;
private String debugInfo;
@@ -106,15 +105,7 @@ public abstract class AbstractClassBuilder implements ClassBuilder {
@Override
public void done() {
if (!fileMappings.isEmpty() && GENERATE_SMAP) {
FileMapping origin = fileMappings.get(0);
assert sourceName == null || origin.getName().equals(sourceName) : "Error " + origin.getName() + " != " + sourceName;
getVisitor().visitSource(origin.getName(), new SMAPBuilder(origin.getName(), origin.getPath(), fileMappings).build());
}
else {
getVisitor().visitSource(sourceName, debugInfo);
}
getVisitor().visitSource(sourceName, debugInfo);
getVisitor().visitEnd();
}
@@ -134,10 +125,23 @@ public abstract class AbstractClassBuilder implements ClassBuilder {
@Override
public void visitSource(@NotNull String name, @Nullable String debug) {
assert sourceName == null || sourceName.equals(name) : "inconsistent file name: " + sourceName + " vs " + name;
sourceName = name;
debugInfo = debug;
}
@Override
public void visitSMAP(@NotNull SourceMapper smap, boolean backwardsCompatibleSyntax) {
if (!GENERATE_SMAP) return;
List<FileMapping> fileMappings = smap.getResultMappings();
if (fileMappings.isEmpty()) return;
FileMapping origin = fileMappings.get(0);
SMAPBuilder builder = new SMAPBuilder(origin.getName(), origin.getPath(), fileMappings, backwardsCompatibleSyntax);
visitSource(origin.getName(), builder.build());
}
@Override
public void visitOuterClass(@NotNull String owner, @Nullable String name, @Nullable String desc) {
getVisitor().visitOuterClass(owner, name, desc);
@@ -154,9 +158,4 @@ public abstract class AbstractClassBuilder implements ClassBuilder {
assert thisName != null : "This name isn't set";
return thisName;
}
@Override
public void addSMAP(FileMapping mapping) {
fileMappings.add(mapping);
}
}
@@ -20,6 +20,7 @@ import com.intellij.psi.PsiElement;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.codegen.inline.FileMapping;
import org.jetbrains.kotlin.codegen.inline.SourceMapper;
import org.jetbrains.kotlin.codegen.serialization.JvmSerializationBindings;
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin;
import org.jetbrains.org.objectweb.asm.AnnotationVisitor;
@@ -71,12 +72,12 @@ public interface ClassBuilder {
void visitSource(@NotNull String name, @Nullable String debug);
void visitSMAP(@NotNull SourceMapper smap, boolean backwardsCompatibleSyntax);
void visitOuterClass(@NotNull String owner, @Nullable String name, @Nullable String desc);
void visitInnerClass(@NotNull String name, @Nullable String outerName, @Nullable String innerName, int access);
@NotNull
String getThisName();
void addSMAP(FileMapping mapping);
}
@@ -20,6 +20,7 @@ import com.intellij.psi.PsiElement;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.codegen.inline.FileMapping;
import org.jetbrains.kotlin.codegen.inline.SourceMapper;
import org.jetbrains.kotlin.codegen.serialization.JvmSerializationBindings;
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin;
import org.jetbrains.org.objectweb.asm.AnnotationVisitor;
@@ -98,6 +99,11 @@ public abstract class DelegatingClassBuilder implements ClassBuilder {
getDelegate().visitSource(name, debug);
}
@Override
public void visitSMAP(@NotNull SourceMapper smap, boolean backwardsCompatibleSyntax) {
getDelegate().visitSMAP(smap, backwardsCompatibleSyntax);
}
@Override
public void visitOuterClass(@NotNull String owner, @Nullable String name, @Nullable String desc) {
getDelegate().visitOuterClass(owner, name, desc);
@@ -113,9 +119,4 @@ public abstract class DelegatingClassBuilder implements ClassBuilder {
public String getThisName() {
return getDelegate().getThisName();
}
@Override
public void addSMAP(FileMapping mapping) {
getDelegate().addSMAP(mapping);
}
}
@@ -21,6 +21,7 @@ import org.jetbrains.kotlin.codegen.state.GenerationState;
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper;
import org.jetbrains.kotlin.codegen.state.TypeMapperUtilsKt;
import org.jetbrains.kotlin.config.ApiVersion;
import org.jetbrains.kotlin.config.LanguageFeature;
import org.jetbrains.kotlin.descriptors.*;
import org.jetbrains.kotlin.descriptors.annotations.AnnotatedImpl;
import org.jetbrains.kotlin.descriptors.annotations.Annotations;
@@ -184,7 +185,7 @@ public abstract class MemberCodegen<T extends KtPureElement/* TODO: & KtDeclarat
writeInnerClasses();
if (sourceMapper != null) {
SourceMapper.Companion.flushToClassBuilder(sourceMapper, v);
v.visitSMAP(sourceMapper, !state.getLanguageVersionSettings().supportsFeature(LanguageFeature.CorrectSourceMappingSyntax));
}
v.done();
@@ -14,6 +14,7 @@ import org.jetbrains.kotlin.codegen.inline.coroutines.CoroutineTransformer
import org.jetbrains.kotlin.codegen.inline.coroutines.FOR_INLINE_SUFFIX
import org.jetbrains.kotlin.codegen.serialization.JvmCodegenStringTable
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapperBase
import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.load.java.JvmAnnotationNames
import org.jetbrains.kotlin.load.kotlin.FileBasedKotlinClass
import org.jetbrains.kotlin.load.kotlin.header.KotlinClassHeader
@@ -183,7 +184,7 @@ class AnonymousObjectTransformer(
}
}
SourceMapper.flushToClassBuilder(sourceMapper, classBuilder)
classBuilder.visitSMAP(sourceMapper, !state.languageVersionSettings.supportsFeature(LanguageFeature.CorrectSourceMappingSyntax))
val visitor = classBuilder.visitor
innerClassNodes.forEach { node ->
@@ -23,7 +23,8 @@ const val KOTLIN_DEBUG_STRATA_NAME = "KotlinDebug"
class SMAPBuilder(
val source: String,
val path: String,
private val fileMappings: List<FileMapping>
private val fileMappings: List<FileMapping>,
private val backwardsCompatibleSyntax: Boolean
) {
private val header = "SMAP\n$source\nKotlin"
@@ -39,25 +40,25 @@ class SMAPBuilder(
val defaultStrata = generateDefaultStrata(realMappings)
val debugStrata = generateDebugStrata(realMappings)
return "$header\n$defaultStrata$debugStrata"
if (backwardsCompatibleSyntax && defaultStrata.isNotEmpty() && debugStrata.isNotEmpty()) {
// Old versions of kotlinc might fail if there is no END between defaultStrata and debugStrata.
// This is not actually correct syntax according to JSR-045.
return "$header\n$defaultStrata$END\n$debugStrata$END\n"
}
return "$header\n$defaultStrata$debugStrata$END\n"
}
private fun generateDefaultStrata(realMappings: List<FileMapping>): String {
val fileIds = FILE_SECTION + realMappings.mapIndexed { id, file -> "\n${file.toSMAPFile(id + 1)}" }.joinToString("")
val lineMappings = LINE_SECTION + realMappings.joinToString("") { it.toSMAPMapping() }
return "$STRATA_SECTION $KOTLIN_STRATA_NAME\n$fileIds\n$lineMappings\n$END\n"
return "$STRATA_SECTION $KOTLIN_STRATA_NAME\n$fileIds\n$lineMappings\n"
}
private fun generateDebugStrata(realMappings: List<FileMapping>): String {
val combinedMapping = FileMapping(source, path)
realMappings.forEach { fileMapping ->
fileMapping.lineMappings.filter { it.callSiteMarker != null }.forEach { (_, dest, range, callSiteMarker) ->
combinedMapping.addRangeMapping(
RangeMapping(
callSiteMarker!!.lineNumber, dest, range
)
)
combinedMapping.addRangeMapping(RangeMapping(callSiteMarker!!.lineNumber, dest, range))
}
}
@@ -66,7 +67,7 @@ class SMAPBuilder(
val newMappings = listOf(combinedMapping)
val fileIds = FILE_SECTION + newMappings.mapIndexed { id, file -> "\n${file.toSMAPFile(id + 1)}" }.joinToString("")
val lineMappings = LINE_SECTION + newMappings.joinToString("") { it.toSMAPMapping() }
return "$STRATA_SECTION $KOTLIN_DEBUG_STRATA_NAME\n$fileIds\n$lineMappings\n$END\n"
return "$STRATA_SECTION $KOTLIN_DEBUG_STRATA_NAME\n$fileIds\n$lineMappings\n"
}
private fun RangeMapping.toSMAP(fileId: Int): String {
@@ -153,10 +154,6 @@ interface SourceMapper {
}
companion object {
fun flushToClassBuilder(mapper: SourceMapper, v: ClassBuilder) {
mapper.resultMappings.forEach { fileMapping -> v.addSMAP(fileMapping) }
}
fun createFromSmap(smap: SMAP): SourceMapper {
return DefaultSourceMapper(smap.sourceInfo, smap.fileMappings)
}
@@ -42,6 +42,8 @@ object SMAPParser {
fun parse(mappingInfo: String): SMAP {
val fileMappings = linkedMapOf<Int, FileMapping>()
// Assuming we want the first stratum (which should be "Kotlin" for Kotlin classes, though you never know).
// Also, JSR-045 allows the line section to come before the file section, but we don't generate SMAPs like this.
val iterator = mappingInfo.lineSequence().dropWhile { it.trim() != SMAP.FILE_SECTION }.drop(1).iterator()
while (iterator.hasNext()) {
val fileDeclaration = iterator.next().trim()
@@ -59,7 +61,8 @@ object SMAPParser {
}
for (lineMapping in iterator) {
if (lineMapping.trim() == SMAP.END) break
// The stratum is terminated either by *E or another stratum.
if (lineMapping.trim().startsWith("*")) break
/*only simple mapping now*/
val targetSplit = lineMapping.indexOf(':')
val originalPart = lineMapping.substring(0, targetSplit)
@@ -18,6 +18,7 @@ import org.jetbrains.kotlin.codegen.inline.ReifiedTypeParametersUsages
import org.jetbrains.kotlin.codegen.inline.SourceMapper
import org.jetbrains.kotlin.codegen.serialization.JvmSerializationBindings
import org.jetbrains.kotlin.codegen.serialization.JvmSerializerExtension
import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.descriptors.Visibility
import org.jetbrains.kotlin.ir.builders.declarations.buildFun
@@ -185,7 +186,7 @@ open class ClassCodegen protected constructor(
generateInnerAndOuterClasses()
sourceMapper?.let {
SourceMapper.flushToClassBuilder(it, visitor)
visitor.visitSMAP(it, !context.state.languageVersionSettings.supportsFeature(LanguageFeature.CorrectSourceMappingSyntax))
}
visitor.done()
@@ -237,6 +237,10 @@ class IrSourceCompilerForInline(
TODO("not implemented")
}
override fun visitSMAP(smap: SourceMapper, backwardsCompatibleSyntax: Boolean) {
TODO("not implemented")
}
override fun visitInnerClass(name: String, outerName: String?, innerName: String?, access: Int) {
TODO("not implemented")
}
@@ -244,10 +248,6 @@ class IrSourceCompilerForInline(
override fun getThisName(): String {
TODO("not implemented")
}
override fun addSMAP(mapping: FileMapping?) {
TODO("not implemented")
}
}
}
}
@@ -0,0 +1,62 @@
// !LANGUAGE: +CorrectSourceMappingSyntax
// FILE: 1.kt
package test
public inline fun inlineFun2(x: () -> String): String {
return x()
}
public inline fun inlineFun(): String {
return inlineFun2 {
"OK"
}
}
// FILE: 2.kt
import test.*
fun box(): String {
return inlineFun()
}
// FILE: 1.smap
SMAP
1.kt
Kotlin
*S Kotlin
*F
+ 1 1.kt
test/_1Kt
*L
1#1,15:1
6#1:16
*S KotlinDebug
*F
+ 1 1.kt
test/_1Kt
*L
10#1:16
*E
// FILE: 2.smap
SMAP
2.kt
Kotlin
*S Kotlin
*F
+ 1 2.kt
_2Kt
+ 2 1.kt
test/_1Kt
*L
1#1,8:1
10#2:9
6#2,6:10
*S KotlinDebug
*F
+ 1 2.kt
_2Kt
*L
5#1:9
5#1,6:10
*E
@@ -0,0 +1,64 @@
// !LANGUAGE: -CorrectSourceMappingSyntax
// FILE: 1.kt
package test
public inline fun inlineFun2(x: () -> String): String {
return x()
}
public inline fun inlineFun(): String {
return inlineFun2 {
"OK"
}
}
// FILE: 2.kt
import test.*
fun box(): String {
return inlineFun()
}
// FILE: 1.smap
SMAP
1.kt
Kotlin
*S Kotlin
*F
+ 1 1.kt
test/_1Kt
*L
1#1,15:1
6#1:16
*E
*S KotlinDebug
*F
+ 1 1.kt
test/_1Kt
*L
10#1:16
*E
// FILE: 2.smap
SMAP
2.kt
Kotlin
*S Kotlin
*F
+ 1 2.kt
_2Kt
+ 2 1.kt
test/_1Kt
*L
1#1,8:1
10#2:9
6#2,6:10
*E
*S KotlinDebug
*F
+ 1 2.kt
_2Kt
*L
5#1:9
5#1,6:10
*E
@@ -3280,6 +3280,16 @@ public class BlackBoxInlineCodegenTestGenerated extends AbstractBlackBoxInlineCo
runTest("compiler/testData/codegen/boxInline/smap/smap.kt");
}
@TestMetadata("smapWithNewSyntax.kt")
public void testSmapWithNewSyntax() throws Exception {
runTest("compiler/testData/codegen/boxInline/smap/smapWithNewSyntax.kt");
}
@TestMetadata("smapWithOldSyntax.kt")
public void testSmapWithOldSyntax() throws Exception {
runTest("compiler/testData/codegen/boxInline/smap/smapWithOldSyntax.kt");
}
@TestMetadata("compiler/testData/codegen/boxInline/smap/anonymous")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
@@ -3280,6 +3280,16 @@ public class CompileKotlinAgainstInlineKotlinTestGenerated extends AbstractCompi
runTest("compiler/testData/codegen/boxInline/smap/smap.kt");
}
@TestMetadata("smapWithNewSyntax.kt")
public void testSmapWithNewSyntax() throws Exception {
runTest("compiler/testData/codegen/boxInline/smap/smapWithNewSyntax.kt");
}
@TestMetadata("smapWithOldSyntax.kt")
public void testSmapWithOldSyntax() throws Exception {
runTest("compiler/testData/codegen/boxInline/smap/smapWithOldSyntax.kt");
}
@TestMetadata("compiler/testData/codegen/boxInline/smap/anonymous")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
@@ -3280,6 +3280,16 @@ public class IrBlackBoxInlineCodegenTestGenerated extends AbstractIrBlackBoxInli
runTest("compiler/testData/codegen/boxInline/smap/smap.kt");
}
@TestMetadata("smapWithNewSyntax.kt")
public void testSmapWithNewSyntax() throws Exception {
runTest("compiler/testData/codegen/boxInline/smap/smapWithNewSyntax.kt");
}
@TestMetadata("smapWithOldSyntax.kt")
public void testSmapWithOldSyntax() throws Exception {
runTest("compiler/testData/codegen/boxInline/smap/smapWithOldSyntax.kt");
}
@TestMetadata("compiler/testData/codegen/boxInline/smap/anonymous")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
@@ -3280,6 +3280,16 @@ public class IrCompileKotlinAgainstInlineKotlinTestGenerated extends AbstractIrC
runTest("compiler/testData/codegen/boxInline/smap/smap.kt");
}
@TestMetadata("smapWithNewSyntax.kt")
public void testSmapWithNewSyntax() throws Exception {
runTest("compiler/testData/codegen/boxInline/smap/smapWithNewSyntax.kt");
}
@TestMetadata("smapWithOldSyntax.kt")
public void testSmapWithOldSyntax() throws Exception {
runTest("compiler/testData/codegen/boxInline/smap/smapWithOldSyntax.kt");
}
@TestMetadata("compiler/testData/codegen/boxInline/smap/anonymous")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
@@ -129,6 +129,7 @@ enum class LanguageFeature(
ProhibitInvisibleAbstractMethodsInSuperclasses(KOTLIN_1_5, kind = BUG_FIX),
ProhibitNonReifiedArraysAsReifiedTypeArguments(KOTLIN_1_5, kind = BUG_FIX),
ProhibitVarargAsArrayAfterSamArgument(KOTLIN_1_5, kind = BUG_FIX),
CorrectSourceMappingSyntax(KOTLIN_1_5, kind = UNSTABLE_FEATURE),
// Temporarily disabled, see KT-27084/KT-22379
SoundSmartcastFromLoopConditionForLoopAssignedVariables(sinceVersion = null, kind = BUG_FIX),
@@ -2895,6 +2895,16 @@ public class IrJsCodegenInlineTestGenerated extends AbstractIrJsCodegenInlineTes
runTest("compiler/testData/codegen/boxInline/smap/smap.kt");
}
@TestMetadata("smapWithNewSyntax.kt")
public void testSmapWithNewSyntax() throws Exception {
runTest("compiler/testData/codegen/boxInline/smap/smapWithNewSyntax.kt");
}
@TestMetadata("smapWithOldSyntax.kt")
public void testSmapWithOldSyntax() throws Exception {
runTest("compiler/testData/codegen/boxInline/smap/smapWithOldSyntax.kt");
}
@TestMetadata("compiler/testData/codegen/boxInline/smap/anonymous")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
@@ -2895,6 +2895,16 @@ public class JsCodegenInlineTestGenerated extends AbstractJsCodegenInlineTest {
runTest("compiler/testData/codegen/boxInline/smap/smap.kt");
}
@TestMetadata("smapWithNewSyntax.kt")
public void testSmapWithNewSyntax() throws Exception {
runTest("compiler/testData/codegen/boxInline/smap/smapWithNewSyntax.kt");
}
@TestMetadata("smapWithOldSyntax.kt")
public void testSmapWithOldSyntax() throws Exception {
runTest("compiler/testData/codegen/boxInline/smap/smapWithOldSyntax.kt");
}
@TestMetadata("compiler/testData/codegen/boxInline/smap/anonymous")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)