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)