Mangle inline class members
<IMPL_SUFFIX> for method is a method signature hash, if method value parameter types contain inline class types, otherwise 'impl'. Constructor methods are named as 'constructor-<IMPL_SUFFIX>'. Synthesized 'box' and 'unbox' methods are named as '<METHOD_NAME>-<IMPL_SUFFIX>'. Erased implementations of overriding and non-overriding methods are named as '<METHOD_NAME>-<IMPL_SUFFIX>'. Fully specialized implementation of 'equals' will have a special suffix.
This commit is contained in:
+16
-9
@@ -16,6 +16,7 @@ import org.jetbrains.kotlin.descriptors.ClassDescriptor;
|
||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor;
|
||||
import org.jetbrains.kotlin.descriptors.PropertyDescriptor;
|
||||
import org.jetbrains.kotlin.lexer.KtTokens;
|
||||
import org.jetbrains.kotlin.load.java.JvmAbi;
|
||||
import org.jetbrains.kotlin.psi.KtClassOrObject;
|
||||
import org.jetbrains.kotlin.resolve.BindingContext;
|
||||
import org.jetbrains.kotlin.resolve.InlineClassesUtilsKt;
|
||||
@@ -74,7 +75,8 @@ public class FunctionsFromAnyGeneratorImpl extends FunctionsFromAnyGenerator {
|
||||
) {
|
||||
MethodContext context = fieldOwnerContext.intoFunction(function);
|
||||
JvmDeclarationOrigin methodOrigin = JvmDeclarationOriginKt.OtherOrigin(function);
|
||||
MethodVisitor mv = v.newMethod(methodOrigin, getAccess(), "toString", getToStringDesc(), null, null);
|
||||
String toStringMethodName = mapFunctionName(function);
|
||||
MethodVisitor mv = v.newMethod(methodOrigin, getAccess(), toStringMethodName, getToStringDesc(), null, null);
|
||||
|
||||
if (fieldOwnerContext.getContextKind() != OwnerKind.ERASED_INLINE_CLASS && classDescriptor.isInline()) {
|
||||
FunctionCodegen.generateMethodInsideInlineClassWrapper(methodOrigin, function, classDescriptor, mv, typeMapper);
|
||||
@@ -84,7 +86,7 @@ public class FunctionsFromAnyGeneratorImpl extends FunctionsFromAnyGenerator {
|
||||
mv.visitAnnotation(Type.getDescriptor(NotNull.class), false);
|
||||
|
||||
if (!generationState.getClassBuilderMode().generateBodies) {
|
||||
FunctionCodegen.endVisit(mv, "toString", getDeclaration());
|
||||
FunctionCodegen.endVisit(mv, toStringMethodName, getDeclaration());
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -129,7 +131,7 @@ public class FunctionsFromAnyGeneratorImpl extends FunctionsFromAnyGenerator {
|
||||
iv.invokevirtual("java/lang/StringBuilder", "toString", "()Ljava/lang/String;", false);
|
||||
iv.areturn(JAVA_STRING_TYPE);
|
||||
|
||||
FunctionCodegen.endVisit(mv, "toString", getDeclaration());
|
||||
FunctionCodegen.endVisit(mv, toStringMethodName, getDeclaration());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -138,7 +140,8 @@ public class FunctionsFromAnyGeneratorImpl extends FunctionsFromAnyGenerator {
|
||||
) {
|
||||
MethodContext context = fieldOwnerContext.intoFunction(function);
|
||||
JvmDeclarationOrigin methodOrigin = JvmDeclarationOriginKt.OtherOrigin(function);
|
||||
MethodVisitor mv = v.newMethod(methodOrigin, getAccess(), "hashCode", getHashCodeDesc(), null, null);
|
||||
String hashCodeMethodName = mapFunctionName(function);
|
||||
MethodVisitor mv = v.newMethod(methodOrigin, getAccess(), hashCodeMethodName, getHashCodeDesc(), null, null);
|
||||
|
||||
if (fieldOwnerContext.getContextKind() != OwnerKind.ERASED_INLINE_CLASS && classDescriptor.isInline()) {
|
||||
FunctionCodegen.generateMethodInsideInlineClassWrapper(methodOrigin, function, classDescriptor, mv, typeMapper);
|
||||
@@ -146,7 +149,7 @@ public class FunctionsFromAnyGeneratorImpl extends FunctionsFromAnyGenerator {
|
||||
}
|
||||
|
||||
if (!generationState.getClassBuilderMode().generateBodies) {
|
||||
FunctionCodegen.endVisit(mv, "hashCode", getDeclaration());
|
||||
FunctionCodegen.endVisit(mv, hashCodeMethodName, getDeclaration());
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -193,8 +196,11 @@ public class FunctionsFromAnyGeneratorImpl extends FunctionsFromAnyGenerator {
|
||||
|
||||
mv.visitInsn(IRETURN);
|
||||
|
||||
FunctionCodegen.endVisit(mv, "hashCode", getDeclaration());
|
||||
FunctionCodegen.endVisit(mv, hashCodeMethodName, getDeclaration());
|
||||
}
|
||||
|
||||
private String mapFunctionName(@NotNull FunctionDescriptor functionDescriptor) {
|
||||
return typeMapper.mapFunctionName(functionDescriptor, fieldOwnerContext.getContextKind());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -203,7 +209,8 @@ public class FunctionsFromAnyGeneratorImpl extends FunctionsFromAnyGenerator {
|
||||
) {
|
||||
MethodContext context = fieldOwnerContext.intoFunction(function);
|
||||
JvmDeclarationOrigin methodOrigin = JvmDeclarationOriginKt.OtherOrigin(function);
|
||||
MethodVisitor mv = v.newMethod(methodOrigin, getAccess(), "equals", getEqualsDesc(), null, null);
|
||||
String equalsMethodName = mapFunctionName(function);
|
||||
MethodVisitor mv = v.newMethod(methodOrigin, getAccess(), equalsMethodName, getEqualsDesc(), null, null);
|
||||
|
||||
boolean isErasedInlineClassKind = fieldOwnerContext.getContextKind() == OwnerKind.ERASED_INLINE_CLASS;
|
||||
if (!isErasedInlineClassKind && classDescriptor.isInline()) {
|
||||
@@ -214,7 +221,7 @@ public class FunctionsFromAnyGeneratorImpl extends FunctionsFromAnyGenerator {
|
||||
mv.visitParameterAnnotation(isErasedInlineClassKind ? 1 : 0, Type.getDescriptor(Nullable.class), false);
|
||||
|
||||
if (!generationState.getClassBuilderMode().generateBodies) {
|
||||
FunctionCodegen.endVisit(mv, "equals", getDeclaration());
|
||||
FunctionCodegen.endVisit(mv, equalsMethodName, getDeclaration());
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -261,7 +268,7 @@ public class FunctionsFromAnyGeneratorImpl extends FunctionsFromAnyGenerator {
|
||||
iv.iconst(0);
|
||||
iv.areturn(Type.INT_TYPE);
|
||||
|
||||
FunctionCodegen.endVisit(mv, "equals", getDeclaration());
|
||||
FunctionCodegen.endVisit(mv, equalsMethodName, getDeclaration());
|
||||
}
|
||||
|
||||
private int generateBasicChecksAndStoreTarget(InstructionAdapter iv, Label eq, Label ne) {
|
||||
|
||||
@@ -414,12 +414,12 @@ public abstract class StackValue {
|
||||
|
||||
private static void invokeBoxMethod(
|
||||
@NotNull InstructionAdapter v,
|
||||
Type boxedType,
|
||||
Type underlyingType
|
||||
@NotNull Type boxedType,
|
||||
@NotNull Type underlyingType
|
||||
) {
|
||||
v.invokestatic(
|
||||
boxedType.getInternalName(),
|
||||
InlineClassDescriptorResolver.BOX_METHOD_NAME.asString(),
|
||||
KotlinTypeMapper.BOX_JVM_METHOD_NAME,
|
||||
Type.getMethodDescriptor(boxedType, underlyingType),
|
||||
false
|
||||
);
|
||||
@@ -440,10 +440,14 @@ public abstract class StackValue {
|
||||
}
|
||||
}
|
||||
|
||||
private static void invokeUnboxMethod(@NotNull InstructionAdapter v, Type owner, Type resultType) {
|
||||
private static void invokeUnboxMethod(
|
||||
@NotNull InstructionAdapter v,
|
||||
@NotNull Type owner,
|
||||
@NotNull Type resultType
|
||||
) {
|
||||
v.invokevirtual(
|
||||
owner.getInternalName(),
|
||||
InlineClassDescriptorResolver.UNBOX_METHOD_NAME.asString(),
|
||||
KotlinTypeMapper.UNBOX_JVM_METHOD_NAME,
|
||||
"()" + resultType.getDescriptor(),
|
||||
false
|
||||
);
|
||||
|
||||
+3
-3
@@ -23,7 +23,7 @@ import org.jetbrains.kotlin.codegen.isRangeOrProgression
|
||||
import org.jetbrains.kotlin.codegen.optimization.common.OptimizationBasicInterpreter
|
||||
import org.jetbrains.kotlin.codegen.optimization.common.StrictBasicValue
|
||||
import org.jetbrains.kotlin.codegen.state.GenerationState
|
||||
import org.jetbrains.kotlin.load.java.JvmAbi
|
||||
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.resolve.InlineClassDescriptorResolver
|
||||
import org.jetbrains.kotlin.resolve.jvm.AsmTypes
|
||||
@@ -236,7 +236,7 @@ private fun AbstractInsnNode.isInlineClassUnboxing(state: GenerationState) =
|
||||
}
|
||||
|
||||
private fun MethodInsnNode.isInlineClassBoxingMethodDescriptor(state: GenerationState): Boolean {
|
||||
if (name != InlineClassDescriptorResolver.BOX_METHOD_NAME.asString()) return false
|
||||
if (name != KotlinTypeMapper.BOX_JVM_METHOD_NAME) return false
|
||||
|
||||
val ownerType = Type.getObjectType(owner)
|
||||
val descriptor = state.jvmBackendClassResolver.resolveToClassDescriptors(ownerType).singleOrNull() ?: return false
|
||||
@@ -247,7 +247,7 @@ private fun MethodInsnNode.isInlineClassBoxingMethodDescriptor(state: Generation
|
||||
}
|
||||
|
||||
private fun MethodInsnNode.isInlineClassUnboxingMethodDescriptor(state: GenerationState): Boolean {
|
||||
if (name != InlineClassDescriptorResolver.UNBOX_METHOD_NAME.asString()) return false
|
||||
if (name != KotlinTypeMapper.UNBOX_JVM_METHOD_NAME) return false
|
||||
|
||||
val ownerType = Type.getObjectType(owner)
|
||||
val descriptor = state.jvmBackendClassResolver.resolveToClassDescriptors(ownerType).singleOrNull() ?: return false
|
||||
|
||||
@@ -1010,7 +1010,7 @@ public class KotlinTypeMapper {
|
||||
? JvmAbi.getterName(propertyName)
|
||||
: JvmAbi.setterName(propertyName);
|
||||
|
||||
return mangleMemberNameIfRequired(isAccessor ? "access$" + accessorName : accessorName, descriptor);
|
||||
return mangleMemberNameIfRequired(isAccessor ? "access$" + accessorName : accessorName, descriptor, kind);
|
||||
}
|
||||
else if (isFunctionLiteral(descriptor)) {
|
||||
PsiElement element = DescriptorToSourceUtils.getSourceFromDescriptor(descriptor);
|
||||
@@ -1029,11 +1029,8 @@ public class KotlinTypeMapper {
|
||||
else if (isLocalFunction(descriptor) || isFunctionExpression(descriptor)) {
|
||||
return OperatorNameConventions.INVOKE.asString();
|
||||
}
|
||||
else if (OwnerKind.ERASED_INLINE_CLASS == kind && descriptor instanceof ConstructorDescriptor) {
|
||||
return JvmAbi.ERASED_INLINE_CONSTRUCTOR_NAME;
|
||||
}
|
||||
else {
|
||||
return mangleMemberNameIfRequired(descriptor.getName().asString(), descriptor);
|
||||
return mangleMemberNameIfRequired(descriptor.getName().asString(), descriptor, kind);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1062,15 +1059,46 @@ public class KotlinTypeMapper {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private String mangleMemberNameIfRequired(@NotNull String name, @NotNull CallableMemberDescriptor descriptor) {
|
||||
if (descriptor.getContainingDeclaration() instanceof ScriptDescriptor) {
|
||||
private String mangleMemberNameIfRequired(
|
||||
@NotNull String name,
|
||||
@NotNull CallableMemberDescriptor descriptor,
|
||||
@Nullable OwnerKind kind
|
||||
) {
|
||||
DeclarationDescriptor containingDeclaration = descriptor.getContainingDeclaration();
|
||||
if (containingDeclaration instanceof ScriptDescriptor && descriptor instanceof PropertyDescriptor) {
|
||||
//script properties should be public
|
||||
return name;
|
||||
}
|
||||
|
||||
String manglingSuffix = InlineClassManglingUtilsKt.getInlineClassValueParametersManglingSuffix(descriptor);
|
||||
if (manglingSuffix != null) {
|
||||
name += "-" + manglingSuffix;
|
||||
// Special methods for inline classes.
|
||||
if (InlineClassDescriptorResolver.isSynthesizedBoxMethod(descriptor)) {
|
||||
return BOX_JVM_METHOD_NAME;
|
||||
}
|
||||
if (InlineClassDescriptorResolver.isSynthesizedUnboxMethod(descriptor)) {
|
||||
return UNBOX_JVM_METHOD_NAME;
|
||||
}
|
||||
if (InlineClassDescriptorResolver.isSpecializedEqualsMethod(descriptor)) {
|
||||
return name;
|
||||
}
|
||||
|
||||
// Constructor:
|
||||
// either a constructor method for inline class (should be mangled),
|
||||
// or should stay as it is ('<init>').
|
||||
if (descriptor instanceof ConstructorDescriptor) {
|
||||
if (kind == OwnerKind.ERASED_INLINE_CLASS) {
|
||||
name = JvmAbi.ERASED_INLINE_CONSTRUCTOR_NAME;
|
||||
}
|
||||
else {
|
||||
return name;
|
||||
}
|
||||
}
|
||||
|
||||
String suffix = InlineClassManglingUtilsKt.getInlineClassSignatureManglingSuffix(descriptor);
|
||||
if (suffix != null) {
|
||||
name += suffix;
|
||||
}
|
||||
else if (kind == OwnerKind.ERASED_INLINE_CLASS) {
|
||||
name += JvmAbi.IMPL_SUFFIX_FOR_INLINE_CLASS_MEMBERS;
|
||||
}
|
||||
|
||||
if (DescriptorUtils.isTopLevelDeclaration(descriptor)) {
|
||||
@@ -1090,6 +1118,12 @@ public class KotlinTypeMapper {
|
||||
return name;
|
||||
}
|
||||
|
||||
public static final String BOX_JVM_METHOD_NAME =
|
||||
InlineClassDescriptorResolver.BOX_METHOD_NAME + JvmAbi.IMPL_SUFFIX_FOR_INLINE_CLASS_MEMBERS;
|
||||
|
||||
public static final String UNBOX_JVM_METHOD_NAME =
|
||||
InlineClassDescriptorResolver.UNBOX_METHOD_NAME + JvmAbi.IMPL_SUFFIX_FOR_INLINE_CLASS_MEMBERS;
|
||||
|
||||
@NotNull
|
||||
private String getModuleName(@NotNull CallableMemberDescriptor descriptor) {
|
||||
String deserialized = ModuleNameKt.getJvmModuleNameForDeserializedDescriptor(descriptor);
|
||||
|
||||
+14
-12
@@ -15,19 +15,24 @@ import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameUnsafe
|
||||
import org.jetbrains.kotlin.resolve.isInlineClassType
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import java.security.MessageDigest
|
||||
import java.util.*
|
||||
|
||||
fun getInlineClassValueParametersManglingSuffix(descriptor: CallableMemberDescriptor): String? {
|
||||
fun getInlineClassSignatureManglingSuffix(descriptor: CallableMemberDescriptor): String? {
|
||||
if (descriptor !is FunctionDescriptor) return null
|
||||
if (descriptor is ConstructorDescriptor) return null
|
||||
if (InlineClassDescriptorResolver.isSynthesizedBoxMethod(descriptor)) return null
|
||||
if (InlineClassDescriptorResolver.isSynthesizedBoxOrUnboxMethod(descriptor)) return null
|
||||
|
||||
val actualValueParameterTypes = listOfNotNull(descriptor.extensionReceiverParameter?.type) + descriptor.valueParameters.map { it.type }
|
||||
|
||||
if (actualValueParameterTypes.none { it.requiresFunctionNameMangling() }) return null
|
||||
|
||||
return md5radix36string(collectSignatureForMangling(actualValueParameterTypes))
|
||||
return getInlineClassSignatureManglingSuffix(actualValueParameterTypes)
|
||||
}
|
||||
|
||||
fun getInlineClassSignatureManglingSuffix(valueParameterTypes: List<KotlinType>) =
|
||||
if (valueParameterTypes.none { it.requiresFunctionNameMangling() })
|
||||
null
|
||||
else
|
||||
"-" + md5base64(collectSignatureForMangling(valueParameterTypes))
|
||||
|
||||
private fun KotlinType.requiresFunctionNameMangling() =
|
||||
isInlineClassThatRequiresMangling() || isTypeParameterWithUpperBoundThatRequiresMangling()
|
||||
|
||||
@@ -61,11 +66,8 @@ private fun getSignatureElementForMangling(type: KotlinType): String = buildStri
|
||||
}
|
||||
}
|
||||
|
||||
private fun md5radix36string(signatureForMangling: String): String {
|
||||
val d = MessageDigest.getInstance("MD5").digest(signatureForMangling.toByteArray())
|
||||
var acc = 0L
|
||||
for (i in 0..4) {
|
||||
acc = (acc shl 8) + (d[i].toLong() and 0xFFL)
|
||||
}
|
||||
return acc.toString(36)
|
||||
private fun md5base64(signatureForMangling: String): String {
|
||||
val d = MessageDigest.getInstance("MD5").digest(signatureForMangling.toByteArray()).copyOfRange(0, 5)
|
||||
// base64 URL encoder without padding uses exactly the characters allowed in both JVM bytecode and Dalvik bytecode names
|
||||
return Base64.getUrlEncoder().withoutPadding().encodeToString(d)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user