Choose proper context for accessor generation: skip inline ones; Fix for KT-6102: Bypass synthetic accessor when inlining lambda which calls private member

#KT-6102 Fixed
This commit is contained in:
Michael Bogdanov
2015-12-14 18:47:29 +03:00
parent 033698c51d
commit 9cad1a912a
22 changed files with 457 additions and 40 deletions
@@ -2122,7 +2122,7 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
if (isBackingFieldInClassCompanion && forceField) {
fieldAccessorKind = FieldAccessorKind.IN_CLASS_COMPANION;
}
else if (syntheticBackingField && context.getParentContext().getContextDescriptor() != containingDeclaration) {
else if (syntheticBackingField && context.getFirstCrossInlineOrNonInlineContext().getParentContext().getContextDescriptor() != containingDeclaration) {
fieldAccessorKind = FieldAccessorKind.FIELD_FROM_LOCAL;
}
boolean isStaticBackingField = DescriptorUtils.isStaticDeclaration(propertyDescriptor) ||
@@ -2163,13 +2163,7 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
if (!skipPropertyAccessors) {
if (!couldUseDirectAccessToProperty(propertyDescriptor, true, isDelegatedProperty, context)) {
if (isSuper && !isJvmInterface(containingDeclaration)) {
CodegenContext c = context.findParentContextWithDescriptor(superCallTarget);
assert c != null : "Couldn't find a context for a super-call: " + propertyDescriptor;
if (c != context.getParentContext()) {
propertyDescriptor = (PropertyDescriptor) c.getAccessor(propertyDescriptor, superCallTarget);
}
}
propertyDescriptor = context.getAccessorForSuperCallIfNeeded(propertyDescriptor, superCallTarget);
propertyDescriptor = context.accessibleDescriptor(propertyDescriptor, superCallTarget);
@@ -2327,15 +2321,8 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
public StackValue invokeFunction(@NotNull Call call, @NotNull ResolvedCall<?> resolvedCall, @NotNull StackValue receiver) {
FunctionDescriptor fd = accessibleFunctionDescriptor(resolvedCall);
ClassDescriptor superCallTarget = getSuperCallTarget(call);
boolean superCall = superCallTarget != null;
if (superCall && !isJvmInterface(fd.getContainingDeclaration())) {
CodegenContext c = context.findParentContextWithDescriptor(superCallTarget);
assert c != null : "Couldn't find a context for a super-call: " + fd;
if (c != context.getParentContext()) {
fd = (FunctionDescriptor) c.getAccessor(fd, superCallTarget);
}
}
fd = context.getAccessorForSuperCallIfNeeded(fd, superCallTarget);
Collection<ExpressionCodegenExtension> codegenExtensions = ExpressionCodegenExtension.Companion.getInstances(state.getProject());
if (!codegenExtensions.isEmpty()) {
@@ -2346,7 +2333,7 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
}
}
Callable callable = resolveToCallable(fd, superCall, resolvedCall);
Callable callable = resolveToCallable(fd, superCallTarget != null, resolvedCall);
return callable.invokeMethodWithArguments(resolvedCall, receiver, this);
}
@@ -134,12 +134,13 @@ public class JvmCodegenUtil {
@NotNull PropertyDescriptor property,
boolean forGetter,
boolean isDelegated,
@NotNull MethodContext context
@NotNull MethodContext contextBeforeInline
) {
if (JetTypeMapper.isAccessor(property)) return false;
CodegenContext context = contextBeforeInline.getFirstCrossInlineOrNonInlineContext();
// Inline functions can't use direct access because a field may not be visible at the call site
if (context.isInlineFunction()) {
if (context.isInlineMethodContext()) {
return false;
}
@@ -164,7 +165,7 @@ public class JvmCodegenUtil {
return Visibilities.isPrivate(property.getVisibility()) || accessor.getModality() == FINAL;
}
private static boolean isDebuggerContext(@NotNull MethodContext context) {
private static boolean isDebuggerContext(@NotNull CodegenContext context) {
KtFile file = DescriptorToSourceUtils.getContainingFile(context.getContextDescriptor());
return file != null && CodeFragmentUtilKt.getSuppressDiagnosticsInDebugMode(file);
}
@@ -37,6 +37,7 @@ import org.jetbrains.org.objectweb.asm.Type;
import java.util.*;
import static org.jetbrains.kotlin.codegen.AsmUtil.getVisibilityAccessFlag;
import static org.jetbrains.kotlin.codegen.JvmCodegenUtil.isJvmInterface;
import static org.jetbrains.org.objectweb.asm.Opcodes.ACC_PRIVATE;
import static org.jetbrains.org.objectweb.asm.Opcodes.ACC_PROTECTED;
@@ -364,11 +365,24 @@ public abstract class CodegenContext<T extends DeclarationDescriptor> {
}
@NotNull
public <D extends CallableMemberDescriptor> D getAccessor(@NotNull D descriptor, @Nullable ClassDescriptor superCallTarget) {
private <D extends CallableMemberDescriptor> D getAccessor(@NotNull D descriptor, @Nullable ClassDescriptor superCallTarget) {
return getAccessor(descriptor, FieldAccessorKind.NORMAL, null, superCallTarget);
}
@SuppressWarnings("unchecked")
@NotNull
public <D extends CallableMemberDescriptor> D getAccessorForSuperCallIfNeeded(@NotNull D descriptor, @Nullable ClassDescriptor superCallTarget) {
if (superCallTarget != null && !isJvmInterface(descriptor.getContainingDeclaration())) {
CodegenContext afterInline = getFirstCrossInlineOrNonInlineContext();
CodegenContext c = afterInline.findParentContextWithDescriptor(superCallTarget);
assert c != null : "Couldn't find a context for a super-call: " + descriptor;
if (c != afterInline.getParentContext()) {
return (D) c.getAccessor(descriptor, superCallTarget);
}
}
return descriptor;
}
@NotNull
public <D extends CallableMemberDescriptor> D getAccessor(
@NotNull D possiblySubstitutedDescriptor,
@@ -506,21 +520,22 @@ public abstract class CodegenContext<T extends DeclarationDescriptor> {
return accessors == null ? Collections.<AccessorForCallableDescriptor<CallableMemberDescriptor>>emptySet() : accessors.values();
}
@SuppressWarnings("unchecked")
@NotNull
public <D extends CallableMemberDescriptor> D accessibleDescriptor(
@NotNull D descriptor,
@Nullable ClassDescriptor superCallTarget
) {
CodegenContext properContext = getFirstCrossInlineOrNonInlineContext();
DeclarationDescriptor enclosing = descriptor.getContainingDeclaration();
boolean isInliningContext = isInlineMethodContext();
boolean isInliningContext = properContext.isInlineMethodContext();
if (!isInliningContext && (
!hasThisDescriptor() ||
enclosing == getThisDescriptor() ||
enclosing == getClassOrPackageParentContext().getContextDescriptor())) {
!properContext.hasThisDescriptor() ||
enclosing == properContext.getThisDescriptor() ||
enclosing == properContext.getClassOrPackageParentContext().getContextDescriptor())) {
return descriptor;
}
return accessibleDescriptorIfNeeded(descriptor, superCallTarget, isInliningContext);
return (D) properContext.accessibleDescriptorIfNeeded(descriptor, superCallTarget, isInliningContext);
}
@SuppressWarnings("unchecked")
@@ -633,18 +648,25 @@ public abstract class CodegenContext<T extends DeclarationDescriptor> {
return value instanceof StackValue.Field && ((StackValue.Field) value).isStaticPut;
}
private boolean isInsideInliningContext() {
CodegenContext current = this;
while (current != null) {
if (current instanceof MethodContext && ((MethodContext) current).isInlineFunction()) {
return true;
}
current = current.getParentContext();
}
return false;
}
private boolean isInlineMethodContext() {
public boolean isInlineMethodContext() {
return this instanceof MethodContext && ((MethodContext) this).isInlineFunction();
}
@NotNull
public CodegenContext getFirstCrossInlineOrNonInlineContext() {
if (!(this instanceof MethodContext)) {
return this;
}
MethodContext context = (MethodContext) this;
if (!context.isInliningLambda() || context.isCrossInline) {
return this;
}
CodegenContext parent = context.getParentContext();
assert parent instanceof ClosureContext : "Parent of inlining lambda body should be ClosureContext, but: " + parent;
parent = parent.getParentContext();
assert parent != null : "Parent context of lambda class context should exist: " + this.contextDescriptor;
return parent.getFirstCrossInlineOrNonInlineContext();
}
}
@@ -39,7 +39,7 @@ public class MethodContext extends CodegenContext<CallableMemberDescriptor> {
// Note: in case of code inside property accessors, functionDescriptor will be that accessor,
// but CodegenContext#contextDescriptor will be the corresponding property
private final FunctionDescriptor functionDescriptor;
private boolean isCrossInline;
public final boolean isCrossInline;
protected MethodContext(
@NotNull FunctionDescriptor functionDescriptor,