Pass KProperty instances to property delegates
Inherit KProperty from PropertyMetadata, cache corresponding KProperty objects instead of PropertyMetadataImpl objects, add support for properties with 2 receivers
This commit is contained in:
@@ -55,7 +55,6 @@ import org.jetbrains.kotlin.incremental.components.NoLookupLocation;
|
||||
import org.jetbrains.kotlin.jvm.RuntimeAssertionInfo;
|
||||
import org.jetbrains.kotlin.jvm.bindingContextSlices.BindingContextSlicesPackage;
|
||||
import org.jetbrains.kotlin.lexer.JetTokens;
|
||||
import org.jetbrains.kotlin.load.java.JvmAbi;
|
||||
import org.jetbrains.kotlin.load.java.descriptors.SamConstructorDescriptor;
|
||||
import org.jetbrains.kotlin.name.Name;
|
||||
import org.jetbrains.kotlin.psi.*;
|
||||
@@ -2774,30 +2773,31 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
|
||||
|
||||
VariableDescriptor variableDescriptor = bindingContext.get(VARIABLE, expression);
|
||||
if (variableDescriptor != null) {
|
||||
return generatePropertyReference(expression, variableDescriptor, resolvedCall);
|
||||
return generatePropertyReference(expression, variableDescriptor, (VariableDescriptor) resolvedCall.getResultingDescriptor(),
|
||||
resolvedCall.getDispatchReceiver());
|
||||
}
|
||||
|
||||
throw new UnsupportedOperationException("Unsupported callable reference expression: " + expression.getText());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private StackValue generatePropertyReference(
|
||||
@NotNull JetCallableReferenceExpression expression,
|
||||
public StackValue generatePropertyReference(
|
||||
@NotNull JetElement element,
|
||||
@NotNull VariableDescriptor variableDescriptor,
|
||||
@NotNull ResolvedCall<?> resolvedCall
|
||||
@NotNull VariableDescriptor target,
|
||||
@NotNull ReceiverValue dispatchReceiver
|
||||
) {
|
||||
ClassDescriptor classDescriptor = CodegenBinding.anonymousClassForCallable(bindingContext, variableDescriptor);
|
||||
|
||||
ClassBuilder classBuilder = state.getFactory().newVisitor(
|
||||
OtherOrigin(expression),
|
||||
OtherOrigin(element),
|
||||
typeMapper.mapClass(classDescriptor),
|
||||
expression.getContainingFile()
|
||||
element.getContainingFile()
|
||||
);
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
PropertyReferenceCodegen codegen = new PropertyReferenceCodegen(
|
||||
state, parentCodegen, context.intoAnonymousClass(classDescriptor, this, OwnerKind.IMPLEMENTATION),
|
||||
expression, classBuilder, classDescriptor, (ResolvedCall<VariableDescriptor>) resolvedCall
|
||||
element, classBuilder, classDescriptor, target, dispatchReceiver
|
||||
);
|
||||
codegen.generate();
|
||||
|
||||
|
||||
@@ -43,6 +43,8 @@ import org.jetbrains.kotlin.resolve.constants.ConstantValue;
|
||||
import org.jetbrains.kotlin.resolve.constants.evaluate.ConstantExpressionEvaluator;
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilPackage;
|
||||
import org.jetbrains.kotlin.resolve.jvm.AsmTypes;
|
||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue;
|
||||
import org.jetbrains.kotlin.resolve.scopes.receivers.TransientReceiver;
|
||||
import org.jetbrains.kotlin.resolve.source.SourcePackage;
|
||||
import org.jetbrains.kotlin.storage.LockBasedStorageManager;
|
||||
import org.jetbrains.kotlin.storage.NotNullLazyValue;
|
||||
@@ -59,7 +61,6 @@ import static org.jetbrains.kotlin.codegen.AsmUtil.calculateInnerClassAccessFlag
|
||||
import static org.jetbrains.kotlin.codegen.AsmUtil.isPrimitive;
|
||||
import static org.jetbrains.kotlin.descriptors.CallableMemberDescriptor.Kind.SYNTHESIZED;
|
||||
import static org.jetbrains.kotlin.resolve.BindingContext.VARIABLE;
|
||||
import static org.jetbrains.kotlin.resolve.jvm.AsmTypes.PROPERTY_METADATA_IMPL_TYPE;
|
||||
import static org.jetbrains.kotlin.resolve.jvm.AsmTypes.PROPERTY_METADATA_TYPE;
|
||||
import static org.jetbrains.kotlin.resolve.jvm.diagnostics.DiagnosticsPackage.OtherOrigin;
|
||||
import static org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin.NO_ORIGIN;
|
||||
@@ -467,7 +468,7 @@ public abstract class MemberCodegen<T extends JetElement/* TODO: & JetDeclaratio
|
||||
}
|
||||
if (delegatedProperties.isEmpty()) return;
|
||||
|
||||
v.newField(NO_ORIGIN, ACC_PRIVATE | ACC_STATIC | ACC_FINAL | ACC_SYNTHETIC, JvmAbi.PROPERTY_METADATA_ARRAY_NAME,
|
||||
v.newField(NO_ORIGIN, ACC_PRIVATE | ACC_STATIC | ACC_FINAL | ACC_SYNTHETIC, JvmAbi.DELEGATED_PROPERTIES_ARRAY_NAME,
|
||||
"[" + PROPERTY_METADATA_TYPE, null, null);
|
||||
|
||||
if (state.getClassBuilderMode() == ClassBuilderMode.LIGHT_CLASSES) return;
|
||||
@@ -481,14 +482,21 @@ public abstract class MemberCodegen<T extends JetElement/* TODO: & JetDeclaratio
|
||||
|
||||
iv.dup();
|
||||
iv.iconst(i);
|
||||
iv.anew(PROPERTY_METADATA_IMPL_TYPE);
|
||||
iv.dup();
|
||||
iv.visitLdcInsn(property.getName().asString());
|
||||
iv.invokespecial(PROPERTY_METADATA_IMPL_TYPE.getInternalName(), "<init>", "(Ljava/lang/String;)V", false);
|
||||
iv.astore(PROPERTY_METADATA_IMPL_TYPE);
|
||||
|
||||
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
|
||||
);
|
||||
|
||||
value.put(PROPERTY_METADATA_TYPE, iv);
|
||||
|
||||
iv.astore(PROPERTY_METADATA_TYPE);
|
||||
}
|
||||
|
||||
iv.putstatic(thisAsmType.getInternalName(), JvmAbi.PROPERTY_METADATA_ARRAY_NAME, "[" + PROPERTY_METADATA_TYPE);
|
||||
iv.putstatic(thisAsmType.getInternalName(), JvmAbi.DELEGATED_PROPERTIES_ARRAY_NAME, "[" + PROPERTY_METADATA_TYPE);
|
||||
}
|
||||
|
||||
public String getClassName() {
|
||||
|
||||
@@ -520,7 +520,7 @@ public class PropertyCodegen {
|
||||
@Override
|
||||
public void putSelector(@NotNull Type type, @NotNull InstructionAdapter v) {
|
||||
Field array = StackValue
|
||||
.field(Type.getType("[" + PROPERTY_METADATA_TYPE), owner, JvmAbi.PROPERTY_METADATA_ARRAY_NAME, true,
|
||||
.field(Type.getType("[" + PROPERTY_METADATA_TYPE), owner, JvmAbi.DELEGATED_PROPERTIES_ARRAY_NAME, true,
|
||||
StackValue.none());
|
||||
StackValue.arrayElement(PROPERTY_METADATA_TYPE, array, StackValue.constant(indexInPropertyMetadataArray, Type.INT_TYPE)).put(type, v);
|
||||
}
|
||||
|
||||
@@ -25,14 +25,14 @@ 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.name.Name
|
||||
import org.jetbrains.kotlin.psi.JetCallableReferenceExpression
|
||||
import org.jetbrains.kotlin.psi.JetElement
|
||||
import org.jetbrains.kotlin.resolve.DescriptorFactory
|
||||
import org.jetbrains.kotlin.resolve.PropertyImportedFromObject
|
||||
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.ReceiverValue
|
||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ScriptReceiver
|
||||
import org.jetbrains.kotlin.utils.sure
|
||||
import org.jetbrains.org.objectweb.asm.Opcodes.ACC_FINAL
|
||||
@@ -47,14 +47,29 @@ public class PropertyReferenceCodegen(
|
||||
state: GenerationState,
|
||||
parentCodegen: MemberCodegen<*>,
|
||||
context: ClassContext,
|
||||
expression: JetCallableReferenceExpression,
|
||||
expression: JetElement,
|
||||
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 target: VariableDescriptor,
|
||||
dispatchReceiver: ReceiverValue
|
||||
) : MemberCodegen<JetElement>(state, parentCodegen, context, expression, classBuilder) {
|
||||
private val asmType = typeMapper.mapClass(classDescriptor)
|
||||
|
||||
private val dispatchReceiverType =
|
||||
when {
|
||||
dispatchReceiver is ScriptReceiver -> {
|
||||
// TODO: fix receiver for scripts, see ScriptReceiver#getType
|
||||
dispatchReceiver.declarationDescriptor.classDescriptor.defaultType
|
||||
}
|
||||
dispatchReceiver.exists() -> dispatchReceiver.type
|
||||
else -> null
|
||||
}
|
||||
|
||||
private val extensionReceiverType = target.extensionReceiverParameter?.type
|
||||
|
||||
private val receiverCount =
|
||||
(if (dispatchReceiverType != null) 1 else 0) + (if (extensionReceiverType != null) 1 else 0)
|
||||
|
||||
// e.g. MutablePropertyReference0
|
||||
private val superAsmType = typeMapper.mapClass(classDescriptor.getSuperClassNotAny().sure { "No super class for $classDescriptor" })
|
||||
|
||||
@@ -62,16 +77,17 @@ public class PropertyReferenceCodegen(
|
||||
private val wrapperMethod: Method
|
||||
|
||||
init {
|
||||
val hasReceiver = target.getDispatchReceiverParameter() != null || target.getExtensionReceiverParameter() != null
|
||||
val isMutable = target.isVar()
|
||||
|
||||
wrapperMethod = when {
|
||||
hasReceiver -> when {
|
||||
isMutable -> method("mutableProperty1", K_MUTABLE_PROPERTY1_TYPE, MUTABLE_PROPERTY_REFERENCE1)
|
||||
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 {
|
||||
isMutable -> method("mutableProperty0", K_MUTABLE_PROPERTY0_TYPE, MUTABLE_PROPERTY_REFERENCE0)
|
||||
target.isVar -> method("mutableProperty0", K_MUTABLE_PROPERTY0_TYPE, MUTABLE_PROPERTY_REFERENCE0)
|
||||
else -> method("property0", K_PROPERTY0_TYPE, PROPERTY_REFERENCE0)
|
||||
}
|
||||
}
|
||||
@@ -127,19 +143,6 @@ public class PropertyReferenceCodegen(
|
||||
}
|
||||
|
||||
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
|
||||
@@ -160,26 +163,27 @@ public class PropertyReferenceCodegen(
|
||||
StackValue.singleton(containingObject, typeMapper).put(typeMapper.mapClass(containingObject), this)
|
||||
}
|
||||
|
||||
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)
|
||||
for ((index, type) in listOf(dispatchReceiverType, extensionReceiverType).filterNotNull().withIndex()) {
|
||||
StackValue.local(index + 1, OBJECT_TYPE).put(typeMapper.mapType(type), this)
|
||||
}
|
||||
|
||||
val value = fakeCodegen.intermediateValueForProperty(target as PropertyDescriptor, false, null, StackValue.none())
|
||||
|
||||
accessorBody(value)
|
||||
}
|
||||
}
|
||||
|
||||
val getterParameters = if (receiverType != null) arrayOf(OBJECT_TYPE) else emptyArray()
|
||||
val getterParameters = (1..receiverCount).map { OBJECT_TYPE }.toTypedArray()
|
||||
generateAccessor(method("get", OBJECT_TYPE, *getterParameters)) { value ->
|
||||
value.put(OBJECT_TYPE, this)
|
||||
}
|
||||
|
||||
if (!target.isVar()) return
|
||||
if (!target.isVar) return
|
||||
|
||||
val setterParameters = (getterParameters + arrayOf(OBJECT_TYPE))
|
||||
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)
|
||||
// Number of receivers (not size) is safe here because there's only java/lang/Object in the signature, no double/long parameters
|
||||
value.store(StackValue.local(receiverCount + 1, OBJECT_TYPE), this)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+20
-23
@@ -140,29 +140,16 @@ class CodegenAnnotatingVisitor extends JetVisitorVoid {
|
||||
return container;
|
||||
}
|
||||
|
||||
private String inventAnonymousClassName(JetElement declaration) {
|
||||
@NotNull
|
||||
private String inventAnonymousClassName() {
|
||||
String top = peekFromStack(nameStack);
|
||||
Integer cnt = anonymousSubclassesCount.get(top);
|
||||
if (cnt == null) {
|
||||
cnt = 0;
|
||||
}
|
||||
String name = top + "$" + (cnt + 1);
|
||||
ClassDescriptor descriptor = bindingContext.get(CLASS, declaration);
|
||||
if (descriptor == null) {
|
||||
if (declaration instanceof JetFunctionLiteralExpression ||
|
||||
declaration instanceof JetNamedFunction ||
|
||||
declaration instanceof JetObjectLiteralExpression ||
|
||||
declaration instanceof JetCallableReferenceExpression) {
|
||||
}
|
||||
else {
|
||||
throw new IllegalStateException(
|
||||
"Class-less declaration which is not JetFunctionLiteralExpression|JetNamedFunction|JetObjectLiteralExpression|JetCallableReferenceExpression : " +
|
||||
declaration.getClass().getName());
|
||||
}
|
||||
}
|
||||
anonymousSubclassesCount.put(top, cnt + 1);
|
||||
|
||||
return name;
|
||||
return top + "$" + (cnt + 1);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -261,7 +248,7 @@ class CodegenAnnotatingVisitor extends JetVisitorVoid {
|
||||
return;
|
||||
}
|
||||
|
||||
String name = inventAnonymousClassName(object);
|
||||
String name = inventAnonymousClassName();
|
||||
recordClosure(classDescriptor, name);
|
||||
|
||||
JetDelegationSpecifierList delegationSpecifierList = object.getDelegationSpecifierList();
|
||||
@@ -287,7 +274,7 @@ class CodegenAnnotatingVisitor extends JetVisitorVoid {
|
||||
// working around a problem with shallow analysis
|
||||
if (functionDescriptor == null) return;
|
||||
|
||||
String name = inventAnonymousClassName(expression);
|
||||
String name = inventAnonymousClassName();
|
||||
Collection<JetType> supertypes = runtimeTypes.getSupertypesForClosure(functionDescriptor);
|
||||
ClassDescriptor classDescriptor = recordClassForCallable(functionLiteral, functionDescriptor, supertypes, name);
|
||||
recordClosure(classDescriptor, name);
|
||||
@@ -324,7 +311,7 @@ class CodegenAnnotatingVisitor extends JetVisitorVoid {
|
||||
return;
|
||||
}
|
||||
|
||||
String name = inventAnonymousClassName(expression);
|
||||
String name = inventAnonymousClassName();
|
||||
ClassDescriptor classDescriptor = recordClassForCallable(expression, callableDescriptor, supertypes, name);
|
||||
recordClosure(classDescriptor, name);
|
||||
|
||||
@@ -342,17 +329,27 @@ class CodegenAnnotatingVisitor extends JetVisitorVoid {
|
||||
|
||||
@Override
|
||||
public void visitProperty(@NotNull JetProperty property) {
|
||||
DeclarationDescriptor propertyDescriptor = bindingContext.get(DECLARATION_TO_DESCRIPTOR, property);
|
||||
DeclarationDescriptor descriptor = bindingContext.get(DECLARATION_TO_DESCRIPTOR, property);
|
||||
// working around a problem with shallow analysis
|
||||
if (propertyDescriptor == null) return;
|
||||
if (descriptor == null) return;
|
||||
|
||||
String nameForClassOrPackageMember = getNameForClassOrPackageMember(propertyDescriptor);
|
||||
String nameForClassOrPackageMember = getNameForClassOrPackageMember(descriptor);
|
||||
if (nameForClassOrPackageMember != null) {
|
||||
nameStack.push(nameForClassOrPackageMember);
|
||||
}
|
||||
else {
|
||||
nameStack.push(peekFromStack(nameStack) + '$' + safeIdentifier(property.getNameAsSafeName()).asString());
|
||||
}
|
||||
|
||||
JetPropertyDelegate delegate = property.getDelegate();
|
||||
if (delegate != null && descriptor instanceof PropertyDescriptor) {
|
||||
PropertyDescriptor propertyDescriptor = (PropertyDescriptor) descriptor;
|
||||
String name = inventAnonymousClassName();
|
||||
JetType supertype = runtimeTypes.getSupertypeForPropertyReference(propertyDescriptor);
|
||||
ClassDescriptor classDescriptor = recordClassForCallable(delegate, propertyDescriptor, Collections.singleton(supertype), name);
|
||||
recordClosure(classDescriptor, name);
|
||||
}
|
||||
|
||||
super.visitProperty(property);
|
||||
nameStack.pop();
|
||||
}
|
||||
@@ -370,7 +367,7 @@ class CodegenAnnotatingVisitor extends JetVisitorVoid {
|
||||
nameStack.pop();
|
||||
}
|
||||
else {
|
||||
String name = inventAnonymousClassName(function);
|
||||
String name = inventAnonymousClassName();
|
||||
Collection<JetType> supertypes = runtimeTypes.getSupertypesForClosure(functionDescriptor);
|
||||
ClassDescriptor classDescriptor = recordClassForCallable(function, functionDescriptor, supertypes, name);
|
||||
recordClosure(classDescriptor, name);
|
||||
|
||||
Reference in New Issue
Block a user