diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/ArgumentGenerator.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/ArgumentGenerator.kt index b508f58f33e..24388fa15cf 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/ArgumentGenerator.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/ArgumentGenerator.kt @@ -31,7 +31,7 @@ abstract class ArgumentGenerator { * * @see kotlin.reflect.jvm.internal.KCallableImpl.callBy */ - open fun generate(valueArgumentsByIndex: List, actualArgs: List): DefaultCallMask { + open fun generate(valueArgumentsByIndex: List, actualArgs: List): DefaultCallArgs { assert(valueArgumentsByIndex.size == actualArgs.size) { "Value arguments collection should have same size, but ${valueArgumentsByIndex.size} != ${actualArgs.size}" } @@ -48,7 +48,7 @@ abstract class ArgumentGenerator { } } - val masks = DefaultCallMask(valueArgumentsByIndex.size) + val defaultArgs = DefaultCallArgs(valueArgumentsByIndex.size) for (argumentWithDeclIndex in actualArgsWithDeclIndex) { val argument = argumentWithDeclIndex.arg @@ -59,7 +59,7 @@ abstract class ArgumentGenerator { generateExpression(declIndex, argument) } is DefaultValueArgument -> { - masks.mark(declIndex) + defaultArgs.mark(declIndex) generateDefault(declIndex, argument) } is VarargValueArgument -> { @@ -73,7 +73,7 @@ abstract class ArgumentGenerator { reorderArgumentsIfNeeded(actualArgsWithDeclIndex) - return masks + return defaultArgs } protected open fun generateExpression(i: Int, argument: ExpressionValueArgument) { diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/CallBasedArgumentGenerator.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/CallBasedArgumentGenerator.java index 85f952b8511..e83e751031d 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/CallBasedArgumentGenerator.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/CallBasedArgumentGenerator.java @@ -51,15 +51,15 @@ public class CallBasedArgumentGenerator extends ArgumentGenerator { @NotNull @Override - public DefaultCallMask generate( + public DefaultCallArgs generate( @NotNull List valueArgumentsByIndex, @NotNull List valueArgs ) { boolean shouldMarkLineNumbers = this.codegen.isShouldMarkLineNumbers(); this.codegen.setShouldMarkLineNumbers(false); - DefaultCallMask masks = super.generate(valueArgumentsByIndex, valueArgs); + DefaultCallArgs defaultArgs = super.generate(valueArgumentsByIndex, valueArgs); this.codegen.setShouldMarkLineNumbers(shouldMarkLineNumbers); - return masks; + return defaultArgs; } @Override diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/CallableMethod.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/CallableMethod.kt index 734a52286be..0ae22eef335 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/CallableMethod.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/CallableMethod.kt @@ -62,7 +62,6 @@ class CallableMethod( val method = getAsmMethod() if ("".equals(method.name)) { - v.aconst(null) v.visitMethodInsn(INVOKESPECIAL, defaultImplOwner.internalName, "", defaultMethodDesc, false) } else { diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/DefaultCallMask.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/DefaultCallArgs.kt similarity index 71% rename from compiler/backend/src/org/jetbrains/kotlin/codegen/DefaultCallMask.kt rename to compiler/backend/src/org/jetbrains/kotlin/codegen/DefaultCallArgs.kt index 70eb98337c5..2f3528c243a 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/DefaultCallMask.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/DefaultCallArgs.kt @@ -16,10 +16,11 @@ package org.jetbrains.kotlin.codegen +import org.jetbrains.kotlin.resolve.jvm.AsmTypes import org.jetbrains.org.objectweb.asm.Type import java.util.* -class DefaultCallMask(val size: Int) { +class DefaultCallArgs(val size: Int) { val bits: BitSet = BitSet(size) @@ -50,10 +51,15 @@ class DefaultCallMask(val size: Int) { return masks } - fun generateOnStackIfNeeded(callGenerator: CallGenerator): Boolean { + fun generateOnStackIfNeeded(callGenerator: CallGenerator, isConstructor: Boolean): Boolean { val toInts = toInts() - for (mask in toInts) { - callGenerator.putValueIfNeeded(Type.INT_TYPE, StackValue.constant(mask, Type.INT_TYPE)) + if (!toInts.isEmpty()) { + for (mask in toInts) { + callGenerator.putValueIfNeeded(Type.INT_TYPE, StackValue.constant(mask, Type.INT_TYPE)) + } + + val parameterType = if (isConstructor) AsmTypes.DEFAULT_CONSTRUCTOR_MARKER else AsmTypes.OBJECT_TYPE + callGenerator.putValueIfNeeded(parameterType, StackValue.constant(null, parameterType)) } return toInts.isNotEmpty(); } diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/DefaultParameterValueSubstitutor.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/DefaultParameterValueSubstitutor.kt index 729fd76ca65..87606e4c7d6 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/DefaultParameterValueSubstitutor.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/DefaultParameterValueSubstitutor.kt @@ -184,14 +184,14 @@ class DefaultParameterValueSubstitutor(val state: GenerationState) { } } masks.add(mask) + for (m in masks) { v.iconst(m) } - // constructors with default arguments has last synthetic argument of specific type - if (functionDescriptor is ConstructorDescriptor) { - v.aconst(null) - } + // for default constructors: just marks default constructor (see DEFAULT_CONSTRUCTOR_MARKER) + // for default methods: contains MethodHandle for super calls ('null' cause not super call) + v.aconst(null) val defaultMethod = typeMapper.mapDefaultMethod(delegateFunctionDescriptor, contextKind) if (functionDescriptor is ConstructorDescriptor) { diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java index c525e1c6da6..144b7b2ae68 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java @@ -2378,7 +2378,8 @@ public class ExpressionCodegen extends KtVisitor impleme @NotNull CallGenerator callGenerator, @NotNull ArgumentGenerator argumentGenerator ) { - if (!(resolvedCall.getResultingDescriptor() instanceof ConstructorDescriptor)) { // otherwise already + boolean isConstructor = resolvedCall.getResultingDescriptor() instanceof ConstructorDescriptor; + if (!isConstructor) { // otherwise already receiver = StackValue.receiver(resolvedCall, receiver, this, callableMethod); receiver.put(receiver.type, v); callableMethod.afterReceiverGeneration(v); @@ -2389,7 +2390,7 @@ public class ExpressionCodegen extends KtVisitor impleme List valueArguments = resolvedCall.getValueArgumentsByIndex(); assert valueArguments != null : "Failed to arrange value arguments by index: " + resolvedCall.getResultingDescriptor(); - DefaultCallMask masks = + DefaultCallArgs defaultArgs = argumentGenerator.generate(valueArguments, new ArrayList(resolvedCall.getValueArguments().values())); if (tailRecursionCodegen.isTailRecursion(resolvedCall)) { @@ -2397,7 +2398,7 @@ public class ExpressionCodegen extends KtVisitor impleme return; } - boolean defaultMaskWasGenerated = masks.generateOnStackIfNeeded(callGenerator); + boolean defaultMaskWasGenerated = defaultArgs.generateOnStackIfNeeded(callGenerator, isConstructor); // Extra constructor marker argument if (callableMethod instanceof CallableMethod) { diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/StackValue.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/StackValue.java index 9dcb9856e02..fe3cc6a3ad1 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/StackValue.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/StackValue.java @@ -774,7 +774,7 @@ public abstract class StackValue { private final StackValue receiver; private final ResolvedCall resolvedGetCall; private final ResolvedCall resolvedSetCall; - private DefaultCallMask mask; + private DefaultCallArgs defaultArgs; private CallGenerator callGenerator; boolean isComplexOperationWithDup; @@ -807,7 +807,7 @@ public abstract class StackValue { newReceiver.put(newReceiver.type, v); callGenerator.putHiddenParams(); - mask = generator.generate(valueArguments, valueArguments); + defaultArgs = generator.generate(valueArguments, valueArguments); } private ArgumentGenerator createArgumentGenerator() { @@ -955,8 +955,8 @@ public abstract class StackValue { } private boolean genDefaultMaskIfPresent(CallGenerator callGenerator) { - DefaultCallMask mask = ((CollectionElementReceiver) receiver).mask; - return mask.generateOnStackIfNeeded(callGenerator); + DefaultCallArgs defaultArgs = ((CollectionElementReceiver) receiver).defaultArgs; + return defaultArgs.generateOnStackIfNeeded(callGenerator, true); } private CallGenerator getCallGenerator() { diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/state/JetTypeMapper.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/state/JetTypeMapper.java index c4ed2636dbf..c35e581a5cd 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/state/JetTypeMapper.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/state/JetTypeMapper.java @@ -88,6 +88,7 @@ import static org.jetbrains.kotlin.resolve.BindingContextUtils.getDelegationCons import static org.jetbrains.kotlin.resolve.BindingContextUtils.isVarCapturedInClosure; import static org.jetbrains.kotlin.resolve.DescriptorUtils.*; import static org.jetbrains.kotlin.resolve.jvm.AsmTypes.DEFAULT_CONSTRUCTOR_MARKER; +import static org.jetbrains.kotlin.resolve.jvm.AsmTypes.OBJECT_TYPE; import static org.jetbrains.kotlin.types.expressions.ExpressionTypingUtils.*; import static org.jetbrains.org.objectweb.asm.Opcodes.*; @@ -1104,9 +1105,7 @@ public class JetTypeMapper { } int maskArgumentsCount = (argumentsCount + Integer.SIZE - 1) / Integer.SIZE; String additionalArgs = StringUtil.repeat(Type.INT_TYPE.getDescriptor(), maskArgumentsCount); - if (isConstructor(method)) { - additionalArgs += DEFAULT_CONSTRUCTOR_MARKER.getDescriptor(); - } + additionalArgs += (isConstructor(method) ? DEFAULT_CONSTRUCTOR_MARKER : OBJECT_TYPE).getDescriptor(); String result = descriptor.replace(")", additionalArgs + ")"); if (dispatchReceiverDescriptor != null && !isConstructor(method)) { return result.replace("(", "(" + dispatchReceiverDescriptor); diff --git a/compiler/testData/diagnostics/tests/duplicateJvmSignature/accidentalOverrides/defaultFunction.kt b/compiler/testData/diagnostics/tests/duplicateJvmSignature/accidentalOverrides/defaultFunction.kt index d4fd75e8dbb..ed43af21a90 100644 --- a/compiler/testData/diagnostics/tests/duplicateJvmSignature/accidentalOverrides/defaultFunction.kt +++ b/compiler/testData/diagnostics/tests/duplicateJvmSignature/accidentalOverrides/defaultFunction.kt @@ -1,7 +1,7 @@ // !DIAGNOSTICS: -UNUSED_PARAMETER open class Base { - open fun `foo$default`(d: Derived, i: Int, mask: Int) {} + open fun `foo$default`(d: Derived, i: Int, mask: Int, mh: Any) {} } class Derived : Base() { diff --git a/compiler/testData/diagnostics/tests/duplicateJvmSignature/accidentalOverrides/defaultFunction.txt b/compiler/testData/diagnostics/tests/duplicateJvmSignature/accidentalOverrides/defaultFunction.txt index f06c1dd7a78..9d23e55ff9f 100644 --- a/compiler/testData/diagnostics/tests/duplicateJvmSignature/accidentalOverrides/defaultFunction.txt +++ b/compiler/testData/diagnostics/tests/duplicateJvmSignature/accidentalOverrides/defaultFunction.txt @@ -3,7 +3,7 @@ package public open class Base { public constructor Base() public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean - public open fun `foo$default`(/*0*/ d: Derived, /*1*/ i: kotlin.Int, /*2*/ mask: kotlin.Int): kotlin.Unit + public open fun `foo$default`(/*0*/ d: Derived, /*1*/ i: kotlin.Int, /*2*/ mask: kotlin.Int, /*3*/ mh: kotlin.Any): kotlin.Unit public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String } @@ -12,7 +12,7 @@ public final class Derived : Base { public constructor Derived() public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean public final fun foo(/*0*/ i: kotlin.Int = ...): kotlin.Unit - public open override /*1*/ /*fake_override*/ fun `foo$default`(/*0*/ d: Derived, /*1*/ i: kotlin.Int, /*2*/ mask: kotlin.Int): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun `foo$default`(/*0*/ d: Derived, /*1*/ i: kotlin.Int, /*2*/ mask: kotlin.Int, /*3*/ mh: kotlin.Any): kotlin.Unit public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String } diff --git a/compiler/testData/diagnostics/tests/duplicateJvmSignature/specialNames/dataClassCopy.kt b/compiler/testData/diagnostics/tests/duplicateJvmSignature/specialNames/dataClassCopy.kt index 568ebb3ba7b..4159e7a9680 100644 --- a/compiler/testData/diagnostics/tests/duplicateJvmSignature/specialNames/dataClassCopy.kt +++ b/compiler/testData/diagnostics/tests/duplicateJvmSignature/specialNames/dataClassCopy.kt @@ -1,5 +1,5 @@ // !DIAGNOSTICS: -UNUSED_PARAMETER data class C(val c: Int) { - fun `copy$default`(c: C, x: Int, m: Int) = C(this.c) + fun `copy$default`(c: C, x: Int, m: Int, mh: Any) = C(this.c) } \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/duplicateJvmSignature/specialNames/dataClassCopy.txt b/compiler/testData/diagnostics/tests/duplicateJvmSignature/specialNames/dataClassCopy.txt index 8b218fd3062..6d1f584217f 100644 --- a/compiler/testData/diagnostics/tests/duplicateJvmSignature/specialNames/dataClassCopy.txt +++ b/compiler/testData/diagnostics/tests/duplicateJvmSignature/specialNames/dataClassCopy.txt @@ -5,7 +5,7 @@ public final data class C { public final val c: kotlin.Int public final operator /*synthesized*/ fun component1(): kotlin.Int public final /*synthesized*/ fun copy(/*0*/ c: kotlin.Int = ...): C - public final fun `copy$default`(/*0*/ c: C, /*1*/ x: kotlin.Int, /*2*/ m: kotlin.Int): C + public final fun `copy$default`(/*0*/ c: C, /*1*/ x: kotlin.Int, /*2*/ m: kotlin.Int, /*3*/ mh: kotlin.Any): C public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String diff --git a/compiler/testData/diagnostics/tests/duplicateJvmSignature/specialNames/defaults.kt b/compiler/testData/diagnostics/tests/duplicateJvmSignature/specialNames/defaults.kt index 154adebc040..44ba8193349 100644 --- a/compiler/testData/diagnostics/tests/duplicateJvmSignature/specialNames/defaults.kt +++ b/compiler/testData/diagnostics/tests/duplicateJvmSignature/specialNames/defaults.kt @@ -1,6 +1,6 @@ // !DIAGNOSTICS: -UNUSED_PARAMETER class C { - fun `a$default`(c: C, x: Int, m: Int) {} + fun `a$default`(c: C, x: Int, m: Int, mh: Any) {} fun a(x: Int = 1) {} } \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/duplicateJvmSignature/specialNames/defaults.txt b/compiler/testData/diagnostics/tests/duplicateJvmSignature/specialNames/defaults.txt index 1989cfaa8ac..ede39d8e205 100644 --- a/compiler/testData/diagnostics/tests/duplicateJvmSignature/specialNames/defaults.txt +++ b/compiler/testData/diagnostics/tests/duplicateJvmSignature/specialNames/defaults.txt @@ -3,7 +3,7 @@ package public final class C { public constructor C() public final fun a(/*0*/ x: kotlin.Int = ...): kotlin.Unit - public final fun `a$default`(/*0*/ c: C, /*1*/ x: kotlin.Int, /*2*/ m: kotlin.Int): kotlin.Unit + public final fun `a$default`(/*0*/ c: C, /*1*/ x: kotlin.Int, /*2*/ m: kotlin.Int, /*3*/ mh: kotlin.Any): kotlin.Unit public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String diff --git a/compiler/testData/diagnostics/testsWithStdLib/duplicateJvmSignature/platformStaticInObject.kt b/compiler/testData/diagnostics/testsWithStdLib/duplicateJvmSignature/platformStaticInObject.kt index d6b5cfe52c5..290609831ef 100644 --- a/compiler/testData/diagnostics/testsWithStdLib/duplicateJvmSignature/platformStaticInObject.kt +++ b/compiler/testData/diagnostics/testsWithStdLib/duplicateJvmSignature/platformStaticInObject.kt @@ -2,7 +2,7 @@ import kotlin.jvm.JvmStatic open class Base { - fun `foo$default`(i: Int, mask: Int) {} + fun `foo$default`(i: Int, mask: Int, mh: Any) {} } object Derived : Base() { diff --git a/compiler/testData/diagnostics/testsWithStdLib/duplicateJvmSignature/platformStaticInObject.txt b/compiler/testData/diagnostics/testsWithStdLib/duplicateJvmSignature/platformStaticInObject.txt index b317d524c2e..4f196048003 100644 --- a/compiler/testData/diagnostics/testsWithStdLib/duplicateJvmSignature/platformStaticInObject.txt +++ b/compiler/testData/diagnostics/testsWithStdLib/duplicateJvmSignature/platformStaticInObject.txt @@ -3,7 +3,7 @@ package public open class Base { public constructor Base() public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean - public final fun `foo$default`(/*0*/ i: kotlin.Int, /*1*/ mask: kotlin.Int): kotlin.Unit + public final fun `foo$default`(/*0*/ i: kotlin.Int, /*1*/ mask: kotlin.Int, /*2*/ mh: kotlin.Any): kotlin.Unit public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String } @@ -12,7 +12,7 @@ public object Derived : Base { private constructor Derived() public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean @kotlin.jvm.JvmStatic() public final fun foo(/*0*/ i: kotlin.Int = ...): kotlin.Unit - public final override /*1*/ /*fake_override*/ fun `foo$default`(/*0*/ i: kotlin.Int, /*1*/ mask: kotlin.Int): kotlin.Unit + public final override /*1*/ /*fake_override*/ fun `foo$default`(/*0*/ i: kotlin.Int, /*1*/ mask: kotlin.Int, /*2*/ mh: kotlin.Any): kotlin.Unit public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String } diff --git a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KCallableImpl.kt b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KCallableImpl.kt index 9e344bb9d85..8fef9178995 100644 --- a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KCallableImpl.kt +++ b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KCallableImpl.kt @@ -107,10 +107,8 @@ internal interface KCallableImpl : KCallable, KAnnotatedElementImpl { arguments.addAll(masks) - if (caller is FunctionCaller.Constructor) { - // DefaultConstructorMarker - arguments.add(null) - } + // DefaultConstructorMarker or MethodHandle + arguments.add(null) @Suppress("UNCHECKED_CAST") return reflectionCall { diff --git a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KDeclarationContainerImpl.kt b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KDeclarationContainerImpl.kt index 249daa0ac31..2c54a8c73a3 100644 --- a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KDeclarationContainerImpl.kt +++ b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KDeclarationContainerImpl.kt @@ -170,7 +170,7 @@ internal abstract class KDeclarationContainerImpl : ClassBasedDeclarationContain if (isMember) { parameterTypes.add(jClass) } - addParametersAndMasks(parameterTypes, desc) + addParametersAndMasks(parameterTypes, desc, false) return jClass.tryGetMethod(name + JvmAbi.DEFAULT_PARAMS_IMPL_SUFFIX, parameterTypes, declared) } @@ -181,18 +181,18 @@ internal abstract class KDeclarationContainerImpl : ClassBasedDeclarationContain fun findDefaultConstructor(desc: String, declared: Boolean): Constructor<*>? { val parameterTypes = arrayListOf>() - addParametersAndMasks(parameterTypes, desc) - parameterTypes.add(DEFAULT_CONSTRUCTOR_MARKER) + addParametersAndMasks(parameterTypes, desc, true) return jClass.tryGetConstructor(parameterTypes, declared) } - private fun addParametersAndMasks(result: MutableList>, desc: String) { + private fun addParametersAndMasks(result: MutableList>, desc: String, isConstructor: Boolean) { val valueParameters = loadParameterTypes(desc) result.addAll(valueParameters) repeat((valueParameters.size + Integer.SIZE - 1) / Integer.SIZE) { result.add(Integer.TYPE) } + result.add(if (isConstructor) DEFAULT_CONSTRUCTOR_MARKER else Any::class.java) } private fun loadParameterTypes(desc: String): List> {