JVM: Mangle functions returning inline class values

Mangling suffix is base64-encoded MD5 of ":<returnTypeFQN>"
This commit is contained in:
Dmitry Petrov
2020-04-29 16:15:03 +03:00
parent 9beb36ca2b
commit b5bd3604b1
21 changed files with 175 additions and 93 deletions
@@ -35,10 +35,10 @@ abstract class ArgumentGenerator {
* @see kotlin.reflect.jvm.internal.KCallableImpl.callBy * @see kotlin.reflect.jvm.internal.KCallableImpl.callBy
*/ */
open fun generate( open fun generate(
valueArgumentsByIndex: List<ResolvedValueArgument>, valueArgumentsByIndex: List<ResolvedValueArgument>,
actualArgs: List<ResolvedValueArgument>, actualArgs: List<ResolvedValueArgument>,
// may be null for a constructor of an object literal // may be null for a constructor of an object literal
calleeDescriptor: CallableDescriptor? calleeDescriptor: CallableDescriptor?
): DefaultCallArgs { ): DefaultCallArgs {
assert(valueArgumentsByIndex.size == actualArgs.size) { assert(valueArgumentsByIndex.size == actualArgs.size) {
"Value arguments collection should have same size, but ${valueArgumentsByIndex.size} != ${actualArgs.size}" "Value arguments collection should have same size, but ${valueArgumentsByIndex.size} != ${actualArgs.size}"
@@ -50,9 +50,9 @@ abstract class ArgumentGenerator {
ArgumentAndDeclIndex(it, arg2Index[it]!!) ArgumentAndDeclIndex(it, arg2Index[it]!!)
}.toMutableList() }.toMutableList()
valueArgumentsByIndex.withIndex().forEach { for ((index, value) in valueArgumentsByIndex.withIndex()) {
if (it.value is DefaultValueArgument) { if (value is DefaultValueArgument) {
actualArgsWithDeclIndex.add(it.index, ArgumentAndDeclIndex(it.value, it.index)) actualArgsWithDeclIndex.add(index, ArgumentAndDeclIndex(value, index))
} }
} }
@@ -70,8 +70,7 @@ abstract class ArgumentGenerator {
is DefaultValueArgument -> { is DefaultValueArgument -> {
if (calleeDescriptor?.defaultValueFromJava(declIndex) == true) { if (calleeDescriptor?.defaultValueFromJava(declIndex) == true) {
generateDefaultJava(declIndex, argument) generateDefaultJava(declIndex, argument)
} } else {
else {
defaultArgs.mark(declIndex) defaultArgs.mark(declIndex)
generateDefault(declIndex, argument) generateDefault(declIndex, argument)
} }
@@ -116,11 +115,11 @@ abstract class ArgumentGenerator {
} }
private fun CallableDescriptor.defaultValueFromJava(index: Int): Boolean = DFS.ifAny( private fun CallableDescriptor.defaultValueFromJava(index: Int): Boolean = DFS.ifAny(
listOf(this), listOf(this),
{ current -> current.original.overriddenDescriptors.map { it.original } }, { current -> current.original.overriddenDescriptors.map { it.original } },
{ descriptor -> { descriptor ->
descriptor.original.overriddenDescriptors.isEmpty() && descriptor.original.overriddenDescriptors.isEmpty() &&
descriptor is JavaCallableMemberDescriptor && descriptor is JavaCallableMemberDescriptor &&
descriptor.valueParameters[index].declaresDefaultValue() descriptor.valueParameters[index].declaresDefaultValue()
} }
) )
@@ -5,7 +5,7 @@
package org.jetbrains.kotlin.codegen package org.jetbrains.kotlin.codegen
import org.jetbrains.kotlin.load.java.JvmAbi import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodParameterKind import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodParameterKind
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodParameterSignature import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodParameterSignature
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature
@@ -20,7 +20,7 @@ import org.jetbrains.org.objectweb.asm.util.Printer
class CallableMethod( class CallableMethod(
override val owner: Type, override val owner: Type,
private val defaultImplOwner: Type?, private val defaultImplOwner: Type?,
computeDefaultMethodDesc: () -> String, computeDefaultMethod: () -> Method,
private val signature: JvmMethodSignature, private val signature: JvmMethodSignature,
val invokeOpcode: Int, val invokeOpcode: Int,
override val dispatchReceiverType: Type?, override val dispatchReceiverType: Type?,
@@ -32,7 +32,10 @@ class CallableMethod(
val isInterfaceMethod: Boolean, val isInterfaceMethod: Boolean,
private val isDefaultMethodInInterface: Boolean private val isDefaultMethodInInterface: Boolean
) : Callable { ) : Callable {
private val defaultMethodDesc: String by lazy(LazyThreadSafetyMode.PUBLICATION, computeDefaultMethodDesc) private val defaultImplMethod: Method by lazy(LazyThreadSafetyMode.PUBLICATION, computeDefaultMethod)
private val defaultImplMethodName: String get() = defaultImplMethod.name
private val defaultMethodDesc: String get() = defaultImplMethod.descriptor
fun getValueParameters(): List<JvmMethodParameterSignature> = fun getValueParameters(): List<JvmMethodParameterSignature> =
signature.valueParameters signature.valueParameters
@@ -68,10 +71,14 @@ class CallableMethod(
} else { } else {
v.visitMethodInsn( v.visitMethodInsn(
INVOKESTATIC, defaultImplOwner.internalName, INVOKESTATIC, defaultImplOwner.internalName,
method.name + JvmAbi.DEFAULT_PARAMS_IMPL_SUFFIX, defaultMethodDesc, isDefaultMethodInInterface defaultImplMethodName, defaultMethodDesc, isDefaultMethodInInterface
) )
StackValue.coerce(Type.getReturnType(defaultMethodDesc), Type.getReturnType(signature.asmMethod.descriptor), v) StackValue.coerce(
Type.getReturnType(defaultMethodDesc),
Type.getReturnType(signature.asmMethod.descriptor),
v
)
} }
} }
@@ -219,6 +219,11 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
return parentCodegen; return parentCodegen;
} }
@NotNull
public KotlinTypeMapper getTypeMapper() {
return typeMapper;
}
@NotNull @NotNull
public ObjectLiteralResult generateObjectLiteral(@NotNull KtObjectLiteralExpression literal) { public ObjectLiteralResult generateObjectLiteral(@NotNull KtObjectLiteralExpression literal) {
KtObjectDeclaration objectDeclaration = literal.getObjectDeclaration(); KtObjectDeclaration objectDeclaration = literal.getObjectDeclaration();
@@ -1038,10 +1038,7 @@ public class FunctionCodegen {
// or all return types are supertypes of inline class (and can't be inline classes). // or all return types are supertypes of inline class (and can't be inline classes).
for (DescriptorBasedFunctionHandleForJvm handle : bridge.getOriginalFunctions()) { for (DescriptorBasedFunctionHandleForJvm handle : bridge.getOriginalFunctions()) {
KotlinType returnType = handle.getDescriptor().getReturnType(); return state.getTypeMapper().getReturnValueType(handle.getDescriptor());
if (returnType != null) {
return returnType;
}
} }
if (state.getClassBuilderMode().mightBeIncorrectCode) { if (state.getClassBuilderMode().mightBeIncorrectCode) {
@@ -1450,8 +1447,8 @@ public class FunctionCodegen {
} }
} }
KotlinType returnType = descriptor.getReturnType(); KotlinType returnValueType = state.getTypeMapper().getReturnValueType(descriptor);
StackValue.coerce(delegateTo.getReturnType(), returnType, bridge.getReturnType(), bridgeReturnType, iv); StackValue.coerce(delegateTo.getReturnType(), returnValueType, bridge.getReturnType(), bridgeReturnType, iv);
iv.areturn(bridge.getReturnType()); iv.areturn(bridge.getReturnType());
endVisit(mv, "bridge method", origin); endVisit(mv, "bridge method", origin);
@@ -1619,7 +1616,7 @@ public class FunctionCodegen {
) )
); );
stackValue.put(delegateMethod.getReturnType(), delegatedTo.getReturnType(), iv); stackValue.put(delegateMethod.getReturnType(), delegateFunction.getReturnType(), iv);
iv.areturn(delegateMethod.getReturnType()); iv.areturn(delegateMethod.getReturnType());
} }
@@ -467,7 +467,7 @@ public abstract class MemberCodegen<T extends KtPureElement/* TODO: & KtDeclarat
Name.special("<clinit>"), SYNTHESIZED, KotlinSourceElementKt.toSourceElement(element)); Name.special("<clinit>"), SYNTHESIZED, KotlinSourceElementKt.toSourceElement(element));
clInit.initialize(null, null, Collections.emptyList(), Collections.emptyList(), clInit.initialize(null, null, Collections.emptyList(), Collections.emptyList(),
DescriptorUtilsKt.getModule(descriptor).getBuiltIns().getUnitType(), DescriptorUtilsKt.getModule(descriptor).getBuiltIns().getUnitType(),
null, Visibilities.PRIVATE); Modality.FINAL, Visibilities.PRIVATE);
return clInit; return clInit;
} }
@@ -53,7 +53,8 @@ internal class ObjectSuperCallArgumentGenerator(
valueArgumentsByIndex: List<ResolvedValueArgument>, valueArgumentsByIndex: List<ResolvedValueArgument>,
actualArgs: List<ResolvedValueArgument>, actualArgs: List<ResolvedValueArgument>,
calleeDescriptor: CallableDescriptor? calleeDescriptor: CallableDescriptor?
): DefaultCallArgs = super.generate(valueArgumentsByIndex, valueArgumentsByIndex, calleeDescriptor) ): DefaultCallArgs =
super.generate(valueArgumentsByIndex, valueArgumentsByIndex, calleeDescriptor)
public override fun generateExpression(i: Int, argument: ExpressionValueArgument) { public override fun generateExpression(i: Int, argument: ExpressionValueArgument) {
generateSuperCallArgument(i) generateSuperCallArgument(i)
@@ -51,10 +51,11 @@ private constructor(
private val INT_PROGRESSION_ITERATOR_VALUE = ProgressionIteratorBasicValue("Int", Type.INT_TYPE) private val INT_PROGRESSION_ITERATOR_VALUE = ProgressionIteratorBasicValue("Int", Type.INT_TYPE)
private val LONG_PROGRESSION_ITERATOR_VALUE = ProgressionIteratorBasicValue("Long", Type.LONG_TYPE) private val LONG_PROGRESSION_ITERATOR_VALUE = ProgressionIteratorBasicValue("Long", Type.LONG_TYPE)
private val UINT_PROGRESSION_ITERATOR_VALUE = // TODO functions returning inline classes are mangled now, should figure out how to work with UInt/ULong iterators here
ProgressionIteratorBasicValue("UInt", Type.INT_TYPE, Type.getObjectType("kotlin/UInt")) // private val UINT_PROGRESSION_ITERATOR_VALUE =
private val ULONG_PROGRESSION_ITERATOR_VALUE = // ProgressionIteratorBasicValue("UInt", Type.INT_TYPE, Type.getObjectType("kotlin/UInt"))
ProgressionIteratorBasicValue("ULong", Type.LONG_TYPE, Type.getObjectType("kotlin/ULong")) // private val ULONG_PROGRESSION_ITERATOR_VALUE =
// ProgressionIteratorBasicValue("ULong", Type.LONG_TYPE, Type.getObjectType("kotlin/ULong"))
private val PROGRESSION_CLASS_NAME_TO_ITERATOR_VALUE: Map<String, ProgressionIteratorBasicValue> = private val PROGRESSION_CLASS_NAME_TO_ITERATOR_VALUE: Map<String, ProgressionIteratorBasicValue> =
hashMapOf( hashMapOf(
@@ -64,10 +65,10 @@ private constructor(
INT_PROGRESSION_FQN to INT_PROGRESSION_ITERATOR_VALUE, INT_PROGRESSION_FQN to INT_PROGRESSION_ITERATOR_VALUE,
LONG_RANGE_FQN to LONG_PROGRESSION_ITERATOR_VALUE, LONG_RANGE_FQN to LONG_PROGRESSION_ITERATOR_VALUE,
LONG_PROGRESSION_FQN to LONG_PROGRESSION_ITERATOR_VALUE, LONG_PROGRESSION_FQN to LONG_PROGRESSION_ITERATOR_VALUE,
UINT_RANGE_FQN to UINT_PROGRESSION_ITERATOR_VALUE, // UINT_RANGE_FQN to UINT_PROGRESSION_ITERATOR_VALUE,
UINT_PROGRESSION_FQN to UINT_PROGRESSION_ITERATOR_VALUE, // UINT_PROGRESSION_FQN to UINT_PROGRESSION_ITERATOR_VALUE,
ULONG_RANGE_FQN to ULONG_PROGRESSION_ITERATOR_VALUE, // ULONG_RANGE_FQN to ULONG_PROGRESSION_ITERATOR_VALUE,
ULONG_PROGRESSION_FQN to ULONG_PROGRESSION_ITERATOR_VALUE // ULONG_PROGRESSION_FQN to ULONG_PROGRESSION_ITERATOR_VALUE
) )
fun byProgressionClassType(progressionClassType: Type): ProgressionIteratorBasicValue? = fun byProgressionClassType(progressionClassType: Type): ProgressionIteratorBasicValue? =
@@ -34,16 +34,13 @@ abstract class AbstractForInProgressionLoopGenerator(
) : AbstractForInProgressionOrRangeLoopGenerator(codegen, forExpression) { ) : AbstractForInProgressionOrRangeLoopGenerator(codegen, forExpression) {
protected var incrementVar: Int = -1 protected var incrementVar: Int = -1
protected val asmLoopRangeType: Type protected val asmLoopRangeType: Type = codegen.asmType(rangeKotlinType)
protected val rangeKotlinType = bindingContext.getType(forExpression.loopRange!!)!!
private val rangeElementKotlinType = getRangeOrProgressionElementType(rangeKotlinType) private val rangeElementKotlinType = getRangeOrProgressionElementType(rangeKotlinType)
?: throw AssertionError("Unexpected loop range type: $rangeKotlinType") ?: throw AssertionError("Unexpected loop range type: $rangeKotlinType")
private val incrementKotlinType: KotlinType private val incrementKotlinType: KotlinType
protected val incrementType: Type protected val incrementType: Type
init { init {
asmLoopRangeType = codegen.asmType(rangeKotlinType)
val incrementProp = rangeKotlinType.memberScope.getContributedVariables(Name.identifier("step"), NoLookupLocation.FROM_BACKEND) val incrementProp = rangeKotlinType.memberScope.getContributedVariables(Name.identifier("step"), NoLookupLocation.FROM_BACKEND)
assert(incrementProp.size == 1) { rangeKotlinType.toString() + " " + incrementProp.size } assert(incrementProp.size == 1) { rangeKotlinType.toString() + " " + incrementProp.size }
incrementKotlinType = incrementProp.single().type incrementKotlinType = incrementProp.single().type
@@ -17,8 +17,12 @@
package org.jetbrains.kotlin.codegen.range.forLoop package org.jetbrains.kotlin.codegen.range.forLoop
import org.jetbrains.kotlin.codegen.ExpressionCodegen import org.jetbrains.kotlin.codegen.ExpressionCodegen
import org.jetbrains.kotlin.codegen.OwnerKind
import org.jetbrains.kotlin.codegen.StackValue import org.jetbrains.kotlin.codegen.StackValue
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.KtForExpression import org.jetbrains.kotlin.psi.KtForExpression
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.org.objectweb.asm.Label import org.jetbrains.org.objectweb.asm.Label
import org.jetbrains.org.objectweb.asm.Type import org.jetbrains.org.objectweb.asm.Type
@@ -28,6 +32,8 @@ abstract class AbstractForInProgressionOrRangeLoopGenerator(codegen: ExpressionC
private var loopParameter: StackValue? = null private var loopParameter: StackValue? = null
protected val rangeKotlinType = bindingContext.getType(forExpression.loopRange!!)!!
init { init {
assert( assert(
asmElementType.sort == Type.INT || asmElementType.sort == Type.INT ||
@@ -36,7 +42,7 @@ abstract class AbstractForInProgressionOrRangeLoopGenerator(codegen: ExpressionC
asmElementType.sort == Type.CHAR || asmElementType.sort == Type.CHAR ||
asmElementType.sort == Type.LONG asmElementType.sort == Type.LONG
) { ) {
"Unexpected range element type: " + asmElementType "Unexpected range element type: $asmElementType"
} }
} }
@@ -48,7 +54,7 @@ abstract class AbstractForInProgressionOrRangeLoopGenerator(codegen: ExpressionC
protected fun checkPostCondition(loopExit: Label) { protected fun checkPostCondition(loopExit: Label) {
assert(endVar != -1) { assert(endVar != -1) {
"endVar must be allocated, endVar = " + endVar "endVar must be allocated, endVar = $endVar"
} }
loopParameter().put(asmElementType, elementType, v) loopParameter().put(asmElementType, elementType, v)
v.load(endVar, asmElementType) v.load(endVar, asmElementType)
@@ -64,4 +70,14 @@ abstract class AbstractForInProgressionOrRangeLoopGenerator(codegen: ExpressionC
protected fun loopParameter(): StackValue = protected fun loopParameter(): StackValue =
loopParameter ?: StackValue.local(loopParameterVar, loopParameterType).also { loopParameter = it } loopParameter ?: StackValue.local(loopParameterVar, loopParameterType).also { loopParameter = it }
protected fun KotlinType.getPropertyGetterName(propertyName: String): String {
// In case of unsigned ranges, getter methods for corresponding range/progression properties would be mangled.
val propertyDescriptor = memberScope.getContributedVariables(Name.identifier(propertyName), NoLookupLocation.FROM_BACKEND)
.singleOrNull()
?: throw AssertionError("No '$propertyName' in member scope of type $this")
val getter = propertyDescriptor.getter
?: throw AssertionError("Property has no getter: $propertyDescriptor")
return codegen.typeMapper.mapFunctionName(getter, OwnerKind.IMPLEMENTATION)
}
} }
@@ -31,8 +31,12 @@ class ForInProgressionExpressionLoopGenerator(
v.dup() v.dup()
v.dup() v.dup()
generateRangeOrProgressionProperty(asmLoopRangeType, "getFirst", asmElementType, loopParameterType, loopParameterVar) val firstName = rangeKotlinType.getPropertyGetterName("first")
generateRangeOrProgressionProperty(asmLoopRangeType, "getLast", asmElementType, asmElementType, endVar) val lastName = rangeKotlinType.getPropertyGetterName("last")
generateRangeOrProgressionProperty(asmLoopRangeType, "getStep", incrementType, incrementType, incrementVar) val stepName = rangeKotlinType.getPropertyGetterName("step")
generateRangeOrProgressionProperty(asmLoopRangeType, firstName, asmElementType, loopParameterType, loopParameterVar)
generateRangeOrProgressionProperty(asmLoopRangeType, lastName, asmElementType, asmElementType, endVar)
generateRangeOrProgressionProperty(asmLoopRangeType, stepName, incrementType, incrementType, incrementVar)
} }
} }
@@ -17,9 +17,13 @@
package org.jetbrains.kotlin.codegen.range.forLoop package org.jetbrains.kotlin.codegen.range.forLoop
import org.jetbrains.kotlin.codegen.ExpressionCodegen import org.jetbrains.kotlin.codegen.ExpressionCodegen
import org.jetbrains.kotlin.codegen.OwnerKind
import org.jetbrains.kotlin.codegen.range.comparison.ComparisonGenerator import org.jetbrains.kotlin.codegen.range.comparison.ComparisonGenerator
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.KtExpression import org.jetbrains.kotlin.psi.KtExpression
import org.jetbrains.kotlin.psi.KtForExpression import org.jetbrains.kotlin.psi.KtForExpression
import org.jetbrains.kotlin.types.KotlinType
class ForInRangeInstanceLoopGenerator( class ForInRangeInstanceLoopGenerator(
codegen: ExpressionCodegen, codegen: ExpressionCodegen,
@@ -30,18 +34,21 @@ class ForInRangeInstanceLoopGenerator(
) : AbstractForInRangeLoopGenerator(codegen, forExpression, if (reversed) -1 else 1, comparisonGenerator) { ) : AbstractForInRangeLoopGenerator(codegen, forExpression, if (reversed) -1 else 1, comparisonGenerator) {
override fun storeRangeStartAndEnd() { override fun storeRangeStartAndEnd() {
val loopRangeType = codegen.bindingContext.getType(rangeExpression)!! val asmLoopRangeType = codegen.asmType(rangeKotlinType)
val asmLoopRangeType = codegen.asmType(loopRangeType) codegen.gen(rangeExpression, asmLoopRangeType, rangeKotlinType)
codegen.gen(rangeExpression, asmLoopRangeType, loopRangeType)
v.dup() v.dup()
val firstName = rangeKotlinType.getPropertyGetterName("first")
val lastName = rangeKotlinType.getPropertyGetterName("last")
// ranges inherit first and last from corresponding progressions // ranges inherit first and last from corresponding progressions
if (reversed) { if (reversed) {
generateRangeOrProgressionProperty(asmLoopRangeType, "getLast", asmElementType, loopParameterType, loopParameterVar) generateRangeOrProgressionProperty(asmLoopRangeType, lastName, asmElementType, loopParameterType, loopParameterVar)
generateRangeOrProgressionProperty(asmLoopRangeType, "getFirst", asmElementType, asmElementType, endVar) generateRangeOrProgressionProperty(asmLoopRangeType, firstName, asmElementType, asmElementType, endVar)
} else { } else {
generateRangeOrProgressionProperty(asmLoopRangeType, "getFirst", asmElementType, loopParameterType, loopParameterVar) generateRangeOrProgressionProperty(asmLoopRangeType, firstName, asmElementType, loopParameterType, loopParameterVar)
generateRangeOrProgressionProperty(asmLoopRangeType, "getLast", asmElementType, asmElementType, endVar) generateRangeOrProgressionProperty(asmLoopRangeType, lastName, asmElementType, asmElementType, endVar)
} }
} }
} }
@@ -364,39 +364,29 @@ class KotlinTypeMapper @JvmOverloads constructor(
// and, more importantly, returns 'kotlin.Any' (so that it can return as a reference value or a special COROUTINE_SUSPENDED object). // and, more importantly, returns 'kotlin.Any' (so that it can return as a reference value or a special COROUTINE_SUSPENDED object).
// This also causes boxing of primitives and inline class values. // This also causes boxing of primitives and inline class values.
// If we have a function returning an inline class value that is mapped to a reference type, we want to avoid boxing. // If we have a function returning an inline class value that is mapped to a reference type, we want to avoid boxing.
// However, we have to do that consistently both on declaration site and on call site in case of covariant overrides. // However, we have to do that consistently both on declaration site and on call site.
if (!functionDescriptor.isSuspend) return null if (!functionDescriptor.isSuspend) return null
val originalSuspendFunction = functionDescriptor.unwrapInitialDescriptorForSuspendFunction() val originalSuspendFunction = functionDescriptor.unwrapInitialDescriptorForSuspendFunction()
val originalReturnType = originalSuspendFunction.returnType!! val originalReturnType = originalSuspendFunction.returnType!!
if (!originalReturnType.isInlineClassType()) return null if (!originalReturnType.isInlineClassType()) return null
if (!originalReturnType.isInlineClassTypeSafeToKeepUnboxedOnSuspendFunReturn()) { // Force boxing for primitives
return originalSuspendFunction.module.builtIns.nullableAnyType if (AsmUtil.isPrimitive(mapType(originalReturnType))) {
return functionDescriptor.builtIns.nullableAnyType
} }
// Lambdas, callable references, and function literals implicitly override corresponding generic method from a base class. // Force boxing for nullable inline class types with nullable underlying type
// NB we don't have suspend function literals so far, but we support it in back-end, just in case. if (originalReturnType.isMarkedNullable && originalReturnType.isNullableUnderlyingType()) {
if (isFunctionLiteral(originalSuspendFunction) || isFunctionExpression(originalSuspendFunction)) { return functionDescriptor.builtIns.nullableAnyType
return originalSuspendFunction.module.builtIns.nullableAnyType
}
// NB JVM view of a Kotlin function overrides JVM views of corresponding overridden functions
val originalOverridden = getAllOverriddenDeclarations(functionDescriptor).map {
it.unwrapInitialDescriptorForSuspendFunction().original
}
if (originalOverridden.any { !it.returnType!!.isInlineClassTypeSafeToKeepUnboxedOnSuspendFunReturn() }) {
return originalSuspendFunction.module.builtIns.nullableAnyType
} }
// Don't box other inline classes
return originalReturnType return originalReturnType
} }
private fun KotlinType.isInlineClassTypeSafeToKeepUnboxedOnSuspendFunReturn(): Boolean =
isInlineClassType() && !AsmUtil.isPrimitive(mapType(this)) && (!isMarkedNullable || !isNullableUnderlyingType())
@JvmOverloads @JvmOverloads
fun mapToCallableMethod( fun mapToCallableMethod(
descriptor: FunctionDescriptor, descriptor: FunctionDescriptor,
@@ -410,7 +400,7 @@ class KotlinTypeMapper @JvmOverloads constructor(
val owner = mapOwner(descriptor) val owner = mapOwner(descriptor)
val originalDescriptor = descriptor.original val originalDescriptor = descriptor.original
return CallableMethod( return CallableMethod(
owner, owner, { mapDefaultMethod(originalDescriptor, OwnerKind.IMPLEMENTATION).descriptor }, method, INVOKESPECIAL, owner, owner, { mapDefaultMethod(originalDescriptor, OwnerKind.IMPLEMENTATION) }, method, INVOKESPECIAL,
null, null, null, null, null, originalDescriptor.returnType, isInterfaceMethod = false, isDefaultMethodInInterface = false null, null, null, null, null, originalDescriptor.returnType, isInterfaceMethod = false, isDefaultMethodInInterface = false
) )
} }
@@ -571,7 +561,7 @@ class KotlinTypeMapper @JvmOverloads constructor(
return CallableMethod( return CallableMethod(
owner, ownerForDefaultImpl, owner, ownerForDefaultImpl,
{ mapDefaultMethod(baseMethodDescriptor, getKindForDefaultImplCall(baseMethodDescriptor)).descriptor }, { mapDefaultMethod(baseMethodDescriptor, getKindForDefaultImplCall(baseMethodDescriptor)) },
signature, invokeOpcode, thisClass, dispatchReceiverKotlinType, receiverParameterType, extensionReceiverKotlinType, signature, invokeOpcode, thisClass, dispatchReceiverKotlinType, receiverParameterType, extensionReceiverKotlinType,
calleeType, returnKotlinType, calleeType, returnKotlinType,
if (jvmTarget >= JvmTarget.JVM_1_8) isInterfaceMember else invokeOpcode == INVOKEINTERFACE, if (jvmTarget >= JvmTarget.JVM_1_8) isInterfaceMember else invokeOpcode == INVOKEINTERFACE,
@@ -663,11 +653,16 @@ class KotlinTypeMapper @JvmOverloads constructor(
} }
} }
val suffix = getInlineClassSignatureManglingSuffix(descriptor) // Skip inline class mangling for property reference signatures,
if (suffix != null) { // so that we don't have to repeat the same logic in reflection
newName += suffix // in case of properties without getter methods.
} else if (kind === OwnerKind.ERASED_INLINE_CLASS) { if (kind !== OwnerKind.PROPERTY_REFERENCE_SIGNATURE || descriptor.isPropertyWithGetterSignaturePresent()) {
newName += JvmAbi.IMPL_SUFFIX_FOR_INLINE_CLASS_MEMBERS val suffix = getManglingSuffixBasedOnKotlinSignature(descriptor)
if (suffix != null) {
newName += suffix
} else if (kind === OwnerKind.ERASED_INLINE_CLASS) {
newName += JvmAbi.IMPL_SUFFIX_FOR_INLINE_CLASS_MEMBERS
}
} }
newName = sanitizeNameIfNeeded(newName, languageVersionSettings) newName = sanitizeNameIfNeeded(newName, languageVersionSettings)
@@ -966,12 +961,12 @@ class KotlinTypeMapper @JvmOverloads constructor(
// implicitly override generic 'invoke' from a corresponding base class. // implicitly override generic 'invoke' from a corresponding base class.
if ((isFunctionExpression(descriptor) || isFunctionLiteral(descriptor)) && returnType.isInlineClassType()) return true if ((isFunctionExpression(descriptor) || isFunctionLiteral(descriptor)) && returnType.isInlineClassType()) return true
return isJvmPrimitiveOrInlineClass(returnType) && return isJvmPrimitive(returnType) &&
getAllOverriddenDescriptors(descriptor).any { !isJvmPrimitiveOrInlineClass(it.returnType!!) } getAllOverriddenDescriptors(descriptor).any { !isJvmPrimitive(it.returnType!!) }
} }
private fun isJvmPrimitiveOrInlineClass(kotlinType: KotlinType) = private fun isJvmPrimitive(kotlinType: KotlinType) =
KotlinBuiltIns.isPrimitiveType(kotlinType) || kotlinType.isInlineClassType() KotlinBuiltIns.isPrimitiveType(kotlinType)
private fun isBoxMethodForInlineClass(descriptor: FunctionDescriptor): Boolean { private fun isBoxMethodForInlineClass(descriptor: FunctionDescriptor): Boolean {
val containingDeclaration = descriptor.containingDeclaration val containingDeclaration = descriptor.containingDeclaration
@@ -5,31 +5,41 @@
package org.jetbrains.kotlin.codegen.state package org.jetbrains.kotlin.codegen.state
import org.jetbrains.kotlin.codegen.coroutines.unwrapInitialDescriptorForSuspendFunction
import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.resolve.InlineClassDescriptorResolver import org.jetbrains.kotlin.resolve.InlineClassDescriptorResolver
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameUnsafe import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameUnsafe
import org.jetbrains.kotlin.resolve.isInlineClassType
import org.jetbrains.kotlin.resolve.jvm.* import org.jetbrains.kotlin.resolve.jvm.*
import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.typeUtil.representativeUpperBound import org.jetbrains.kotlin.types.typeUtil.representativeUpperBound
import java.security.MessageDigest import java.security.MessageDigest
import java.util.* import java.util.*
fun getInlineClassSignatureManglingSuffix(descriptor: CallableMemberDescriptor): String? { fun getManglingSuffixBasedOnKotlinSignature(descriptor: CallableMemberDescriptor): String? {
if (descriptor !is FunctionDescriptor) return null if (descriptor !is FunctionDescriptor) return null
if (descriptor is ConstructorDescriptor) return null if (descriptor is ConstructorDescriptor) return null
if (InlineClassDescriptorResolver.isSynthesizedBoxOrUnboxMethod(descriptor)) return null if (InlineClassDescriptorResolver.isSynthesizedBoxOrUnboxMethod(descriptor)) return null
// If a function accepts inline class parameters, mangle its name.
val actualValueParameterTypes = listOfNotNull(descriptor.extensionReceiverParameter?.type) + descriptor.valueParameters.map { it.type } val actualValueParameterTypes = listOfNotNull(descriptor.extensionReceiverParameter?.type) + descriptor.valueParameters.map { it.type }
if (requiresFunctionNameMangling(actualValueParameterTypes)) {
return "-" + md5base64(collectSignatureForMangling(actualValueParameterTypes))
}
return getInlineClassSignatureManglingSuffix(actualValueParameterTypes) // If a class member function returns inline class value, mangle its name.
// NB here function can be a suspend function JVM view with return type replaced with 'Any',
// should unwrap it and take original return type instead.
if (descriptor.containingDeclaration is ClassDescriptor) {
val returnType = descriptor.unwrapInitialDescriptorForSuspendFunction().returnType!!
// NB functions returning all inline classes (including our special 'kotlin.Result') should be mangled.
if (returnType.isInlineClassType()) {
return "-" + md5base64(":" + getSignatureElementForMangling(returnType))
}
}
return null
} }
private fun getInlineClassSignatureManglingSuffix(valueParameterTypes: List<KotlinType>) =
if (requiresFunctionNameMangling(valueParameterTypes))
"-" + md5base64(collectSignatureForMangling(valueParameterTypes))
else
null
private fun collectSignatureForMangling(types: List<KotlinType>) = private fun collectSignatureForMangling(types: List<KotlinType>) =
types.joinToString { getSignatureElementForMangling(it) } types.joinToString { getSignatureElementForMangling(it) }
@@ -12908,6 +12908,11 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
runTest("compiler/testData/codegen/box/inlineClasses/kt37998.kt"); runTest("compiler/testData/codegen/box/inlineClasses/kt37998.kt");
} }
@TestMetadata("kt38680.kt")
public void testKt38680() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/kt38680.kt");
}
@TestMetadata("mangledDefaultParameterFunction.kt") @TestMetadata("mangledDefaultParameterFunction.kt")
public void testMangledDefaultParameterFunction() throws Exception { public void testMangledDefaultParameterFunction() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/mangledDefaultParameterFunction.kt"); runTest("compiler/testData/codegen/box/inlineClasses/mangledDefaultParameterFunction.kt");
@@ -8,7 +8,7 @@ enum class RequestFields {
ENUM_ONE ENUM_ONE
} }
data class RequestInputParameters( class RequestInputParameters(
private val backingMap: Map<RequestFields, FieldValue> private val backingMap: Map<RequestFields, FieldValue>
) : Map<RequestFields, FieldValue> by backingMap ) : Map<RequestFields, FieldValue> by backingMap
+13
View File
@@ -0,0 +1,13 @@
// !LANGUAGE: +InlineClasses
inline class IC(val s: String)
interface IFoo<T> {
fun foo(x: T, s: String = "K"): String
}
class FooImpl : IFoo<IC> {
override fun foo(x: IC, s: String): String = x.s + s
}
fun box(): String = FooImpl().foo(IC("O"))
@@ -14123,6 +14123,11 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
runTest("compiler/testData/codegen/box/inlineClasses/kt37998.kt"); runTest("compiler/testData/codegen/box/inlineClasses/kt37998.kt");
} }
@TestMetadata("kt38680.kt")
public void testKt38680() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/kt38680.kt");
}
@TestMetadata("mangledDefaultParameterFunction.kt") @TestMetadata("mangledDefaultParameterFunction.kt")
public void testMangledDefaultParameterFunction() throws Exception { public void testMangledDefaultParameterFunction() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/mangledDefaultParameterFunction.kt"); runTest("compiler/testData/codegen/box/inlineClasses/mangledDefaultParameterFunction.kt");
@@ -14128,6 +14128,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
runTest("compiler/testData/codegen/box/inlineClasses/kt37998.kt"); runTest("compiler/testData/codegen/box/inlineClasses/kt37998.kt");
} }
@TestMetadata("kt38680.kt")
public void testKt38680() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/kt38680.kt");
}
@TestMetadata("mangledDefaultParameterFunction.kt") @TestMetadata("mangledDefaultParameterFunction.kt")
public void testMangledDefaultParameterFunction() throws Exception { public void testMangledDefaultParameterFunction() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/mangledDefaultParameterFunction.kt"); runTest("compiler/testData/codegen/box/inlineClasses/mangledDefaultParameterFunction.kt");
@@ -12908,6 +12908,11 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
runTest("compiler/testData/codegen/box/inlineClasses/kt37998.kt"); runTest("compiler/testData/codegen/box/inlineClasses/kt37998.kt");
} }
@TestMetadata("kt38680.kt")
public void testKt38680() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/kt38680.kt");
}
@TestMetadata("mangledDefaultParameterFunction.kt") @TestMetadata("mangledDefaultParameterFunction.kt")
public void testMangledDefaultParameterFunction() throws Exception { public void testMangledDefaultParameterFunction() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/mangledDefaultParameterFunction.kt"); runTest("compiler/testData/codegen/box/inlineClasses/mangledDefaultParameterFunction.kt");
@@ -11118,6 +11118,11 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest {
runTest("compiler/testData/codegen/box/inlineClasses/kt37998.kt"); runTest("compiler/testData/codegen/box/inlineClasses/kt37998.kt");
} }
@TestMetadata("kt38680.kt")
public void testKt38680() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/kt38680.kt");
}
@TestMetadata("mangledDefaultParameterFunction.kt") @TestMetadata("mangledDefaultParameterFunction.kt")
public void testMangledDefaultParameterFunction() throws Exception { public void testMangledDefaultParameterFunction() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/mangledDefaultParameterFunction.kt"); runTest("compiler/testData/codegen/box/inlineClasses/mangledDefaultParameterFunction.kt");
@@ -11183,6 +11183,11 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
runTest("compiler/testData/codegen/box/inlineClasses/kt37998.kt"); runTest("compiler/testData/codegen/box/inlineClasses/kt37998.kt");
} }
@TestMetadata("kt38680.kt")
public void testKt38680() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/kt38680.kt");
}
@TestMetadata("mangledDefaultParameterFunction.kt") @TestMetadata("mangledDefaultParameterFunction.kt")
public void testMangledDefaultParameterFunction() throws Exception { public void testMangledDefaultParameterFunction() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/mangledDefaultParameterFunction.kt"); runTest("compiler/testData/codegen/box/inlineClasses/mangledDefaultParameterFunction.kt");