Fix protected call to super method from lambda

Previously JVM back-end had an assumption that if we're calling a method
declared in the super class from a lambda via a synthetic accessor, that should
be a super call and it must be done with 'invokespecial'. Which is wrong
because a method declared in the super class may be open and overridden in the
subclass, so 'invokevirtual' should be used. Surprisingly, Java SE verifier
allowed both instructions, but on Android only the latter is possible

 #KT-8899 Fixed
 #KT-9052 Fixed
This commit is contained in:
Alexander Udalov
2015-09-07 13:34:15 +03:00
parent 1ccd0f9fc2
commit 3c4b2994a9
15 changed files with 281 additions and 146 deletions
@@ -17,9 +17,14 @@
package org.jetbrains.kotlin.codegen;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor;
import org.jetbrains.kotlin.psi.JetSuperExpression;
public interface AccessorForCallableDescriptor<T extends CallableMemberDescriptor> {
@NotNull
T getCalleeDescriptor();
@Nullable
JetSuperExpression getSuperCallExpression();
}
@@ -17,37 +17,35 @@
package org.jetbrains.kotlin.codegen
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.descriptors.impl.SimpleFunctionDescriptorImpl
import org.jetbrains.kotlin.descriptors.impl.TypeParameterDescriptorImpl
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.JetSuperExpression
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.jvm.AsmTypes
import org.jetbrains.kotlin.types.JetType
import java.util.*
public class AccessorForConstructorDescriptor(
private val calleeDescriptor: ConstructorDescriptor,
containingDeclaration: DeclarationDescriptor
) : AbstractAccessorForFunctionDescriptor(containingDeclaration, Name.special("<init>"))
, ConstructorDescriptor
, AccessorForCallableDescriptor<ConstructorDescriptor> {
containingDeclaration: DeclarationDescriptor,
private val superCallExpression: JetSuperExpression?
) : AbstractAccessorForFunctionDescriptor(containingDeclaration, Name.special("<init>")),
ConstructorDescriptor,
AccessorForCallableDescriptor<ConstructorDescriptor> {
override fun getCalleeDescriptor(): ConstructorDescriptor = calleeDescriptor
override fun getContainingDeclaration(): ClassDescriptor = calleeDescriptor.getContainingDeclaration()
override fun getContainingDeclaration(): ClassDescriptor = calleeDescriptor.containingDeclaration
override fun isPrimary(): Boolean = false
override fun getReturnType(): JetType = super<AbstractAccessorForFunctionDescriptor>.getReturnType()!!
override fun getReturnType(): JetType = super.getReturnType()!!
override fun getSuperCallExpression(): JetSuperExpression? = superCallExpression
init {
initialize(
DescriptorUtils.getReceiverParameterType(getExtensionReceiverParameter()),
calleeDescriptor.getDispatchReceiverParameter(),
DescriptorUtils.getReceiverParameterType(extensionReceiverParameter),
calleeDescriptor.dispatchReceiverParameter,
copyTypeParameters(calleeDescriptor),
copyValueParameters(calleeDescriptor),
calleeDescriptor.getReturnType(),
calleeDescriptor.returnType,
Modality.FINAL,
Visibilities.INTERNAL
)
@@ -17,23 +17,27 @@
package org.jetbrains.kotlin.codegen;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.descriptors.*;
import org.jetbrains.kotlin.name.Name;
import org.jetbrains.kotlin.psi.JetSuperExpression;
import org.jetbrains.kotlin.resolve.DescriptorUtils;
import org.jetbrains.kotlin.resolve.annotations.AnnotationsPackage;
public class AccessorForFunctionDescriptor extends AbstractAccessorForFunctionDescriptor implements AccessorForCallableDescriptor<FunctionDescriptor> {
private final FunctionDescriptor calleeDescriptor;
private final JetSuperExpression superCallExpression;
public AccessorForFunctionDescriptor(
@NotNull FunctionDescriptor descriptor,
@NotNull DeclarationDescriptor containingDeclaration,
int index
int index,
@Nullable JetSuperExpression superCallExpression
) {
super(containingDeclaration,
Name.identifier("access$" + (descriptor instanceof ConstructorDescriptor ? "init" : descriptor.getName()) + "$" + index));
this.calleeDescriptor = descriptor;
this.superCallExpression = superCallExpression;
initialize(DescriptorUtils.getReceiverParameterType(descriptor.getExtensionReceiverParameter()),
descriptor instanceof ConstructorDescriptor || AnnotationsPackage.isPlatformStaticInObjectOrClass(descriptor)
@@ -51,4 +55,9 @@ public class AccessorForFunctionDescriptor extends AbstractAccessorForFunctionDe
public FunctionDescriptor getCalleeDescriptor() {
return calleeDescriptor;
}
@Override
public JetSuperExpression getSuperCallExpression() {
return superCallExpression;
}
}
@@ -23,13 +23,12 @@ import org.jetbrains.kotlin.descriptors.PropertyDescriptor;
import org.jetbrains.kotlin.types.JetType;
public class AccessorForPropertyBackingFieldInOuterClass extends AccessorForPropertyDescriptor {
public AccessorForPropertyBackingFieldInOuterClass(
@NotNull PropertyDescriptor pd,
@NotNull PropertyDescriptor property,
@NotNull DeclarationDescriptor containingDeclaration,
int index,
@Nullable JetType delegationType
) {
super(pd, delegationType != null ? delegationType : pd.getType(), null, null, containingDeclaration, index);
super(property, delegationType != null ? delegationType : property.getType(), null, null, containingDeclaration, index, null);
}
}
@@ -25,6 +25,7 @@ import org.jetbrains.kotlin.descriptors.impl.PropertyGetterDescriptorImpl;
import org.jetbrains.kotlin.descriptors.impl.PropertySetterDescriptorImpl;
import org.jetbrains.kotlin.descriptors.impl.TypeParameterDescriptorImpl;
import org.jetbrains.kotlin.name.Name;
import org.jetbrains.kotlin.psi.JetSuperExpression;
import org.jetbrains.kotlin.resolve.DescriptorUtils;
import org.jetbrains.kotlin.types.JetType;
@@ -33,9 +34,16 @@ import java.util.Collections;
public class AccessorForPropertyDescriptor extends PropertyDescriptorImpl implements AccessorForCallableDescriptor<PropertyDescriptor> {
private final PropertyDescriptor calleeDescriptor;
private final int accessorIndex;
private final JetSuperExpression superCallExpression;
public AccessorForPropertyDescriptor(@NotNull PropertyDescriptor pd, @NotNull DeclarationDescriptor containingDeclaration, int index) {
this(pd, pd.getType(), DescriptorUtils.getReceiverParameterType(pd.getExtensionReceiverParameter()), pd.getDispatchReceiverParameter(), containingDeclaration, index);
public AccessorForPropertyDescriptor(
@NotNull PropertyDescriptor property,
@NotNull DeclarationDescriptor containingDeclaration,
int index,
@Nullable JetSuperExpression superCallExpression
) {
this(property, property.getType(), DescriptorUtils.getReceiverParameterType(property.getExtensionReceiverParameter()),
property.getDispatchReceiverParameter(), containingDeclaration, index, superCallExpression);
}
protected AccessorForPropertyDescriptor(
@@ -44,7 +52,8 @@ public class AccessorForPropertyDescriptor extends PropertyDescriptorImpl implem
@Nullable JetType receiverType,
@Nullable ReceiverParameterDescriptor dispatchReceiverParameter,
@NotNull DeclarationDescriptor containingDeclaration,
int index
int index,
@Nullable JetSuperExpression superCallExpression
) {
super(containingDeclaration, null, Annotations.EMPTY, Modality.FINAL, Visibilities.LOCAL,
original.isVar(), Name.identifier("access$" + getIndexedAccessorSuffix(original, index)),
@@ -52,6 +61,7 @@ public class AccessorForPropertyDescriptor extends PropertyDescriptorImpl implem
this.calleeDescriptor = original;
this.accessorIndex = index;
this.superCallExpression = superCallExpression;
setType(propertyType, Collections.<TypeParameterDescriptorImpl>emptyList(), dispatchReceiverParameter, receiverType);
initialize(new Getter(this), new Setter(this));
}
@@ -69,6 +79,12 @@ public class AccessorForPropertyDescriptor extends PropertyDescriptorImpl implem
//noinspection ConstantConditions
return ((AccessorForPropertyDescriptor) getCorrespondingProperty()).getCalleeDescriptor().getGetter();
}
@Nullable
@Override
public JetSuperExpression getSuperCallExpression() {
return ((AccessorForPropertyDescriptor) getCorrespondingProperty()).getSuperCallExpression();
}
}
public static class Setter extends PropertySetterDescriptorImpl implements AccessorForCallableDescriptor<PropertySetterDescriptor>{
@@ -84,6 +100,12 @@ public class AccessorForPropertyDescriptor extends PropertyDescriptorImpl implem
//noinspection ConstantConditions
return ((AccessorForPropertyDescriptor) getCorrespondingProperty()).getCalleeDescriptor().getSetter();
}
@Nullable
@Override
public JetSuperExpression getSuperCallExpression() {
return ((AccessorForPropertyDescriptor) getCorrespondingProperty()).getSuperCallExpression();
}
}
@NotNull
@@ -92,6 +114,11 @@ public class AccessorForPropertyDescriptor extends PropertyDescriptorImpl implem
return calleeDescriptor;
}
@Override
public JetSuperExpression getSuperCallExpression() {
return superCallExpression;
}
@NotNull
public String getIndexedAccessorSuffix() {
return getIndexedAccessorSuffix(calleeDescriptor, accessorIndex);
@@ -356,11 +356,15 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
@Override
public StackValue visitSuperExpression(@NotNull JetSuperExpression expression, StackValue data) {
return StackValue.thisOrOuter(this, getSuperCallLabelTarget(expression), true, true);
return StackValue.thisOrOuter(this, getSuperCallLabelTarget(context, expression), true, true);
}
@NotNull
private ClassDescriptor getSuperCallLabelTarget(JetSuperExpression expression) {
public static ClassDescriptor getSuperCallLabelTarget(
@NotNull CodegenContext<?> context,
@NotNull JetSuperExpression expression
) {
BindingContext bindingContext = context.getState().getBindingContext();
PsiElement labelPsi = bindingContext.get(LABEL_TARGET, expression.getTargetLabel());
ClassDescriptor labelTarget = (ClassDescriptor) bindingContext.get(DECLARATION_TO_DESCRIPTOR, labelPsi);
DeclarationDescriptor descriptor = bindingContext.get(REFERENCE_TARGET, expression.getInstanceReference());
@@ -2007,7 +2011,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
expression.getReferencedNameElementType() == JetTokens.FIELD_IDENTIFIER && contextKind() != OwnerKind.TRAIT_IMPL;
JetSuperExpression superExpression =
resolvedCall == null ? null : CallResolverUtilPackage.getSuperCallExpression(resolvedCall.getCall());
propertyDescriptor = context.accessibleDescriptor(propertyDescriptor);
propertyDescriptor = context.accessibleDescriptor(propertyDescriptor, superExpression);
if (directToField) {
receiver = StackValue.receiverWithoutReceiverArgument(receiver);
@@ -2137,14 +2141,14 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
@Nullable JetSuperExpression superExpression,
@NotNull StackValue receiver
) {
return intermediateValueForProperty(propertyDescriptor, forceField, superExpression, MethodKind.GENERAL, receiver);
return intermediateValueForProperty(propertyDescriptor, forceField, superExpression, false, receiver);
}
public StackValue.Property intermediateValueForProperty(
@NotNull PropertyDescriptor propertyDescriptor,
boolean forceField,
@Nullable JetSuperExpression superExpression,
@NotNull MethodKind methodKind,
boolean skipAccessorsForPrivateFieldInOuterClass,
StackValue receiver
) {
if (propertyDescriptor instanceof SyntheticJavaPropertyDescriptor) {
@@ -2165,56 +2169,54 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
CallableMethod callableGetter = null;
CallableMethod callableSetter = null;
boolean skipPropertyAccessors = forceField && !isBackingFieldInAnotherClass;
CodegenContext backingFieldContext = context.getParentContext();
boolean changeOwnerOnTypeMapping = isBackingFieldInAnotherClass;
CodegenContext backingFieldContext;
boolean changeOwnerOnTypeMapping;
boolean skipPropertyAccessors;
if (isBackingFieldInAnotherClass && forceField) {
backingFieldContext = context.findParentContextWithDescriptor(containingDeclaration.getContainingDeclaration());
int flags = AsmUtil.getVisibilityForSpecialPropertyBackingField(propertyDescriptor, isDelegatedProperty);
skipPropertyAccessors =
(flags & ACC_PRIVATE) == 0 || methodKind == MethodKind.SYNTHETIC_ACCESSOR || methodKind == MethodKind.INITIALIZER;
skipPropertyAccessors = (flags & ACC_PRIVATE) == 0 || skipAccessorsForPrivateFieldInOuterClass;
if (!skipPropertyAccessors) {
propertyDescriptor = (PropertyDescriptor) backingFieldContext.getAccessor(propertyDescriptor, true, delegateType);
changeOwnerOnTypeMapping =
changeOwnerOnTypeMapping && !(propertyDescriptor instanceof AccessorForPropertyBackingFieldInOuterClass);
//noinspection ConstantConditions
propertyDescriptor = (PropertyDescriptor) backingFieldContext.getAccessor(
propertyDescriptor, true, delegateType, superExpression
);
changeOwnerOnTypeMapping = !(propertyDescriptor instanceof AccessorForPropertyBackingFieldInOuterClass);
}
else {
changeOwnerOnTypeMapping = true;
}
}
else {
backingFieldContext = context.getParentContext();
changeOwnerOnTypeMapping = isBackingFieldInAnotherClass;
skipPropertyAccessors = forceField;
}
if (!skipPropertyAccessors) {
if (couldUseDirectAccessToProperty(propertyDescriptor, true, isDelegatedProperty, context)) {
callableGetter = null;
}
else {
if (!couldUseDirectAccessToProperty(propertyDescriptor, true, isDelegatedProperty, context)) {
if (isSuper && !isInterface(containingDeclaration)) {
ClassDescriptor owner = getSuperCallLabelTarget(superExpression);
ClassDescriptor owner = getSuperCallLabelTarget(context, superExpression);
CodegenContext c = context.findParentContextWithDescriptor(owner);
assert c != null : "Couldn't find a context for a super-call: " + propertyDescriptor;
if (c != context.getParentContext()) {
propertyDescriptor = (PropertyDescriptor) c.getAccessor(propertyDescriptor);
propertyDescriptor = (PropertyDescriptor) c.getAccessor(propertyDescriptor, superExpression);
}
}
propertyDescriptor = context.accessibleDescriptor(propertyDescriptor);
propertyDescriptor = context.accessibleDescriptor(propertyDescriptor, superExpression);
PropertyGetterDescriptor getter = propertyDescriptor.getGetter();
if (getter != null) {
callableGetter =
typeMapper.mapToCallableMethod(getter, isSuper || MethodKind.SYNTHETIC_ACCESSOR == methodKind, context);
callableGetter = typeMapper.mapToCallableMethod(getter, isSuper, context);
}
}
if (propertyDescriptor.isVar()) {
PropertySetterDescriptor setter = propertyDescriptor.getSetter();
if (setter != null) {
if (couldUseDirectAccessToProperty(propertyDescriptor, false, isDelegatedProperty, context)) {
callableSetter = null;
}
else {
callableSetter =
typeMapper.mapToCallableMethod(setter, isSuper || MethodKind.SYNTHETIC_ACCESSOR == methodKind, context);
}
if (setter != null && !couldUseDirectAccessToProperty(propertyDescriptor, false, isDelegatedProperty, context)) {
callableSetter = typeMapper.mapToCallableMethod(setter, isSuper, context);
}
}
}
@@ -2329,7 +2331,9 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
descriptor = originalIfSamAdapter;
}
// $default method is not private, so you need no accessor to call it
return usesDefaultArguments(resolvedCall) ? descriptor : context.accessibleDescriptor(descriptor);
return usesDefaultArguments(resolvedCall)
? descriptor
: context.accessibleDescriptor(descriptor, CallResolverUtilPackage.getSuperCallExpression(resolvedCall.getCall()));
}
private static boolean usesDefaultArguments(@NotNull ResolvedCall<?> resolvedCall) {
@@ -2355,11 +2359,11 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
boolean superCall = superCallExpression != null;
if (superCall && !isInterface(fd.getContainingDeclaration())) {
ClassDescriptor owner = getSuperCallLabelTarget(superCallExpression);
ClassDescriptor owner = getSuperCallLabelTarget(context, superCallExpression);
CodegenContext c = context.findParentContextWithDescriptor(owner);
assert c != null : "Couldn't find a context for a super-call: " + fd;
if (c != context.getParentContext()) {
fd = (FunctionDescriptor) c.getAccessor(fd);
fd = (FunctionDescriptor) c.getAccessor(fd, superCallExpression);
}
}
@@ -210,7 +210,7 @@ public class FunctionCodegen {
mv.visitCode();
FunctionDescriptor staticFunctionDescriptor = PlatformStaticGenerator.createStaticFunctionDescriptor(functionDescriptor);
JvmMethodSignature jvmMethodSignature =
typeMapper.mapSignature(memberCodegen.getContext().accessibleDescriptor(staticFunctionDescriptor));
typeMapper.mapSignature(memberCodegen.getContext().accessibleDescriptor(staticFunctionDescriptor, null));
Type owningType = typeMapper.mapClass((ClassifierDescriptor) staticFunctionDescriptor.getContainingDeclaration());
generateDelegateToMethodBody(false, mv, jvmMethodSignature.getAsmMethod(), owningType.getInternalName());
}
@@ -857,32 +857,31 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
}
protected void generateSyntheticAccessors() {
Map<DeclarationDescriptor, DeclarationDescriptor> accessors = ((CodegenContext<?>) context).getAccessors();
for (Map.Entry<DeclarationDescriptor, DeclarationDescriptor> entry : accessors.entrySet()) {
generateSyntheticAccessor(entry);
for (AccessorForCallableDescriptor<?> accessor : ((CodegenContext<?>) context).getAccessors()) {
generateSyntheticAccessor(accessor);
}
}
private void generateSyntheticAccessor(Map.Entry<DeclarationDescriptor, DeclarationDescriptor> entry) {
if (entry.getValue() instanceof FunctionDescriptor) {
final FunctionDescriptor bridge = (FunctionDescriptor) entry.getValue();
final FunctionDescriptor original = (FunctionDescriptor) entry.getKey();
private void generateSyntheticAccessor(@NotNull AccessorForCallableDescriptor<?> accessorForCallableDescriptor) {
if (accessorForCallableDescriptor instanceof FunctionDescriptor) {
final FunctionDescriptor accessor = (FunctionDescriptor) accessorForCallableDescriptor;
final FunctionDescriptor original = (FunctionDescriptor) accessorForCallableDescriptor.getCalleeDescriptor();
functionCodegen.generateMethod(
Synthetic(null, original), bridge,
new FunctionGenerationStrategy.CodegenBased<FunctionDescriptor>(state, bridge) {
Synthetic(null, original), accessor,
new FunctionGenerationStrategy.CodegenBased<FunctionDescriptor>(state, accessor) {
@Override
public void doGenerateBody(@NotNull ExpressionCodegen codegen, @NotNull JvmMethodSignature signature) {
markLineNumberForSyntheticFunction(descriptor, codegen.v);
generateMethodCallTo(original, bridge, codegen.v);
generateMethodCallTo(original, accessor, codegen.v);
codegen.v.areturn(signature.getReturnType());
}
}
);
}
else if (entry.getValue() instanceof PropertyDescriptor) {
final PropertyDescriptor bridge = (PropertyDescriptor) entry.getValue();
final PropertyDescriptor original = (PropertyDescriptor) entry.getKey();
else if (accessorForCallableDescriptor instanceof AccessorForPropertyDescriptor) {
final AccessorForPropertyDescriptor accessor = (AccessorForPropertyDescriptor) accessorForCallableDescriptor;
final PropertyDescriptor original = accessor.getCalleeDescriptor();
class PropertyAccessorStrategy extends FunctionGenerationStrategy.CodegenBased<PropertyAccessorDescriptor> {
public PropertyAccessorStrategy(@NotNull PropertyAccessorDescriptor callableDescriptor) {
@@ -892,10 +891,10 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
@Override
public void doGenerateBody(@NotNull ExpressionCodegen codegen, @NotNull JvmMethodSignature signature) {
boolean forceField = AsmUtil.isPropertyWithBackingFieldInOuterClass(original) &&
!isCompanionObject(bridge.getContainingDeclaration());
StackValue property =
codegen.intermediateValueForProperty(original, forceField, null, MethodKind.SYNTHETIC_ACCESSOR,
StackValue.none());
!isCompanionObject(accessor.getContainingDeclaration());
StackValue property = codegen.intermediateValueForProperty(
original, forceField, accessor.getSuperCallExpression(), true, StackValue.none()
);
InstructionAdapter iv = codegen.v;
@@ -920,14 +919,14 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
}
}
PropertyGetterDescriptor getter = bridge.getGetter();
PropertyGetterDescriptor getter = accessor.getGetter();
assert getter != null;
functionCodegen.generateMethod(Synthetic(null, original.getGetter() != null ? original.getGetter() : original),
getter, new PropertyAccessorStrategy(getter));
if (bridge.isVar()) {
PropertySetterDescriptor setter = bridge.getSetter();
if (accessor.isVar()) {
PropertySetterDescriptor setter = accessor.getSetter();
assert setter != null;
functionCodegen.generateMethod(Synthetic(null, original.getSetter() != null ? original.getSetter() : original),
@@ -957,24 +956,25 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
private void generateMethodCallTo(
@NotNull FunctionDescriptor functionDescriptor,
@Nullable FunctionDescriptor bridgeDescriptor,
@Nullable FunctionDescriptor accessorDescriptor,
@NotNull InstructionAdapter iv
) {
boolean isConstructor = functionDescriptor instanceof ConstructorDescriptor;
boolean bridgeIsAccessorConstructor = bridgeDescriptor instanceof AccessorForConstructorDescriptor;
boolean callFromAccessor = bridgeIsAccessorConstructor
|| (bridgeDescriptor != null && JetTypeMapper.isAccessor(bridgeDescriptor));
boolean accessorIsConstructor = accessorDescriptor instanceof AccessorForConstructorDescriptor;
boolean superCall = accessorDescriptor instanceof AccessorForCallableDescriptor &&
((AccessorForCallableDescriptor) accessorDescriptor).getSuperCallExpression() != null;
CallableMethod callableMethod = isConstructor ?
typeMapper.mapToCallableMethod((ConstructorDescriptor) functionDescriptor) :
typeMapper.mapToCallableMethod(functionDescriptor, callFromAccessor, context);
typeMapper.mapToCallableMethod(functionDescriptor, superCall, context);
int reg = 1;
if (isConstructor && !bridgeIsAccessorConstructor) {
if (isConstructor && !accessorIsConstructor) {
iv.anew(callableMethod.getOwner());
iv.dup();
reg = 0;
}
else if (callFromAccessor) {
else if (accessorIsConstructor || (accessorDescriptor != null && JetTypeMapper.isAccessor(accessorDescriptor))) {
if (!AnnotationsPackage.isPlatformStaticInObjectOrClass(functionDescriptor)) {
iv.load(0, OBJECT_TYPE);
}
@@ -989,6 +989,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
reg += argType.getSize();
}
}
callableMethod.genInvokeInstruction(iv);
}
@@ -1074,8 +1075,9 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
private void generateCompanionObjectInitializer(@NotNull ClassDescriptor companionObject) {
ExpressionCodegen codegen = createOrGetClInitCodegen();
FunctionDescriptor constructor =
(FunctionDescriptor) context.accessibleDescriptor(KotlinPackage.single(companionObject.getConstructors()));
FunctionDescriptor constructor = (FunctionDescriptor) context.accessibleDescriptor(
KotlinPackage.single(companionObject.getConstructors()), /* superCallExpression = */ null
);
generateMethodCallTo(constructor, null, codegen.v);
codegen.v.dup();
StackValue instance = StackValue.onStack(typeMapper.mapClass(companionObject));
@@ -360,8 +360,7 @@ public abstract class MemberCodegen<T extends JetElement/* TODO: & JetDeclaratio
JetExpression initializer = property.getDelegateExpressionOrInitializer();
assert initializer != null : "shouldInitializeProperty must return false if initializer is null";
StackValue.Property propValue = codegen.intermediateValueForProperty(propertyDescriptor, true, null, MethodKind.INITIALIZER,
StackValue.LOCAL_0);
StackValue.Property propValue = codegen.intermediateValueForProperty(propertyDescriptor, true, null, true, StackValue.LOCAL_0);
propValue.store(codegen.gen(initializer), codegen.v);
@@ -1,23 +0,0 @@
/*
* 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;
public enum MethodKind {
GENERAL,
INITIALIZER,
SYNTHETIC_ACCESSOR
}
@@ -23,20 +23,19 @@ import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.descriptors.PropertyAccessorDescriptor
import org.jetbrains.kotlin.psi.JetElement
import org.jetbrains.kotlin.psi.JetNamedFunction
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin
import org.jetbrains.kotlin.resolve.jvm.diagnostics.Synthetic
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature
import org.jetbrains.org.objectweb.asm.MethodVisitor
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
import kotlin.platform.platformStatic
class PlatformStaticGenerator(
val descriptor: FunctionDescriptor,
val declarationOrigin: JvmDeclarationOrigin,
val state: GenerationState
) : Function2<ImplementationBodyCodegen, ClassBuilder, Unit> {
private val typeMapper = state.typeMapper
override fun invoke(codegen: ImplementationBodyCodegen, classBuilder: ClassBuilder) {
val staticFunctionDescriptor = createStaticFunctionDescriptor(descriptor)
@@ -51,40 +50,37 @@ class PlatformStaticGenerator(
frameMap: FrameMap,
signature: JvmMethodSignature,
context: MethodContext,
parentCodegen: MemberCodegen<out JetElement>
parentCodegen: MemberCodegen<*>
) {
val typeMapper = parentCodegen.typeMapper
val iv = InstructionAdapter(mv)
val classDescriptor = descriptor.getContainingDeclaration() as ClassDescriptor
val classDescriptor = descriptor.containingDeclaration as ClassDescriptor
val singletonValue = StackValue.singleton(classDescriptor, typeMapper)
singletonValue.put(singletonValue.type, iv);
var index = 0;
val asmMethod = signature.getAsmMethod()
for (paramType in asmMethod.getArgumentTypes()) {
iv.load(index, paramType);
index += paramType.getSize();
singletonValue.put(singletonValue.type, iv)
var index = 0
val asmMethod = signature.asmMethod
for (paramType in asmMethod.argumentTypes) {
iv.load(index, paramType)
index += paramType.size
}
val syntheticOrOriginalMethod = typeMapper.mapToCallableMethod(
codegen.getContext().accessibleDescriptor(descriptor),
codegen.getContext().accessibleDescriptor(descriptor, /* superCallExpression = */ null),
false,
codegen.getContext()
)
syntheticOrOriginalMethod.genInvokeInstruction(iv)
iv.areturn(asmMethod.getReturnType());
iv.areturn(asmMethod.returnType)
}
}
)
if (originElement is JetNamedFunction) {
codegen.functionCodegen.generateOverloadsWithDefaultValues(originElement, staticFunctionDescriptor, descriptor)
}
}
companion object {
@platformStatic
@JvmStatic
public fun createStaticFunctionDescriptor(descriptor: FunctionDescriptor): FunctionDescriptor {
val memberDescriptor = if (descriptor is PropertyAccessorDescriptor) descriptor.getCorrespondingProperty() else descriptor
val copies = CodegenUtil.copyFunctions(
@@ -24,6 +24,7 @@ import org.jetbrains.kotlin.codegen.binding.MutableClosure;
import org.jetbrains.kotlin.codegen.state.GenerationState;
import org.jetbrains.kotlin.codegen.state.JetTypeMapper;
import org.jetbrains.kotlin.descriptors.*;
import org.jetbrains.kotlin.psi.JetSuperExpression;
import org.jetbrains.kotlin.resolve.BindingContext;
import org.jetbrains.kotlin.resolve.DescriptorUtils;
import org.jetbrains.kotlin.storage.LockBasedStorageManager;
@@ -47,8 +48,38 @@ public abstract class CodegenContext<T extends DeclarationDescriptor> {
private final LocalLookup enclosingLocalLookup;
private final NullableLazyValue<StackValue.Field> outerExpression;
private Map<DeclarationDescriptor, DeclarationDescriptor> accessors;
private Map<DeclarationDescriptor, CodegenContext> childContexts;
private Map<AccessorKey, AccessorForCallableDescriptor<?>> accessors;
private static class AccessorKey {
public final DeclarationDescriptor descriptor;
public final ClassDescriptor superCallLabelTarget;
public AccessorKey(@NotNull DeclarationDescriptor descriptor, @Nullable ClassDescriptor superCallLabelTarget) {
this.descriptor = descriptor;
this.superCallLabelTarget = superCallLabelTarget;
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof AccessorKey)) return false;
AccessorKey other = (AccessorKey) obj;
return descriptor.equals(other.descriptor) &&
(superCallLabelTarget == null
? other.superCallLabelTarget == null
: superCallLabelTarget.equals(other.superCallLabelTarget));
}
@Override
public int hashCode() {
return 31 * descriptor.hashCode() + (superCallLabelTarget == null ? 0 : superCallLabelTarget.hashCode());
}
@Override
public String toString() {
return descriptor.toString();
}
}
public CodegenContext(
@NotNull T contextDescriptor,
@@ -227,20 +258,28 @@ public abstract class CodegenContext<T extends DeclarationDescriptor> {
}
@NotNull
public <D extends CallableMemberDescriptor> D getAccessor(@NotNull D descriptor) {
return getAccessor(descriptor, false, null);
public <D extends CallableMemberDescriptor> D getAccessor(@NotNull D descriptor, @Nullable JetSuperExpression superCallExpression) {
return getAccessor(descriptor, false, null, superCallExpression);
}
@SuppressWarnings("unchecked")
@NotNull
public <D extends CallableMemberDescriptor> D getAccessor(
@NotNull D descriptor, boolean isForBackingFieldInOuterClass, @Nullable JetType delegateType
@NotNull D possiblySubstitutedDescriptor,
boolean isForBackingFieldInOuterClass,
@Nullable JetType delegateType,
@Nullable JetSuperExpression superCallExpression
) {
if (accessors == null) {
accessors = new LinkedHashMap<DeclarationDescriptor, DeclarationDescriptor>();
accessors = new LinkedHashMap<AccessorKey, AccessorForCallableDescriptor<?>>();
}
descriptor = (D) descriptor.getOriginal();
DeclarationDescriptor accessor = accessors.get(descriptor);
D descriptor = (D) possiblySubstitutedDescriptor.getOriginal();
AccessorKey key = new AccessorKey(
descriptor, superCallExpression == null ? null : ExpressionCodegen.getSuperCallLabelTarget(this, superCallExpression)
);
AccessorForCallableDescriptor<?> accessor = accessors.get(key);
if (accessor != null) {
assert !isForBackingFieldInOuterClass ||
accessor instanceof AccessorForPropertyBackingFieldInOuterClass : "There is already exists accessor with isForBackingFieldInOuterClass = false in this context";
@@ -249,10 +288,12 @@ public abstract class CodegenContext<T extends DeclarationDescriptor> {
int accessorIndex = accessors.size();
if (descriptor instanceof SimpleFunctionDescriptor) {
accessor = new AccessorForFunctionDescriptor((FunctionDescriptor) descriptor, contextDescriptor, accessorIndex);
accessor = new AccessorForFunctionDescriptor(
(FunctionDescriptor) descriptor, contextDescriptor, accessorIndex, superCallExpression
);
}
else if (descriptor instanceof ConstructorDescriptor) {
accessor = new AccessorForConstructorDescriptor((ConstructorDescriptor) descriptor, contextDescriptor);
accessor = new AccessorForConstructorDescriptor((ConstructorDescriptor) descriptor, contextDescriptor, superCallExpression);
}
else if (descriptor instanceof PropertyDescriptor) {
if (isForBackingFieldInOuterClass) {
@@ -260,13 +301,16 @@ public abstract class CodegenContext<T extends DeclarationDescriptor> {
accessorIndex, delegateType);
}
else {
accessor = new AccessorForPropertyDescriptor((PropertyDescriptor) descriptor, contextDescriptor, accessorIndex);
accessor = new AccessorForPropertyDescriptor((PropertyDescriptor) descriptor, contextDescriptor,
accessorIndex, superCallExpression);
}
}
else {
throw new UnsupportedOperationException("Do not know how to create accessor for descriptor " + descriptor);
}
accessors.put(descriptor, accessor);
accessors.put(key, accessor);
return (D) accessor;
}
@@ -314,25 +358,29 @@ public abstract class CodegenContext<T extends DeclarationDescriptor> {
}
@NotNull
public Map<DeclarationDescriptor, DeclarationDescriptor> getAccessors() {
return accessors == null ? Collections.<DeclarationDescriptor, DeclarationDescriptor>emptyMap() : accessors;
public Collection<? extends AccessorForCallableDescriptor<?>> getAccessors() {
return accessors == null ? Collections.<AccessorForCallableDescriptor<CallableMemberDescriptor>>emptySet() : accessors.values();
}
@NotNull
public <D extends CallableMemberDescriptor> D accessibleDescriptor(D descriptor) {
public <D extends CallableMemberDescriptor> D accessibleDescriptor(
@NotNull D descriptor,
@Nullable JetSuperExpression superCallExpression
) {
DeclarationDescriptor enclosing = descriptor.getContainingDeclaration();
if (!hasThisDescriptor() || enclosing == getThisDescriptor() ||
enclosing == getClassOrPackageParentContext().getContextDescriptor()) {
return descriptor;
}
return accessibleDescriptorIfNeeded(descriptor);
return accessibleDescriptorIfNeeded(descriptor, superCallExpression);
}
public void recordSyntheticAccessorIfNeeded(@NotNull CallableMemberDescriptor descriptor, @NotNull BindingContext bindingContext) {
if (hasThisDescriptor() &&
(descriptor instanceof ConstructorDescriptor || Boolean.TRUE.equals(bindingContext.get(NEED_SYNTHETIC_ACCESSOR, descriptor)))) {
accessibleDescriptorIfNeeded(descriptor);
// Not a super call because neither constructors nor private members can be targets of super calls
accessibleDescriptorIfNeeded(descriptor, /* superCallExpression = */ null);
}
}
@@ -352,7 +400,10 @@ public abstract class CodegenContext<T extends DeclarationDescriptor> {
@SuppressWarnings("unchecked")
@NotNull
private <D extends CallableMemberDescriptor> D accessibleDescriptorIfNeeded(@NotNull D descriptor) {
private <D extends CallableMemberDescriptor> D accessibleDescriptorIfNeeded(
@NotNull D descriptor,
@Nullable JetSuperExpression superCallExpression
) {
CallableMemberDescriptor unwrappedDescriptor = DescriptorUtils.unwrapFakeOverride(descriptor);
int flag = getAccessFlags(unwrappedDescriptor);
if ((flag & ACC_PRIVATE) == 0 && (flag & ACC_PROTECTED) == 0) {
@@ -385,7 +436,7 @@ public abstract class CodegenContext<T extends DeclarationDescriptor> {
}
}
return (D) descriptorContext.getAccessor(descriptor);
return (D) descriptorContext.getAccessor(descriptor, superCallExpression);
}
private void addChild(@NotNull CodegenContext child) {
@@ -0,0 +1,49 @@
import test.A
import kotlin.test.assertEquals
open class B : A() {
fun box(): String {
val overriddenMethod: () -> String = {
method()
}
assertEquals("C.method", overriddenMethod())
val superMethod: () -> String = {
super.method()
}
assertEquals("A.method", superMethod())
val overriddenPropertyGetter: () -> String = {
property
}
assertEquals("C.property", overriddenPropertyGetter())
val superPropertyGetter: () -> String = {
super.property
}
assertEquals("A.property", superPropertyGetter())
val overriddenPropertySetter: () -> Unit = {
property = ""
}
overriddenPropertySetter()
val superPropertySetter: () -> Unit = {
super.property = ""
}
superPropertySetter()
assertEquals("C.property;A.property;", state)
return "OK"
}
}
class C : B() {
override fun method() = "C.method"
override var property: String
get() = "C.property"
set(value) { state += "C.property;" }
}
fun box() = C().box()
@@ -0,0 +1,13 @@
package test
abstract class A {
public var state = ""
// These implementations should not be called, because they are overridden in C
protected open fun method(): String = "A.method"
protected open var property: String
get() = "A.property"
set(value) { state += "A.property;" }
}
@@ -37,6 +37,12 @@ public class BlackBoxMultiFileCodegenTestGenerated extends AbstractBlackBoxCodeg
doTestMultiFile(fileName);
}
@TestMetadata("accessorForProtectedInvokeVirtual")
public void testAccessorForProtectedInvokeVirtual() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxMultiFile/accessorForProtectedInvokeVirtual/");
doTestMultiFile(fileName);
}
public void testAllFilesPresentInBoxMultiFile() throws Exception {
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/boxMultiFile"), Pattern.compile("^([^\\.]+)$"), false);
}