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()) {
@Override
public void visit(int version, int access, @NotNull String name, String signature, String superName, String[] interfaces) {
InlineCodegenUtil.assertVersionNotGreaterThanJava6(version);
if (signature != null) {
ReifiedTypeInliner.SignatureReificationResult signatureResult = inliningContext.reifedTypeInliner.reifySignature(signature);
signature = signatureResult.getNewSignature();
@@ -97,7 +99,7 @@ public class AnonymousObjectTransformer {
}
@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));
}
@@ -162,7 +164,7 @@ public class AnonymousObjectTransformer {
}
else {
//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) {
classBuilder.visitSource(sourceInfo, debugInfo);
@@ -172,7 +174,7 @@ public class AnonymousObjectTransformer {
if (sourceInfo != null) {
classBuilder.visitSource(sourceInfo, debugInfo);
}
sourceMapper = IdenticalSourceMapper.INSTANCE$;
sourceMapper = IdenticalSourceMapper.INSTANCE;
}
ParametersBuilder allCapturedParamBuilder = ParametersBuilder.newBuilder();
@@ -180,7 +182,7 @@ public class AnonymousObjectTransformer {
List<CapturedParamInfo> additionalFakeParams =
extractParametersMappingAndPatchConstructor(constructor, allCapturedParamBuilder, constructorParamBuilder,
anonymousObjectGen, parentRemapper);
List<MethodVisitor> deferringMethods = new ArrayList();
List<MethodVisitor> deferringMethods = new ArrayList<MethodVisitor>();
for (MethodNode next : methodsToTransform) {
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.IncrementalCompilationComponents;
import org.jetbrains.kotlin.modules.TargetId;
import org.jetbrains.kotlin.name.ClassId;
import org.jetbrains.kotlin.name.Name;
import org.jetbrains.kotlin.psi.*;
import org.jetbrains.kotlin.renderer.DescriptorRenderer;
@@ -192,11 +193,15 @@ public class InlineCodegen extends CallGenerator {
JetTypeMapper.ContainingClassesInfo containingClasses = typeMapper.getContainingClassesForDeserializedCallable(
(DeserializedSimpleFunctionDescriptor) functionDescriptor);
VirtualFile file = InlineCodegenUtil.getVirtualFileForCallable(containingClasses.getImplClassId(), state);
nodeAndSMAP = InlineCodegenUtil.getMethodNode(file.contentsToByteArray(),
asmMethod.getName(),
asmMethod.getDescriptor(),
containingClasses.getFacadeClassId());
ClassId containerId = containingClasses.getImplClassId();
VirtualFile file = InlineCodegenUtil.findVirtualFile(state, containerId);
if (file == null) {
throw new IllegalStateException("Couldn't find declaration file for " + containerId);
}
nodeAndSMAP = InlineCodegenUtil.getMethodNode(
file.contentsToByteArray(), asmMethod.getName(), asmMethod.getDescriptor(), containingClasses.getFacadeClassId()
);
if (nodeAndSMAP == null) {
throw new RuntimeException("Couldn't obtain compiled function body for " + descriptorName(functionDescriptor));
@@ -16,11 +16,10 @@
package org.jetbrains.kotlin.codegen.inline;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import kotlin.StringsKt;
import kotlin.text.StringsKt;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.TestOnly;
@@ -92,6 +91,10 @@ public class InlineCodegenUtil {
lines[0] = Integer.MAX_VALUE;
lines[1] = Integer.MIN_VALUE;
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
public void visitSource(String source, String debug) {
@@ -127,40 +130,44 @@ public class InlineCodegenUtil {
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).isInlineMethodContext()) {
//just init default one to one mapping
codegen.getOrCreateSourceMapper();
break;
}
}
parentContext = parentContext.getParentContext();
}
public static void assertVersionNotGreaterThanJava6(int version) {
// TODO: report a proper diagnostic
if (version > Opcodes.V1_6) {
throw new UnsupportedOperationException(
"Cannot inline bytecode of version " + version + ". " +
"This compiler can only inline Java 1.6 bytecode (version " + Opcodes.V1_6 + ")"
);
}
}
@NotNull
public static VirtualFile getVirtualFileForCallable(@NotNull ClassId containerClassId, @NotNull GenerationState state) {
JvmVirtualFileFinder fileFinder = JvmVirtualFileFinder.SERVICE.getInstance(state.getProject());
VirtualFile file = fileFinder.findVirtualFileWithHeader(containerClassId);
if (file == null) {
throw new IllegalStateException("Couldn't find declaration file for " + containerClassId);
public static void initDefaultSourceMappingIfNeeded(
@NotNull CodegenContext context, @NotNull MemberCodegen codegen, @NotNull GenerationState state
) {
if (!state.isInlineEnabled()) return;
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
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();
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
// 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(
@@ -362,8 +369,9 @@ public class InlineCodegenUtil {
OutputFile outputFile = state.getFactory().get(internalName + ".class");
if (outputFile != null) {
return new ClassReader(outputFile.asByteArray());
} else {
VirtualFile file = findVirtualFile(state.getProject(), internalName);
}
else {
VirtualFile file = findVirtualFileImprecise(state, internalName);
if (file == null) {
throw new RuntimeException("Couldn't find virtual file for " + internalName);
}