Generate separate anonymous class for each property reference

Each property reference obtained by the '::' operator now causes back-end to
generate an anonymous subclass of the corresponding KProperty class, with the
customized behavior. This fixes a number of issues:

- get/set/name of property references now works without kotlin-reflect.jar in
  the classpath
- get/set/name methods are now overridden with statically-generated property
  access instead of the default KPropertyImpl's behavior of using Java
  reflection, which should be a lot faster
- references to private/protected properties now work without the need to set
  'accessible' flag, because corresponding synthetic accessors are generated at
  compile-time near the target property

 #KT-6870 Fixed
 #KT-6873 Fixed
 #KT-7033 Fixed
This commit is contained in:
Alexander Udalov
2015-06-30 16:07:51 +03:00
parent 30794060a9
commit 048a9b686e
40 changed files with 833 additions and 304 deletions
@@ -202,7 +202,7 @@ public class ClosureCodegen extends MemberCodegen<JetElement> {
this.constructor = generateConstructor();
if (isConst(closure)) {
generateConstInstance();
generateConstInstance(asmType);
}
genClosureFields(closure, v, typeMapper);
@@ -251,30 +251,12 @@ public class ClosureCodegen extends MemberCodegen<JetElement> {
);
}
private void generateConstInstance() {
MethodVisitor mv = v.newMethod(OtherOrigin(element, funDescriptor), ACC_STATIC | ACC_SYNTHETIC, "<clinit>", "()V", null,
ArrayUtil.EMPTY_STRING_ARRAY);
InstructionAdapter iv = new InstructionAdapter(mv);
v.newField(OtherOrigin(element, funDescriptor), ACC_STATIC | ACC_FINAL | ACC_PUBLIC, JvmAbi.INSTANCE_FIELD, asmType.getDescriptor(),
null, null);
if (state.getClassBuilderMode() == ClassBuilderMode.FULL) {
mv.visitCode();
iv.anew(asmType);
iv.dup();
iv.invokespecial(asmType.getInternalName(), "<init>", "()V", false);
iv.putstatic(asmType.getInternalName(), JvmAbi.INSTANCE_FIELD, asmType.getDescriptor());
mv.visitInsn(RETURN);
FunctionCodegen.endVisit(mv, "<clinit>", element);
}
}
private void generateBridge(@NotNull Method bridge, @NotNull Method delegate) {
if (bridge.equals(delegate)) return;
MethodVisitor mv =
v.newMethod(OtherOrigin(element, funDescriptor), ACC_PUBLIC | ACC_BRIDGE, bridge.getName(), bridge.getDescriptor(), null, ArrayUtil.EMPTY_STRING_ARRAY);
v.newMethod(OtherOrigin(element, funDescriptor), ACC_PUBLIC | ACC_BRIDGE,
bridge.getName(), bridge.getDescriptor(), null, ArrayUtil.EMPTY_STRING_ARRAY);
if (state.getClassBuilderMode() != ClassBuilderMode.FULL) return;
@@ -306,6 +288,7 @@ public class ClosureCodegen extends MemberCodegen<JetElement> {
FunctionCodegen.endVisit(mv, "bridge", element);
}
// TODO: ImplementationBodyCodegen.markLineNumberForSyntheticFunction?
private void generateFunctionReferenceMethods(@NotNull FunctionDescriptor descriptor) {
int flags = ACC_PUBLIC | ACC_FINAL;
boolean generateBody = state.getClassBuilderMode() == ClassBuilderMode.FULL;
@@ -316,7 +299,7 @@ public class ClosureCodegen extends MemberCodegen<JetElement> {
if (generateBody) {
mv.visitCode();
InstructionAdapter iv = new InstructionAdapter(mv);
generateFunctionReferenceDeclarationContainer(iv, descriptor, typeMapper);
generateCallableReferenceDeclarationContainer(iv, descriptor, typeMapper);
iv.areturn(K_DECLARATION_CONTAINER_TYPE);
FunctionCodegen.endVisit(iv, "function reference getOwner", element);
}
@@ -347,9 +330,9 @@ public class ClosureCodegen extends MemberCodegen<JetElement> {
}
}
private static void generateFunctionReferenceDeclarationContainer(
public static void generateCallableReferenceDeclarationContainer(
@NotNull InstructionAdapter iv,
@NotNull FunctionDescriptor descriptor,
@NotNull CallableDescriptor descriptor,
@NotNull JetTypeMapper typeMapper
) {
DeclarationDescriptor container = descriptor.getContainingDeclaration();
@@ -32,6 +32,7 @@ import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.backend.common.CodegenUtil;
import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
import org.jetbrains.kotlin.codegen.binding.CalculatedClosure;
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.*;
@@ -51,7 +52,6 @@ import org.jetbrains.kotlin.lexer.JetTokens;
import org.jetbrains.kotlin.load.java.JvmAbi;
import org.jetbrains.kotlin.load.java.descriptors.JavaClassDescriptor;
import org.jetbrains.kotlin.load.java.descriptors.SamConstructorDescriptor;
import org.jetbrains.kotlin.load.kotlin.PackageClassUtils;
import org.jetbrains.kotlin.name.Name;
import org.jetbrains.kotlin.psi.*;
import org.jetbrains.kotlin.renderer.DescriptorRenderer;
@@ -85,7 +85,6 @@ import org.jetbrains.org.objectweb.asm.MethodVisitor;
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;
import java.util.*;
@@ -2755,29 +2754,39 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
(FunctionDescriptor) resolvedCall.getResultingDescriptor());
}
VariableDescriptor variableDescriptor = bindingContext.get(VARIABLE, expression);
if (variableDescriptor == null) {
throw new UnsupportedOperationException("Unsupported callable reference expression: " + expression.getText());
}
// TODO: this diagnostic should also be reported on function references once they obtain reflection
checkReflectionIsAvailable(expression);
VariableDescriptor descriptor = (VariableDescriptor) resolvedCall.getResultingDescriptor();
VariableDescriptor variableDescriptor = bindingContext.get(VARIABLE, expression);
if (variableDescriptor != null) {
return generatePropertyReference(expression, variableDescriptor, resolvedCall);
}
DeclarationDescriptor containingDeclaration = descriptor.getContainingDeclaration();
if (containingDeclaration instanceof PackageFragmentDescriptor) {
return generateTopLevelPropertyReference(descriptor);
}
else if (containingDeclaration instanceof ClassDescriptor) {
return generateMemberPropertyReference(descriptor, (ClassDescriptor) containingDeclaration);
}
else if (containingDeclaration instanceof ScriptDescriptor) {
return generateMemberPropertyReference(descriptor, ((ScriptDescriptor) containingDeclaration).getClassDescriptor());
}
else {
throw new UnsupportedOperationException("Unsupported callable reference container: " + containingDeclaration);
}
throw new UnsupportedOperationException("Unsupported callable reference expression: " + expression.getText());
}
@NotNull
private StackValue generatePropertyReference(
@NotNull JetCallableReferenceExpression expression,
@NotNull VariableDescriptor variableDescriptor,
@NotNull ResolvedCall<?> resolvedCall
) {
ClassDescriptor classDescriptor = CodegenBinding.anonymousClassForCallable(bindingContext, variableDescriptor);
ClassBuilder classBuilder = state.getFactory().newVisitor(
OtherOrigin(expression),
typeMapper.mapClass(classDescriptor),
expression.getContainingFile()
);
@SuppressWarnings("unchecked")
PropertyReferenceCodegen codegen = new PropertyReferenceCodegen(
state, parentCodegen, context.intoAnonymousClass(classDescriptor, this, OwnerKind.IMPLEMENTATION),
expression, classBuilder, classDescriptor, (ResolvedCall<VariableDescriptor>) resolvedCall
);
codegen.generate();
return codegen.putInstanceOnStack();
}
private void checkReflectionIsAvailable(@NotNull JetExpression expression) {
@@ -2786,64 +2795,6 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
}
}
@NotNull
private StackValue generateTopLevelPropertyReference(@NotNull final VariableDescriptor descriptor) {
PackageFragmentDescriptor containingPackage = (PackageFragmentDescriptor) descriptor.getContainingDeclaration();
final String packageClassInternalName = PackageClassUtils.getPackageClassInternalName(containingPackage.getFqName());
final ReceiverParameterDescriptor receiverParameter = descriptor.getExtensionReceiverParameter();
final Method factoryMethod;
if (receiverParameter != null) {
Type[] parameterTypes = new Type[] {JAVA_STRING_TYPE, K_PACKAGE_TYPE, getType(Class.class)};
factoryMethod = descriptor.isVar()
? method("mutableTopLevelExtensionProperty", K_MUTABLE_PROPERTY1_TYPE, parameterTypes)
: method("topLevelExtensionProperty", K_PROPERTY1_TYPE, parameterTypes);
}
else {
Type[] parameterTypes = new Type[] {JAVA_STRING_TYPE, K_PACKAGE_TYPE};
factoryMethod = descriptor.isVar()
? method("mutableTopLevelVariable", K_MUTABLE_PROPERTY0_TYPE, parameterTypes)
: method("topLevelVariable", K_PROPERTY0_TYPE, parameterTypes);
}
return StackValue.operation(factoryMethod.getReturnType(), new Function1<InstructionAdapter, Unit>() {
@Override
public Unit invoke(InstructionAdapter v) {
v.visitLdcInsn(descriptor.getName().asString());
v.getstatic(packageClassInternalName, JvmAbi.KOTLIN_PACKAGE_FIELD_NAME, K_PACKAGE_TYPE.getDescriptor());
if (receiverParameter != null) {
putJavaLangClassInstance(v, typeMapper.mapType(receiverParameter));
}
v.invokestatic(REFLECTION, factoryMethod.getName(), factoryMethod.getDescriptor(), false);
return Unit.INSTANCE$;
}
});
}
@NotNull
private StackValue generateMemberPropertyReference(
@NotNull final VariableDescriptor descriptor,
@NotNull final ClassDescriptor containingClass
) {
final Method factoryMethod = descriptor.isVar()
? method("mutableMemberProperty", K_MUTABLE_PROPERTY1_TYPE, JAVA_STRING_TYPE, K_CLASS_TYPE)
: method("memberProperty", K_PROPERTY1_TYPE, JAVA_STRING_TYPE, K_CLASS_TYPE);
return StackValue.operation(factoryMethod.getReturnType(), new Function1<InstructionAdapter, Unit>() {
@Override
public Unit invoke(InstructionAdapter v) {
v.visitLdcInsn(descriptor.getName().asString());
StackValue receiverClass = generateClassLiteralReference(typeMapper, containingClass.getDefaultType());
receiverClass.put(receiverClass.type, v);
v.invokestatic(REFLECTION, factoryMethod.getName(), factoryMethod.getDescriptor(), false);
return Unit.INSTANCE$;
}
});
}
@NotNull
public static StackValue generateClassLiteralReference(@NotNull final JetTypeMapper typeMapper, @NotNull final JetType type) {
return StackValue.operation(K_CLASS_TYPE, new Function1<InstructionAdapter, Unit>() {
@@ -29,15 +29,15 @@ import org.jetbrains.kotlin.storage.LockBasedStorageManager;
import org.jetbrains.kotlin.types.JetType;
import org.jetbrains.kotlin.types.expressions.ExpressionTypingUtils;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.*;
import static org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilPackage.getBuiltIns;
public class JvmRuntimeTypes {
private final ClassDescriptor lambda;
private final ClassDescriptor functionReference;
private final List<ClassDescriptor> propertyReferences;
private final List<ClassDescriptor> mutablePropertyReferences;
public JvmRuntimeTypes() {
ModuleDescriptorImpl module = new ModuleDescriptorImpl(
@@ -49,6 +49,13 @@ public class JvmRuntimeTypes {
this.lambda = createClass(kotlinJvmInternal, "Lambda");
this.functionReference = createClass(kotlinJvmInternal, "FunctionReference");
this.propertyReferences = new ArrayList<ClassDescriptor>(3);
this.mutablePropertyReferences = new ArrayList<ClassDescriptor>(3);
for (int i = 0; i <= 2; i++) {
propertyReferences.add(createClass(kotlinJvmInternal, "PropertyReference" + i));
mutablePropertyReferences.add(createClass(kotlinJvmInternal, "MutablePropertyReference" + i));
}
}
@NotNull
@@ -98,4 +105,11 @@ public class JvmRuntimeTypes {
return Arrays.asList(functionReference.getDefaultType(), functionType);
}
@NotNull
public JetType getSupertypeForPropertyReference(@NotNull PropertyDescriptor descriptor) {
int arity = (descriptor.getExtensionReceiverParameter() != null ? 1 : 0) +
(descriptor.getDispatchReceiverParameter() != null ? 1 : 0);
return (descriptor.isVar() ? mutablePropertyReferences : propertyReferences).get(arity).getDefaultType();
}
}
@@ -532,4 +532,16 @@ public abstract class MemberCodegen<T extends JetElement/* TODO: & JetDeclaratio
}
return sourceMapper;
}
protected void generateConstInstance(@NotNull Type asmType) {
v.newField(OtherOrigin(element), ACC_STATIC | ACC_FINAL | ACC_PUBLIC, JvmAbi.INSTANCE_FIELD, asmType.getDescriptor(), null, null);
if (state.getClassBuilderMode() == ClassBuilderMode.FULL) {
InstructionAdapter iv = createOrGetClInitCodegen().v;
iv.anew(asmType);
iv.dup();
iv.invokespecial(asmType.getInternalName(), "<init>", "()V", false);
iv.putstatic(asmType.getInternalName(), JvmAbi.INSTANCE_FIELD, asmType.getDescriptor());
}
}
}
@@ -0,0 +1,201 @@
/*
* 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 org.jetbrains.kotlin.codegen
import org.jetbrains.kotlin.codegen.AsmUtil.method
import org.jetbrains.kotlin.codegen.AsmUtil.writeKotlinSyntheticClassAnnotation
import org.jetbrains.kotlin.codegen.context.ClassContext
import org.jetbrains.kotlin.codegen.state.GenerationState
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.descriptors.impl.SimpleFunctionDescriptorImpl
import org.jetbrains.kotlin.load.java.JvmAbi
import org.jetbrains.kotlin.load.java.JvmAnnotationNames.KotlinSyntheticClass
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.JetCallableReferenceExpression
import org.jetbrains.kotlin.resolve.DescriptorFactory
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns
import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassNotAny
import org.jetbrains.kotlin.resolve.jvm.AsmTypes.*
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin
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.Type
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
import org.jetbrains.org.objectweb.asm.commons.Method
public class PropertyReferenceCodegen(
state: GenerationState,
parentCodegen: MemberCodegen<*>,
context: ClassContext,
expression: JetCallableReferenceExpression,
classBuilder: ClassBuilder,
private val classDescriptor: ClassDescriptor,
private val resolvedCall: ResolvedCall<VariableDescriptor>
) : MemberCodegen<JetCallableReferenceExpression>(state, parentCodegen, context, expression, classBuilder) {
private val target = resolvedCall.getResultingDescriptor()
private val asmType = typeMapper.mapClass(classDescriptor)
private val superAsmType: Type
init {
val superClass = classDescriptor.getSuperClassNotAny().sure { "No super class for $classDescriptor" }
superAsmType = typeMapper.mapClass(superClass)
}
override fun generateDeclaration() {
v.defineClass(
element,
V1_6,
ACC_FINAL or ACC_SUPER or AsmUtil.getVisibilityAccessFlagForAnonymous(classDescriptor), // TODO: test inline
asmType.getInternalName(),
null,
superAsmType.getInternalName(),
emptyArray()
)
v.visitSource(element.getContainingFile().getName(), null)
}
// TODO: ImplementationBodyCodegen.markLineNumberForSyntheticFunction?
override fun generateBody() {
// TODO: instance should be already wrapped by Reflection
generateConstInstance(asmType)
generateMethod("property reference init", 0, method("<init>", Type.VOID_TYPE)) {
load(0, OBJECT_TYPE)
invokespecial(superAsmType.getInternalName(), "<init>", "()V", false)
}
generateMethod("property reference getOwner", ACC_PUBLIC, method("getOwner", K_DECLARATION_CONTAINER_TYPE)) {
ClosureCodegen.generateCallableReferenceDeclarationContainer(this, target, typeMapper)
}
generateMethod("property reference getName", ACC_PUBLIC, method("getName", JAVA_STRING_TYPE)) {
aconst(target.getName().asString())
}
generateMethod("property reference getSignature", ACC_PUBLIC, method("getSignature", JAVA_STRING_TYPE)) {
target as PropertyDescriptor
val getter = target.getGetter() ?: run {
val defaultGetter = DescriptorFactory.createDefaultGetter(target)
defaultGetter.initialize(target.getType())
defaultGetter
}
val method = typeMapper.mapSignature(getter.sure { "No getter: $target" }).getAsmMethod()
aconst(method.getName() + method.getDescriptor())
}
generateAccessors()
}
private fun generateAccessors() {
val dispatchReceiver = resolvedCall.getDispatchReceiver()
val extensionReceiver = resolvedCall.getExtensionReceiver()
val receiverType =
when {
dispatchReceiver is ScriptReceiver -> {
// TODO: fix receiver for scripts, see ScriptReceiver#getType
dispatchReceiver.getDeclarationDescriptor().getClassDescriptor().getDefaultType()
}
dispatchReceiver.exists() -> dispatchReceiver.getType()
extensionReceiver.exists() -> extensionReceiver.getType()
else -> null
}
fun generateAccessor(method: Method, accessorBody: InstructionAdapter.(StackValue) -> Unit) {
generateMethod("property reference $method", ACC_PUBLIC, method) {
// Note: this descriptor is an inaccurate representation of the get/set method. In particular, it has incorrect
// return type and value parameter types. However, it's created only to be able to use
// ExpressionCodegen#intermediateValueForProperty, which is poorly coupled with everything else.
val fakeDescriptor = SimpleFunctionDescriptorImpl.create(
classDescriptor, Annotations.EMPTY, Name.identifier(method.getName()), CallableMemberDescriptor.Kind.DECLARATION,
SourceElement.NO_SOURCE
)
fakeDescriptor.initialize(null, classDescriptor.getThisAsReceiverParameter(), emptyList(), emptyList(),
classDescriptor.builtIns.getAnyType(), Modality.OPEN, Visibilities.PUBLIC)
val fakeCodegen = ExpressionCodegen(
this, FrameMap(), OBJECT_TYPE, context.intoFunction(fakeDescriptor), state, this@PropertyReferenceCodegen
)
val receiver =
if (receiverType != null) StackValue.coercion(StackValue.local(1, OBJECT_TYPE), typeMapper.mapType(receiverType))
else StackValue.none()
val value = fakeCodegen.intermediateValueForProperty(target as PropertyDescriptor, false, null, receiver)
accessorBody(value)
}
}
val getterParameters = if (receiverType != null) arrayOf(OBJECT_TYPE) else emptyArray()
generateAccessor(method("get", OBJECT_TYPE, *getterParameters)) { value ->
value.put(OBJECT_TYPE, this)
}
if (!target.isVar()) return
val setterParameters = (getterParameters + arrayOf(OBJECT_TYPE)).toTypedArray()
generateAccessor(method("set", Type.VOID_TYPE, *setterParameters)) { value ->
// Hard-coded 1 or 2 is safe here because there's only java/lang/Object in the signature, no double/long parameters
value.store(StackValue.local(if (receiverType != null) 2 else 1, OBJECT_TYPE), this)
}
}
private fun generateMethod(debugString: String, access: Int, method: Method, generate: InstructionAdapter.() -> Unit) {
val mv = v.newMethod(JvmDeclarationOrigin.NO_ORIGIN, access, method.getName(), method.getDescriptor(), null, null)
if (state.getClassBuilderMode() == ClassBuilderMode.FULL) {
val iv = InstructionAdapter(mv)
iv.visitCode()
iv.generate()
iv.areturn(method.getReturnType())
FunctionCodegen.endVisit(mv, debugString, element)
}
}
override fun generateKotlinAnnotation() {
writeKotlinSyntheticClassAnnotation(v, KotlinSyntheticClass.Kind.CALLABLE_REFERENCE_WRAPPER)
}
public fun putInstanceOnStack(): StackValue {
val hasReceiver = target.getDispatchReceiverParameter() != null || target.getExtensionReceiverParameter() != null
val method =
when {
hasReceiver -> 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)
}
}
return StackValue.operation(method.getReturnType()) { iv ->
iv.getstatic(asmType.getInternalName(), JvmAbi.INSTANCE_FIELD, asmType.getDescriptor())
iv.invokestatic(REFLECTION, method.getName(), method.getDescriptor(), false)
}
}
}
@@ -84,15 +84,15 @@ class CodegenAnnotatingVisitor extends JetVisitorVoid {
}
@NotNull
private ClassDescriptor recordClassForFunction(
private ClassDescriptor recordClassForCallable(
@NotNull JetElement element,
@NotNull FunctionDescriptor funDescriptor,
@NotNull CallableDescriptor callableDescriptor,
@NotNull Collection<JetType> supertypes,
@NotNull String name
) {
String simpleName = name.substring(name.lastIndexOf('/') + 1);
ClassDescriptorImpl classDescriptor = new ClassDescriptorImpl(
correctContainerForLambda(funDescriptor, element),
correctContainerForLambda(callableDescriptor, element),
Name.special("<closure-" + simpleName + ">"),
Modality.FINAL,
supertypes,
@@ -100,13 +100,13 @@ class CodegenAnnotatingVisitor extends JetVisitorVoid {
);
classDescriptor.initialize(JetScope.Empty.INSTANCE$, Collections.<ConstructorDescriptor>emptySet(), null);
bindingTrace.record(CLASS_FOR_FUNCTION, funDescriptor, classDescriptor);
bindingTrace.record(CLASS_FOR_CALLABLE, callableDescriptor, classDescriptor);
return classDescriptor;
}
@NotNull
@SuppressWarnings("ConstantConditions")
private DeclarationDescriptor correctContainerForLambda(@NotNull FunctionDescriptor descriptor, @NotNull JetElement function) {
private DeclarationDescriptor correctContainerForLambda(@NotNull CallableDescriptor descriptor, @NotNull JetElement function) {
DeclarationDescriptor container = descriptor.getContainingDeclaration();
// In almost all cases the function's direct container is the correct container to consider in JVM back-end
@@ -286,7 +286,7 @@ class CodegenAnnotatingVisitor extends JetVisitorVoid {
String name = inventAnonymousClassName(expression);
Collection<JetType> supertypes = runtimeTypes.getSupertypesForClosure(functionDescriptor);
ClassDescriptor classDescriptor = recordClassForFunction(functionLiteral, functionDescriptor, supertypes, name);
ClassDescriptor classDescriptor = recordClassForCallable(functionLiteral, functionDescriptor, supertypes, name);
recordClosure(classDescriptor, name);
classStack.push(classDescriptor);
@@ -298,17 +298,31 @@ class CodegenAnnotatingVisitor extends JetVisitorVoid {
@Override
public void visitCallableReferenceExpression(@NotNull JetCallableReferenceExpression expression) {
FunctionDescriptor functionDescriptor = bindingContext.get(FUNCTION, expression);
// working around a problem with shallow analysis
if (functionDescriptor == null) return;
ResolvedCall<?> referencedFunction = CallUtilPackage.getResolvedCall(expression.getCallableReference(), bindingContext);
if (referencedFunction == null) return;
Collection<JetType> supertypes =
runtimeTypes.getSupertypesForFunctionReference((FunctionDescriptor) referencedFunction.getResultingDescriptor());
CallableDescriptor target = referencedFunction.getResultingDescriptor();
CallableDescriptor callableDescriptor;
Collection<JetType> supertypes;
if (target instanceof FunctionDescriptor) {
callableDescriptor = bindingContext.get(FUNCTION, expression);
if (callableDescriptor == null) return;
supertypes = runtimeTypes.getSupertypesForFunctionReference((FunctionDescriptor) target);
}
else if (target instanceof PropertyDescriptor) {
callableDescriptor = bindingContext.get(VARIABLE, expression);
if (callableDescriptor == null) return;
supertypes = Collections.singleton(runtimeTypes.getSupertypeForPropertyReference((PropertyDescriptor) target));
}
else {
return;
}
String name = inventAnonymousClassName(expression);
ClassDescriptor classDescriptor = recordClassForFunction(expression, functionDescriptor, supertypes, name);
ClassDescriptor classDescriptor = recordClassForCallable(expression, callableDescriptor, supertypes, name);
recordClosure(classDescriptor, name);
classStack.push(classDescriptor);
@@ -354,7 +368,7 @@ class CodegenAnnotatingVisitor extends JetVisitorVoid {
else {
String name = inventAnonymousClassName(function);
Collection<JetType> supertypes = runtimeTypes.getSupertypesForClosure(functionDescriptor);
ClassDescriptor classDescriptor = recordClassForFunction(function, functionDescriptor, supertypes, name);
ClassDescriptor classDescriptor = recordClassForCallable(function, functionDescriptor, supertypes, name);
recordClosure(classDescriptor, name);
classStack.push(classDescriptor);
@@ -40,16 +40,14 @@ import org.jetbrains.org.objectweb.asm.Type;
import java.util.*;
import static org.jetbrains.kotlin.codegen.JvmCodegenUtil.isInterface;
import static org.jetbrains.kotlin.resolve.BindingContext.*;
import static org.jetbrains.kotlin.resolve.DescriptorToSourceUtils.descriptorToDeclaration;
import static org.jetbrains.kotlin.resolve.calls.callUtil.CallUtilPackage.getResolvedCall;
import static org.jetbrains.kotlin.resolve.source.SourcePackage.toSourceElement;
public class CodegenBinding {
public static final WritableSlice<ClassDescriptor, MutableClosure> CLOSURE = Slices.createSimpleSlice();
public static final WritableSlice<FunctionDescriptor, ClassDescriptor> CLASS_FOR_FUNCTION = Slices.createSimpleSlice();
public static final WritableSlice<CallableDescriptor, ClassDescriptor> CLASS_FOR_CALLABLE = Slices.createSimpleSlice();
public static final WritableSlice<ScriptDescriptor, ClassDescriptor> CLASS_FOR_SCRIPT = Slices.createSimpleSlice();
@@ -110,34 +108,41 @@ public class CodegenBinding {
}
@NotNull
public static ClassDescriptor anonymousClassForFunction(
public static ClassDescriptor anonymousClassForCallable(
@NotNull BindingContext bindingContext,
@NotNull FunctionDescriptor descriptor
@NotNull CallableDescriptor descriptor
) {
//noinspection ConstantConditions
return bindingContext.get(CLASS_FOR_FUNCTION, descriptor);
return bindingContext.get(CLASS_FOR_CALLABLE, descriptor);
}
@NotNull
public static Type asmTypeForAnonymousClass(@NotNull BindingContext bindingContext, @NotNull JetElement expression) {
if (expression instanceof JetObjectLiteralExpression) {
JetObjectLiteralExpression jetObjectLiteralExpression = (JetObjectLiteralExpression) expression;
expression = jetObjectLiteralExpression.getObjectDeclaration();
expression = ((JetObjectLiteralExpression) expression).getObjectDeclaration();
}
ClassDescriptor descriptor = bindingContext.get(CLASS, expression);
if (descriptor == null) {
SimpleFunctionDescriptor functionDescriptor = bindingContext.get(FUNCTION, expression);
assert functionDescriptor != null : "Couldn't find function descriptor for " + PsiUtilPackage.getElementTextWithContext(expression);
if (descriptor != null) {
return getAsmType(bindingContext, descriptor);
}
SimpleFunctionDescriptor functionDescriptor = bindingContext.get(FUNCTION, expression);
if (functionDescriptor != null) {
return asmTypeForAnonymousClass(bindingContext, functionDescriptor);
}
return getAsmType(bindingContext, descriptor);
VariableDescriptor variableDescriptor = bindingContext.get(VARIABLE, expression);
if (variableDescriptor != null) {
return asmTypeForAnonymousClass(bindingContext, variableDescriptor);
}
throw new IllegalStateException("Couldn't compute ASM type for " + PsiUtilPackage.getElementTextWithContext(expression));
}
@NotNull
public static Type asmTypeForAnonymousClass(@NotNull BindingContext bindingContext, @NotNull FunctionDescriptor descriptor) {
return getAsmType(bindingContext, anonymousClassForFunction(bindingContext, descriptor));
public static Type asmTypeForAnonymousClass(@NotNull BindingContext bindingContext, @NotNull CallableDescriptor descriptor) {
return getAsmType(bindingContext, anonymousClassForCallable(bindingContext, descriptor));
}
public static boolean canHaveOuter(@NotNull BindingContext bindingContext, @NotNull ClassDescriptor classDescriptor) {
@@ -22,7 +22,7 @@ import org.jetbrains.kotlin.codegen.OwnerKind;
import org.jetbrains.kotlin.codegen.state.JetTypeMapper;
import org.jetbrains.kotlin.descriptors.FunctionDescriptor;
import static org.jetbrains.kotlin.codegen.binding.CodegenBinding.anonymousClassForFunction;
import static org.jetbrains.kotlin.codegen.binding.CodegenBinding.anonymousClassForCallable;
public class ClosureContext extends ClassContext {
private final FunctionDescriptor functionDescriptor;
@@ -33,7 +33,7 @@ public class ClosureContext extends ClassContext {
@Nullable CodegenContext parentContext,
@NotNull LocalLookup localLookup
) {
super(typeMapper, anonymousClassForFunction(typeMapper.getBindingContext(), functionDescriptor),
super(typeMapper, anonymousClassForCallable(typeMapper.getBindingContext(), functionDescriptor),
OwnerKind.IMPLEMENTATION, parentContext, localLookup);
this.functionDescriptor = functionDescriptor;
@@ -103,7 +103,7 @@ public interface LocalLookup {
BindingContext bindingContext = state.getBindingContext();
Type localType = asmTypeForAnonymousClass(bindingContext, vd);
MutableClosure localFunClosure = bindingContext.get(CLOSURE, bindingContext.get(CLASS_FOR_FUNCTION, vd));
MutableClosure localFunClosure = bindingContext.get(CLOSURE, bindingContext.get(CLASS_FOR_CALLABLE, vd));
if (localFunClosure != null && JvmCodegenUtil.isConst(localFunClosure)) {
// This is an optimization: we can obtain an instance of a const closure simply by GETSTATIC ...$instance
// (instead of passing this instance to the constructor and storing as a field)
@@ -234,7 +234,7 @@ public class InlineCodegenUtil {
return type.getInternalName();
} else if (currentDescriptor instanceof FunctionDescriptor) {
ClassDescriptor descriptor =
typeMapper.getBindingContext().get(CodegenBinding.CLASS_FOR_FUNCTION, (FunctionDescriptor) currentDescriptor);
typeMapper.getBindingContext().get(CodegenBinding.CLASS_FOR_CALLABLE, (FunctionDescriptor) currentDescriptor);
if (descriptor != null) {
Type type = typeMapper.mapType(descriptor);
return type.getInternalName();
@@ -70,7 +70,7 @@ public class LambdaInfo implements CapturedParamOwner, LabelOwner {
functionDescriptor = bindingContext.get(BindingContext.FUNCTION, expression);
assert functionDescriptor != null : "Function is not resolved to descriptor: " + expression.getText();
classDescriptor = anonymousClassForFunction(bindingContext, functionDescriptor);
classDescriptor = anonymousClassForCallable(bindingContext, functionDescriptor);
closureClassType = asmTypeForAnonymousClass(bindingContext, functionDescriptor);
closure = bindingContext.get(CLOSURE, classDescriptor);
@@ -36,6 +36,10 @@ public class AsmTypes {
public static final Type LAMBDA = Type.getObjectType("kotlin/jvm/internal/Lambda");
public static final Type FUNCTION_REFERENCE = Type.getObjectType("kotlin/jvm/internal/FunctionReference");
public static final Type PROPERTY_REFERENCE0 = Type.getObjectType("kotlin/jvm/internal/PropertyReference0");
public static final Type PROPERTY_REFERENCE1 = Type.getObjectType("kotlin/jvm/internal/PropertyReference1");
public static final Type MUTABLE_PROPERTY_REFERENCE0 = Type.getObjectType("kotlin/jvm/internal/MutablePropertyReference0");
public static final Type MUTABLE_PROPERTY_REFERENCE1 = Type.getObjectType("kotlin/jvm/internal/MutablePropertyReference1");
public static final Type K_CLASS_TYPE = reflect("KClass");
public static final Type K_CLASS_ARRAY_TYPE = Type.getObjectType("[" + K_CLASS_TYPE.getDescriptor());
@@ -10,8 +10,8 @@ fun box(): String {
val s = J::s
// Check that correct reflection objects are created
assert(i.javaClass.getSimpleName() == "KProperty1Impl", "Fail i class")
assert(s.javaClass.getSimpleName() == "KMutableProperty1Impl", "Fail s class")
assert(i !is KMutableProperty<*>, "Fail i class: ${i.javaClass}")
assert(s is KMutableProperty<*>, "Fail s class: ${s.javaClass}")
// Check that no Method objects are created for such properties
assert(i.javaGetter == null, "Fail i getter")
@@ -0,0 +1,22 @@
class Test {
private var iv = 1
public fun exec() {
val t = object : Thread() {
override fun run() {
::iv.get(this@Test)
::iv.set(this@Test, 2)
}
}
t.start()
t.join(1000)
}
fun result() = if (iv == 2) "OK" else "Fail $iv"
}
fun box(): String {
val t = Test()
t.exec()
return t.result()
}
@@ -5,7 +5,7 @@ import kotlin.reflect.jvm.accessible
class Result {
private val value = "OK"
fun ref(): KProperty1<Result, String> = ::value
fun ref() = Result::class.properties.single() as KProperty1<Result, String>
}
fun box(): String {
@@ -5,7 +5,7 @@ import kotlin.reflect.jvm.accessible
class A {
private var value = 0
fun ref(): KMutableProperty1<A, Int> = ::value
fun ref() = A::class.properties.single() as KMutableProperty1<A, Int>
}
fun box(): String {
@@ -1,10 +1,11 @@
import kotlin.reflect.IllegalPropertyAccessException
import kotlin.reflect.jvm.accessible
import kotlin.reflect.KMutableProperty1
class A(param: String) {
protected var v: String = param
fun ref() = ::v
fun ref() = A::class.properties.single() as KMutableProperty1<A, String>
}
fun box(): String {
@@ -795,6 +795,12 @@ public class BlackBoxWithStdlibCodegenTestGenerated extends AbstractBlackBoxCode
doTestWithStdlib(fileName);
}
@TestMetadata("kt6870_privatePropertyReference.kt")
public void testKt6870_privatePropertyReference() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/callableReference/property/kt6870_privatePropertyReference.kt");
doTestWithStdlib(fileName);
}
@TestMetadata("localClassVar.kt")
public void testLocalClassVar() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/callableReference/property/localClassVar.kt");
@@ -813,24 +819,6 @@ public class BlackBoxWithStdlibCodegenTestGenerated extends AbstractBlackBoxCode
doTestWithStdlib(fileName);
}
@TestMetadata("privateClassVal.kt")
public void testPrivateClassVal() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/callableReference/property/privateClassVal.kt");
doTestWithStdlib(fileName);
}
@TestMetadata("privateClassVar.kt")
public void testPrivateClassVar() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/callableReference/property/privateClassVar.kt");
doTestWithStdlib(fileName);
}
@TestMetadata("protectedClassVar.kt")
public void testProtectedClassVar() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/callableReference/property/protectedClassVar.kt");
doTestWithStdlib(fileName);
}
@TestMetadata("publicClassValAccessible.kt")
public void testPublicClassValAccessible() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/callableReference/property/publicClassValAccessible.kt");
@@ -3222,6 +3210,18 @@ public class BlackBoxWithStdlibCodegenTestGenerated extends AbstractBlackBoxCode
doTestWithStdlib(fileName);
}
@TestMetadata("privateClassVal.kt")
public void testPrivateClassVal() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/reflection/properties/privateClassVal.kt");
doTestWithStdlib(fileName);
}
@TestMetadata("privateClassVar.kt")
public void testPrivateClassVar() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/reflection/properties/privateClassVar.kt");
doTestWithStdlib(fileName);
}
@TestMetadata("privateFakeOverrideFromSuperclass.kt")
public void testPrivateFakeOverrideFromSuperclass() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/reflection/properties/privateFakeOverrideFromSuperclass.kt");
@@ -3240,6 +3240,12 @@ public class BlackBoxWithStdlibCodegenTestGenerated extends AbstractBlackBoxCode
doTestWithStdlib(fileName);
}
@TestMetadata("protectedClassVar.kt")
public void testProtectedClassVar() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/reflection/properties/protectedClassVar.kt");
doTestWithStdlib(fileName);
}
@TestMetadata("simpleGetProperties.kt")
public void testSimpleGetProperties() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/reflection/properties/simpleGetProperties.kt");
@@ -30,17 +30,17 @@ import java.lang.reflect.Method
abstract class DescriptorBasedProperty protected constructor(
container: KCallableContainerImpl,
name: String,
receiverParameterDesc: String?,
signature: String,
descriptorInitialValue: PropertyDescriptor?
) {
constructor(container: KCallableContainerImpl, name: String, receiverParameterClass: Class<*>?) : this(
container, name, receiverParameterClass?.desc, null
constructor(container: KCallableContainerImpl, name: String, signature: String) : this(
container, name, signature, null
)
constructor(container: KCallableContainerImpl, descriptor: PropertyDescriptor) : this(
container,
descriptor.getName().asString(),
descriptor.getExtensionReceiverParameter()?.getType()?.let { type -> RuntimeTypeMapper.mapTypeToJvmDesc(type) },
RuntimeTypeMapper.mapPropertySignature(descriptor),
descriptor
)
@@ -51,7 +51,7 @@ abstract class DescriptorBasedProperty protected constructor(
)
protected val descriptor: PropertyDescriptor by ReflectProperties.lazySoft<PropertyDescriptor>(descriptorInitialValue) {
container.findPropertyDescriptor(name, receiverParameterDesc)
container.findPropertyDescriptor(name, signature)
}
// null if this is a property declared in a foreign (Java) class
@@ -43,20 +43,16 @@ abstract class KCallableContainerImpl : KDeclarationContainer {
abstract val scope: JetScope
fun findPropertyDescriptor(name: String, receiverDesc: String? = null): PropertyDescriptor {
fun findPropertyDescriptor(name: String, signature: String): PropertyDescriptor {
val properties = scope
.getProperties(Name.guess(name))
.filter { descriptor ->
descriptor is PropertyDescriptor &&
descriptor.getName().asString() == name &&
with(descriptor.getExtensionReceiverParameter()) {
(this == null && receiverDesc == null) ||
(this != null && RuntimeTypeMapper.mapTypeToJvmDesc(getType()) == receiverDesc)
}
RuntimeTypeMapper.mapPropertySignature(descriptor) == signature
}
if (properties.size() != 1) {
val debugText = if (receiverDesc == null) name else "'$receiverDesc.$name'"
val debugText = "'$name' (JVM signature: $signature)"
throw KotlinReflectionInternalError(
if (properties.isEmpty()) "Property $debugText not resolved in $this"
else "${properties.size()} properties $debugText resolved in $this: $properties"
@@ -104,12 +104,6 @@ class KClassImpl<T>(override val jClass: Class<T>) : KCallableContainerImpl(), K
.map(create)
.toList()
fun memberProperty(name: String): KProperty1<T, *> =
KProperty1Impl<T, Any>(this, name, null)
fun mutableMemberProperty(name: String): KMutableProperty1<T, *> =
KMutableProperty1Impl<T, Any>(this, name, null)
override fun equals(other: Any?): Boolean =
other is KClassImpl<*> && jClass == other.jClass
@@ -31,18 +31,6 @@ class KPackageImpl(override val jClass: Class<*>) : KCallableContainerImpl(), KP
override val scope: JetScope get() = descriptor.memberScope
fun topLevelVariable(name: String): KProperty0<*> =
KProperty0Impl<Any?>(this, name)
fun mutableTopLevelVariable(name: String): KMutableProperty0<*> =
KMutableProperty0Impl<Any?>(this, name)
fun <T> topLevelExtensionProperty(name: String, receiver: Class<T>): KProperty1<T, *> =
KProperty1Impl<T, Any?>(this, name, receiver)
fun <T> mutableTopLevelExtensionProperty(name: String, receiver: Class<T>): KMutableProperty1<T, *> =
KMutableProperty1Impl<T, Any?>(this, name, receiver)
override fun equals(other: Any?): Boolean =
other is KPackageImpl && jClass == other.jClass
@@ -17,12 +17,14 @@
package kotlin.reflect.jvm.internal
import java.lang.reflect.Method
import kotlin.jvm.internal.MutablePropertyReference0
import kotlin.jvm.internal.PropertyReference0
import kotlin.reflect.IllegalPropertyAccessException
import kotlin.reflect.KMutableProperty0
import kotlin.reflect.KProperty0
open class KProperty0Impl<out R> : DescriptorBasedProperty, KProperty0<R>, KPropertyImpl<R> {
constructor(container: KPackageImpl, name: String) : super(container, name, null)
constructor(container: KCallableContainerImpl, name: String, signature: String) : super(container, name, signature)
override val name: String get() = descriptor.getName().asString()
@@ -39,8 +41,8 @@ open class KProperty0Impl<out R> : DescriptorBasedProperty, KProperty0<R>, KProp
}
}
class KMutableProperty0Impl<R> : KProperty0Impl<R>, KMutableProperty0<R>, KMutablePropertyImpl<R> {
constructor(container: KPackageImpl, name: String) : super(container, name)
open class KMutableProperty0Impl<R> : KProperty0Impl<R>, KMutableProperty0<R>, KMutablePropertyImpl<R> {
constructor(container: KCallableContainerImpl, name: String, signature: String) : super(container, name, signature)
override val setter: Method get() = super<KProperty0Impl>.setter!!
@@ -53,3 +55,33 @@ class KMutableProperty0Impl<R> : KProperty0Impl<R>, KMutableProperty0<R>, KMutab
}
}
}
class KProperty0FromReferenceImpl(
val reference: PropertyReference0
) : KProperty0Impl<Any?>(
reference.getOwner() as KCallableContainerImpl,
reference.getName(),
reference.getSignature()
) {
override val name: String get() = reference.getName()
override fun get(): Any? = reference.get()
}
class KMutableProperty0FromReferenceImpl(
val reference: MutablePropertyReference0
) : KMutableProperty0Impl<Any?>(
reference.getOwner() as KCallableContainerImpl,
reference.getName(),
reference.getSignature()
) {
override val name: String get() = reference.getName()
override fun get(): Any? = reference.get()
override fun set(value: Any?) {
reference.set(value)
}
}
@@ -21,11 +21,11 @@ import java.lang.reflect.Modifier
import kotlin.reflect.IllegalPropertyAccessException
import kotlin.reflect.KMutableProperty1
import kotlin.reflect.KProperty1
import kotlin.jvm.internal.MutablePropertyReference1
import kotlin.jvm.internal.PropertyReference1
open class KProperty1Impl<T, out R> : DescriptorBasedProperty, KProperty1<T, R>, KPropertyImpl<R> {
constructor(container: KCallableContainerImpl, name: String, receiverParameterClass: Class<*>?) : super(
container, name, receiverParameterClass
)
constructor(container: KCallableContainerImpl, name: String, signature: String) : super(container, name, signature)
constructor(container: KCallableContainerImpl, descriptor: PropertyDescriptor) : super(container, descriptor)
@@ -56,10 +56,8 @@ open class KProperty1Impl<T, out R> : DescriptorBasedProperty, KProperty1<T, R>,
}
class KMutableProperty1Impl<T, R> : KProperty1Impl<T, R>, KMutableProperty1<T, R>, KMutablePropertyImpl<R> {
constructor(container: KCallableContainerImpl, name: String, receiverParameterClass: Class<*>?) : super(
container, name, receiverParameterClass
)
open class KMutableProperty1Impl<T, R> : KProperty1Impl<T, R>, KMutableProperty1<T, R>, KMutablePropertyImpl<R> {
constructor(container: KCallableContainerImpl, name: String, signature: String) : super(container, name, signature)
constructor(container: KCallableContainerImpl, descriptor: PropertyDescriptor) : super(container, descriptor)
@@ -86,3 +84,33 @@ class KMutableProperty1Impl<T, R> : KProperty1Impl<T, R>, KMutableProperty1<T, R
}
}
}
class KProperty1FromReferenceImpl(
val reference: PropertyReference1
) : KProperty1Impl<Any?, Any?>(
reference.getOwner() as KCallableContainerImpl,
reference.getName(),
reference.getSignature()
) {
override val name: String get() = reference.getName()
override fun get(receiver: Any?): Any? = reference.get(receiver)
}
class KMutableProperty1FromReferenceImpl(
val reference: MutablePropertyReference1
) : KMutableProperty1Impl<Any?, Any?>(
reference.getOwner() as KCallableContainerImpl,
reference.getName(),
reference.getSignature()
) {
override val name: String get() = reference.getName()
override fun get(receiver: Any?): Any? = reference.get(receiver)
override fun set(receiver: Any?, value: Any?) {
reference.set(receiver, value)
}
}
@@ -24,7 +24,7 @@ import kotlin.reflect.KMutableProperty2
import kotlin.reflect.KProperty2
open class KProperty2Impl<D, E, out R> : DescriptorBasedProperty, KProperty2<D, E, R>, KPropertyImpl<R> {
constructor(container: KClassImpl<D>, name: String, receiverParameterClass: Class<E>) : super(container, name, receiverParameterClass)
constructor(container: KClassImpl<D>, name: String, signature: String) : super(container, name, signature)
constructor(container: KClassImpl<D>, descriptor: PropertyDescriptor) : super(container, descriptor)
@@ -47,7 +47,7 @@ open class KProperty2Impl<D, E, out R> : DescriptorBasedProperty, KProperty2<D,
class KMutableProperty2Impl<D, E, R> : KProperty2Impl<D, E, R>, KMutableProperty2<D, E, R>, KMutablePropertyImpl<R> {
constructor(container: KClassImpl<D>, name: String, receiverParameterClass: Class<E>) : super(container, name, receiverParameterClass)
constructor(container: KClassImpl<D>, name: String, signature: String) : super(container, name, signature)
constructor(container: KClassImpl<D>, descriptor: PropertyDescriptor) : super(container, descriptor)
@@ -16,8 +16,7 @@
package kotlin.reflect.jvm.internal;
import kotlin.jvm.internal.FunctionReference;
import kotlin.jvm.internal.ReflectionFactory;
import kotlin.jvm.internal.*;
import kotlin.reflect.*;
/**
@@ -50,32 +49,34 @@ public class ReflectionFactoryImpl extends ReflectionFactory {
// Properties
@Override
public KProperty1 memberProperty(String name, KClass owner) {
return ((KClassImpl) owner).memberProperty(name);
public KProperty0 property0(PropertyReference0 p) {
return new KProperty0FromReferenceImpl(p);
}
@Override
public KMutableProperty1 mutableMemberProperty(String name, KClass owner) {
return ((KClassImpl) owner).mutableMemberProperty(name);
public KMutableProperty0 mutableProperty0(MutablePropertyReference0 p) {
return new KMutableProperty0FromReferenceImpl(p);
}
@Override
public KProperty0 topLevelVariable(String name, KPackage owner) {
return ((KPackageImpl) owner).topLevelVariable(name);
public KProperty1 property1(PropertyReference1 p) {
return new KProperty1FromReferenceImpl(p);
}
@Override
public KMutableProperty0 mutableTopLevelVariable(String name, KPackage owner) {
return ((KPackageImpl) owner).mutableTopLevelVariable(name);
public KMutableProperty1 mutableProperty1(MutablePropertyReference1 p) {
return new KMutableProperty1FromReferenceImpl(p);
}
@Override
public KProperty1 topLevelExtensionProperty(String name, KPackage owner, Class receiver) {
return ((KPackageImpl) owner).topLevelExtensionProperty(name, receiver);
public KProperty2 property2(PropertyReference2 p) {
// TODO: support member extension property references
return p;
}
@Override
public KMutableProperty1 mutableTopLevelExtensionProperty(String name, KPackage owner, Class receiver) {
return ((KPackageImpl) owner).mutableTopLevelExtensionProperty(name, receiver);
public KMutableProperty2 mutableProperty2(MutablePropertyReference2 p) {
// TODO: support member extension property references
return p;
}
}
@@ -18,58 +18,25 @@ package kotlin.reflect.jvm.internal
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.builtins.PrimitiveType
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
import org.jetbrains.kotlin.load.java.JvmAbi
import org.jetbrains.kotlin.load.java.descriptors.JavaMethodDescriptor
import org.jetbrains.kotlin.load.java.descriptors.JavaPropertyDescriptor
import org.jetbrains.kotlin.load.java.sources.JavaSourceElement
import org.jetbrains.kotlin.load.java.structure.*
import org.jetbrains.kotlin.load.java.structure.reflect.*
import org.jetbrains.kotlin.load.kotlin.SignatureDeserializer
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.platform.JavaToKotlinClassMap
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.descriptorUtil.classId
import org.jetbrains.kotlin.resolve.jvm.JvmClassName
import org.jetbrains.kotlin.resolve.jvm.JvmPrimitiveType
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedPropertyDescriptor
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedSimpleFunctionDescriptor
import org.jetbrains.kotlin.serialization.jvm.JvmProtoBuf
import org.jetbrains.kotlin.types.JetType
import org.jetbrains.kotlin.types.TypeUtils
import kotlin.reflect.KotlinReflectionInternalError
object RuntimeTypeMapper {
// TODO: this logic must be shared with JetTypeMapper
fun mapTypeToJvmDesc(type: JetType): String {
val classifier = type.getConstructor().getDeclarationDescriptor()
if (classifier is TypeParameterDescriptor) {
return mapTypeToJvmDesc(classifier.getUpperBounds().first())
}
if (KotlinBuiltIns.isArray(type)) {
val elementType = KotlinBuiltIns.getInstance().getArrayElementType(type)
// makeNullable is called here to map primitive types to the corresponding wrappers,
// because the given type is Array<Something>, not SomethingArray
return "[" + mapTypeToJvmDesc(TypeUtils.makeNullable(elementType))
}
val classDescriptor = classifier as ClassDescriptor
val fqName = DescriptorUtils.getFqName(classDescriptor)
KotlinBuiltIns.getPrimitiveTypeByFqName(fqName)?.let { primitiveType ->
val jvmType = JvmPrimitiveType.get(primitiveType)
return if (TypeUtils.isNullableType(type)) ClassId.topLevel(jvmType.getWrapperFqName()).desc else jvmType.getDesc()
}
KotlinBuiltIns.getPrimitiveTypeByArrayClassFqName(fqName)?.let { primitiveType ->
return "[" + JvmPrimitiveType.get(primitiveType).getDesc()
}
JavaToKotlinClassMap.INSTANCE.mapKotlinToJava(fqName)?.let { return it.desc }
return classDescriptor.classId.desc
}
fun mapSignature(function: FunctionDescriptor): String {
if (function is DeserializedSimpleFunctionDescriptor) {
val proto = function.getProto()
@@ -125,6 +92,50 @@ object RuntimeTypeMapper {
}
}
fun mapPropertySignature(property: PropertyDescriptor): String {
if (property is DeserializedPropertyDescriptor) {
val proto = property.proto
val nameResolver = property.nameResolver
if (!proto.hasExtension(JvmProtoBuf.propertySignature)) {
throw KotlinReflectionInternalError("No metadata found for $property")
}
val signature = proto.getExtension(JvmProtoBuf.propertySignature)
val deserializer = SignatureDeserializer(nameResolver)
if (signature.hasGetter()) {
return deserializer.methodSignatureString(signature.getGetter())
}
// In case the property doesn't have a getter, construct the signature of its imaginary default getter.
// See PropertyReference#getSignature
val field = signature.getField()
// TODO: some kind of test on the Java Bean convention?
return getterName(nameResolver.getString(field.getName())) +
"()" +
deserializer.typeDescriptor(field.getType())
}
else if (property is JavaPropertyDescriptor) {
val method = (property.getSource() as? JavaSourceElement)?.javaElement as? JavaField ?:
throw KotlinReflectionInternalError("Incorrect resolution sequence for Java field $property")
return StringBuilder {
append(getterName(method.getName().asString()))
append("()")
appendJavaType(method.getType())
}.toString()
}
else throw KotlinReflectionInternalError("Unknown origin of $property (${property.javaClass})")
}
private fun getterName(propertyName: String): String {
return JvmAbi.GETTER_PREFIX + propertyName.capitalizeWithJavaBeanConvention()
}
private fun String.capitalizeWithJavaBeanConvention(): String {
return if (length() > 1 && this[1].isUpperCase()) this else capitalize()
}
fun mapJvmClassToKotlinClassId(klass: Class<*>): ClassId {
if (klass.isArray()) {
klass.getComponentType().primitiveType?.let {
@@ -147,7 +158,4 @@ object RuntimeTypeMapper {
private val Class<*>.primitiveType: PrimitiveType?
get() = if (isPrimitive()) JvmPrimitiveType.get(getSimpleName()).getPrimitiveType() else null
private val ClassId.desc: String
get() = "L${JvmClassName.byClassId(this).getInternalName()};"
}
@@ -95,17 +95,10 @@ public val Field.kotlin: KProperty<*>?
get() {
if (isSynthetic()) return null
val clazz = getDeclaringClass()
val name = getName()
val modifiers = getModifiers()
val static = Modifier.isStatic(modifiers)
val final = Modifier.isFinal(modifiers)
if (static) {
val kPackage = clazz.kotlinPackage
return if (final) Reflection.topLevelVariable(name, kPackage) else Reflection.mutableTopLevelVariable(name, kPackage)
}
else {
val kClass = clazz.kotlin
return if (final) Reflection.memberProperty(name, kClass) else Reflection.mutableMemberProperty(name, kClass)
val clazz = getDeclaringClass().kotlin as KClassImpl
// TODO: optimize (search by name)
return clazz.properties.firstOrNull { p: KProperty<*> ->
(p as KPropertyImpl<*>).field == this
}
}
@@ -0,0 +1,68 @@
/*
* 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.jvm.KotlinReflectionNotSupportedError;
import kotlin.reflect.KCallable;
import kotlin.reflect.KDeclarationContainer;
/**
* A superclass for all classes generated by Kotlin compiler for callable references.
*
* All methods from reflection API should be implemented here to throw informative exceptions (see KotlinReflectionNotSupportedError)
*/
public abstract class CallableReference implements KCallable {
// The following methods provide the information identifying this callable, which is used by the reflection implementation.
// They are supposed to be overridden in each subclass (each anonymous class generated for a callable reference).
/**
* @return the class or package where the callable should be located, usually specified on the LHS of the '::' operator
*/
public KDeclarationContainer getOwner() {
throw error();
}
/**
* @return Kotlin name of the callable, the one which was declared in the source code (@platformName doesn't change it)
*/
@Override
public String getName() {
throw error();
}
/**
* @return JVM signature of the callable, e.g. "println(Ljava/lang/Object;)V". If this is a property reference,
* returns the JVM signature of its getter, e.g. "getFoo(Ljava/lang/String;)I". If the property has no getter in the bytecode
* (e.g. private property in a class), it's still the signature of the imaginary default getter that would be generated otherwise.
*
* Note that technically the signature itself is not even used as a signature per se in reflection implementation,
* but only as a unique and unambiguous way to map a function/property descriptor to a string.
*/
public String getSignature() {
throw error();
}
// The following methods are the stub implementations of reflection functions.
// They are called when you're using reflection on a property reference without the reflection implementation in the classpath.
// (nothing here yet)
protected static Error error() {
throw new KotlinReflectionNotSupportedError();
}
}
@@ -37,29 +37,22 @@ public class FunctionReference extends FunctionImpl implements KFunction {
return arity;
}
// The following methods provide the information identifying this function, which is used by the reflection implementation.
// They are supposed to be overridden in each subclass (each anonymous class generated for a function reference).
// Most of the following methods are copies from CallableReference, since this class cannot inherit from it
public KDeclarationContainer getOwner() {
throw error();
}
// Kotlin name of the function, the one which was declared in the source code (@platformName can't change it)
@Override
public String getName() {
throw error();
}
// JVM signature of the function, e.g. "println(Ljava/lang/Object;)V"
public String getSignature() {
throw error();
}
// The following methods are the stub implementations of reflection functions.
// They are called when you're using reflection on a function reference without the reflection implementation in the classpath.
// (nothing here yet)
private static Error error() {
protected static Error error() {
throw new KotlinReflectionNotSupportedError();
}
}
@@ -0,0 +1,22 @@
/*
* 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.KMutableProperty;
public abstract class MutablePropertyReference extends PropertyReference implements KMutableProperty {
}
@@ -0,0 +1,31 @@
/*
* 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.KMutableProperty0;
public class MutablePropertyReference0 extends MutablePropertyReference implements KMutableProperty0 {
@Override
public Object get() {
throw error();
}
@Override
public void set(Object value) {
throw error();
}
}
@@ -0,0 +1,31 @@
/*
* 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.KMutableProperty1;
public class MutablePropertyReference1 extends MutablePropertyReference implements KMutableProperty1 {
@Override
public Object get(Object receiver) {
throw error();
}
@Override
public void set(Object receiver, Object value) {
throw error();
}
}
@@ -0,0 +1,31 @@
/*
* 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.KMutableProperty2;
public class MutablePropertyReference2 extends MutablePropertyReference implements KMutableProperty2 {
@Override
public Object get(Object receiver1, Object receiver2) {
throw error();
}
@Override
public void set(Object receiver1, Object receiver2, Object value) {
throw error();
}
}
@@ -0,0 +1,22 @@
/*
* 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.KProperty;
public abstract class PropertyReference extends CallableReference implements KProperty {
}
@@ -0,0 +1,26 @@
/*
* 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.KProperty0;
public class PropertyReference0 extends PropertyReference implements KProperty0 {
@Override
public Object get() {
throw error();
}
}
@@ -0,0 +1,26 @@
/*
* 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.KProperty1;
public class PropertyReference1 extends PropertyReference implements KProperty1 {
@Override
public Object get(Object receiver) {
throw error();
}
}
@@ -0,0 +1,26 @@
/*
* 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.KProperty2;
public class PropertyReference2 extends PropertyReference implements KProperty2 {
@Override
public Object get(Object receiver1, Object receiver2) {
throw error();
}
}
@@ -67,27 +67,27 @@ public class Reflection {
// Properties
public static KProperty1 memberProperty(String name, KClass owner) {
return factory.memberProperty(name, owner);
public static KProperty0 property0(PropertyReference0 p) {
return factory.property0(p);
}
public static KMutableProperty1 mutableMemberProperty(String name, KClass owner) {
return factory.mutableMemberProperty(name, owner);
public static KMutableProperty0 mutableProperty0(MutablePropertyReference0 p) {
return factory.mutableProperty0(p);
}
public static KProperty0 topLevelVariable(String name, KPackage owner) {
return factory.topLevelVariable(name, owner);
public static KProperty1 property1(PropertyReference1 p) {
return factory.property1(p);
}
public static KMutableProperty0 mutableTopLevelVariable(String name, KPackage owner) {
return factory.mutableTopLevelVariable(name, owner);
public static KMutableProperty1 mutableProperty1(MutablePropertyReference1 p) {
return factory.mutableProperty1(p);
}
public static KProperty1 topLevelExtensionProperty(String name, KPackage owner, Class receiver) {
return factory.topLevelExtensionProperty(name, owner, receiver);
public static KProperty2 property2(PropertyReference2 p) {
return factory.property2(p);
}
public static KMutableProperty1 mutableTopLevelExtensionProperty(String name, KPackage owner, Class receiver) {
return factory.mutableTopLevelExtensionProperty(name, owner, receiver);
public static KMutableProperty2 mutableProperty2(MutablePropertyReference2 p) {
return factory.mutableProperty2(p);
}
}
@@ -40,28 +40,28 @@ public class ReflectionFactory {
// Properties
public KProperty1 memberProperty(String name, KClass owner) {
throw error();
public KProperty0 property0(PropertyReference0 p) {
return p;
}
public KMutableProperty1 mutableMemberProperty(String name, KClass owner) {
throw error();
public KMutableProperty0 mutableProperty0(MutablePropertyReference0 p) {
return p;
}
public KProperty0 topLevelVariable(String name, KPackage owner) {
throw error();
public KProperty1 property1(PropertyReference1 p) {
return p;
}
public KMutableProperty0 mutableTopLevelVariable(String name, KPackage owner) {
throw error();
public KMutableProperty1 mutableProperty1(MutablePropertyReference1 p) {
return p;
}
public KProperty1 topLevelExtensionProperty(String name, KPackage owner, Class receiver) {
throw error();
public KProperty2 property2(PropertyReference2 p) {
return p;
}
public KMutableProperty1 mutableTopLevelExtensionProperty(String name, KPackage owner, Class receiver) {
throw error();
public KMutableProperty2 mutableProperty2(MutablePropertyReference2 p) {
return p;
}
private Error error() {