From a97567ea0c51babf44a19165cd799874cc7cd7bf Mon Sep 17 00:00:00 2001 From: Alexander Udalov Date: Sun, 25 Oct 2015 15:42:13 +0300 Subject: [PATCH] Optimize KProperty objects for delegated properties Don't generate anonymous classes with a lot of methods because this hurts Android. Add special classes to the runtime instead (also add FunctionReferenceImpl, to be used later) and just create their instances in the static initializer of each class --- .../kotlin/codegen/MemberCodegen.java | 40 ++++++++--- .../codegen/PropertyReferenceCodegen.kt | 66 ++++++++++--------- .../kotlin/resolve/jvm/AsmTypes.java | 11 ++++ .../jvm/internal/FunctionReferenceImpl.java | 47 +++++++++++++ .../MutablePropertyReference0Impl.java | 56 ++++++++++++++++ .../MutablePropertyReference1Impl.java | 56 ++++++++++++++++ .../MutablePropertyReference2Impl.java | 56 ++++++++++++++++ .../jvm/internal/PropertyReference0Impl.java | 51 ++++++++++++++ .../jvm/internal/PropertyReference1Impl.java | 51 ++++++++++++++ .../jvm/internal/PropertyReference2Impl.java | 51 ++++++++++++++ 10 files changed, 444 insertions(+), 41 deletions(-) create mode 100644 core/runtime.jvm/src/kotlin/jvm/internal/FunctionReferenceImpl.java create mode 100644 core/runtime.jvm/src/kotlin/jvm/internal/MutablePropertyReference0Impl.java create mode 100644 core/runtime.jvm/src/kotlin/jvm/internal/MutablePropertyReference1Impl.java create mode 100644 core/runtime.jvm/src/kotlin/jvm/internal/MutablePropertyReference2Impl.java create mode 100644 core/runtime.jvm/src/kotlin/jvm/internal/PropertyReference0Impl.java create mode 100644 core/runtime.jvm/src/kotlin/jvm/internal/PropertyReference1Impl.java create mode 100644 core/runtime.jvm/src/kotlin/jvm/internal/PropertyReference2Impl.java diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/MemberCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/MemberCodegen.java index b14f04b251a..b8ac8c66642 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/MemberCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/MemberCodegen.java @@ -66,8 +66,7 @@ import static org.jetbrains.kotlin.descriptors.CallableMemberDescriptor.Kind.SYN import static org.jetbrains.kotlin.resolve.BindingContext.VARIABLE; import static org.jetbrains.kotlin.resolve.DescriptorUtils.isCompanionObject; import static org.jetbrains.kotlin.resolve.DescriptorUtils.isTopLevelDeclaration; -import static org.jetbrains.kotlin.resolve.jvm.AsmTypes.OBJECT_TYPE; -import static org.jetbrains.kotlin.resolve.jvm.AsmTypes.PROPERTY_METADATA_TYPE; +import static org.jetbrains.kotlin.resolve.jvm.AsmTypes.*; import static org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin.NO_ORIGIN; import static org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOriginKt.Synthetic; import static org.jetbrains.org.objectweb.asm.Opcodes.*; @@ -509,18 +508,41 @@ public abstract class MemberCodegen", + Type.getMethodDescriptor(Type.VOID_TYPE, K_DECLARATION_CONTAINER_TYPE, JAVA_STRING_TYPE, JAVA_STRING_TYPE), false + ); + value = StackValue.onStack(implType); + Method wrapper = PropertyReferenceCodegen.getWrapperMethodForPropertyReference(property, receiverCount); + iv.invokestatic(REFLECTION, wrapper.getName(), wrapper.getDescriptor(), false); + } + else { + ReceiverParameterDescriptor dispatchReceiver = property.getDispatchReceiverParameter(); - //noinspection ConstantConditions - StackValue value = createOrGetClInitCodegen().generatePropertyReference( - delegatedProperties.get(i).getDelegate(), property, property, - dispatchReceiver != null ? new TransientReceiver(dispatchReceiver.getType()) : ReceiverValue.NO_RECEIVER - ); + //noinspection ConstantConditions + value = createOrGetClInitCodegen().generatePropertyReference( + delegatedProperties.get(i).getDelegate(), property, property, + dispatchReceiver != null ? new TransientReceiver(dispatchReceiver.getType()) : ReceiverValue.NO_RECEIVER + ); + } value.put(PROPERTY_METADATA_TYPE, iv); diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/PropertyReferenceCodegen.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/PropertyReferenceCodegen.kt index 56038f0855e..290a9626e33 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/PropertyReferenceCodegen.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/PropertyReferenceCodegen.kt @@ -35,10 +35,7 @@ import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue import org.jetbrains.kotlin.resolve.scopes.receivers.ScriptReceiver import org.jetbrains.kotlin.utils.sure -import org.jetbrains.org.objectweb.asm.Opcodes.ACC_FINAL -import org.jetbrains.org.objectweb.asm.Opcodes.ACC_PUBLIC -import org.jetbrains.org.objectweb.asm.Opcodes.ACC_SUPER -import org.jetbrains.org.objectweb.asm.Opcodes.V1_6 +import org.jetbrains.org.objectweb.asm.Opcodes.* import org.jetbrains.org.objectweb.asm.Type import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter import org.jetbrains.org.objectweb.asm.commons.Method @@ -74,24 +71,7 @@ public class PropertyReferenceCodegen( private val superAsmType = typeMapper.mapClass(classDescriptor.getSuperClassNotAny().sure { "No super class for $classDescriptor" }) // e.g. mutableProperty0(Lkotlin/jvm/internal/MutablePropertyReference0;)Lkotlin/reflect/KMutableProperty0; - private val wrapperMethod: Method - - init { - wrapperMethod = when (receiverCount) { - 2 -> when { - target.isVar -> method("mutableProperty2", K_MUTABLE_PROPERTY2_TYPE, MUTABLE_PROPERTY_REFERENCE2) - else -> method("property2", K_PROPERTY2_TYPE, PROPERTY_REFERENCE2) - } - 1 -> when { - target.isVar -> method("mutableProperty1", K_MUTABLE_PROPERTY1_TYPE, MUTABLE_PROPERTY_REFERENCE1) - else -> method("property1", K_PROPERTY1_TYPE, PROPERTY_REFERENCE1) - } - else -> when { - target.isVar -> method("mutableProperty0", K_MUTABLE_PROPERTY0_TYPE, MUTABLE_PROPERTY_REFERENCE0) - else -> method("property0", K_PROPERTY0_TYPE, PROPERTY_REFERENCE0) - } - } - } + private val wrapperMethod = getWrapperMethodForPropertyReference(target, receiverCount) override fun generateDeclaration() { v.defineClass( @@ -127,16 +107,7 @@ public class PropertyReferenceCodegen( } generateMethod("property reference getSignature", ACC_PUBLIC, method("getSignature", JAVA_STRING_TYPE)) { - target as PropertyDescriptor - - val getter = target.getGetter() ?: run { - val defaultGetter = DescriptorFactory.createDefaultGetter(target, Annotations.EMPTY) - defaultGetter.initialize(target.getType()) - defaultGetter - } - - val method = typeMapper.mapSignature(getter).getAsmMethod() - aconst(method.getName() + method.getDescriptor()) + aconst(getPropertyReferenceSignature(target as PropertyDescriptor, state)) } generateAccessors() @@ -207,4 +178,35 @@ public class PropertyReferenceCodegen( StackValue.operation(wrapperMethod.getReturnType()) { iv -> iv.getstatic(asmType.getInternalName(), JvmAbi.INSTANCE_FIELD, wrapperMethod.getReturnType().getDescriptor()) } + + companion object { + @JvmStatic + fun getPropertyReferenceSignature(property: PropertyDescriptor, state: GenerationState): String { + val getter = + property.getter ?: DescriptorFactory.createDefaultGetter(property, Annotations.EMPTY).apply { + initialize(property.type) + } + + val method = state.typeMapper.mapSignature(getter).asmMethod + return method.name + method.descriptor + } + + @JvmStatic + fun getWrapperMethodForPropertyReference(property: VariableDescriptor, receiverCount: Int): Method { + return when (receiverCount) { + 2 -> when { + property.isVar -> method("mutableProperty2", K_MUTABLE_PROPERTY2_TYPE, MUTABLE_PROPERTY_REFERENCE2) + else -> method("property2", K_PROPERTY2_TYPE, PROPERTY_REFERENCE2) + } + 1 -> when { + property.isVar -> method("mutableProperty1", K_MUTABLE_PROPERTY1_TYPE, MUTABLE_PROPERTY_REFERENCE1) + else -> method("property1", K_PROPERTY1_TYPE, PROPERTY_REFERENCE1) + } + else -> when { + property.isVar -> method("mutableProperty0", K_MUTABLE_PROPERTY0_TYPE, MUTABLE_PROPERTY_REFERENCE0) + else -> method("property0", K_PROPERTY0_TYPE, PROPERTY_REFERENCE0) + } + } + } + } } diff --git a/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/AsmTypes.java b/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/AsmTypes.java index 70657d72a4d..f2e46e210fa 100644 --- a/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/AsmTypes.java +++ b/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/AsmTypes.java @@ -42,6 +42,17 @@ public class AsmTypes { public static final Type MUTABLE_PROPERTY_REFERENCE1 = Type.getObjectType("kotlin/jvm/internal/MutablePropertyReference1"); public static final Type MUTABLE_PROPERTY_REFERENCE2 = Type.getObjectType("kotlin/jvm/internal/MutablePropertyReference2"); + public static final Type[] PROPERTY_REFERENCE_IMPL = { + Type.getObjectType("kotlin/jvm/internal/PropertyReference0Impl"), + Type.getObjectType("kotlin/jvm/internal/PropertyReference1Impl"), + Type.getObjectType("kotlin/jvm/internal/PropertyReference2Impl") + }; + public static final Type[] MUTABLE_PROPERTY_REFERENCE_IMPL = { + Type.getObjectType("kotlin/jvm/internal/MutablePropertyReference0Impl"), + Type.getObjectType("kotlin/jvm/internal/MutablePropertyReference1Impl"), + Type.getObjectType("kotlin/jvm/internal/MutablePropertyReference2Impl") + }; + public static final Type K_CLASS_TYPE = reflect("KClass"); public static final Type K_CLASS_ARRAY_TYPE = Type.getObjectType("[" + K_CLASS_TYPE.getDescriptor()); public static final Type K_DECLARATION_CONTAINER_TYPE = reflect("KDeclarationContainer"); diff --git a/core/runtime.jvm/src/kotlin/jvm/internal/FunctionReferenceImpl.java b/core/runtime.jvm/src/kotlin/jvm/internal/FunctionReferenceImpl.java new file mode 100644 index 00000000000..2f02c4f979e --- /dev/null +++ b/core/runtime.jvm/src/kotlin/jvm/internal/FunctionReferenceImpl.java @@ -0,0 +1,47 @@ +/* + * Copyright 2010-2015 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.jvm.internal; + +import kotlin.reflect.KDeclarationContainer; + +public class FunctionReferenceImpl extends FunctionReference { + private final KDeclarationContainer owner; + private final String name; + private final String signature; + + public FunctionReferenceImpl(int arity, KDeclarationContainer owner, String name, String signature) { + super(arity); + this.owner = owner; + this.name = name; + this.signature = signature; + } + + @Override + public KDeclarationContainer getOwner() { + return owner; + } + + @Override + public String getName() { + return name; + } + + @Override + public String getSignature() { + return signature; + } +} diff --git a/core/runtime.jvm/src/kotlin/jvm/internal/MutablePropertyReference0Impl.java b/core/runtime.jvm/src/kotlin/jvm/internal/MutablePropertyReference0Impl.java new file mode 100644 index 00000000000..88f4f9caa43 --- /dev/null +++ b/core/runtime.jvm/src/kotlin/jvm/internal/MutablePropertyReference0Impl.java @@ -0,0 +1,56 @@ + /* + * Copyright 2010-2015 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.jvm.internal; + +import kotlin.reflect.KDeclarationContainer; + +public class MutablePropertyReference0Impl extends MutablePropertyReference0 { + private final KDeclarationContainer owner; + private final String name; + private final String signature; + + public MutablePropertyReference0Impl(KDeclarationContainer owner, String name, String signature) { + this.owner = owner; + this.name = name; + this.signature = signature; + } + + @Override + public KDeclarationContainer getOwner() { + return owner; + } + + @Override + public String getName() { + return name; + } + + @Override + public String getSignature() { + return signature; + } + + @Override + public Object get() { + return getGetter().call(); + } + + @Override + public void set(Object value) { + getSetter().call(value); + } +} diff --git a/core/runtime.jvm/src/kotlin/jvm/internal/MutablePropertyReference1Impl.java b/core/runtime.jvm/src/kotlin/jvm/internal/MutablePropertyReference1Impl.java new file mode 100644 index 00000000000..0f283bdad9b --- /dev/null +++ b/core/runtime.jvm/src/kotlin/jvm/internal/MutablePropertyReference1Impl.java @@ -0,0 +1,56 @@ +/* + * Copyright 2010-2015 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.jvm.internal; + +import kotlin.reflect.KDeclarationContainer; + +public class MutablePropertyReference1Impl extends MutablePropertyReference1 { + private final KDeclarationContainer owner; + private final String name; + private final String signature; + + public MutablePropertyReference1Impl(KDeclarationContainer owner, String name, String signature) { + this.owner = owner; + this.name = name; + this.signature = signature; + } + + @Override + public KDeclarationContainer getOwner() { + return owner; + } + + @Override + public String getName() { + return name; + } + + @Override + public String getSignature() { + return signature; + } + + @Override + public Object get(Object receiver) { + return getGetter().call(receiver); + } + + @Override + public void set(Object receiver, Object value) { + getSetter().call(receiver, value); + } +} diff --git a/core/runtime.jvm/src/kotlin/jvm/internal/MutablePropertyReference2Impl.java b/core/runtime.jvm/src/kotlin/jvm/internal/MutablePropertyReference2Impl.java new file mode 100644 index 00000000000..178aa4b3d64 --- /dev/null +++ b/core/runtime.jvm/src/kotlin/jvm/internal/MutablePropertyReference2Impl.java @@ -0,0 +1,56 @@ +/* + * Copyright 2010-2015 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.jvm.internal; + +import kotlin.reflect.KDeclarationContainer; + +public class MutablePropertyReference2Impl extends MutablePropertyReference2 { + private final KDeclarationContainer owner; + private final String name; + private final String signature; + + public MutablePropertyReference2Impl(KDeclarationContainer owner, String name, String signature) { + this.owner = owner; + this.name = name; + this.signature = signature; + } + + @Override + public KDeclarationContainer getOwner() { + return owner; + } + + @Override + public String getName() { + return name; + } + + @Override + public String getSignature() { + return signature; + } + + @Override + public Object get(Object receiver1, Object receiver2) { + return getGetter().call(receiver1, receiver2); + } + + @Override + public void set(Object receiver1, Object receiver2, Object value) { + getSetter().call(receiver1, receiver2, value); + } +} diff --git a/core/runtime.jvm/src/kotlin/jvm/internal/PropertyReference0Impl.java b/core/runtime.jvm/src/kotlin/jvm/internal/PropertyReference0Impl.java new file mode 100644 index 00000000000..7f731aecb91 --- /dev/null +++ b/core/runtime.jvm/src/kotlin/jvm/internal/PropertyReference0Impl.java @@ -0,0 +1,51 @@ +/* + * Copyright 2010-2015 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.jvm.internal; + +import kotlin.reflect.KDeclarationContainer; + +public class PropertyReference0Impl extends PropertyReference0 { + private final KDeclarationContainer owner; + private final String name; + private final String signature; + + public PropertyReference0Impl(KDeclarationContainer owner, String name, String signature) { + this.owner = owner; + this.name = name; + this.signature = signature; + } + + @Override + public KDeclarationContainer getOwner() { + return owner; + } + + @Override + public String getName() { + return name; + } + + @Override + public String getSignature() { + return signature; + } + + @Override + public Object get() { + return getGetter().call(); + } +} diff --git a/core/runtime.jvm/src/kotlin/jvm/internal/PropertyReference1Impl.java b/core/runtime.jvm/src/kotlin/jvm/internal/PropertyReference1Impl.java new file mode 100644 index 00000000000..6eaf3803e2f --- /dev/null +++ b/core/runtime.jvm/src/kotlin/jvm/internal/PropertyReference1Impl.java @@ -0,0 +1,51 @@ +/* + * Copyright 2010-2015 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.jvm.internal; + +import kotlin.reflect.KDeclarationContainer; + +public class PropertyReference1Impl extends PropertyReference1 { + private final KDeclarationContainer owner; + private final String name; + private final String signature; + + public PropertyReference1Impl(KDeclarationContainer owner, String name, String signature) { + this.owner = owner; + this.name = name; + this.signature = signature; + } + + @Override + public KDeclarationContainer getOwner() { + return owner; + } + + @Override + public String getName() { + return name; + } + + @Override + public String getSignature() { + return signature; + } + + @Override + public Object get(Object receiver) { + return getGetter().call(receiver); + } +} diff --git a/core/runtime.jvm/src/kotlin/jvm/internal/PropertyReference2Impl.java b/core/runtime.jvm/src/kotlin/jvm/internal/PropertyReference2Impl.java new file mode 100644 index 00000000000..8d7a62628eb --- /dev/null +++ b/core/runtime.jvm/src/kotlin/jvm/internal/PropertyReference2Impl.java @@ -0,0 +1,51 @@ +/* + * Copyright 2010-2015 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.jvm.internal; + +import kotlin.reflect.KDeclarationContainer; + +public class PropertyReference2Impl extends PropertyReference2 { + private final KDeclarationContainer owner; + private final String name; + private final String signature; + + public PropertyReference2Impl(KDeclarationContainer owner, String name, String signature) { + this.owner = owner; + this.name = name; + this.signature = signature; + } + + @Override + public KDeclarationContainer getOwner() { + return owner; + } + + @Override + public String getName() { + return name; + } + + @Override + public String getSignature() { + return signature; + } + + @Override + public Object get(Object receiver1, Object receiver2) { + return getGetter().call(receiver1, receiver2); + } +}