Minor: extract CallReceiver to a top-level class, move code around
This commit is contained in:
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2282,12 +2282,12 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
|||||||
// But the problem is that we should leave the receiver itself on the stack, so we store it in a temporary variable.
|
// 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) {
|
if (isSuspendCall && isSafeCallOrOnStack) {
|
||||||
boolean bothReceivers =
|
boolean bothReceivers =
|
||||||
receiver instanceof StackValue.CallReceiver
|
receiver instanceof CallReceiver
|
||||||
&& ((StackValue.CallReceiver) receiver).getDispatchReceiver().type.getSort() != Type.VOID
|
&& ((CallReceiver) receiver).getDispatchReceiver().type.getSort() != Type.VOID
|
||||||
&& ((StackValue.CallReceiver) receiver).getExtensionReceiver().type.getSort() != Type.VOID;
|
&& ((CallReceiver) receiver).getExtensionReceiver().type.getSort() != Type.VOID;
|
||||||
Type firstReceiverType =
|
Type firstReceiverType =
|
||||||
bothReceivers
|
bothReceivers
|
||||||
? ((StackValue.CallReceiver) receiver).getDispatchReceiver().type
|
? ((CallReceiver) receiver).getDispatchReceiver().type
|
||||||
: receiver.type;
|
: receiver.type;
|
||||||
|
|
||||||
Type secondReceiverType = bothReceivers ? receiver.type : null;
|
Type secondReceiverType = bothReceivers ? receiver.type : null;
|
||||||
|
|||||||
@@ -19,7 +19,6 @@ package org.jetbrains.kotlin.codegen;
|
|||||||
import com.intellij.psi.tree.IElementType;
|
import com.intellij.psi.tree.IElementType;
|
||||||
import kotlin.Unit;
|
import kotlin.Unit;
|
||||||
import kotlin.collections.ArraysKt;
|
import kotlin.collections.ArraysKt;
|
||||||
import kotlin.collections.CollectionsKt;
|
|
||||||
import kotlin.jvm.functions.Function1;
|
import kotlin.jvm.functions.Function1;
|
||||||
import org.jetbrains.annotations.Contract;
|
import org.jetbrains.annotations.Contract;
|
||||||
import org.jetbrains.annotations.NotNull;
|
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.KotlinBuiltIns;
|
||||||
import org.jetbrains.kotlin.builtins.PrimitiveType;
|
import org.jetbrains.kotlin.builtins.PrimitiveType;
|
||||||
import org.jetbrains.kotlin.codegen.intrinsics.IntrinsicMethods;
|
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.codegen.state.KotlinTypeMapper;
|
||||||
import org.jetbrains.kotlin.descriptors.*;
|
import org.jetbrains.kotlin.descriptors.*;
|
||||||
import org.jetbrains.kotlin.descriptors.impl.SyntheticFieldDescriptor;
|
import org.jetbrains.kotlin.descriptors.impl.SyntheticFieldDescriptor;
|
||||||
@@ -518,9 +515,11 @@ public abstract class StackValue {
|
|||||||
descriptor
|
descriptor
|
||||||
);
|
);
|
||||||
StackValue extensionReceiver = genReceiver(receiver, codegen, resolvedCall, callableMethod, callExtensionReceiver, true);
|
StackValue extensionReceiver = genReceiver(receiver, codegen, resolvedCall, callableMethod, callExtensionReceiver, true);
|
||||||
Type type = CallReceiver.calcType(resolvedCall, dispatchReceiverParameter, extensionReceiverParameter, codegen.typeMapper, callableMethod, codegen.getState());
|
return CallReceiver.generateCallReceiver(
|
||||||
assert type != null : "Could not map receiver type for " + resolvedCall;
|
resolvedCall, codegen, callableMethod,
|
||||||
return new CallReceiver(dispatchReceiver, extensionReceiver, type);
|
dispatchReceiverParameter, dispatchReceiver,
|
||||||
|
extensionReceiverParameter, extensionReceiver
|
||||||
|
);
|
||||||
}
|
}
|
||||||
return receiver;
|
return receiver;
|
||||||
}
|
}
|
||||||
@@ -569,14 +568,13 @@ public abstract class StackValue {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Contract("null -> false")
|
@Contract("null -> false")
|
||||||
private static boolean isLocalFunCall(@Nullable Callable callableMethod) {
|
static boolean isLocalFunCall(@Nullable Callable callableMethod) {
|
||||||
return callableMethod != null && callableMethod.getGenerateCalleeType() != null;
|
return callableMethod != null && callableMethod.getGenerateCalleeType() != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static StackValue receiverWithoutReceiverArgument(StackValue receiverWithParameter) {
|
public static StackValue receiverWithoutReceiverArgument(StackValue receiverWithParameter) {
|
||||||
if (receiverWithParameter instanceof CallReceiver) {
|
if (receiverWithParameter instanceof CallReceiver) {
|
||||||
CallReceiver callReceiver = (CallReceiver) receiverWithParameter;
|
return ((CallReceiver) receiverWithParameter).withoutReceiverArgument();
|
||||||
return new CallReceiver(callReceiver.dispatchReceiver, none(), callReceiver.type);
|
|
||||||
}
|
}
|
||||||
return receiverWithParameter;
|
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 abstract static class StackValueWithSimpleReceiver extends StackValue {
|
||||||
|
|
||||||
public final boolean isStaticPut;
|
public final boolean isStaticPut;
|
||||||
|
|||||||
Reference in New Issue
Block a user