Fixed generating method calls from same module when inlining.

This commit is contained in:
Evgeny Gerashchenko
2014-07-10 17:26:40 +04:00
parent 6f1bdd1227
commit 708816f09c
9 changed files with 111 additions and 61 deletions
@@ -1899,7 +1899,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
propertyDescriptor = DescriptorUtils.unwrapFakeOverride(propertyDescriptor); propertyDescriptor = DescriptorUtils.unwrapFakeOverride(propertyDescriptor);
if (callableMethod == null) { if (callableMethod == null) {
owner = typeMapper.mapOwner(isBackingFieldInAnotherClass ? propertyDescriptor.getContainingDeclaration() : propertyDescriptor, owner = typeMapper.mapOwner(isBackingFieldInAnotherClass ? propertyDescriptor.getContainingDeclaration() : propertyDescriptor,
isCallInsideSameModuleAsDeclared(propertyDescriptor, context)); isCallInsideSameModuleAsDeclared(propertyDescriptor, context, state.getOutDirectory()));
} }
else { else {
owner = callableMethod.getOwner(); owner = callableMethod.getOwner();
@@ -16,6 +16,9 @@
package org.jetbrains.jet.codegen; package org.jetbrains.jet.codegen;
import com.intellij.openapi.vfs.StandardFileSystems;
import com.intellij.openapi.vfs.VfsUtilCore;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.containers.Stack; import com.intellij.util.containers.Stack;
import kotlin.Function1; import kotlin.Function1;
import kotlin.KotlinPackage; import kotlin.KotlinPackage;
@@ -26,20 +29,26 @@ import org.jetbrains.jet.codegen.context.CodegenContext;
import org.jetbrains.jet.codegen.context.MethodContext; import org.jetbrains.jet.codegen.context.MethodContext;
import org.jetbrains.jet.codegen.context.PackageContext; import org.jetbrains.jet.codegen.context.PackageContext;
import org.jetbrains.jet.codegen.state.JetTypeMapper; import org.jetbrains.jet.codegen.state.JetTypeMapper;
import org.jetbrains.jet.config.IncrementalCompilation; import org.jetbrains.jet.descriptors.serialization.descriptors.DeserializedCallableMemberDescriptor;
import org.jetbrains.jet.lang.descriptors.*; import org.jetbrains.jet.lang.descriptors.*;
import org.jetbrains.jet.lang.descriptors.annotations.Annotations; import org.jetbrains.jet.lang.descriptors.annotations.Annotations;
import org.jetbrains.jet.lang.descriptors.impl.SimpleFunctionDescriptorImpl; import org.jetbrains.jet.lang.descriptors.impl.SimpleFunctionDescriptorImpl;
import org.jetbrains.jet.lang.descriptors.impl.TypeParameterDescriptorImpl; import org.jetbrains.jet.lang.descriptors.impl.TypeParameterDescriptorImpl;
import org.jetbrains.jet.lang.resolve.DescriptorUtils; import org.jetbrains.jet.lang.resolve.DescriptorUtils;
import org.jetbrains.jet.lang.resolve.calls.CallResolverUtil; import org.jetbrains.jet.lang.resolve.calls.CallResolverUtil;
import org.jetbrains.jet.lang.resolve.java.descriptor.JavaPackageFragmentDescriptor;
import org.jetbrains.jet.lang.resolve.java.lazy.descriptors.LazyPackageFragmentScopeForJavaPackage;
import org.jetbrains.jet.lang.resolve.kotlin.KotlinJvmBinaryClass;
import org.jetbrains.jet.lang.resolve.kotlin.VirtualFileKotlinClass;
import org.jetbrains.jet.lang.resolve.kotlin.incremental.IncrementalPackageFragmentProvider; import org.jetbrains.jet.lang.resolve.kotlin.incremental.IncrementalPackageFragmentProvider;
import org.jetbrains.jet.lang.resolve.name.Name; import org.jetbrains.jet.lang.resolve.name.Name;
import org.jetbrains.jet.lang.resolve.scopes.JetScope;
import org.jetbrains.jet.lang.types.JetType; import org.jetbrains.jet.lang.types.JetType;
import org.jetbrains.jet.lang.types.TypeUtils; import org.jetbrains.jet.lang.types.TypeUtils;
import org.jetbrains.jet.lang.types.checker.JetTypeChecker; import org.jetbrains.jet.lang.types.checker.JetTypeChecker;
import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns; import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
import java.io.File;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
@@ -173,12 +182,55 @@ public class JvmCodegenUtil {
return false; return false;
} }
public static boolean isCallInsideSameModuleAsDeclared(CallableMemberDescriptor declarationDescriptor, CodegenContext context) { public static boolean isCallInsideSameModuleAsDeclared(
@NotNull CallableMemberDescriptor declarationDescriptor,
@NotNull CodegenContext context,
@Nullable File outDirectory
) {
if (context == CodegenContext.STATIC) { if (context == CodegenContext.STATIC) {
return true; return true;
} }
DeclarationDescriptor contextDescriptor = context.getContextDescriptor(); DeclarationDescriptor contextDescriptor = context.getContextDescriptor();
return DescriptorUtils.areInSameModule(declarationDescriptor, contextDescriptor);
CallableMemberDescriptor directMember = getDirectMember(declarationDescriptor);
if (directMember instanceof DeserializedCallableMemberDescriptor) {
return isContainedByCompiledPartOfOurModule(((DeserializedCallableMemberDescriptor) directMember), outDirectory);
}
else {
return DescriptorUtils.areInSameModule(directMember, contextDescriptor);
}
}
private static boolean isContainedByCompiledPartOfOurModule(
@NotNull DeserializedCallableMemberDescriptor descriptor,
@Nullable File outDirectory
) {
if (descriptor.getContainingDeclaration() instanceof IncrementalPackageFragmentProvider.IncrementalPackageFragment) {
return true;
}
if (outDirectory == null) {
return false;
}
if (!(descriptor.getContainingDeclaration() instanceof JavaPackageFragmentDescriptor)) {
return false;
}
JavaPackageFragmentDescriptor packageFragment = (JavaPackageFragmentDescriptor) descriptor.getContainingDeclaration();
JetScope packageScope = packageFragment.getMemberScope();
if (!(packageScope instanceof LazyPackageFragmentScopeForJavaPackage)) {
return false;
}
KotlinJvmBinaryClass binaryClass = ((LazyPackageFragmentScopeForJavaPackage) packageScope).getKotlinBinaryClass();
if (binaryClass instanceof VirtualFileKotlinClass) {
VirtualFile file = ((VirtualFileKotlinClass) binaryClass).getFile();
if (file.getFileSystem().getProtocol() == StandardFileSystems.FILE_PROTOCOL) {
File ioFile = VfsUtilCore.virtualToIoFile(file);
return ioFile.getAbsolutePath().startsWith(outDirectory.getAbsolutePath() + File.separator);
}
}
return false;
} }
public static boolean hasAbstractMembers(@NotNull ClassDescriptor classDescriptor) { public static boolean hasAbstractMembers(@NotNull ClassDescriptor classDescriptor) {
@@ -267,4 +319,11 @@ public class JvmCodegenUtil {
return "values".equals(functionDescriptor.getName().asString()) return "values".equals(functionDescriptor.getName().asString())
&& methodTypeParameters.isEmpty(); && methodTypeParameters.isEmpty();
} }
@NotNull
public static CallableMemberDescriptor getDirectMember(@NotNull CallableMemberDescriptor descriptor) {
return descriptor instanceof PropertyAccessorDescriptor
? ((PropertyAccessorDescriptor) descriptor).getCorrespondingProperty()
: descriptor;
}
} }
@@ -103,7 +103,7 @@ public class InlineCodegen implements CallGenerator {
codegen.getContext().isInlineFunction() ? InlineStrategy.IN_PLACE : functionDescriptor.getInlineStrategy(); codegen.getContext().isInlineFunction() ? InlineStrategy.IN_PLACE : functionDescriptor.getInlineStrategy();
this.asFunctionInline = false; this.asFunctionInline = false;
isSameModule = JvmCodegenUtil.isCallInsideSameModuleAsDeclared(functionDescriptor, codegen.getContext()); isSameModule = JvmCodegenUtil.isCallInsideSameModuleAsDeclared(functionDescriptor, codegen.getContext(), state.getOutDirectory());
} }
@Override @Override
@@ -105,6 +105,9 @@ public class GenerationState {
@Nullable @Nullable
private final String moduleId; // for PackageCodegen in incremental compilation mode private final String moduleId; // for PackageCodegen in incremental compilation mode
@Nullable
private final File outDirectory; // TODO: temporary hack, see JetTypeMapperWithOutDirectory state for details
public GenerationState( public GenerationState(
@NotNull Project project, @NotNull Project project,
@NotNull ClassBuilderFactory builderFactory, @NotNull ClassBuilderFactory builderFactory,
@@ -144,6 +147,7 @@ public class GenerationState {
this.bindingTrace = new DelegatingBindingTrace(bindingContext, "trace in GenerationState"); this.bindingTrace = new DelegatingBindingTrace(bindingContext, "trace in GenerationState");
this.bindingContext = bindingTrace.getBindingContext(); this.bindingContext = bindingTrace.getBindingContext();
this.outDirectory = outDirectory;
this.typeMapper = new JetTypeMapperWithOutDirectory(this.bindingContext, classBuilderMode, outDirectory); this.typeMapper = new JetTypeMapperWithOutDirectory(this.bindingContext, classBuilderMode, outDirectory);
this.intrinsics = new IntrinsicMethods(); this.intrinsics = new IntrinsicMethods();
@@ -269,4 +273,9 @@ public class GenerationState {
public String getModuleId() { public String getModuleId() {
return moduleId; return moduleId;
} }
@Nullable
public File getOutDirectory() {
return outDirectory;
}
} }
@@ -46,7 +46,6 @@ import org.jetbrains.jet.lang.resolve.java.jvmSignature.JvmMethodParameterSignat
import org.jetbrains.jet.lang.resolve.java.jvmSignature.JvmMethodSignature; import org.jetbrains.jet.lang.resolve.java.jvmSignature.JvmMethodSignature;
import org.jetbrains.jet.lang.resolve.java.mapping.KotlinToJavaTypesMap; import org.jetbrains.jet.lang.resolve.java.mapping.KotlinToJavaTypesMap;
import org.jetbrains.jet.lang.resolve.kotlin.PackagePartClassUtils; import org.jetbrains.jet.lang.resolve.kotlin.PackagePartClassUtils;
import org.jetbrains.jet.lang.resolve.kotlin.incremental.IncrementalPackageFragmentProvider;
import org.jetbrains.jet.lang.resolve.name.FqName; import org.jetbrains.jet.lang.resolve.name.FqName;
import org.jetbrains.jet.lang.resolve.name.FqNameUnsafe; import org.jetbrains.jet.lang.resolve.name.FqNameUnsafe;
import org.jetbrains.jet.lang.types.*; import org.jetbrains.jet.lang.types.*;
@@ -54,6 +53,7 @@ import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
import org.jetbrains.org.objectweb.asm.Type; import org.jetbrains.org.objectweb.asm.Type;
import org.jetbrains.org.objectweb.asm.commons.Method; import org.jetbrains.org.objectweb.asm.commons.Method;
import java.io.File;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@@ -110,7 +110,11 @@ public class JetTypeMapper {
return mapClass(((JavaClassStaticsPackageFragmentDescriptor) container).getCorrespondingClass()); return mapClass(((JavaClassStaticsPackageFragmentDescriptor) container).getCorrespondingClass());
} }
else if (container instanceof PackageFragmentDescriptor) { else if (container instanceof PackageFragmentDescriptor) {
return Type.getObjectType(internalNameForPackage((PackageFragmentDescriptor) container, descriptor, isInsideModule)); return Type.getObjectType(internalNameForPackage(
(PackageFragmentDescriptor) container,
(CallableMemberDescriptor) descriptor,
isInsideModule
));
} }
else if (container instanceof ClassDescriptor) { else if (container instanceof ClassDescriptor) {
return mapClass((ClassDescriptor) container); return mapClass((ClassDescriptor) container);
@@ -123,14 +127,10 @@ public class JetTypeMapper {
} }
} }
protected boolean isContainedByCompiledPartOfOurModule(@NotNull DeclarationDescriptor descriptor) {
return false;
}
@NotNull @NotNull
private String internalNameForPackage( private static String internalNameForPackage(
@NotNull PackageFragmentDescriptor packageFragment, @NotNull PackageFragmentDescriptor packageFragment,
@NotNull DeclarationDescriptor descriptor, @NotNull CallableMemberDescriptor descriptor,
boolean insideModule boolean insideModule
) { ) {
if (insideModule) { if (insideModule) {
@@ -139,17 +139,11 @@ public class JetTypeMapper {
return PackagePartClassUtils.getPackagePartInternalName(file); return PackagePartClassUtils.getPackagePartInternalName(file);
} }
DeclarationDescriptor descriptorToCheck = descriptor instanceof PropertyAccessorDescriptor CallableMemberDescriptor directMember = getDirectMember(descriptor);
? ((PropertyAccessorDescriptor) descriptor).getCorrespondingProperty()
: descriptor;
if (descriptorToCheck instanceof DeserializedCallableMemberDescriptor) { if (directMember instanceof DeserializedCallableMemberDescriptor) {
// TODO Temporary hack until modules infrastructure is implemented. See JetTypeMapperWithOutDirectory for details FqName packagePartFqName = PackagePartClassUtils.getPackagePartFqName((DeserializedCallableMemberDescriptor) directMember);
if (descriptor.getContainingDeclaration() instanceof IncrementalPackageFragmentProvider.IncrementalPackageFragment || return AsmUtil.internalNameByFqNameWithoutInnerClasses(packagePartFqName);
isContainedByCompiledPartOfOurModule(descriptor)) {
FqName packagePartFqName = PackagePartClassUtils.getPackagePartFqName((DeserializedCallableMemberDescriptor) descriptorToCheck);
return AsmUtil.internalNameByFqNameWithoutInnerClasses(packagePartFqName);
}
} }
} }
@@ -469,7 +463,7 @@ public class JetTypeMapper {
} }
else { else {
signature = mapSignature(functionDescriptor.getOriginal()); signature = mapSignature(functionDescriptor.getOriginal());
owner = mapOwner(functionDescriptor, isCallInsideSameModuleAsDeclared(functionDescriptor, context)); owner = mapOwner(functionDescriptor, isCallInsideSameModuleAsDeclared(functionDescriptor, context, getOutDirectory()));
ownerForDefaultParam = owner; ownerForDefaultParam = owner;
ownerForDefaultImpl = owner; ownerForDefaultImpl = owner;
if (functionParent instanceof PackageFragmentDescriptor) { if (functionParent instanceof PackageFragmentDescriptor) {
@@ -620,7 +614,7 @@ public class JetTypeMapper {
@NotNull @NotNull
public Method mapDefaultMethod(@NotNull FunctionDescriptor functionDescriptor, @NotNull OwnerKind kind, @NotNull CodegenContext<?> context) { public Method mapDefaultMethod(@NotNull FunctionDescriptor functionDescriptor, @NotNull OwnerKind kind, @NotNull CodegenContext<?> context) {
Method jvmSignature = mapSignature(functionDescriptor, kind).getAsmMethod(); Method jvmSignature = mapSignature(functionDescriptor, kind).getAsmMethod();
Type ownerType = mapOwner(functionDescriptor, isCallInsideSameModuleAsDeclared(functionDescriptor, context)); Type ownerType = mapOwner(functionDescriptor, isCallInsideSameModuleAsDeclared(functionDescriptor, context, getOutDirectory()));
String descriptor = jvmSignature.getDescriptor().replace(")", "I)"); String descriptor = jvmSignature.getDescriptor().replace(")", "I)");
boolean isConstructor = "<init>".equals(jvmSignature.getName()); boolean isConstructor = "<init>".equals(jvmSignature.getName());
if (!isStatic(kind) && !isConstructor) { if (!isStatic(kind) && !isConstructor) {
@@ -865,4 +859,10 @@ public class JetTypeMapper {
} }
return null; return null;
} }
// TODO Temporary hack until modules infrastructure is implemented. See JetTypeMapperWithOutDirectory for details
@Nullable
protected File getOutDirectory() {
return null;
}
} }
@@ -16,22 +16,12 @@
package org.jetbrains.jet.codegen.state; package org.jetbrains.jet.codegen.state;
import com.intellij.openapi.vfs.StandardFileSystems;
import com.intellij.openapi.vfs.VfsUtilCore;
import com.intellij.openapi.vfs.VirtualFile;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.codegen.ClassBuilderMode; import org.jetbrains.jet.codegen.ClassBuilderMode;
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.resolve.java.descriptor.JavaPackageFragmentDescriptor;
import org.jetbrains.jet.lang.resolve.java.lazy.descriptors.LazyPackageFragmentScopeForJavaPackage;
import org.jetbrains.jet.lang.resolve.kotlin.KotlinJvmBinaryClass;
import org.jetbrains.jet.lang.resolve.kotlin.VirtualFileKotlinClass;
import org.jetbrains.jet.lang.resolve.scopes.JetScope;
import java.io.File; import java.io.File;
import java.util.Set;
// TODO Temporary hack until modules infrastructure is implemented. // TODO Temporary hack until modules infrastructure is implemented.
// This class is necessary for detecting if compiled class is from the same module as callee. // This class is necessary for detecting if compiled class is from the same module as callee.
@@ -42,37 +32,15 @@ public class JetTypeMapperWithOutDirectory extends JetTypeMapper {
public JetTypeMapperWithOutDirectory( public JetTypeMapperWithOutDirectory(
@NotNull BindingContext bindingContext, @NotNull BindingContext bindingContext,
@NotNull ClassBuilderMode classBuilderMode, @NotNull ClassBuilderMode classBuilderMode,
@Nullable File outDirectory @NotNull File outDirectory
) { ) {
super(bindingContext, classBuilderMode); super(bindingContext, classBuilderMode);
this.outDirectory = outDirectory; this.outDirectory = outDirectory;
} }
@Nullable
@Override @Override
protected boolean isContainedByCompiledPartOfOurModule(@NotNull DeclarationDescriptor descriptor) { public File getOutDirectory() {
if (outDirectory == null) { return outDirectory;
return false;
}
if (!(descriptor.getContainingDeclaration() instanceof JavaPackageFragmentDescriptor)) {
return false;
}
JavaPackageFragmentDescriptor packageFragment = (JavaPackageFragmentDescriptor) descriptor.getContainingDeclaration();
JetScope packageScope = packageFragment.getMemberScope();
if (!(packageScope instanceof LazyPackageFragmentScopeForJavaPackage)) {
return false;
}
KotlinJvmBinaryClass binaryClass = ((LazyPackageFragmentScopeForJavaPackage) packageScope).getKotlinBinaryClass();
if (binaryClass instanceof VirtualFileKotlinClass) {
VirtualFile file = ((VirtualFileKotlinClass) binaryClass).getFile();
if (file.getFileSystem().getProtocol() == StandardFileSystems.FILE_PROTOCOL) {
File ioFile = VfsUtilCore.virtualToIoFile(file);
return ioFile.getAbsolutePath().startsWith(outDirectory.getAbsolutePath() + File.separator);
}
}
return false;
} }
} }
@@ -0,0 +1,7 @@
fun foo() {
assert(1 == 1) { "Hahaha" }
}
// assert function will be inlined, and we assure that there are no calls via package part, but is call via package facade in inlined code
// 0 INVOKESTATIC kotlin\/KotlinPackage-[^-]+-[^-]+.getASSERTIONS_ENABLED \(\)Z
// 1 INVOKESTATIC kotlin\/KotlinPackage.getASSERTIONS_ENABLED \(\)Z
@@ -77,6 +77,11 @@ public class BytecodeTextTestGenerated extends AbstractBytecodeTextTest {
doTest("compiler/testData/codegen/bytecodeText/defaultDelegation.kt"); doTest("compiler/testData/codegen/bytecodeText/defaultDelegation.kt");
} }
@TestMetadata("inlineFromOtherModule.kt")
public void testInlineFromOtherModule() throws Exception {
doTest("compiler/testData/codegen/bytecodeText/inlineFromOtherModule.kt");
}
@TestMetadata("intConstantNotNull.kt") @TestMetadata("intConstantNotNull.kt")
public void testIntConstantNotNull() throws Exception { public void testIntConstantNotNull() throws Exception {
doTest("compiler/testData/codegen/bytecodeText/intConstantNotNull.kt"); doTest("compiler/testData/codegen/bytecodeText/intConstantNotNull.kt");
@@ -117,6 +117,8 @@ public class DescriptorUtils {
return descriptor.getContainingDeclaration() instanceof PackageFragmentDescriptor; return descriptor.getContainingDeclaration() instanceof PackageFragmentDescriptor;
} }
// WARNING! Don't use this method in JVM backend, use JvmCodegenUtil.isCallInsideSameModuleAsDeclared() instead.
// The latter handles compilation against compiled part of our module correctly.
public static boolean areInSameModule(@NotNull DeclarationDescriptor first, @NotNull DeclarationDescriptor second) { public static boolean areInSameModule(@NotNull DeclarationDescriptor first, @NotNull DeclarationDescriptor second) {
return getContainingModule(first).equals(getContainingModule(second)); return getContainingModule(first).equals(getContainingModule(second));
} }