Smap refactorings

This commit is contained in:
Michael Bogdanov
2015-03-05 15:26:36 +03:00
parent 52999afc4a
commit a4117360a2
19 changed files with 491 additions and 165 deletions
@@ -19,9 +19,14 @@ package org.jetbrains.kotlin.codegen;
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.SMAPBuilder;
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin;
import org.jetbrains.org.objectweb.asm.*;
import java.util.ArrayList;
import java.util.List;
public abstract class AbstractClassBuilder implements ClassBuilder {
protected static final MethodVisitor EMPTY_METHOD_VISITOR = new MethodVisitor(Opcodes.ASM5) {};
protected static final FieldVisitor EMPTY_FIELD_VISITOR = new FieldVisitor(Opcodes.ASM5) {};
@@ -30,6 +35,12 @@ public abstract class AbstractClassBuilder implements ClassBuilder {
private final JvmSerializationBindings serializationBindings = new JvmSerializationBindings();
private final List<FileMapping> fileMappings = new ArrayList<FileMapping>();
private String sourceName;
private String debugInfo;
public static class Concrete extends AbstractClassBuilder {
private final ClassVisitor v;
@@ -92,6 +103,15 @@ public abstract class AbstractClassBuilder implements ClassBuilder {
@Override
public void done() {
if (!fileMappings.isEmpty()) {
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().visitEnd();
}
@@ -111,7 +131,8 @@ public abstract class AbstractClassBuilder implements ClassBuilder {
@Override
public void visitSource(@NotNull String name, @Nullable String debug) {
getVisitor().visitSource(name, debug);
sourceName = name;
debugInfo = debug;
}
@Override
@@ -130,4 +151,9 @@ 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);
}
}
@@ -19,6 +19,7 @@ package org.jetbrains.kotlin.codegen;
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.resolve.jvm.diagnostics.JvmDeclarationOrigin;
import org.jetbrains.org.objectweb.asm.AnnotationVisitor;
import org.jetbrains.org.objectweb.asm.ClassVisitor;
@@ -75,4 +76,6 @@ public interface ClassBuilder {
@NotNull
String getThisName();
void addSMAP(FileMapping mapping);
}
@@ -25,6 +25,7 @@ import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
import org.jetbrains.kotlin.codegen.binding.CalculatedClosure;
import org.jetbrains.kotlin.codegen.context.ClosureContext;
import org.jetbrains.kotlin.codegen.inline.InlineCodegenUtil;
import org.jetbrains.kotlin.codegen.signature.BothSignatureWriter;
import org.jetbrains.kotlin.codegen.state.GenerationState;
import org.jetbrains.kotlin.codegen.state.JetTypeMapper;
@@ -141,6 +142,9 @@ public class ClosureCodegen extends MemberCodegen<JetElement> {
superClassAsmType.getInternalName(),
superInterfaceAsmTypes
);
InlineCodegenUtil.initDefaultSourceMappingIfNeeded(context, this, state);
v.visitSource(element.getContainingFile().getName(), null);
}
@@ -19,6 +19,7 @@ package org.jetbrains.kotlin.codegen;
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.resolve.jvm.diagnostics.JvmDeclarationOrigin;
import org.jetbrains.org.objectweb.asm.AnnotationVisitor;
import org.jetbrains.org.objectweb.asm.ClassVisitor;
@@ -111,4 +112,9 @@ public abstract class DelegatingClassBuilder implements ClassBuilder {
public String getThisName() {
return getDelegate().getThisName();
}
@Override
public void addSMAP(FileMapping mapping) {
getDelegate().addSMAP(mapping);
}
}
@@ -30,6 +30,7 @@ import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
import org.jetbrains.kotlin.codegen.binding.MutableClosure;
import org.jetbrains.kotlin.codegen.context.*;
import org.jetbrains.kotlin.codegen.extensions.ExpressionCodegenExtension;
import org.jetbrains.kotlin.codegen.inline.InlineCodegenUtil;
import org.jetbrains.kotlin.codegen.signature.BothSignatureWriter;
import org.jetbrains.kotlin.codegen.state.GenerationState;
import org.jetbrains.kotlin.codegen.state.JetTypeMapper;
@@ -209,6 +210,8 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
);
v.visitSource(myClass.getContainingFile().getName(), null);
InlineCodegenUtil.initDefaultSourceMappingIfNeeded(context, this, state);
writeEnclosingMethod();
AnnotationCodegen.forClass(v.getVisitor(), typeMapper).genAnnotations(descriptor, null);
@@ -20,7 +20,6 @@ import com.intellij.openapi.progress.ProcessCanceledException;
import kotlin.Function0;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.backend.common.CodegenUtil;
import org.jetbrains.kotlin.codegen.context.*;
import org.jetbrains.kotlin.codegen.inline.*;
import org.jetbrains.kotlin.codegen.state.GenerationState;
@@ -100,8 +99,8 @@ public abstract class MemberCodegen<T extends JetElement/* TODO: & JetDeclaratio
this.parentCodegen = parentCodegen;
}
protected MemberCodegen(@NotNull MemberCodegen<T> wrapped) {
this(wrapped.state, wrapped.getParentCodegen(), wrapped.getContext(), wrapped.element, wrapped.v);
protected MemberCodegen(@NotNull MemberCodegen<T> wrapped, T declaration, FieldOwnerContext codegenContext) {
this(wrapped.state, wrapped.getParentCodegen(), codegenContext, declaration, wrapped.v);
}
public void generate() {
@@ -136,14 +135,10 @@ public abstract class MemberCodegen<T extends JetElement/* TODO: & JetDeclaratio
FunctionCodegen.endVisit(clInit.v, "static initializer", element);
}
writeInnerClasses();
if (sourceMapper != null) {
List<RawFileMapping> mapping = sourceMapper.getFileMapping();
for (RawFileMapping fileMapping : mapping) {
v.addSMAP(fileMapping.toFileMapping());
}
SourceMapper.Default.flushToClassBuilder(sourceMapper, v);
}
v.done();
@@ -207,8 +202,7 @@ public abstract class MemberCodegen<T extends JetElement/* TODO: & JetDeclaratio
if (aClass instanceof JetClass && ((JetClass) aClass).isTrait()) {
Type traitImplType = state.getTypeMapper().mapTraitImpl(descriptor);
ClassBuilder traitImplBuilder = state.getFactory().newVisitor(TraitImpl(aClass, descriptor), traitImplType,
aClass.getContainingFile());
ClassBuilder traitImplBuilder = state.getFactory().newVisitor(TraitImpl(aClass, descriptor), traitImplType, aClass.getContainingFile());
ClassContext traitImplContext = parentContext.intoClass(descriptor, OwnerKind.TRAIT_IMPL, state);
new TraitImplBodyCodegen(aClass, traitImplContext, traitImplBuilder, state, parentCodegen).generate();
}
@@ -515,22 +509,15 @@ public abstract class MemberCodegen<T extends JetElement/* TODO: & JetDeclaratio
return parentCodegen;
}
@Override
public String toString() {
return context.toString();
}
public void addSMAP(FileMapping fm) {
v.addSMAP(fm);
}
public SourceMapper getSourceMapper() {
@NotNull
public SourceMapper getOrCreateSourceMapper() {
if (sourceMapper == null) {
assert element != null : "Couldn't create source mapper for null element " + this;
Integer lineNumbers = CodegenUtil.getLineNumberForElement(element.getContainingFile(), true);
assert lineNumbers != null : "Couldn't extract line count in " + element.getContainingFile();
sourceMapper = new SourceMapper(lineNumbers);
sourceMapper = new DefaultSourceMapper(SourceInfo.Default.createInfo(element, getClassName()), null);
}
return sourceMapper;
}
@@ -0,0 +1,42 @@
/*
* Copyright 2010-2015 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.codegen
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.psi.JetElement
import org.jetbrains.kotlin.backend.common.CodegenUtil
import org.jetbrains.kotlin.psi.JetFile
import org.jetbrains.kotlin.psi.JetNamedFunction
data public class SourceInfo(val source: String, val pathOrCleanFQN: String, val linesInFile: Int) {
default object {
fun createInfo(element: JetElement?, internalClassName: String): SourceInfo {
assert(element != null) { "Couldn't create source mapper for null element " + internalClassName }
val lineNumbers = CodegenUtil.getLineNumberForElement(element!!.getContainingFile(), true)
assert(lineNumbers != null) { "Couldn't extract line count in " + element.getContainingFile() }
//TODO hack condition for package parts cleaning
val isTopLevel = element is JetFile || (element is JetNamedFunction && element.getParent() is JetFile)
val cleanedClassFqName = if (!isTopLevel) internalClassName else internalClassName.substringBefore('$')
return SourceInfo(element.getContainingJetFile().getName(), cleanedClassFqName, lineNumbers!!)
}
}
}
@@ -44,6 +44,14 @@ public class AnonymousObjectTransformer {
private MethodNode constructor;
private String sourceInfo;
private String debugInfo;
private SMAP smap;
private SourceMapper sourceMapper;
private final InliningContext inliningContext;
private final Type oldObjectType;
@@ -140,8 +148,29 @@ public class AnonymousObjectTransformer {
return super.visitField(access, name, desc, signature, value);
}
}
@Override
public void visitSource(String source, String debug) {
sourceInfo = source;
debugInfo = debug;
}
@Override
public void visitEnd() {
}
}, ClassReader.SKIP_FRAMES);
if (!inliningContext.isInliningLambda) {
assert debugInfo != null && !debugInfo.isEmpty() : "Debug info is null for " + oldObjectType;
smap = new SMAPParser(debugInfo, sourceInfo, "notused", 1, 2).parse();
sourceMapper = SourceMapper.Default.createFromSmap(smap);
}
else {
classBuilder.visitSource(sourceInfo, debugInfo);
sourceMapper = IdenticalSourceMapper.INSTANCE$;
}
ParametersBuilder allCapturedParamBuilder = ParametersBuilder.newBuilder();
ParametersBuilder constructorParamBuilder = ParametersBuilder.newBuilder();
List<CapturedParamInfo> additionalFakeParams =
@@ -159,6 +188,8 @@ public class AnonymousObjectTransformer {
result.addAllClassesToRemove(constructorResult);
SourceMapper.Default.flushToClassBuilder(sourceMapper, classBuilder);
classBuilder.done();
anonymousObjectGen.setNewLambdaType(newLambdaType);
@@ -183,7 +214,7 @@ public class AnonymousObjectTransformer {
MethodInliner inliner = new MethodInliner(sourceNode, parameters, inliningContext.subInline(inliningContext.nameGenerator.subGenerator("lambda")),
remapper, isSameModule, "Transformer for " + anonymousObjectGen.getOwnerInternalName(),
null);
sourceMapper);
InlineResult result = inliner.doInline(resultVisitor, new LocalVarRemapper(parameters, 0), false, LabelOwner.NOT_APPLICABLE);
result.getReifiedTypeParametersUsages().mergeAll(typeParametersToReify);
@@ -272,7 +303,7 @@ public class AnonymousObjectTransformer {
MethodInliner inliner = new MethodInliner(constructor, constructorParameters, inliningContext.subInline(inliningContext.nameGenerator.subGenerator("lambda")),
remapper, isSameModule, "Transformer for constructor of " + anonymousObjectGen.getOwnerInternalName(),
null);
sourceMapper);
InlineResult result = inliner.doInline(capturedFieldInitializer, new LocalVarRemapper(constructorParameters, 0), false,
LabelOwner.NOT_APPLICABLE);
constructorVisitor.visitMaxs(-1, -1);
@@ -16,6 +16,7 @@
package org.jetbrains.kotlin.codegen.inline;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.org.objectweb.asm.Label;
import org.jetbrains.org.objectweb.asm.MethodVisitor;
import org.jetbrains.org.objectweb.asm.Opcodes;
@@ -35,7 +36,7 @@ public class InlineAdapter extends InstructionAdapter {
private int nextLocalIndexBeforeInline = -1;
public InlineAdapter(MethodVisitor mv, int localsSize, SourceMapper sourceMapper) {
public InlineAdapter(MethodVisitor mv, int localsSize, @NotNull SourceMapper sourceMapper) {
super(InlineCodegenUtil.API, mv);
nextLocalIndex = localsSize;
this.sourceMapper = sourceMapper;
@@ -86,13 +87,7 @@ public class InlineAdapter extends InstructionAdapter {
@Override
public void visitLineNumber(int line, Label start) {
if (!isLambdaInlining) {
if (sourceMapper != null) {
sourceMapper.visitLineNumber(mv, line, start);
}
} else {
super.visitLineNumber(line, start);
}
sourceMapper.visitLineNumber(mv, line, start);
}
@Override
@@ -26,11 +26,13 @@ import org.jetbrains.kotlin.builtins.InlineStrategy;
import org.jetbrains.kotlin.builtins.InlineUtil;
import org.jetbrains.kotlin.codegen.*;
import org.jetbrains.kotlin.codegen.context.CodegenContext;
import org.jetbrains.kotlin.codegen.context.FieldOwnerContext;
import org.jetbrains.kotlin.codegen.context.MethodContext;
import org.jetbrains.kotlin.codegen.context.PackageContext;
import org.jetbrains.kotlin.codegen.state.GenerationState;
import org.jetbrains.kotlin.codegen.state.JetTypeMapper;
import org.jetbrains.kotlin.descriptors.*;
import org.jetbrains.kotlin.load.kotlin.PackageClassUtils;
import org.jetbrains.kotlin.name.ClassId;
import org.jetbrains.kotlin.psi.*;
import org.jetbrains.kotlin.renderer.DescriptorRenderer;
@@ -38,7 +40,6 @@ import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils;
import org.jetbrains.kotlin.resolve.DescriptorUtils;
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall;
import org.jetbrains.kotlin.resolve.jvm.AsmTypes;
import org.jetbrains.kotlin.resolve.jvm.JvmClassName;
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodParameterKind;
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodParameterSignature;
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature;
@@ -83,7 +84,7 @@ public class InlineCodegen extends CallGenerator {
private LambdaInfo activeLambda;
private SourceMapper sourceMapper;
private final SourceMapper sourceMapper;
public InlineCodegen(
@NotNull ExpressionCodegen codegen,
@@ -113,10 +114,10 @@ public class InlineCodegen extends CallGenerator {
isSameModule = JvmCodegenUtil.isCallInsideSameModuleAsDeclared(functionDescriptor, codegen.getContext(), state.getOutDirectory());
Integer lineNumbers = CodegenUtil.getLineNumberForElement(callElement.getContainingFile(), true);
assert lineNumbers != null : "Couldn't extract line count in " + callElement.getContainingFile();
Integer lastLineNumber = CodegenUtil.getLineNumberForElement(callElement.getContainingFile(), true);
assert lastLineNumber != null : "Couldn't extract line count in " + callElement.getContainingFile();
sourceMapper = codegen.getParentCodegen().getSourceMapper();
sourceMapper = codegen.getParentCodegen().getOrCreateSourceMapper();
}
@Override
@@ -176,8 +177,14 @@ public class InlineCodegen extends CallGenerator {
(DeserializedSimpleFunctionDescriptor) functionDescriptor);
VirtualFile file = InlineCodegenUtil.getVirtualFileForCallable(containerClassId, state);
nodeAndSMAP = InlineCodegenUtil.getMethodNode(file.contentsToByteArray(), asmMethod.getName(), asmMethod.getDescriptor(),
JvmClassName.byClassId(containerClassId).getInternalName());
if (functionDescriptor.getContainingDeclaration() instanceof PackageFragmentDescriptor) {
/*use facade class*/
containerClassId = PackageClassUtils.getPackageClassId(containerClassId.getPackageFqName());
}
nodeAndSMAP = InlineCodegenUtil.getMethodNode(file.contentsToByteArray(),
asmMethod.getName(),
asmMethod.getDescriptor(),
containerClassId);
if (nodeAndSMAP == null) {
throw new RuntimeException("Couldn't obtain compiled function body for " + descriptorName(functionDescriptor));
@@ -185,11 +192,11 @@ public class InlineCodegen extends CallGenerator {
}
else {
PsiElement element = DescriptorToSourceUtils.descriptorToDeclaration(functionDescriptor);
Type ownerType = typeMapper.mapOwner(functionDescriptor, false);
if (element == null) {
if (element == null || !(element instanceof JetNamedFunction)) {
throw new RuntimeException("Couldn't find declaration for function " + descriptorName(functionDescriptor));
}
JetNamedFunction inliningFunction = (JetNamedFunction) element;
MethodNode node = new MethodNode(InlineCodegenUtil.API,
getMethodAsmFlags(functionDescriptor, context.getContextKind()) | (callDefault ? Opcodes.ACC_STATIC : 0),
@@ -201,22 +208,24 @@ public class InlineCodegen extends CallGenerator {
//for maxLocals calculation
MethodVisitor maxCalcAdapter = InlineCodegenUtil.wrapWithMaxLocalCalc(node);
MethodContext methodContext = context.getParentContext().intoFunction(functionDescriptor);
SMAP smap;
if (callDefault) {
FakeMemberCodegen parentCodegen = new FakeMemberCodegen(codegen.getParentCodegen());
Type ownerType = typeMapper.mapOwner(functionDescriptor, false/*use facade class*/);
FakeMemberCodegen parentCodegen = new FakeMemberCodegen(codegen.getParentCodegen(), inliningFunction,
(FieldOwnerContext) methodContext.getParentContext(),
ownerType.getInternalName());
FunctionCodegen.generateDefaultImplBody(
methodContext, functionDescriptor, maxCalcAdapter, DefaultParameterValueLoader.DEFAULT,
(JetNamedFunction) element, parentCodegen
inliningFunction, parentCodegen
);
smap = new SMAP(parentCodegen.mappings);
smap = createSMAPWithDefaultMapping(inliningFunction, parentCodegen.getOrCreateSourceMapper().getResultMappings());
}
else {
smap = generateMethodBody(maxCalcAdapter, functionDescriptor, methodContext, (JetDeclarationWithBody) element,
jvmSignature);
smap = generateMethodBody(maxCalcAdapter, functionDescriptor, methodContext, inliningFunction, jvmSignature, false);
}
PsiFile file = element.getContainingFile();
nodeAndSMAP = new SMAPAndMethodNode(node, file.getName(), ownerType.getInternalName(), smap);
nodeAndSMAP = new SMAPAndMethodNode(node, smap);
maxCalcAdapter.visitMaxs(-1, -1);
maxCalcAdapter.visitEnd();
}
@@ -224,8 +233,6 @@ public class InlineCodegen extends CallGenerator {
}
private InlineResult inlineCall(SMAPAndMethodNode nodeAndSmap) {
sourceMapper.visitSource(nodeAndSmap.getSource(), nodeAndSmap.getSourcePath());
MethodNode node = nodeAndSmap.getNode();
ReifiedTypeParametersUsages reificationResult = reifiedTypeInliner.reifyInstructions(node.instructions);
generateClosuresBodies();
@@ -246,7 +253,8 @@ public class InlineCodegen extends CallGenerator {
codegen.getParentCodegen().getClassName(), reifiedTypeInliner);
MethodInliner inliner = new MethodInliner(node, parameters, info, new FieldRemapper(null, null, parameters), isSameModule,
"Method inlining " + callElement.getText(), sourceMapper); //with captured
"Method inlining " + callElement.getText(),
createNestedSourceMapper(nodeAndSmap)); //with captured
LocalVarRemapper remapper = new LocalVarRemapper(parameters, initialFrameSize);
@@ -287,7 +295,7 @@ public class InlineCodegen extends CallGenerator {
}
}
private MethodNode generateLambdaBody(LambdaInfo info) {
private SMAPAndMethodNode generateLambdaBody(LambdaInfo info) {
JetFunctionLiteral declaration = info.getFunctionLiteral();
FunctionDescriptor descriptor = info.getFunctionDescriptor();
@@ -301,10 +309,9 @@ public class InlineCodegen extends CallGenerator {
MethodVisitor adapter = InlineCodegenUtil.wrapWithMaxLocalCalc(methodNode);
generateMethodBody(adapter, descriptor, context, declaration, jvmMethodSignature);
SMAP smap = generateMethodBody(adapter, descriptor, context, declaration, jvmMethodSignature, true);
adapter.visitMaxs(-1, -1);
return methodNode;
return new SMAPAndMethodNode(methodNode, smap);
}
private SMAP generateMethodBody(
@@ -312,28 +319,44 @@ public class InlineCodegen extends CallGenerator {
@NotNull FunctionDescriptor descriptor,
@NotNull MethodContext context,
@NotNull JetDeclarationWithBody declaration,
@NotNull JvmMethodSignature jvmMethodSignature
@NotNull JvmMethodSignature jvmMethodSignature,
boolean isLambda
) {
FakeMemberCodegen parentCodegen = new FakeMemberCodegen(codegen.getParentCodegen());
FakeMemberCodegen parentCodegen =
new FakeMemberCodegen(codegen.getParentCodegen(), declaration,
(FieldOwnerContext) context.getParentContext(),
isLambda ? codegen.getParentCodegen().getClassName() : typeMapper.mapOwner(descriptor, false).getInternalName());
FunctionCodegen.generateMethodBody(
adapter, descriptor, context, jvmMethodSignature,
new FunctionGenerationStrategy.FunctionDefault(state, descriptor, declaration),
// Wrapping for preventing marking actual parent codegen as containing reifier markers
parentCodegen
adapter, descriptor, context, jvmMethodSignature,
new FunctionGenerationStrategy.FunctionDefault(state, descriptor, declaration),
// Wrapping for preventing marking actual parent codegen as containing reifier markers
parentCodegen
);
return new SMAP(parentCodegen.mappings);
return createSMAPWithDefaultMapping(declaration, parentCodegen.getOrCreateSourceMapper().getResultMappings());
}
private static SMAP createSMAPWithDefaultMapping(
@NotNull JetDeclarationWithBody declaration,
@NotNull List<FileMapping> mappings
) {
PsiFile containingFile = declaration.getContainingFile();
Integer lineNumbers = CodegenUtil.getLineNumberForElement(containingFile, true);
assert lineNumbers != null : "Couldn't extract line count in " + containingFile;
return new SMAP(mappings);
}
private static class FakeMemberCodegen extends MemberCodegen {
private final MemberCodegen delegate;
@NotNull private final String className;
List<FileMapping> mappings = new ArrayList<FileMapping>();
public FakeMemberCodegen(@NotNull MemberCodegen wrapped) {
super(wrapped);
public FakeMemberCodegen(@NotNull MemberCodegen wrapped, @NotNull JetElement declaration, @NotNull FieldOwnerContext codegenContext, @NotNull String className) {
super(wrapped, declaration, codegenContext);
delegate = wrapped;
this.className = className;
}
@Override
@@ -357,6 +380,11 @@ public class InlineCodegen extends CallGenerator {
return delegate.getInlineNameGenerator();
}
@NotNull
@Override
public String getClassName() {
return className;
}
}
@Override
@@ -627,4 +655,8 @@ public class InlineCodegen extends CallGenerator {
}
}
private SourceMapper createNestedSourceMapper(@NotNull SMAPAndMethodNode nodeAndSmap) {
return new NestedSourceMapper(sourceMapper, nodeAndSmap.getRanges(), nodeAndSmap.getClassSMAP().getSourceInfo());
}
}
@@ -24,8 +24,10 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.TestOnly;
import org.jetbrains.kotlin.backend.common.output.OutputFile;
import org.jetbrains.kotlin.codegen.MemberCodegen;
import org.jetbrains.kotlin.codegen.binding.CodegenBinding;
import org.jetbrains.kotlin.codegen.context.CodegenContext;
import org.jetbrains.kotlin.codegen.context.MethodContext;
import org.jetbrains.kotlin.codegen.context.PackageContext;
import org.jetbrains.kotlin.codegen.state.GenerationState;
import org.jetbrains.kotlin.codegen.state.JetTypeMapper;
@@ -43,6 +45,7 @@ import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils;
import org.jetbrains.kotlin.resolve.DescriptorUtils;
import org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilPackage;
import org.jetbrains.kotlin.resolve.jvm.AsmTypes;
import org.jetbrains.kotlin.resolve.jvm.JvmClassName;
import org.jetbrains.kotlin.serialization.ProtoBuf;
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedSimpleFunctionDescriptor;
import org.jetbrains.kotlin.serialization.jvm.JvmProtoBuf;
@@ -83,11 +86,14 @@ public class InlineCodegenUtil {
byte[] classData,
final String methodName,
final String methodDescriptor,
String containerInternalName
ClassId classId
) throws ClassNotFoundException, IOException {
ClassReader cr = new ClassReader(classData);
final MethodNode[] node = new MethodNode[1];
final String [] debugInfo = new String[2];
final String[] debugInfo = new String[2];
final int[] lines = new int[2];
lines[0] = Integer.MAX_VALUE;
lines[1] = Integer.MIN_VALUE;
cr.accept(new ClassVisitor(API) {
@Override
@@ -98,22 +104,53 @@ public class InlineCodegenUtil {
}
@Override
public MethodVisitor visitMethod(int access, @NotNull String name, @NotNull String desc, String signature, String[] exceptions) {
public MethodVisitor visitMethod(
int access,
@NotNull String name,
@NotNull String desc,
String signature,
String[] exceptions
) {
if (methodName.equals(name) && methodDescriptor.equals(desc)) {
node[0] = new MethodNode(access, name, desc, signature, exceptions);
node[0] = new MethodNode(API, access, name, desc, signature, exceptions) {
@Override
public void visitLineNumber(int line, Label start) {
super.visitLineNumber(line, start);
lines[0] = Math.min(lines[0], line);
lines[1] = Math.max(lines[1], line);
}
};
return node[0];
}
return null;
}
}, ClassReader.SKIP_FRAMES);
return new SMAPAndMethodNode(node[0], debugInfo[0], containerInternalName, new SMAPParser(debugInfo[1], "TODO").parse());
SMAP smap = new SMAPParser(debugInfo[1], debugInfo[0], classId.toString(), lines[0], lines[1]).parse();
return new SMAPAndMethodNode(node[0], smap);
}
public static void initDefaultSourceMappingIfNeeded(@NotNull CodegenContext context, @NotNull MemberCodegen codegen, @NotNull GenerationState state) {
if (state.isInlineEnabled()) {
CodegenContext<?> parentContext = context.getParentContext();
while (parentContext != null) {
if (parentContext instanceof MethodContext) {
if (((MethodContext) parentContext).isInlineFunction()) {
//just init default one to one mapping
codegen.getOrCreateSourceMapper();
break;
}
}
parentContext = parentContext.getParentContext();
}
}
}
@NotNull
public static VirtualFile getVirtualFileForCallable(@NotNull ClassId containerClassId, @NotNull GenerationState state) {
VirtualFile file = findVirtualFileWithHeader(state.getProject(), containerClassId);
VirtualFileFinder fileFinder = VirtualFileFinder.SERVICE.getInstance(state.getProject());
VirtualFile file = fileFinder.findVirtualFileWithHeader(containerClassId.asSingleFqName().toSafe());
if (file == null) {
throw new IllegalStateException("Couldn't find declaration file for " + containerClassId);
}
@@ -129,8 +166,7 @@ public class InlineCodegenUtil {
throw new IllegalStateException("Function in namespace should have implClassName property in proto: " + deserializedDescriptor);
}
Name name = deserializedDescriptor.getNameResolver().getName(proto.getExtension(JvmProtoBuf.implClassName));
ClassId packageClassId = PackageClassUtils.getPackageClassId(((PackageFragmentDescriptor) parentDeclaration).getFqName());
containerClassId = new ClassId(packageClassId.getPackageFqName(), name);
containerClassId = new ClassId(((PackageFragmentDescriptor) parentDeclaration).getFqName(), name);
} else {
containerClassId = getContainerClassId(deserializedDescriptor);
}
@@ -140,12 +176,6 @@ public class InlineCodegenUtil {
return containerClassId;
}
@Nullable
public static VirtualFile findVirtualFileWithHeader(@NotNull Project project, @NotNull ClassId containerClassId) {
VirtualFileFinder fileFinder = VirtualFileFinder.SERVICE.getInstance(project);
return fileFinder.findVirtualFileWithHeader(containerClassId.asSingleFqName().toSafe());
}
@Nullable
public static VirtualFile findVirtualFile(@NotNull Project project, @NotNull String internalName) {
VirtualFileFinder fileFinder = VirtualFileFinder.SERVICE.getInstance(project);
@@ -163,8 +193,9 @@ public class InlineCodegenUtil {
if (containerDescriptor instanceof ClassDescriptor) {
ClassId classId = DescriptorUtilPackage.getClassId((ClassDescriptor) containerDescriptor);
if (isTrait(containerDescriptor)) {
FqNameUnsafe shortName = classId.getRelativeClassName();
classId = new ClassId(classId.getPackageFqName(), Name.identifier(shortName.shortName().toString() + JvmAbi.TRAIT_IMPL_SUFFIX));
FqNameUnsafe relativeClassName = classId.getRelativeClassName();
//TODO test nested trait fun inlining
classId = new ClassId(classId.getPackageFqName(), Name.identifier(relativeClassName.shortName().asString() + JvmAbi.TRAIT_IMPL_SUFFIX));
}
return classId;
}
@@ -32,7 +32,6 @@ import org.jetbrains.kotlin.resolve.BindingContext;
import org.jetbrains.kotlin.resolve.jvm.AsmTypes;
import org.jetbrains.org.objectweb.asm.Type;
import org.jetbrains.org.objectweb.asm.tree.FieldInsnNode;
import org.jetbrains.org.objectweb.asm.tree.MethodNode;
import java.util.ArrayList;
import java.util.Arrays;
@@ -51,7 +50,7 @@ public class LambdaInfo implements CapturedParamOwner, LabelOwner {
private final CalculatedClosure closure;
private MethodNode node;
private SMAPAndMethodNode node;
private List<CapturedParamDesc> capturedVars;
@@ -76,11 +75,11 @@ public class LambdaInfo implements CapturedParamOwner, LabelOwner {
assert closure != null : "Closure for lambda should be not null " + expression.getText();
}
public MethodNode getNode() {
public SMAPAndMethodNode getNode() {
return node;
}
public void setNode(MethodNode node) {
public void setNode(SMAPAndMethodNode node) {
this.node = node;
}
@@ -54,7 +54,7 @@ public class MethodInliner {
private final String errorPrefix;
private SourceMapper sourceMapper;
private final SourceMapper sourceMapper;
private final JetTypeMapper typeMapper;
@@ -83,7 +83,7 @@ public class MethodInliner {
@NotNull FieldRemapper nodeRemapper,
boolean isSameModule,
@NotNull String errorPrefix,
SourceMapper sourceMapper
@NotNull SourceMapper sourceMapper
) {
this.node = node;
this.parameters = parameters;
@@ -132,6 +132,7 @@ public class MethodInliner {
//flush transformed node to output
resultNode.accept(new InliningInstructionAdapter(adapter));
sourceMapper.endMapping();
return result;
}
@@ -216,11 +217,16 @@ public class MethodInliner {
new InlinedLambdaRemapper(info.getLambdaClassType().getInternalName(), nodeRemapper, lambdaParameters);
setLambdaInlining(true);
MethodInliner inliner = new MethodInliner(info.getNode(), lambdaParameters,
SMAP lambdaSMAP = info.getNode().getClassSMAP();
SourceMapper mapper =
inliningContext.classRegeneration && !inliningContext.isInliningLambda ?
new NestedSourceMapper(sourceMapper, lambdaSMAP.getIntervals(), lambdaSMAP.getSourceInfo())
: new InlineLambdaSourceMapper(sourceMapper.getParent(), info.getNode());
MethodInliner inliner = new MethodInliner(info.getNode().getNode(), lambdaParameters,
inliningContext.subInlineLambda(info),
newCapturedRemapper, true /*cause all calls in same module as lambda*/,
"Lambda inlining " + info.getLambdaClassType().getInternalName(),
IdenticalSourceMapper.INSTANCE$);
mapper);
LocalVarRemapper remapper = new LocalVarRemapper(lambdaParameters, valueParamShift);
InlineResult lambdaResult = inliner.doInline(this.mv, remapper, true, info);//TODO add skipped this and receiver
@@ -233,6 +239,7 @@ public class MethodInliner {
StackValue.onStack(delegate.getReturnType()).put(bridge.getReturnType(), this);
setLambdaInlining(false);
addInlineMarker(this, false);
mapper.endMapping();
}
else if (isAnonymousConstructorCall(owner, name)) { //TODO add method
assert anonymousObjectGen != null : "<init> call not corresponds to new call" + owner + " " + name;
@@ -272,7 +279,6 @@ public class MethodInliner {
};
node.accept(lambdaInliner);
return resultNode;
@@ -81,4 +81,5 @@ public class RemappingClassBuilder extends DelegatingClassBuilder {
public ClassVisitor getVisitor() {
return new RemappingClassAdapter(builder.getVisitor(), remapper);
}
}
@@ -16,16 +16,20 @@
package org.jetbrains.kotlin.codegen.inline
import com.intellij.openapi.application.ApplicationManager
import org.jetbrains.org.objectweb.asm.MethodVisitor
import org.jetbrains.org.objectweb.asm.Label
import java.util
import java.util.HashSet
import java.util.Arrays
import java.util.LinkedHashMap
import java.util.Collections
import java.util.ArrayList
import org.jetbrains.kotlin.codegen.SourceInfo
import org.jetbrains.kotlin.codegen.ClassBuilder
//TODO join parameter
public class SMAPBuilder(val source: String,
val path: String,
val fileMappings: List<FileMapping>,
val lineCountInOriginalFile: Int) {
val fileMappings: List<FileMapping>) {
val header = "SMAP\n$source\nKotlin\n*S Kotlin"
@@ -34,29 +38,13 @@ public class SMAPBuilder(val source: String,
return null;
}
val fileIds = "*F" + fileMappings.mapIndexed {(id, file) -> "\n${file.toSMAPFile(id + 1)}" }.join("")
val lineMappings = "*L" + fileMappings.map { it.toSMAPMapping() }.join("")
val defaultSourceMapping = RawFileMapping(source, path)
for(i in 1..lineCountInOriginalFile) {
defaultSourceMapping.mapLine(i, i - 1, true)
}
val allMappings = arrayListOf(defaultSourceMapping.toFileMapping())
allMappings.addAll(fileMappings)
var id = 1;
val fileIds = "*F" +
allMappings.fold("") {(a, e) ->
a + "\n${e.toSMAPFile(id++)}"
}
val fileMappings = "*L" +
allMappings.fold("") {(a, e) ->
a + "${e.toSMAPMapping()}"
}
return header + "\n" + fileIds +"\n" + fileMappings + "\n*E\n"
return "$header\n$fileIds\n$lineMappings\n*E\n"
}
fun RangeMapping.toSMAP(fileId: Int): String {
return if (range == 1) "$source#$fileId:$dest" else "$source#$fileId,$range:$dest"
}
@@ -66,55 +54,193 @@ public class SMAPBuilder(val source: String,
return "+ $id $name\n$path"
}
//TODO inline
fun FileMapping.toSMAPMapping(): String {
return lineMappings.fold("") {
(a, e) ->
"$a\n${e.toSMAP(id)}"
return lineMappings.map {
"\n${it.toSMAP(id)}"
}.join("")
}
}
public open class NestedSourceMapper(parent: SourceMapper, val ranges: List<RangeMapping>, sourceInfo: SourceInfo) : DefaultSourceMapper(sourceInfo, parent) {
override fun visitLineNumber(iv: MethodVisitor, lineNumber: Int, start: Label) {
val index = Collections.binarySearch(ranges, RangeMapping(lineNumber, lineNumber, 1)) {
(value, key) ->
if (value.contains(key.dest)) 0 else RangeMapping.Comparator.compare(value, key)
}
if (index < 0) {
parent!!.visitSource(sourceInfo.source, sourceInfo.pathOrCleanFQN)
parent!!.visitLineNumber(iv, lineNumber, start)
}
else {
val rangeMapping = ranges[index]
parent!!.visitSource(rangeMapping.parent!!.name, rangeMapping.parent!!.path)
parent!!.visitLineNumber(iv, rangeMapping.map(lineNumber), start)
}
}
}
public object IdenticalSourceMapper: SourceMapper(-1) {
public open class InlineLambdaSourceMapper(parent: SourceMapper, smap: SMAPAndMethodNode) : NestedSourceMapper(parent, smap.ranges, smap.classSMAP.sourceInfo) {
override fun visitSource(name: String, path: String) {
super.visitSource(name, path)
if (isOriginalVisited()) {
parent!!.visitOrigin()
}
}
override fun visitOrigin() {
super.visitOrigin()
parent!!.visitOrigin()
}
private fun isOriginalVisited(): Boolean {
return lastVisited == origin
}
override fun visitLineNumber(iv: MethodVisitor, lineNumber: Int, start: Label) {
val index = Collections.binarySearch(ranges, RangeMapping(lineNumber, lineNumber, 1)) {
(value, key) ->
if (value.contains(key.dest)) 0 else RangeMapping.Comparator.compare(value, key)
}
if (index >= 0) {
val fmapping = ranges[index].parent!!
if (fmapping.path == origin.path && fmapping.name == origin.name) {
parent!!.visitOrigin()
parent!!.visitLineNumber(iv, lineNumber, start)
return
}
}
super.visitLineNumber(iv, lineNumber, start)
}
}
trait SourceMapper {
val resultMappings: List<FileMapping>
val parent: SourceMapper?
open fun visitSource(name: String, path: String) {
throw UnsupportedOperationException("fail")
}
open fun visitOrigin() {
throw UnsupportedOperationException("fail")
}
open fun visitLineNumber(iv: MethodVisitor, lineNumber: Int, start: Label) {
throw UnsupportedOperationException("fail")
}
open fun endMapping() {
parent?.visitOrigin()
}
default object {
fun flushToClassBuilder(mapper: SourceMapper, v: ClassBuilder) {
for (fileMapping in mapper.resultMappings) {
v.addSMAP(fileMapping)
}
}
fun createFromSmap(smap: SMAP): DefaultSourceMapper {
val sourceMapper = DefaultSourceMapper(smap.sourceInfo, null)
smap.fileMappings.stream()
//default one mapped through sourceInfo
.filterNot { it == smap.default }
.forEach { fileMapping ->
sourceMapper.visitSource(fileMapping.name, fileMapping.path)
fileMapping.lineMappings.forEach {
sourceMapper.lastVisited!!.mapNewInterval(it.source, it.dest, it.range)
}
}
return sourceMapper
}
}
}
public object IdenticalSourceMapper : SourceMapper {
override val resultMappings: List<FileMapping>
get() = emptyList()
override val parent: SourceMapper?
get() = null
override fun visitSource(name: String, path: String) {}
override fun visitOrigin() {}
override fun visitLineNumber(iv: MethodVisitor, lineNumber: Int, start: Label) {
iv.visitLineNumber(lineNumber, start)
}
}
public open class SourceMapper(val lineNumbers: Int) {
public open class DefaultSourceMapper(val sourceInfo: SourceInfo, override val parent: SourceMapper?): SourceMapper {
private var maxUsedValue = lineNumbers;
protected var maxUsedValue: Int = sourceInfo.linesInFile
private var lastMappedWithChanges: RawFileMapping? = null;
var lastVisited: RawFileMapping? = null
var fileMapping: MutableList<RawFileMapping> = arrayListOf();
private var lastMappedWithChanges: RawFileMapping? = null
open fun visitSource(name: String, path: String) {
fileMapping.add(RawFileMapping(name, path))
var fileMappings: LinkedHashMap<String, RawFileMapping> = linkedMapOf();
protected val origin: RawFileMapping
{
visitSource(sourceInfo.source, sourceInfo.pathOrCleanFQN)
origin = lastVisited!!
//map interval
(1..maxUsedValue).forEach {origin.mapLine(it, it - 1, true) }
}
open fun visitLineNumber(iv: MethodVisitor, lineNumber: Int, start: Label) {
val fileMapping = fileMapping.last()
val mappedLineIndex = fileMapping.mapLine(lineNumber, maxUsedValue, true)
override val resultMappings: List<FileMapping>
get() = fileMappings.values().map { it.toFileMapping() }
override fun visitSource(name: String, path: String) {
lastVisited = fileMappings.getOrPut("$name#$path", { RawFileMapping(name, path) })
}
override fun visitOrigin() {
lastVisited = origin
}
override fun visitLineNumber(iv: MethodVisitor, lineNumber: Int, start: Label) {
val mappedLineIndex = createMapping(lineNumber)
iv.visitLineNumber(mappedLineIndex, start)
}
protected fun createMapping(lineNumber: Int): Int {
val fileMapping = lastVisited!!
val mappedLineIndex = fileMapping.mapLine(lineNumber, maxUsedValue, lastMappedWithChanges == lastVisited)
if (mappedLineIndex > maxUsedValue) {
lastMappedWithChanges = fileMapping
maxUsedValue = mappedLineIndex
}
return mappedLineIndex
}
}
/*Source Mapping*/
class SMAP(val fileMappings: List<FileMapping>) {
init {
assert(fileMappings.isNotEmpty(), "File Mappings shouldn't be empty")
}
}
/*Source Mapping*/
class SMAP(fileMappings: List<FileMapping>) {
var fileMappings: List<FileMapping> = fileMappings
val default: FileMapping
get() = fileMappings.first()
val intervals = fileMappings.flatMap { it -> it.lineMappings }.sortBy(RangeMapping.Comparator)
val intervals = fileMappings.flatMap { it.lineMappings }.sortBy(RangeMapping.Comparator)
class object {
val sourceInfo: SourceInfo
init {
val defaultMapping = default.lineMappings.single()
sourceInfo = SourceInfo(default.name, default.path, defaultMapping.source + defaultMapping.range - 1)
}
default object {
val FILE_SECTION = "*F"
val LINE_SECTION = "*L"
@@ -138,27 +264,38 @@ class RawFileMapping(val name: String, val path: String) {
}
fun mapLine(source: Int, currentIndex: Int, isLastMapped: Boolean): Int {
var dest = lineMappings.get(source);
var dest = lineMappings[source]
if (dest == null) {
val rangeMapping: RangeMapping
if (rangeMappings.isNotEmpty() && isLastMapped && couldFoldInRange(lastMappedWithNewIndex, source)) {
rangeMapping = rangeMappings.last()
rangeMapping.range += source - lastMappedWithNewIndex;
dest = lineMappings.get(lastMappedWithNewIndex) + source - lastMappedWithNewIndex;
} else {
dest = currentIndex + 1;
rangeMapping.range += source - lastMappedWithNewIndex
dest = lineMappings[lastMappedWithNewIndex] + source - lastMappedWithNewIndex
}
else {
dest = currentIndex + 1
rangeMapping = RangeMapping(source, dest)
rangeMappings.add(rangeMapping)
}
lineMappings.put(source, dest)
lastMappedWithNewIndex = source;
lastMappedWithNewIndex = source
}
return dest
}
fun mapNewInterval(source: Int, dest: Int, range: Int) {
val rangeMapping = RangeMapping(source, dest, range)
rangeMappings.add(rangeMapping)
(source..(source + range - 1)).forEach {
lineMappings.put(source, dest)
}
}
private fun couldFoldInRange(first: Int, second: Int): Boolean {
//TODO
val delta = second - first
return delta > 0 && delta <= 10;
}
@@ -175,7 +312,8 @@ public class FileMapping(val name: String, val path: String) {
}
}
public class RangeMapping(val source: Int, val dest: Int, var range: Int = 1) {
//TODO comparable
data public class RangeMapping(val source: Int, val dest: Int, var range: Int = 1) {
var parent: FileMapping? = null;
@@ -184,7 +322,7 @@ public class RangeMapping(val source: Int, val dest: Int, var range: Int = 1) {
}
fun map(destLine: Int): Int {
return source + destLine - dest
return source + (destLine - dest)
}
object Comparator : util.Comparator<RangeMapping> {
@@ -194,7 +332,8 @@ public class RangeMapping(val source: Int, val dest: Int, var range: Int = 1) {
val res = o1.dest - o2.dest
if (res == 0) {
return o1.range - o2.range
} else {
}
else {
return res
}
}
@@ -22,23 +22,24 @@ import org.jetbrains.org.objectweb.asm.tree.LineNumberNode
import org.jetbrains.org.objectweb.asm.Label
import kotlin.properties.Delegates
import java.util.Collections
import kotlin.properties.ReadOnlyProperty
import org.jetbrains.kotlin.codegen.SourceInfo
class SMAPAndMethodNode(val node: MethodNode, val source: String, val sourcePath: String, classSMAP: SMAP) {
//TODO comment
class SMAPAndMethodNode(val node: MethodNode, val classSMAP: SMAP) {
val lineNumbers = Delegates.lazy {
InsnStream(node.instructions.getFirst(), null).filterIsInstance(javaClass<LineNumberNode>()).map {
val index = Collections.binarySearch(classSMAP.intervals, RangeMapping(it.line, it.line, 1), {
(value, key) -> if (value.contains(key.dest)) 0 else RangeMapping.Comparator.compare(value, key)
})
if (index < 0) throw IllegalStateException("Unmapped lable in inlined function " + it)
val lineNumbers =
InsnStream(node.instructions.getFirst(), null).stream().filterIsInstance<LineNumberNode>().map {
val index = Collections.binarySearch(classSMAP.intervals, RangeMapping(it.line, it.line, 1)) {
(value, key) ->
if (value.contains(key.dest)) 0 else RangeMapping.Comparator.compare(value, key)
}
if (index < 0)
throw IllegalStateException("Unmapped label in inlined function $it ${it.line}")
LabelAndMapping(it, classSMAP.intervals[index])
}
};
}.toList()
val ranges = lineNumbers.stream().map { it.mapper }.toList().distinct().toList();
}
class LabelAndMapping(val lineNumberNode: LineNumberNode, val mapper: RangeMapping) {
val getOriginalLine = mapper.map(lineNumberNode.line)
val getOriginalFileName = mapper.parent!!.name
val getOriginalPath = mapper.parent!!.path
}
class LabelAndMapping(val lineNumberNode: LineNumberNode, val mapper: RangeMapping)
@@ -16,18 +16,23 @@
package org.jetbrains.kotlin.codegen.inline
class SMAPParser(val input: String?, val path: String) {
class SMAPParser(val mappingInfo: String?, val source: String, val path: String, val methodStartLine: Int, val methodEndLine: Int) {
val fileMappings = linkedMapOf<Int, FileMapping>()
fun parse() : SMAP {
if (input == null || input.isEmpty()) {
return SMAP(listOf())
if (mappingInfo == null || mappingInfo.isEmpty()) {
val fm = FileMapping(source, path)
if (methodStartLine <= methodEndLine) {
//one to one
fm.addRangeMapping(RangeMapping(methodStartLine, methodStartLine, methodEndLine - methodStartLine + 1))
}
return SMAP(listOf(fm))
}
val fileSectionStart = input.indexOf(SMAP.FILE_SECTION) + SMAP.FILE_SECTION.length()
val lineSectionAnchor = input.indexOf(SMAP.LINE_SECTION)
val files = input.substring(fileSectionStart, lineSectionAnchor)
val fileSectionStart = mappingInfo.indexOf(SMAP.FILE_SECTION) + SMAP.FILE_SECTION.length()
val lineSectionAnchor = mappingInfo.indexOf(SMAP.LINE_SECTION)
val files = mappingInfo.substring(fileSectionStart, lineSectionAnchor)
val fileEntries = files.trim().split('+')
@@ -44,7 +49,7 @@ class SMAPParser(val input: String?, val path: String) {
}
val lines = input.substring(lineSectionAnchor + SMAP.LINE_SECTION.length(), input.indexOf(SMAP.END)).trim().split('\n')
val lines = mappingInfo.substring(lineSectionAnchor + SMAP.LINE_SECTION.length(), mappingInfo.indexOf(SMAP.END)).trim().split('\n')
for (lineMapping in lines) {
/*only simple mapping now*/
val targetSplit = lineMapping.indexOf(':')
@@ -0,0 +1,9 @@
inline fun inlineFun(s: () -> Unit) {
s()
}
fun main(args: Array<String>) {
inlineFun {
test.lineNumber()
}
}
@@ -114,6 +114,12 @@ public class LineNumberTestGenerated extends AbstractLineNumberTest {
doTest(fileName);
}
@TestMetadata("simpleSmap.kt")
public void testSimpleSmap() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/lineNumber/simpleSmap.kt");
doTest(fileName);
}
@TestMetadata("topLevel.kt")
public void testTopLevel() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/lineNumber/topLevel.kt");