diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java index 3c5481265ce..ac878f2bbaa 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java @@ -38,13 +38,10 @@ import org.jetbrains.kotlin.codegen.binding.CodegenBinding; import org.jetbrains.kotlin.codegen.context.*; import org.jetbrains.kotlin.codegen.extensions.ExpressionCodegenExtension; import org.jetbrains.kotlin.codegen.inline.*; -import org.jetbrains.kotlin.codegen.intrinsics.IntrinsicCallable; -import org.jetbrains.kotlin.codegen.intrinsics.IntrinsicMethod; -import org.jetbrains.kotlin.codegen.intrinsics.IntrinsicMethods; -import org.jetbrains.kotlin.codegen.intrinsics.IntrinsicPropertyGetter; +import org.jetbrains.kotlin.codegen.intrinsics.*; import org.jetbrains.kotlin.codegen.pseudoInsns.PseudoInsnsKt; -import org.jetbrains.kotlin.codegen.signature.JvmSignatureWriter; import org.jetbrains.kotlin.codegen.signature.BothSignatureWriter; +import org.jetbrains.kotlin.codegen.signature.JvmSignatureWriter; import org.jetbrains.kotlin.codegen.state.GenerationState; import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper; import org.jetbrains.kotlin.codegen.when.SwitchCodegen; @@ -1983,8 +1980,14 @@ public class ExpressionCodegen extends KtVisitor impleme VariableAsFunctionResolvedCall call = (VariableAsFunctionResolvedCall) resolvedCall; resolvedCall = call.getVariableCall(); } - receiver = StackValue.receiver(resolvedCall, receiver, this, null); + descriptor = resolvedCall.getResultingDescriptor(); + + //Check early if KCallableNameProperty is applicable to prevent closure generation + StackValue intrinsicResult = applyIntrinsic(descriptor, KCallableNameProperty.class, resolvedCall, receiver); + if (intrinsicResult != null) return intrinsicResult; + + receiver = StackValue.receiver(resolvedCall, receiver, this, null); if (descriptor instanceof FakeCallableDescriptorForObject) { descriptor = ((FakeCallableDescriptorForObject) descriptor).getReferencedDescriptor(); } @@ -1997,17 +2000,9 @@ public class ExpressionCodegen extends KtVisitor impleme if (isSyntheticField) { descriptor = ((SyntheticFieldDescriptor) descriptor).getPropertyDescriptor(); } - if (descriptor instanceof CallableMemberDescriptor) { - CallableMemberDescriptor memberDescriptor = DescriptorUtils.unwrapFakeOverride((CallableMemberDescriptor) descriptor); - IntrinsicMethod intrinsic = state.getIntrinsics().getIntrinsic(memberDescriptor); - if (intrinsic instanceof IntrinsicPropertyGetter) { - //TODO: intrinsic properties (see intermediateValueForProperty) - Type returnType = typeMapper.mapType(memberDescriptor); - StackValue intrinsicResult = ((IntrinsicPropertyGetter) intrinsic).generate(resolvedCall, this, returnType, receiver); - if (intrinsicResult != null) return intrinsicResult; - } - } + StackValue intrinsicResult = applyIntrinsic(descriptor, IntrinsicPropertyGetter.class, resolvedCall, receiver); + if (intrinsicResult != null) return intrinsicResult; if (descriptor instanceof PropertyDescriptor) { PropertyDescriptor propertyDescriptor = (PropertyDescriptor) descriptor; @@ -2056,6 +2051,25 @@ public class ExpressionCodegen extends KtVisitor impleme throw new UnsupportedOperationException("don't know how to generate reference " + descriptor); } + @Nullable + private StackValue applyIntrinsic( + DeclarationDescriptor descriptor, + Class intrinsicType, + ResolvedCall resolvedCall, + @NotNull StackValue receiver + ) { + if (descriptor instanceof CallableMemberDescriptor) { + CallableMemberDescriptor memberDescriptor = DescriptorUtils.unwrapFakeOverride((CallableMemberDescriptor) descriptor); + IntrinsicMethod intrinsic = state.getIntrinsics().getIntrinsic(memberDescriptor); + if (intrinsicType.isInstance(intrinsic)) { + //TODO: intrinsic properties (see intermediateValueForProperty) + Type returnType = typeMapper.mapType(memberDescriptor); + return ((IntrinsicPropertyGetter) intrinsic).generate(resolvedCall, this, returnType, receiver); + } + } + return null; + } + @Nullable private ClassDescriptor getSuperCallTarget(@NotNull Call call) { KtSuperExpression superExpression = CallResolverUtilKt.getSuperCallExpression(call); diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/intrinsics/IntrinsicMethods.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/intrinsics/IntrinsicMethods.java index d14fc274348..2b6a1cfd6e7 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/intrinsics/IntrinsicMethods.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/intrinsics/IntrinsicMethods.java @@ -62,6 +62,7 @@ public class IntrinsicMethods { public IntrinsicMethods() { intrinsicsMap.registerIntrinsic(KOTLIN_JVM, RECEIVER_PARAMETER_FQ_NAME, "javaClass", -1, new JavaClassProperty()); intrinsicsMap.registerIntrinsic(KOTLIN_JVM, KotlinBuiltIns.FQ_NAMES.kClass, "java", -1, new KClassJavaProperty()); + intrinsicsMap.registerIntrinsic(KotlinBuiltIns.FQ_NAMES.kCallable.toSafe(), null, "name", -1, new KCallableNameProperty()); intrinsicsMap.registerIntrinsic(new FqName("kotlin.jvm.internal.unsafe"), null, "monitorEnter", 1, MonitorInstruction.MONITOR_ENTER); intrinsicsMap.registerIntrinsic(new FqName("kotlin.jvm.internal.unsafe"), null, "monitorExit", 1, MonitorInstruction.MONITOR_EXIT); intrinsicsMap.registerIntrinsic(KOTLIN_JVM, KotlinBuiltIns.FQ_NAMES.array, "isArrayOf", 0, new IsArrayOf()); diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/intrinsics/KCallableNameProperty.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/intrinsics/KCallableNameProperty.kt new file mode 100644 index 00000000000..dd6b9cb1df8 --- /dev/null +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/intrinsics/KCallableNameProperty.kt @@ -0,0 +1,41 @@ +/* + * Copyright 2010-2016 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.kotlin.codegen.intrinsics + +import org.jetbrains.kotlin.codegen.ExpressionCodegen +import org.jetbrains.kotlin.codegen.StackValue +import org.jetbrains.kotlin.psi.KtCallableReferenceExpression +import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall +import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall +import org.jetbrains.kotlin.resolve.jvm.AsmTypes +import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver +import org.jetbrains.org.objectweb.asm.Type + +class KCallableNameProperty : IntrinsicPropertyGetter() { + override fun generate(resolvedCall: ResolvedCall<*>?, codegen: ExpressionCodegen, returnType: Type, receiver: StackValue): StackValue? { + val expressionReceiver = resolvedCall!!.dispatchReceiver as? ExpressionReceiver ?: return null + val expression = expressionReceiver.expression as? KtCallableReferenceExpression ?: return null + val callableReference = expression.callableReference + val descriptor = callableReference.getResolvedCall(codegen.bindingContext)?.resultingDescriptor ?: return null + val name = descriptor.name.asString() + + return StackValue.operation(returnType) { iv -> + iv.aconst(name) + StackValue.coerce(AsmTypes.JAVA_STRING_TYPE, returnType, iv) + } + } +} \ No newline at end of file diff --git a/compiler/testData/codegen/bytecodeListing/callableNameIntrinsic.kt b/compiler/testData/codegen/bytecodeListing/callableNameIntrinsic.kt new file mode 100644 index 00000000000..f321d18358c --- /dev/null +++ b/compiler/testData/codegen/bytecodeListing/callableNameIntrinsic.kt @@ -0,0 +1,10 @@ +class A { + val a = "" + fun b() = "" + + fun test() { + val a = A::a.name + val b = A::b.name + val c = ::A.name + } +} diff --git a/compiler/testData/codegen/bytecodeListing/callableNameIntrinsic.txt b/compiler/testData/codegen/bytecodeListing/callableNameIntrinsic.txt new file mode 100644 index 00000000000..f82d272c817 --- /dev/null +++ b/compiler/testData/codegen/bytecodeListing/callableNameIntrinsic.txt @@ -0,0 +1,8 @@ +@kotlin.Metadata +public final class A { + private final @org.jetbrains.annotations.NotNull field a: java.lang.String + public method (): void + public final @org.jetbrains.annotations.NotNull method b(): java.lang.String + public final @org.jetbrains.annotations.NotNull method getA(): java.lang.String + public final method test(): void +} \ No newline at end of file diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeListingTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeListingTestGenerated.java index 58747d3a60e..38fec7660ef 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeListingTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeListingTestGenerated.java @@ -35,6 +35,12 @@ public class BytecodeListingTestGenerated extends AbstractBytecodeListingTest { KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/bytecodeListing"), Pattern.compile("^(.+)\\.kt$"), true); } + @TestMetadata("callableNameIntrinsic.kt") + public void testCallableNameIntrinsic() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeListing/callableNameIntrinsic.kt"); + doTest(fileName); + } + @TestMetadata("defaultImpls.kt") public void testDefaultImpls() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeListing/defaultImpls.kt");