From f73b8b9ff842a3fdf77ecc32b4a7aee45f132f7d Mon Sep 17 00:00:00 2001 From: Alexander Udalov Date: Wed, 25 Jun 2014 17:37:48 +0400 Subject: [PATCH] Extract KForeignMemberProperty out of KMemberPropertyImpl KClassImpl is now able to create a property by the name, according to its origin --- .../jet/codegen/ExpressionCodegen.java | 111 ++++++++++-------- .../lang/resolve/java/AsmTypeConstants.java | 5 +- .../kotlin/reflect/jvm/internal/KClassImpl.kt | 29 ++++- .../jvm/internal/KForeignMemberProperty.kt | 43 +++++++ .../jvm/internal/KMemberPropertyImpl.kt | 38 ++---- .../kotlin/reflect/jvm/internal/factory.kt | 7 -- .../src/kotlin/reflect/jvm/internal/util.kt | 12 -- .../src/kotlin/reflect/jvm/properties.kt | 24 ++-- 8 files changed, 151 insertions(+), 118 deletions(-) create mode 100644 core/runtime.jvm/src/kotlin/reflect/jvm/internal/KForeignMemberProperty.kt diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java index 92a0a2c1856..1b04b121b57 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java @@ -70,7 +70,6 @@ import org.jetbrains.org.objectweb.asm.commons.Method; import java.util.*; import static org.jetbrains.jet.codegen.AsmUtil.*; -import static org.jetbrains.jet.lang.resolve.java.diagnostics.DiagnosticsPackage.OtherOrigin; import static org.jetbrains.jet.codegen.JvmCodegenUtil.*; import static org.jetbrains.jet.codegen.binding.CodegenBinding.*; import static org.jetbrains.jet.lang.resolve.BindingContext.*; @@ -78,6 +77,7 @@ import static org.jetbrains.jet.lang.resolve.BindingContextUtils.getNotNull; import static org.jetbrains.jet.lang.resolve.BindingContextUtils.isVarCapturedInClosure; import static org.jetbrains.jet.lang.resolve.java.AsmTypeConstants.*; import static org.jetbrains.jet.lang.resolve.java.JvmAnnotationNames.KotlinSyntheticClass; +import static org.jetbrains.jet.lang.resolve.java.diagnostics.DiagnosticsPackage.OtherOrigin; import static org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverValue.NO_RECEIVER; import static org.jetbrains.org.objectweb.asm.Opcodes.*; @@ -2427,70 +2427,77 @@ public class ExpressionCodegen extends JetVisitor implem if (variableDescriptor != null) { VariableDescriptor descriptor = (VariableDescriptor) resolvedCall.getResultingDescriptor(); - ReceiverParameterDescriptor receiverParameter = descriptor.getReceiverParameter(); - - String reflectionFieldOwner; - Type ownerType; - String reflectionFieldName; - Method factory; - DeclarationDescriptor containingDeclaration = descriptor.getContainingDeclaration(); if (containingDeclaration instanceof PackageFragmentDescriptor) { - reflectionFieldOwner = - PackageClassUtils.getPackageClassInternalName(((PackageFragmentDescriptor) containingDeclaration).getFqName()); - - ownerType = K_PACKAGE_IMPL_TYPE; - reflectionFieldName = JvmAbi.KOTLIN_PACKAGE_FIELD_NAME; - - if (receiverParameter != null) { - factory = descriptor.isVar() - ? method("mutableExtensionProperty", K_MUTABLE_EXTENSION_PROPERTY_IMPL_TYPE, JAVA_STRING_TYPE, ownerType, - getType(Class.class)) - : method("extensionProperty", K_EXTENSION_PROPERTY_IMPL_TYPE, JAVA_STRING_TYPE, ownerType, - getType(Class.class)); - } - else { - factory = descriptor.isVar() - ? method("mutableTopLevelProperty", K_MUTABLE_TOP_LEVEL_PROPERTY_IMPL_TYPE, JAVA_STRING_TYPE, ownerType) - : method("topLevelProperty", K_TOP_LEVEL_PROPERTY_IMPL_TYPE, JAVA_STRING_TYPE, ownerType); - } + return generateTopLevelPropertyReference(descriptor); } else if (containingDeclaration instanceof ClassDescriptor) { - reflectionFieldOwner = typeMapper.mapClass((ClassDescriptor) containingDeclaration).getInternalName(); - ownerType = K_CLASS_IMPL_TYPE; - reflectionFieldName = JvmAbi.KOTLIN_CLASS_FIELD_NAME; - - factory = descriptor.isVar() - ? method("mutableMemberProperty", K_MUTABLE_MEMBER_PROPERTY_IMPL_TYPE, JAVA_STRING_TYPE, ownerType) - : method("memberProperty", K_MEMBER_PROPERTY_IMPL_TYPE, JAVA_STRING_TYPE, ownerType); + return generateMemberPropertyReference(descriptor); } else { throw new UnsupportedOperationException("Unsupported callable reference container: " + containingDeclaration); } - - v.visitLdcInsn(descriptor.getName().asString()); - - if (containingDeclaration instanceof JavaClassDescriptor) { - v.aconst(Type.getObjectType(reflectionFieldOwner)); - v.invokestatic(REFLECTION_INTERNAL_PACKAGE, "foreignKotlinClass", - Type.getMethodDescriptor(K_CLASS_IMPL_TYPE, getType(Class.class)), false); - } - else { - // TODO: built-in classes - v.getstatic(reflectionFieldOwner, reflectionFieldName, ownerType.getDescriptor()); - } - - if (receiverParameter != null) { - putJavaLangClassInstance(v, typeMapper.mapType(receiverParameter)); - } - - v.invokestatic(REFLECTION_INTERNAL_PACKAGE, factory.getName(), factory.getDescriptor(), false); - return StackValue.onStack(factory.getReturnType()); } throw new UnsupportedOperationException("Unsupported callable reference expression: " + expression.getText()); } + @NotNull + private StackValue generateTopLevelPropertyReference(@NotNull VariableDescriptor descriptor) { + PackageFragmentDescriptor containingPackage = (PackageFragmentDescriptor) descriptor.getContainingDeclaration(); + String packageClassInternalName = PackageClassUtils.getPackageClassInternalName(containingPackage.getFqName()); + + ReceiverParameterDescriptor receiverParameter = descriptor.getReceiverParameter(); + Method factoryMethod; + if (receiverParameter != null) { + Type[] parameterTypes = new Type[] {JAVA_STRING_TYPE, K_PACKAGE_IMPL_TYPE, getType(Class.class)}; + factoryMethod = descriptor.isVar() + ? method("mutableExtensionProperty", K_MUTABLE_EXTENSION_PROPERTY_IMPL_TYPE, parameterTypes) + : method("extensionProperty", K_EXTENSION_PROPERTY_IMPL_TYPE, parameterTypes); + } + else { + Type[] parameterTypes = new Type[] {JAVA_STRING_TYPE, K_PACKAGE_IMPL_TYPE}; + factoryMethod = descriptor.isVar() + ? method("mutableTopLevelProperty", K_MUTABLE_TOP_LEVEL_PROPERTY_IMPL_TYPE, parameterTypes) + : method("topLevelProperty", K_TOP_LEVEL_PROPERTY_IMPL_TYPE, parameterTypes); + } + + v.visitLdcInsn(descriptor.getName().asString()); + v.getstatic(packageClassInternalName, JvmAbi.KOTLIN_PACKAGE_FIELD_NAME, K_PACKAGE_IMPL_TYPE.getDescriptor()); + + if (receiverParameter != null) { + putJavaLangClassInstance(v, typeMapper.mapType(receiverParameter)); + } + + v.invokestatic(REFLECTION_INTERNAL_PACKAGE, factoryMethod.getName(), factoryMethod.getDescriptor(), false); + + return StackValue.onStack(factoryMethod.getReturnType()); + } + + @NotNull + private StackValue generateMemberPropertyReference(@NotNull VariableDescriptor descriptor) { + ClassDescriptor containingClass = (ClassDescriptor) descriptor.getContainingDeclaration(); + Type classAsmType = typeMapper.mapClass(containingClass); + + if (containingClass instanceof JavaClassDescriptor) { + v.aconst(classAsmType); + v.invokestatic(REFLECTION_INTERNAL_PACKAGE, "foreignKotlinClass", + Type.getMethodDescriptor(K_CLASS_IMPL_TYPE, getType(Class.class)), false); + } + else { + v.getstatic(classAsmType.getInternalName(), JvmAbi.KOTLIN_CLASS_FIELD_NAME, K_CLASS_IMPL_TYPE.getDescriptor()); + } + + Method factoryMethod = descriptor.isVar() + ? method("mutableMemberProperty", K_MUTABLE_MEMBER_PROPERTY_TYPE, JAVA_STRING_TYPE) + : method("memberProperty", K_MEMBER_PROPERTY_TYPE, JAVA_STRING_TYPE); + + v.visitLdcInsn(descriptor.getName().asString()); + v.invokevirtual(K_CLASS_IMPL_TYPE.getInternalName(), factoryMethod.getName(), factoryMethod.getDescriptor(), false); + + return StackValue.onStack(factoryMethod.getReturnType()); + } + private static class CallableReferenceGenerationStrategy extends FunctionGenerationStrategy.CodegenBased { private final ResolvedCall resolvedCall; private final FunctionDescriptor referencedFunction; diff --git a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/AsmTypeConstants.java b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/AsmTypeConstants.java index e1099d1dbc6..c4d094cb347 100644 --- a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/AsmTypeConstants.java +++ b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/AsmTypeConstants.java @@ -38,12 +38,13 @@ public class AsmTypeConstants { public static final Type PROPERTY_METADATA_TYPE = Type.getObjectType(BUILT_INS_PACKAGE_FQ_NAME + "/PropertyMetadata"); public static final Type PROPERTY_METADATA_IMPL_TYPE = Type.getObjectType(BUILT_INS_PACKAGE_FQ_NAME + "/PropertyMetadataImpl"); + public static final Type K_MEMBER_PROPERTY_TYPE = Type.getObjectType("kotlin/reflect/KMemberProperty"); + public static final Type K_MUTABLE_MEMBER_PROPERTY_TYPE = Type.getObjectType("kotlin/reflect/KMutableMemberProperty"); + public static final Type K_CLASS_IMPL_TYPE = reflectInternal("KClassImpl"); public static final Type K_PACKAGE_IMPL_TYPE = reflectInternal("KPackageImpl"); public static final Type K_TOP_LEVEL_PROPERTY_IMPL_TYPE = reflectInternal("KTopLevelPropertyImpl"); public static final Type K_MUTABLE_TOP_LEVEL_PROPERTY_IMPL_TYPE = reflectInternal("KMutableTopLevelPropertyImpl"); - public static final Type K_MEMBER_PROPERTY_IMPL_TYPE = reflectInternal("KMemberPropertyImpl"); - public static final Type K_MUTABLE_MEMBER_PROPERTY_IMPL_TYPE = reflectInternal("KMutableMemberPropertyImpl"); public static final Type K_EXTENSION_PROPERTY_IMPL_TYPE = reflectInternal("KExtensionPropertyImpl"); public static final Type K_MUTABLE_EXTENSION_PROPERTY_IMPL_TYPE = reflectInternal("KMutableExtensionPropertyImpl"); diff --git a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KClassImpl.kt b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KClassImpl.kt index cb8d2f337b4..ca2f4efba63 100644 --- a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KClassImpl.kt +++ b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KClassImpl.kt @@ -16,23 +16,40 @@ package kotlin.reflect.jvm.internal -import kotlin.reflect.jvm.KOTLIN_CLASS_ANNOTATION_CLASS - enum class KClassOrigin { BUILT_IN KOTLIN FOREIGN } -class KClassImpl( - val jClass: Class -) : KClass { +private val KOTLIN_CLASS_ANNOTATION_CLASS = Class.forName("kotlin.jvm.internal.KotlinClass") as Class +private val KOTLIN_SYNTHETIC_CLASS_ANNOTATION_CLASS = Class.forName("kotlin.jvm.internal.KotlinSyntheticClass") as Class + +class KClassImpl(val jClass: Class) : KClass { + // TODO: write metadata to local classes val origin: KClassOrigin = - if (K_OBJECT_CLASS.isAssignableFrom(jClass) && jClass.isAnnotationPresent(KOTLIN_CLASS_ANNOTATION_CLASS)) { + if (jClass.isAnnotationPresent(KOTLIN_CLASS_ANNOTATION_CLASS) || + jClass.isAnnotationPresent(KOTLIN_SYNTHETIC_CLASS_ANNOTATION_CLASS)) { KClassOrigin.KOTLIN } else { KClassOrigin.FOREIGN // TODO: built-in classes } + + fun memberProperty(name: String): KMemberProperty = + if (origin identityEquals KClassOrigin.KOTLIN) { + KMemberPropertyImpl(name, this) + } + else { + KForeignMemberProperty(name, this) + } + + fun mutableMemberProperty(name: String): KMutableMemberProperty = + if (origin identityEquals KClassOrigin.KOTLIN) { + KMutableMemberPropertyImpl(name, this) + } + else { + KMutableForeignMemberProperty(name, this) + } } diff --git a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KForeignMemberProperty.kt b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KForeignMemberProperty.kt new file mode 100644 index 00000000000..97ef4430acf --- /dev/null +++ b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KForeignMemberProperty.kt @@ -0,0 +1,43 @@ +/* + * Copyright 2010-2014 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 kotlin.reflect.jvm.internal + +import java.lang.reflect.* + +open class KForeignMemberProperty( + public override val name: String, + protected val owner: KClassImpl +) : KMemberProperty, KPropertyImpl { + override val field: Field = owner.jClass.getField(name) + + override val getter: Method? get() = null + + override fun get(receiver: T): R { + return field.get(receiver) as R + } +} + +class KMutableForeignMemberProperty( + name: String, + owner: KClassImpl +) : KMutableMemberProperty, KMutablePropertyImpl, KForeignMemberProperty(name, owner) { + override val setter: Method? get() = null + + override fun set(receiver: T, value: R) { + field.set(receiver, value) + } +} diff --git a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KMemberPropertyImpl.kt b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KMemberPropertyImpl.kt index 6df4129886a..d237f450004 100644 --- a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KMemberPropertyImpl.kt +++ b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KMemberPropertyImpl.kt @@ -18,29 +18,25 @@ package kotlin.reflect.jvm.internal import java.lang.reflect.* +// TODO: properties of built-in classes + open class KMemberPropertyImpl( public override val name: String, protected val owner: KClassImpl ) : KMemberProperty, KPropertyImpl { - override val field: Field? = - if (owner.origin == KClassOrigin.FOREIGN) { - owner.jClass.getField(name) - } - else null + override val field: Field? + get() = try { + owner.jClass.getDeclaredField(name) + } + catch (e: NoSuchFieldException) { + null + } // TODO: extract, make lazy (weak?), use our descriptors knowledge - override val getter: Method? = - if (owner.origin == KClassOrigin.KOTLIN) { - owner.jClass.getMaybeDeclaredMethod(getterName(name)) - } - else null + override val getter: Method = owner.jClass.getMaybeDeclaredMethod(getterName(name)) - // TODO: built-in classes override fun get(receiver: T): R { - if (getter != null) { - return getter!!(receiver) as R - } - return field!!.get(receiver) as R + return getter(receiver) as R } } @@ -48,17 +44,9 @@ class KMutableMemberPropertyImpl( name: String, owner: KClassImpl ) : KMutableMemberProperty, KMutablePropertyImpl, KMemberPropertyImpl(name, owner) { - override val setter: Method? = - if (owner.origin == KClassOrigin.KOTLIN) { - owner.jClass.getMaybeDeclaredMethod(setterName(name), getter!!.getReturnType()!!) - } - else null + override val setter: Method = owner.jClass.getMaybeDeclaredMethod(setterName(name), getter.getReturnType()!!) override fun set(receiver: T, value: R) { - if (setter != null) { - setter!!(receiver, value) - return - } - field!!.set(receiver, value) + setter(receiver, value) } } diff --git a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/factory.kt b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/factory.kt index 1979953a35c..9ec07585bef 100644 --- a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/factory.kt +++ b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/factory.kt @@ -34,10 +34,3 @@ fun extensionProperty(name: String, owner: KPackageImpl, receiver: Class) fun mutableExtensionProperty(name: String, owner: KPackageImpl, receiver: Class): KMutableExtensionPropertyImpl = KMutableExtensionPropertyImpl(name, owner, receiver) - -fun memberProperty(name: String, owner: KClassImpl): KMemberPropertyImpl = - KMemberPropertyImpl(name, owner) - -fun mutableMemberProperty(name: String, owner: KClassImpl): KMutableMemberPropertyImpl = - KMutableMemberPropertyImpl(name, owner) - diff --git a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/util.kt b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/util.kt index 1ea227e338a..84d6b0a3120 100644 --- a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/util.kt +++ b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/util.kt @@ -43,15 +43,3 @@ private fun Class<*>.getMaybeDeclaredMethod(name: String, vararg parameterTypes: return getDeclaredMethod(name, *parameterTypes) } } - - -private val K_OBJECT_CLASS = Class.forName("kotlin.jvm.internal.KObject") - -fun kotlinClass(jClass: Class): KClassImpl { - if (K_OBJECT_CLASS.isAssignableFrom(jClass)) { - val field = jClass.getDeclaredField("\$kotlinClass") - return field.get(null) as KClassImpl - } - // TODO: built-in classes - return foreignKotlinClass(jClass) -} diff --git a/core/runtime.jvm/src/kotlin/reflect/jvm/properties.kt b/core/runtime.jvm/src/kotlin/reflect/jvm/properties.kt index e7e4abdd452..1c7825f0489 100644 --- a/core/runtime.jvm/src/kotlin/reflect/jvm/properties.kt +++ b/core/runtime.jvm/src/kotlin/reflect/jvm/properties.kt @@ -16,19 +16,14 @@ package kotlin.reflect.jvm -import kotlin.reflect.jvm.internal.KMemberPropertyImpl -import kotlin.reflect.jvm.internal.KMutableMemberPropertyImpl +import kotlin.reflect.jvm.internal.* public var KProperty.accessible: Boolean get() { return when (this) { - is KMutableMemberPropertyImpl<*, R> -> - field?.isAccessible() ?: true && - getter?.isAccessible() ?: true && - setter?.isAccessible() ?: true - is KMemberPropertyImpl<*, R> -> - field?.isAccessible() ?: true && - getter?.isAccessible() ?: true + is KMutableMemberPropertyImpl<*, R> -> getter.isAccessible() && setter.isAccessible() + is KMemberPropertyImpl<*, R> -> getter.isAccessible() + is KForeignMemberProperty<*, R> -> field.isAccessible() else -> { // Non-member properties always have public visibility on JVM, thus accessible has no effect on them true @@ -38,13 +33,14 @@ public var KProperty.accessible: Boolean set(value) { when (this) { is KMutableMemberPropertyImpl<*, R> -> { - field?.setAccessible(value) - getter?.setAccessible(value) - setter?.setAccessible(value) + getter.setAccessible(value) + setter.setAccessible(value) } is KMemberPropertyImpl<*, R> -> { - field?.setAccessible(value) - getter?.setAccessible(value) + getter.setAccessible(value) + } + is KForeignMemberProperty<*, R> -> { + field.setAccessible(value) } } }