Throw exception on inlining bytecode of version > 1.6

To prevent ASM from failing with a meaningless exception in this case as soon
as we support target 1.8 and someone tries to compile some code with the
current compiler against the new (1.8) code.
This commit is contained in:
Alexander Udalov
2015-12-21 16:24:01 +03:00
parent 7449ad2763
commit 97ce61ac44
3 changed files with 51 additions and 36 deletions
@@ -88,6 +88,8 @@ public class AnonymousObjectTransformer {
reader.accept(new ClassVisitor(InlineCodegenUtil.API, classBuilder.getVisitor()) { reader.accept(new ClassVisitor(InlineCodegenUtil.API, classBuilder.getVisitor()) {
@Override @Override
public void visit(int version, int access, @NotNull String name, String signature, String superName, String[] interfaces) { public void visit(int version, int access, @NotNull String name, String signature, String superName, String[] interfaces) {
InlineCodegenUtil.assertVersionNotGreaterThanJava6(version);
if (signature != null) { if (signature != null) {
ReifiedTypeInliner.SignatureReificationResult signatureResult = inliningContext.reifedTypeInliner.reifySignature(signature); ReifiedTypeInliner.SignatureReificationResult signatureResult = inliningContext.reifedTypeInliner.reifySignature(signature);
signature = signatureResult.getNewSignature(); signature = signatureResult.getNewSignature();
@@ -97,7 +99,7 @@ public class AnonymousObjectTransformer {
} }
@Override @Override
public void visitInnerClass(String name, String outerName, String innerName, int access) { public void visitInnerClass(@NotNull String name, String outerName, String innerName, int access) {
innerClassNodes.add(new InnerClassNode(name, outerName, innerName, access)); innerClassNodes.add(new InnerClassNode(name, outerName, innerName, access));
} }
@@ -162,7 +164,7 @@ public class AnonymousObjectTransformer {
} }
else { else {
//seems we can't do any clever mapping cause we don't know any about original class name //seems we can't do any clever mapping cause we don't know any about original class name
sourceMapper = IdenticalSourceMapper.INSTANCE$; sourceMapper = IdenticalSourceMapper.INSTANCE;
} }
if (sourceInfo != null && !InlineCodegenUtil.GENERATE_SMAP) { if (sourceInfo != null && !InlineCodegenUtil.GENERATE_SMAP) {
classBuilder.visitSource(sourceInfo, debugInfo); classBuilder.visitSource(sourceInfo, debugInfo);
@@ -172,7 +174,7 @@ public class AnonymousObjectTransformer {
if (sourceInfo != null) { if (sourceInfo != null) {
classBuilder.visitSource(sourceInfo, debugInfo); classBuilder.visitSource(sourceInfo, debugInfo);
} }
sourceMapper = IdenticalSourceMapper.INSTANCE$; sourceMapper = IdenticalSourceMapper.INSTANCE;
} }
ParametersBuilder allCapturedParamBuilder = ParametersBuilder.newBuilder(); ParametersBuilder allCapturedParamBuilder = ParametersBuilder.newBuilder();
@@ -180,7 +182,7 @@ public class AnonymousObjectTransformer {
List<CapturedParamInfo> additionalFakeParams = List<CapturedParamInfo> additionalFakeParams =
extractParametersMappingAndPatchConstructor(constructor, allCapturedParamBuilder, constructorParamBuilder, extractParametersMappingAndPatchConstructor(constructor, allCapturedParamBuilder, constructorParamBuilder,
anonymousObjectGen, parentRemapper); anonymousObjectGen, parentRemapper);
List<MethodVisitor> deferringMethods = new ArrayList(); List<MethodVisitor> deferringMethods = new ArrayList<MethodVisitor>();
for (MethodNode next : methodsToTransform) { for (MethodNode next : methodsToTransform) {
MethodVisitor deferringVisitor = newMethod(classBuilder, next); MethodVisitor deferringVisitor = newMethod(classBuilder, next);
@@ -33,6 +33,7 @@ import org.jetbrains.kotlin.descriptors.*;
import org.jetbrains.kotlin.load.kotlin.incremental.components.IncrementalCache; import org.jetbrains.kotlin.load.kotlin.incremental.components.IncrementalCache;
import org.jetbrains.kotlin.load.kotlin.incremental.components.IncrementalCompilationComponents; import org.jetbrains.kotlin.load.kotlin.incremental.components.IncrementalCompilationComponents;
import org.jetbrains.kotlin.modules.TargetId; import org.jetbrains.kotlin.modules.TargetId;
import org.jetbrains.kotlin.name.ClassId;
import org.jetbrains.kotlin.name.Name; import org.jetbrains.kotlin.name.Name;
import org.jetbrains.kotlin.psi.*; import org.jetbrains.kotlin.psi.*;
import org.jetbrains.kotlin.renderer.DescriptorRenderer; import org.jetbrains.kotlin.renderer.DescriptorRenderer;
@@ -192,11 +193,15 @@ public class InlineCodegen extends CallGenerator {
JetTypeMapper.ContainingClassesInfo containingClasses = typeMapper.getContainingClassesForDeserializedCallable( JetTypeMapper.ContainingClassesInfo containingClasses = typeMapper.getContainingClassesForDeserializedCallable(
(DeserializedSimpleFunctionDescriptor) functionDescriptor); (DeserializedSimpleFunctionDescriptor) functionDescriptor);
VirtualFile file = InlineCodegenUtil.getVirtualFileForCallable(containingClasses.getImplClassId(), state); ClassId containerId = containingClasses.getImplClassId();
nodeAndSMAP = InlineCodegenUtil.getMethodNode(file.contentsToByteArray(), VirtualFile file = InlineCodegenUtil.findVirtualFile(state, containerId);
asmMethod.getName(), if (file == null) {
asmMethod.getDescriptor(), throw new IllegalStateException("Couldn't find declaration file for " + containerId);
containingClasses.getFacadeClassId()); }
nodeAndSMAP = InlineCodegenUtil.getMethodNode(
file.contentsToByteArray(), asmMethod.getName(), asmMethod.getDescriptor(), containingClasses.getFacadeClassId()
);
if (nodeAndSMAP == null) { if (nodeAndSMAP == null) {
throw new RuntimeException("Couldn't obtain compiled function body for " + descriptorName(functionDescriptor)); throw new RuntimeException("Couldn't obtain compiled function body for " + descriptorName(functionDescriptor));
@@ -16,11 +16,10 @@
package org.jetbrains.kotlin.codegen.inline; package org.jetbrains.kotlin.codegen.inline;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiElement; import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile; import com.intellij.psi.PsiFile;
import kotlin.StringsKt; import kotlin.text.StringsKt;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.TestOnly; import org.jetbrains.annotations.TestOnly;
@@ -92,6 +91,10 @@ public class InlineCodegenUtil {
lines[0] = Integer.MAX_VALUE; lines[0] = Integer.MAX_VALUE;
lines[1] = Integer.MIN_VALUE; lines[1] = Integer.MIN_VALUE;
cr.accept(new ClassVisitor(API) { cr.accept(new ClassVisitor(API) {
@Override
public void visit(int version, int access, @NotNull String name, String signature, String superName, String[] interfaces) {
assertVersionNotGreaterThanJava6(version);
}
@Override @Override
public void visitSource(String source, String debug) { public void visitSource(String source, String debug) {
@@ -127,40 +130,44 @@ public class InlineCodegenUtil {
return new SMAPAndMethodNode(node[0], smap); return new SMAPAndMethodNode(node[0], smap);
} }
public static void initDefaultSourceMappingIfNeeded(@NotNull CodegenContext context, @NotNull MemberCodegen codegen, @NotNull GenerationState state) { public static void assertVersionNotGreaterThanJava6(int version) {
if (state.isInlineEnabled()) { // TODO: report a proper diagnostic
CodegenContext<?> parentContext = context.getParentContext(); if (version > Opcodes.V1_6) {
while (parentContext != null) { throw new UnsupportedOperationException(
if (parentContext instanceof MethodContext) { "Cannot inline bytecode of version " + version + ". " +
if (((MethodContext) parentContext).isInlineMethodContext()) { "This compiler can only inline Java 1.6 bytecode (version " + Opcodes.V1_6 + ")"
//just init default one to one mapping );
codegen.getOrCreateSourceMapper();
break;
}
}
parentContext = parentContext.getParentContext();
}
} }
} }
@NotNull public static void initDefaultSourceMappingIfNeeded(
public static VirtualFile getVirtualFileForCallable(@NotNull ClassId containerClassId, @NotNull GenerationState state) { @NotNull CodegenContext context, @NotNull MemberCodegen codegen, @NotNull GenerationState state
JvmVirtualFileFinder fileFinder = JvmVirtualFileFinder.SERVICE.getInstance(state.getProject()); ) {
VirtualFile file = fileFinder.findVirtualFileWithHeader(containerClassId); if (!state.isInlineEnabled()) return;
if (file == null) {
throw new IllegalStateException("Couldn't find declaration file for " + containerClassId); CodegenContext<?> parentContext = context.getParentContext();
while (parentContext != null) {
if (parentContext.isInlineMethodContext()) {
//just init default one to one mapping
codegen.getOrCreateSourceMapper();
break;
}
parentContext = parentContext.getParentContext();
} }
return file;
} }
@Nullable @Nullable
public static VirtualFile findVirtualFile(@NotNull Project project, @NotNull String internalClassName) { public static VirtualFile findVirtualFile(@NotNull GenerationState state, @NotNull ClassId classId) {
return JvmVirtualFileFinder.SERVICE.getInstance(state.getProject()).findVirtualFileWithHeader(classId);
}
@Nullable
public static VirtualFile findVirtualFileImprecise(@NotNull GenerationState state, @NotNull String internalClassName) {
FqName packageFqName = JvmClassName.byInternalName(internalClassName).getPackageFqName(); FqName packageFqName = JvmClassName.byInternalName(internalClassName).getPackageFqName();
String classNameWithDollars = StringsKt.substringAfterLast(internalClassName, "/", internalClassName); String classNameWithDollars = StringsKt.substringAfterLast(internalClassName, "/", internalClassName);
JvmVirtualFileFinder fileFinder = JvmVirtualFileFinder.SERVICE.getInstance(project);
//TODO: we cannot construct proper classId at this point, we need to read InnerClasses info from class file //TODO: we cannot construct proper classId at this point, we need to read InnerClasses info from class file
// we construct valid.package.name/RelativeClassNameAsSingleName that should work in compiler, but fails for inner classes in IDE // we construct valid.package.name/RelativeClassNameAsSingleName that should work in compiler, but fails for inner classes in IDE
return fileFinder.findVirtualFileWithHeader(new ClassId(packageFqName, Name.identifier(classNameWithDollars))); return findVirtualFile(state, new ClassId(packageFqName, Name.identifier(classNameWithDollars)));
} }
public static String getInlineName( public static String getInlineName(
@@ -362,8 +369,9 @@ public class InlineCodegenUtil {
OutputFile outputFile = state.getFactory().get(internalName + ".class"); OutputFile outputFile = state.getFactory().get(internalName + ".class");
if (outputFile != null) { if (outputFile != null) {
return new ClassReader(outputFile.asByteArray()); return new ClassReader(outputFile.asByteArray());
} else { }
VirtualFile file = findVirtualFile(state.getProject(), internalName); else {
VirtualFile file = findVirtualFileImprecise(state, internalName);
if (file == null) { if (file == null) {
throw new RuntimeException("Couldn't find virtual file for " + internalName); throw new RuntimeException("Couldn't find virtual file for " + internalName);
} }