Drop erased class for inline class

This commit is contained in:
Dmitry Petrov
2018-09-04 12:55:04 +03:00
parent 4c7430e990
commit c094b3a5a2
18 changed files with 254 additions and 163 deletions
@@ -5,7 +5,6 @@
package org.jetbrains.kotlin.codegen
import com.intellij.util.ArrayUtil
import org.jetbrains.kotlin.codegen.context.ClassContext
import org.jetbrains.kotlin.codegen.state.GenerationState
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper
@@ -15,13 +14,9 @@ import org.jetbrains.kotlin.psi.KtClassOrObject
import org.jetbrains.kotlin.resolve.InlineClassDescriptorResolver
import org.jetbrains.kotlin.resolve.descriptorUtil.secondaryConstructors
import org.jetbrains.kotlin.resolve.jvm.AsmTypes
import org.jetbrains.kotlin.resolve.jvm.diagnostics.ErasedInlineClassOrigin
import org.jetbrains.kotlin.resolve.jvm.diagnostics.Synthetic
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodGenericSignature
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature
import org.jetbrains.org.objectweb.asm.Opcodes
import org.jetbrains.org.objectweb.asm.Type
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
class ErasedInlineClassBodyCodegen(
aClass: KtClass,
@@ -31,25 +26,19 @@ class ErasedInlineClassBodyCodegen(
parentCodegen: MemberCodegen<*>?
) : ClassBodyCodegen(aClass, context, v, state, parentCodegen) {
private val classAsmType = typeMapper.mapErasedInlineClass(descriptor)
private val classAsmType = typeMapper.mapClass(descriptor)
private val constructorCodegen = ConstructorCodegen(
descriptor, context, functionCodegen, this, this, state, kind, v, classAsmType, aClass, bindingContext
)
override fun generateDeclaration() {
v.defineClass(
myClass.psiOrParent, state.classFileVersion, Opcodes.ACC_STATIC,
classAsmType.internalName, null, "java/lang/Object", ArrayUtil.EMPTY_STRING_ARRAY
)
v.visitSource(myClass.containingKtFile.name, null)
}
override fun generateDeclaration() {}
override fun generateKotlinMetadataAnnotation() {}
override fun done() {}
override fun generateConstructors() {
val delegationFieldsInfo = DelegationFieldsInfo(classAsmType, descriptor, state, bindingContext)
generateDefaultConstructorForErasedInlineClass()
constructorCodegen.generatePrimaryConstructor(delegationFieldsInfo, AsmTypes.OBJECT_TYPE)
for (secondaryConstructor in descriptor.secondaryConstructors) {
@@ -57,21 +46,6 @@ class ErasedInlineClassBodyCodegen(
}
}
private fun generateDefaultConstructorForErasedInlineClass() {
val mv = v.newMethod(
ErasedInlineClassOrigin(myClass.psiOrParent, descriptor), 0,
"<init>", "()V", null, ArrayUtil.EMPTY_STRING_ARRAY
)
mv.visitCode()
InstructionAdapter(mv).apply {
load(0, AsmTypes.OBJECT_TYPE)
invokespecial(AsmTypes.OBJECT_TYPE.internalName, "<init>", "()V", false)
areturn(Type.VOID_TYPE)
}
mv.visitMaxs(1, 1)
mv.visitEnd()
}
override fun generateSyntheticPartsAfterBody() {
super.generateSyntheticPartsAfterBody()
@@ -141,8 +115,4 @@ class ErasedInlineClassBodyCodegen(
}
)
}
override fun generateKotlinMetadataAnnotation() {
writeSyntheticClassMetadata(v, state)
}
}
@@ -225,7 +225,7 @@ public class FunctionCodegen {
asmMethod.getDescriptor()
);
if (CodegenContextUtil.isImplClassOwner(owner)) {
if (CodegenContextUtil.isImplementationOwner(owner, functionDescriptor)) {
v.getSerializationBindings().put(METHOD_FOR_FUNCTION, CodegenUtilKt.unwrapFrontendVersion(functionDescriptor), asmMethod);
}
@@ -307,7 +307,7 @@ public class FunctionCodegen {
}
// base check
boolean isInlineClass = isClass(containingDeclaration) && ((ClassDescriptor) containingDeclaration).isInline();
boolean isInlineClass = InlineClassesUtilsKt.isInlineClass(containingDeclaration);
boolean simpleFunctionOrProperty =
!(functionDescriptor instanceof ConstructorDescriptor) && !KotlinTypeMapper.isAccessor(functionDescriptor);
@@ -323,10 +323,8 @@ public class FunctionCodegen {
) {
mv.visitCode();
Type inlineErasedType = typeMapper.mapErasedInlineClass(containingDeclaration);
Method erasedMethodImpl = typeMapper.mapAsmMethod(functionDescriptor.getOriginal(), OwnerKind.ERASED_INLINE_CLASS);
Type fieldOwnerType = typeMapper.mapClass(containingDeclaration);
Method erasedMethodImpl = typeMapper.mapAsmMethod(functionDescriptor.getOriginal(), OwnerKind.ERASED_INLINE_CLASS);
ValueParameterDescriptor valueRepresentation = InlineClassesUtilsKt.underlyingRepresentation(containingDeclaration);
if (valueRepresentation == null) return;
@@ -334,7 +332,7 @@ public class FunctionCodegen {
Type fieldType = typeMapper.mapType(valueRepresentation);
generateDelegateToStaticErasedVersion(
mv, erasedMethodImpl, inlineErasedType.getInternalName(),
mv, erasedMethodImpl,
fieldOwnerType, valueRepresentation.getName().asString(), fieldType
);
@@ -915,11 +913,11 @@ public class FunctionCodegen {
private static void generateDelegateToStaticErasedVersion(
@NotNull MethodVisitor mv,
@NotNull Method erasedStaticAsmMethod,
@NotNull String classToDelegateTo,
@NotNull Type fieldOwnerType,
@NotNull String fieldName,
@NotNull Type fieldType
) {
String internalName = fieldOwnerType.getInternalName();
InstructionAdapter iv = new InstructionAdapter(mv);
Type[] argTypes = erasedStaticAsmMethod.getArgumentTypes();
@@ -928,7 +926,7 @@ public class FunctionCodegen {
iv.visitLineNumber(1, label);
iv.load(0, AsmTypes.OBJECT_TYPE);
iv.visitFieldInsn(Opcodes.GETFIELD, fieldOwnerType.getInternalName(), fieldName, fieldType.getDescriptor());
iv.visitFieldInsn(Opcodes.GETFIELD, internalName, fieldName, fieldType.getDescriptor());
int k = 1;
for (int i = 1; i < argTypes.length; i++) {
@@ -937,7 +935,7 @@ public class FunctionCodegen {
k += argType.getSize();
}
iv.invokestatic(classToDelegateTo, erasedStaticAsmMethod.getName(), erasedStaticAsmMethod.getDescriptor(), false);
iv.invokestatic(internalName, erasedStaticAsmMethod.getName(), erasedStaticAsmMethod.getDescriptor(), false);
iv.areturn(erasedStaticAsmMethod.getReturnType());
}
@@ -256,18 +256,11 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
if (!(myClass instanceof KtClass)) return;
if (!descriptor.isInline()) return;
Type erasedInlineClassType = state.getTypeMapper().mapErasedInlineClass(descriptor);
ClassBuilder builder = state.getFactory().newVisitor(
JvmDeclarationOriginKt.ErasedInlineClassOrigin(myClass.getPsiOrParent(), descriptor),
erasedInlineClassType,
myClass.getContainingKtFile()
);
CodegenContext parentContext = context.getParentContext();
assert parentContext != null : "Parent context of inline class declaration should not be null";
ClassContext erasedInlineClassContext = parentContext.intoWrapperForErasedInlineClass(descriptor, state);
new ErasedInlineClassBodyCodegen((KtClass) myClass, erasedInlineClassContext, builder, state, this).generate();
new ErasedInlineClassBodyCodegen((KtClass) myClass, erasedInlineClassContext, v, state, this).generate();
}
@Override
@@ -243,7 +243,7 @@ public abstract class MemberCodegen<T extends KtPureElement/* TODO: & KtDeclarat
}
private void genTypeAliasAnnotationsMethodIfRequired(TypeAliasDescriptor typeAliasDescriptor) {
boolean isAnnotationsMethodOwner = CodegenContextUtil.isImplClassOwner(context);
boolean isAnnotationsMethodOwner = CodegenContextUtil.isImplementationOwner(context, typeAliasDescriptor);
Annotations annotations = typeAliasDescriptor.getAnnotations();
if (!isAnnotationsMethodOwner || annotations.isEmpty()) return;
@@ -159,7 +159,7 @@ public class PropertyCodegen {
// Fields and '$annotations' methods for non-private const properties are generated in the multi-file facade
boolean isBackingFieldOwner = descriptor.isConst() && !Visibilities.isPrivate(descriptor.getVisibility())
? !(context instanceof MultifileClassPartContext)
: CodegenContextUtil.isImplClassOwner(context);
: CodegenContextUtil.isImplementationOwner(context, descriptor);
assert declaration != null : "Declaration is null: " + descriptor + " (context=" + context + ")";
generateBackingField(declaration, descriptor, isBackingFieldOwner);
@@ -338,7 +338,7 @@ public class PropertyCodegen {
if (annotations.isEmpty()) return;
Method signature = getSyntheticMethodSignature(descriptor);
if (kind != OwnerKind.DEFAULT_IMPLS && CodegenContextUtil.isImplClassOwner(context)) {
if (kind != OwnerKind.DEFAULT_IMPLS && CodegenContextUtil.isImplementationOwner(context, descriptor)) {
v.getSerializationBindings().put(SYNTHETIC_METHOD_FOR_PROPERTY, descriptor, signature);
}
@@ -37,10 +37,6 @@ class SuperClassInfo(
return SuperClassInfo(OBJECT_TYPE, null)
}
if (descriptor.isInline) {
return SuperClassInfo(typeMapper.mapErasedInlineClass(descriptor), null)
}
for (supertype in descriptor.typeConstructor.supertypes) {
val superClass = supertype.constructor.declarationDescriptor
if (superClass != null && !isJvmInterface(superClass)) {
@@ -16,16 +16,31 @@
package org.jetbrains.kotlin.codegen.context
import org.jetbrains.kotlin.codegen.OwnerKind
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
import org.jetbrains.kotlin.resolve.isInlineClass
import org.jetbrains.org.objectweb.asm.Type
object CodegenContextUtil {
@JvmStatic fun getImplementationOwnerClassType(owner: CodegenContext<*>): Type? =
when (owner) {
is MultifileClassFacadeContext -> owner.filePartType
is DelegatingToPartContext -> owner.implementationOwnerClassType
else -> null
}
@JvmStatic
fun getImplementationOwnerClassType(owner: CodegenContext<*>): Type? =
when (owner) {
is MultifileClassFacadeContext -> owner.filePartType
is DelegatingToPartContext -> owner.implementationOwnerClassType
else -> null
}
@JvmStatic fun isImplClassOwner(owner: CodegenContext<*>): Boolean =
owner !is MultifileClassFacadeContext
@JvmStatic
fun isImplementationOwner(owner: CodegenContext<*>, descriptor: DeclarationDescriptor): Boolean {
if (descriptor.containingDeclaration?.isInlineClass() == true) {
val isInErasedMethod = owner.contextKind == OwnerKind.ERASED_INLINE_CLASS
when (descriptor) {
is FunctionDescriptor -> return isInErasedMethod
is PropertyDescriptor -> return !isInErasedMethod
}
}
return owner !is MultifileClassFacadeContext
}
}
@@ -327,9 +327,6 @@ public class KotlinTypeMapper {
if (isInterface(classDescriptor)) {
nestedClass = JvmAbi.DEFAULT_IMPLS_SUFFIX;
}
else if (classDescriptor.isInline()) {
nestedClass = JvmAbi.ERASED_INLINE_CLASS_SUFFIX;
}
else {
nestedClass = null;
}
@@ -479,10 +476,6 @@ public class KotlinTypeMapper {
return mapTypeAsDeclaration(descriptor.getReturnType());
}
public Type mapErasedInlineClass(@NotNull ClassDescriptor descriptor) {
return Type.getObjectType(mapClass(descriptor).getInternalName() + JvmAbi.ERASED_INLINE_CLASS_SUFFIX);
}
@NotNull
public JvmMethodGenericSignature mapAnnotationParameterSignature(@NotNull PropertyDescriptor descriptor) {
JvmSignatureWriter sw = new BothSignatureWriter(BothSignatureWriter.Mode.METHOD);
@@ -533,13 +526,6 @@ public class KotlinTypeMapper {
return mapInlineClassType(underlyingType, TypeMappingMode.DEFAULT);
}
@NotNull
public static Type mapToErasedInlineClassType(@NotNull KotlinType kotlinType) {
return Type.getObjectType(
mapInlineClassTypeAsDeclaration(kotlinType).getInternalName() + JvmAbi.ERASED_INLINE_CLASS_SUFFIX
);
}
@NotNull
public static Type mapInlineClassType(@NotNull KotlinType kotlinType) {
return mapInlineClassType(kotlinType, TypeMappingMode.DEFAULT);