From 3f34a97880cb2335e3d1a98e912e8db84c13206d Mon Sep 17 00:00:00 2001 From: Dmitry Petrov Date: Fri, 21 Jul 2017 10:19:57 +0300 Subject: [PATCH] Minor: extract CallReceiver to a top-level class, move code around --- .../kotlin/codegen/CallReceiver.java | 158 ++++++++++++++++++ .../kotlin/codegen/ExpressionCodegen.java | 8 +- .../jetbrains/kotlin/codegen/StackValue.java | 111 +----------- 3 files changed, 169 insertions(+), 108 deletions(-) create mode 100644 compiler/backend/src/org/jetbrains/kotlin/codegen/CallReceiver.java diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/CallReceiver.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/CallReceiver.java new file mode 100644 index 00000000000..27da29f5dd7 --- /dev/null +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/CallReceiver.java @@ -0,0 +1,158 @@ +/* + * Copyright 2010-2017 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.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.kotlin.codegen.intrinsics.JavaClassProperty; +import org.jetbrains.kotlin.codegen.state.GenerationState; +import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper; +import org.jetbrains.kotlin.descriptors.*; +import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall; +import org.jetbrains.org.objectweb.asm.Type; +import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter; + +public class CallReceiver extends StackValue { + private final StackValue dispatchReceiver; + private final StackValue extensionReceiver; + + private CallReceiver( + @NotNull StackValue dispatchReceiver, + @NotNull StackValue extensionReceiver, + @NotNull Type type + ) { + super(type, dispatchReceiver.canHaveSideEffects() || extensionReceiver.canHaveSideEffects()); + this.dispatchReceiver = dispatchReceiver; + this.extensionReceiver = extensionReceiver; + } + + public StackValue withoutReceiverArgument() { + return new CallReceiver(dispatchReceiver, none(), type); + } + + public static StackValue generateCallReceiver( + @NotNull ResolvedCall resolvedCall, + @NotNull ExpressionCodegen codegen, + @Nullable Callable callableMethod, + @Nullable ReceiverParameterDescriptor dispatchReceiverParameter, + @NotNull StackValue dispatchReceiver, + @Nullable ReceiverParameterDescriptor extensionReceiverParameter, + @NotNull StackValue extensionReceiver + ) { + KotlinTypeMapper typeMapper = codegen.typeMapper; + GenerationState state = codegen.getState(); + + Type type; + if (extensionReceiverParameter != null) { + type = calcExtensionReceiverType(resolvedCall, extensionReceiverParameter, typeMapper, callableMethod, state); + } + else if (dispatchReceiverParameter != null) { + type = calcDispatchReceiverType(resolvedCall, dispatchReceiverParameter, typeMapper, callableMethod); + } + else if (isLocalFunCall(callableMethod)) { + type = callableMethod.getGenerateCalleeType(); + } + else { + type = Type.VOID_TYPE; + } + + assert type != null : "Could not map receiver type for " + resolvedCall; + + return new CallReceiver(dispatchReceiver, extensionReceiver, type); + } + + private static Type calcDispatchReceiverType( + @NotNull ResolvedCall resolvedCall, + @Nullable ReceiverParameterDescriptor dispatchReceiver, + @NotNull KotlinTypeMapper typeMapper, + @Nullable Callable callableMethod + ) { + if (dispatchReceiver == null) return null; + + CallableDescriptor descriptor = resolvedCall.getResultingDescriptor(); + + if (CodegenUtilKt.isJvmStaticInObjectOrClass(descriptor)) { + return Type.VOID_TYPE; + } + + if (callableMethod != null) { + return callableMethod.getDispatchReceiverType(); + } + + // Extract the receiver from the resolved call, workarounding the fact that ResolvedCall#dispatchReceiver doesn't have + // all the needed information, for example there's no way to find out whether or not a smart cast was applied to the receiver. + DeclarationDescriptor container = descriptor.getContainingDeclaration(); + if (container instanceof ClassDescriptor) { + return typeMapper.mapClass((ClassDescriptor) container); + } + + return typeMapper.mapType(dispatchReceiver); + } + + private static Type calcExtensionReceiverType( + @NotNull ResolvedCall resolvedCall, + @Nullable ReceiverParameterDescriptor extensionReceiver, + @NotNull KotlinTypeMapper typeMapper, + @Nullable Callable callableMethod, + @NotNull GenerationState state + ) { + if (extensionReceiver == null) return null; + + CallableDescriptor descriptor = resolvedCall.getCandidateDescriptor(); + + if (descriptor instanceof PropertyDescriptor && + // hackaround: boxing changes behaviour of T.javaClass intrinsic + state.getIntrinsics().getIntrinsic((PropertyDescriptor) descriptor) != JavaClassProperty.INSTANCE + ) { + ReceiverParameterDescriptor receiverCandidate = descriptor.getExtensionReceiverParameter(); + assert receiverCandidate != null; + return typeMapper.mapType(receiverCandidate.getType()); + } + + return callableMethod != null ? callableMethod.getExtensionReceiverType() : typeMapper.mapType(extensionReceiver.getType()); + } + + @Override + public void putSelector(@NotNull Type type, @NotNull InstructionAdapter v) { + StackValue currentExtensionReceiver = extensionReceiver; + boolean hasExtensionReceiver = extensionReceiver != none(); + if (extensionReceiver instanceof SafeCall) { + currentExtensionReceiver.put(currentExtensionReceiver.type, v); + currentExtensionReceiver = StackValue.onStack(currentExtensionReceiver.type); + } + + dispatchReceiver.put(hasExtensionReceiver ? dispatchReceiver.type : type, v); + + currentExtensionReceiver + .moveToTopOfStack(hasExtensionReceiver ? type : currentExtensionReceiver.type, v, dispatchReceiver.type.getSize()); + } + + @Override + public void dup(@NotNull InstructionAdapter v, boolean withReceiver) { + AsmUtil.dup(v, extensionReceiver.type, dispatchReceiver.type); + } + + @NotNull + public StackValue getDispatchReceiver() { + return dispatchReceiver; + } + + @NotNull + public StackValue getExtensionReceiver() { + return extensionReceiver; + } +} diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java index 7f56d86c3c8..305c35ede40 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java @@ -2282,12 +2282,12 @@ public class ExpressionCodegen extends KtVisitor impleme // But the problem is that we should leave the receiver itself on the stack, so we store it in a temporary variable. if (isSuspendCall && isSafeCallOrOnStack) { boolean bothReceivers = - receiver instanceof StackValue.CallReceiver - && ((StackValue.CallReceiver) receiver).getDispatchReceiver().type.getSort() != Type.VOID - && ((StackValue.CallReceiver) receiver).getExtensionReceiver().type.getSort() != Type.VOID; + receiver instanceof CallReceiver + && ((CallReceiver) receiver).getDispatchReceiver().type.getSort() != Type.VOID + && ((CallReceiver) receiver).getExtensionReceiver().type.getSort() != Type.VOID; Type firstReceiverType = bothReceivers - ? ((StackValue.CallReceiver) receiver).getDispatchReceiver().type + ? ((CallReceiver) receiver).getDispatchReceiver().type : receiver.type; Type secondReceiverType = bothReceivers ? receiver.type : null; diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/StackValue.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/StackValue.java index 2683910afdd..d511bcede73 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/StackValue.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/StackValue.java @@ -19,7 +19,6 @@ package org.jetbrains.kotlin.codegen; import com.intellij.psi.tree.IElementType; import kotlin.Unit; import kotlin.collections.ArraysKt; -import kotlin.collections.CollectionsKt; import kotlin.jvm.functions.Function1; import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.NotNull; @@ -27,8 +26,6 @@ import org.jetbrains.annotations.Nullable; import org.jetbrains.kotlin.builtins.KotlinBuiltIns; import org.jetbrains.kotlin.builtins.PrimitiveType; import org.jetbrains.kotlin.codegen.intrinsics.IntrinsicMethods; -import org.jetbrains.kotlin.codegen.intrinsics.JavaClassProperty; -import org.jetbrains.kotlin.codegen.state.GenerationState; import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper; import org.jetbrains.kotlin.descriptors.*; import org.jetbrains.kotlin.descriptors.impl.SyntheticFieldDescriptor; @@ -518,9 +515,11 @@ public abstract class StackValue { descriptor ); StackValue extensionReceiver = genReceiver(receiver, codegen, resolvedCall, callableMethod, callExtensionReceiver, true); - Type type = CallReceiver.calcType(resolvedCall, dispatchReceiverParameter, extensionReceiverParameter, codegen.typeMapper, callableMethod, codegen.getState()); - assert type != null : "Could not map receiver type for " + resolvedCall; - return new CallReceiver(dispatchReceiver, extensionReceiver, type); + return CallReceiver.generateCallReceiver( + resolvedCall, codegen, callableMethod, + dispatchReceiverParameter, dispatchReceiver, + extensionReceiverParameter, extensionReceiver + ); } return receiver; } @@ -569,14 +568,13 @@ public abstract class StackValue { } @Contract("null -> false") - private static boolean isLocalFunCall(@Nullable Callable callableMethod) { + static boolean isLocalFunCall(@Nullable Callable callableMethod) { return callableMethod != null && callableMethod.getGenerateCalleeType() != null; } public static StackValue receiverWithoutReceiverArgument(StackValue receiverWithParameter) { if (receiverWithParameter instanceof CallReceiver) { - CallReceiver callReceiver = (CallReceiver) receiverWithParameter; - return new CallReceiver(callReceiver.dispatchReceiver, none(), callReceiver.type); + return ((CallReceiver) receiverWithParameter).withoutReceiverArgument(); } return receiverWithParameter; } @@ -1517,101 +1515,6 @@ public abstract class StackValue { } } - public static class CallReceiver extends StackValue { - private final StackValue dispatchReceiver; - private final StackValue extensionReceiver; - - public CallReceiver( - @NotNull StackValue dispatchReceiver, - @NotNull StackValue extensionReceiver, - @NotNull Type type - ) { - super(type, dispatchReceiver.canHaveSideEffects() || extensionReceiver.canHaveSideEffects()); - this.dispatchReceiver = dispatchReceiver; - this.extensionReceiver = extensionReceiver; - } - - @Nullable - public static Type calcType( - @NotNull ResolvedCall resolvedCall, - @Nullable ReceiverParameterDescriptor dispatchReceiver, - @Nullable ReceiverParameterDescriptor extensionReceiver, - @NotNull KotlinTypeMapper typeMapper, - @Nullable Callable callableMethod, - @NotNull GenerationState state - ) { - if (extensionReceiver != null) { - CallableDescriptor descriptor = resolvedCall.getCandidateDescriptor(); - - if (descriptor instanceof PropertyDescriptor && - // hackaround: boxing changes behaviour of T.javaClass intrinsic - state.getIntrinsics().getIntrinsic((PropertyDescriptor) descriptor) != JavaClassProperty.INSTANCE - ) { - ReceiverParameterDescriptor receiverCandidate = descriptor.getExtensionReceiverParameter(); - assert receiverCandidate != null; - return typeMapper.mapType(receiverCandidate.getType()); - } - - return callableMethod != null ? callableMethod.getExtensionReceiverType() : typeMapper.mapType(extensionReceiver.getType()); - } - else if (dispatchReceiver != null) { - CallableDescriptor descriptor = resolvedCall.getResultingDescriptor(); - - if (CodegenUtilKt.isJvmStaticInObjectOrClass(descriptor)) { - return Type.VOID_TYPE; - } - - if (callableMethod != null) { - return callableMethod.getDispatchReceiverType(); - } - - // Extract the receiver from the resolved call, workarounding the fact that ResolvedCall#dispatchReceiver doesn't have - // all the needed information, for example there's no way to find out whether or not a smart cast was applied to the receiver. - DeclarationDescriptor container = descriptor.getContainingDeclaration(); - if (container instanceof ClassDescriptor) { - return typeMapper.mapClass((ClassDescriptor) container); - } - - return typeMapper.mapType(dispatchReceiver); - } - else if (isLocalFunCall(callableMethod)) { - return callableMethod.getGenerateCalleeType(); - } - - return Type.VOID_TYPE; - } - - @Override - public void putSelector(@NotNull Type type, @NotNull InstructionAdapter v) { - StackValue currentExtensionReceiver = extensionReceiver; - boolean hasExtensionReceiver = extensionReceiver != none(); - if (extensionReceiver instanceof StackValue.SafeCall) { - currentExtensionReceiver.put(currentExtensionReceiver.type, v); - currentExtensionReceiver = StackValue.onStack(currentExtensionReceiver.type); - } - - dispatchReceiver.put(hasExtensionReceiver ? dispatchReceiver.type : type, v); - - currentExtensionReceiver - .moveToTopOfStack(hasExtensionReceiver ? type : currentExtensionReceiver.type, v, dispatchReceiver.type.getSize()); - } - - @Override - public void dup(@NotNull InstructionAdapter v, boolean withReceiver) { - AsmUtil.dup(v, extensionReceiver.type, dispatchReceiver.type); - } - - @NotNull - public StackValue getDispatchReceiver() { - return dispatchReceiver; - } - - @NotNull - public StackValue getExtensionReceiver() { - return extensionReceiver; - } - } - public abstract static class StackValueWithSimpleReceiver extends StackValue { public final boolean isStaticPut;