Support boxing/unboxing for method return types

This commit is contained in:
Mikhail Zarechenskiy
2018-02-05 11:43:10 +03:00
parent 390c214943
commit c5c8d84719
15 changed files with 210 additions and 100 deletions
@@ -110,7 +110,7 @@ public class CallReceiver extends StackValue {
return new AsmTypeAndKotlinType(typeMapper.mapType(classDescriptor), classDescriptor.getDefaultType());
}
//noinspection ConstantConditions
return new AsmTypeAndKotlinType(callableMethod.getDispatchReceiverType(), null);
return new AsmTypeAndKotlinType(callableMethod.getDispatchReceiverType(), callableMethod.getDispatchReceiverKotlinType());
}
// Extract the receiver from the resolved call, workarounding the fact that ResolvedCall#dispatchReceiver doesn't have
@@ -147,7 +147,7 @@ public class CallReceiver extends StackValue {
}
return callableMethod != null ?
new AsmTypeAndKotlinType(callableMethod.getExtensionReceiverType(), null) :
new AsmTypeAndKotlinType(callableMethod.getExtensionReceiverType(), callableMethod.getExtensionReceiverKotlinType()) :
new AsmTypeAndKotlinType(typeMapper.mapType(extensionReceiver.getType()), extensionReceiver.getType());
}
@@ -1,22 +1,12 @@
/*
* 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.
* Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.codegen
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.org.objectweb.asm.Type
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
@@ -25,8 +15,12 @@ interface Callable {
val dispatchReceiverType: Type?
val dispatchReceiverKotlinType: KotlinType?
val extensionReceiverType: Type?
val extensionReceiverKotlinType: KotlinType?
val generateCalleeType: Type?
val valueParameterTypes: List<Type>
@@ -35,12 +29,14 @@ interface Callable {
val returnType: Type
val returnKotlinType: KotlinType?
fun genInvokeInstruction(v: InstructionAdapter)
fun isStaticCall(): Boolean
fun invokeMethodWithArguments(resolvedCall: ResolvedCall<*>, receiver: StackValue, codegen: ExpressionCodegen): StackValue {
return StackValue.functionCall(returnType) {
return StackValue.functionCall(returnType, resolvedCall.resultingDescriptor.returnType) {
codegen.invokeMethodWithArguments(this, resolvedCall, receiver)
}
}
@@ -1,17 +1,6 @@
/*
* 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.
* Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.codegen
@@ -20,6 +9,7 @@ import org.jetbrains.kotlin.load.java.JvmAbi
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodParameterKind
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodParameterSignature
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.org.objectweb.asm.Opcodes
import org.jetbrains.org.objectweb.asm.Opcodes.INVOKESPECIAL
import org.jetbrains.org.objectweb.asm.Opcodes.INVOKESTATIC
@@ -35,8 +25,11 @@ class CallableMethod(
private val signature: JvmMethodSignature,
private val invokeOpcode: Int,
override val dispatchReceiverType: Type?,
override val dispatchReceiverKotlinType: KotlinType?,
override val extensionReceiverType: Type?,
override val extensionReceiverKotlinType: KotlinType?,
override val generateCalleeType: Type?,
override val returnKotlinType: KotlinType?,
private val isInterfaceMethod: Boolean = Opcodes.INVOKEINTERFACE == invokeOpcode
) : Callable {
fun getValueParameters(): List<JvmMethodParameterSignature> =
@@ -3879,7 +3879,7 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
@NotNull
public StackValue generateConstructorCall(@NotNull ResolvedCall<?> resolvedCall, @NotNull Type objectType) {
return StackValue.functionCall(objectType, v -> {
return StackValue.functionCall(objectType, null, v -> {
v.anew(objectType);
v.dup();
@@ -717,11 +717,15 @@ public abstract class StackValue {
}
public static StackValue operation(Type type, Function1<InstructionAdapter, Unit> lambda) {
return new OperationStackValue(type, lambda);
return operation(type, null, lambda);
}
public static StackValue functionCall(Type type, Function1<InstructionAdapter, Unit> lambda) {
return new FunctionCallStackValue(type, lambda);
public static StackValue operation(Type type, KotlinType kotlinType, Function1<InstructionAdapter, Unit> lambda) {
return new OperationStackValue(type, kotlinType, lambda);
}
public static StackValue functionCall(Type type, KotlinType kotlinType, Function1<InstructionAdapter, Unit> lambda) {
return new FunctionCallStackValue(type, kotlinType, lambda);
}
public static boolean couldSkipReceiverOnStaticCall(StackValue value) {
@@ -60,7 +60,11 @@ class StackValueWithLeaveTask(
}
}
open class OperationStackValue(resultType: Type, val lambda: (v: InstructionAdapter) -> Unit) : StackValue(resultType) {
open class OperationStackValue(
resultType: Type,
resultKotlinType: KotlinType?,
val lambda: (v: InstructionAdapter) -> Unit
) : StackValue(resultType, resultKotlinType) {
override fun putSelector(type: Type, kotlinType: KotlinType?, v: InstructionAdapter) {
lambda(v)
@@ -68,7 +72,11 @@ open class OperationStackValue(resultType: Type, val lambda: (v: InstructionAdap
}
}
class FunctionCallStackValue(resultType: Type, lambda: (v: InstructionAdapter) -> Unit) : OperationStackValue(resultType, lambda)
class FunctionCallStackValue(
resultType: Type,
resultKotlinType: KotlinType?,
lambda: (v: InstructionAdapter) -> Unit
) : OperationStackValue(resultType, resultKotlinType, lambda)
fun ValueParameterDescriptor.findJavaDefaultArgumentValue(targetType: Type, typeMapper: KotlinTypeMapper): StackValue {
val descriptorWithDefaultValue = DFS.dfs(
@@ -1,17 +1,6 @@
/*
* 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.
* Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.codegen.intrinsics
@@ -19,6 +8,7 @@ package org.jetbrains.kotlin.codegen.intrinsics
import org.jetbrains.kotlin.codegen.AsmUtil
import org.jetbrains.kotlin.codegen.Callable
import org.jetbrains.kotlin.codegen.CallableMethod
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.org.objectweb.asm.Type
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
@@ -52,6 +42,15 @@ open class IntrinsicCallable(
override val parameterTypes: Array<Type>
get() = throw UnsupportedOperationException()
override val dispatchReceiverKotlinType: KotlinType?
get() = null
override val extensionReceiverKotlinType: KotlinType?
get() = null
override val returnKotlinType: KotlinType?
get() = null
override fun isStaticCall() = false
override val generateCalleeType: Type?
@@ -745,10 +745,11 @@ public class KotlinTypeMapper {
if (descriptor instanceof ConstructorDescriptor) {
JvmMethodSignature method = mapSignatureSkipGeneric(descriptor.getOriginal());
Type owner = mapOwner(descriptor);
String defaultImplDesc = mapDefaultMethod(descriptor.getOriginal(), OwnerKind.IMPLEMENTATION).getDescriptor();
FunctionDescriptor originalDescriptor = descriptor.getOriginal();
String defaultImplDesc = mapDefaultMethod(originalDescriptor, OwnerKind.IMPLEMENTATION).getDescriptor();
return new CallableMethod(
owner, owner, defaultImplDesc, method, INVOKESPECIAL,
null, null, null, false
null, null, null, null, null, originalDescriptor.getReturnType(), false
);
}
@@ -764,11 +765,13 @@ public class KotlinTypeMapper {
FunctionDescriptor functionDescriptor = findSuperDeclaration(descriptor.getOriginal(), superCall);
JvmMethodSignature signature;
KotlinType returnKotlinType;
Type owner;
Type ownerForDefaultImpl;
FunctionDescriptor baseMethodDescriptor;
int invokeOpcode;
Type thisClass;
KotlinType dispatchReceiverKotlinType;
boolean isInterfaceMember = false;
if (functionParent instanceof ClassDescriptor) {
@@ -790,15 +793,19 @@ public class KotlinTypeMapper {
if (isInterface && (superCall || descriptor.getVisibility() == Visibilities.PRIVATE || isAccessor(descriptor))) {
thisClass = mapClass(currentOwner);
dispatchReceiverKotlinType = currentOwner.getDefaultType();
if (declarationOwner instanceof JavaClassDescriptor || isJvm8InterfaceWithDefaults(declarationOwner)) {
invokeOpcode = INVOKESPECIAL;
signature = mapSignatureSkipGeneric(functionDescriptor);
returnKotlinType = functionDescriptor.getReturnType();
owner = thisClass;
isInterfaceMember = true;
}
else {
invokeOpcode = INVOKESTATIC;
signature = mapSignatureSkipGeneric(descriptor.getOriginal(), OwnerKind.DEFAULT_IMPLS);
FunctionDescriptor originalDescriptor = descriptor.getOriginal();
signature = mapSignatureSkipGeneric(originalDescriptor, OwnerKind.DEFAULT_IMPLS);
returnKotlinType = originalDescriptor.getReturnType();
owner = mapDefaultImpls(currentOwner);
}
}
@@ -834,41 +841,53 @@ public class KotlinTypeMapper {
signature = isInsideInlineClass
? mapSignatureForInlineErasedClassSkipGeneric(functionToCall)
: mapSignatureSkipGeneric(functionToCall);
returnKotlinType = functionToCall.getReturnType();
ClassDescriptor receiver = (currentIsInterface && !originalIsInterface) || currentOwner instanceof FunctionClassDescriptor
? declarationOwner
: currentOwner;
owner = isInsideInlineClass ? mapErasedInlineClass(receiver) : mapClass(receiver);
thisClass = owner;
dispatchReceiverKotlinType = receiver.getDefaultType();
}
}
else {
signature = mapSignatureSkipGeneric(functionDescriptor.getOriginal());
FunctionDescriptor originalDescriptor = functionDescriptor.getOriginal();
signature = mapSignatureSkipGeneric(originalDescriptor);
returnKotlinType = originalDescriptor.getReturnType();
owner = mapOwner(functionDescriptor);
ownerForDefaultImpl = owner;
baseMethodDescriptor = functionDescriptor;
if (functionParent instanceof PackageFragmentDescriptor) {
invokeOpcode = INVOKESTATIC;
thisClass = null;
dispatchReceiverKotlinType = null;
}
else if (functionDescriptor instanceof ConstructorDescriptor) {
invokeOpcode = INVOKESPECIAL;
thisClass = null;
dispatchReceiverKotlinType = null;
}
else {
invokeOpcode = INVOKEVIRTUAL;
thisClass = owner;
DeclarationDescriptor ownerDescriptor = functionDescriptor.getContainingDeclaration();
dispatchReceiverKotlinType = ownerDescriptor instanceof ClassDescriptor ?
((ClassDescriptor) ownerDescriptor).getDefaultType() : null;
}
}
Type calleeType = isLocalFunction(functionDescriptor) ? owner : null;
Type receiverParameterType;
KotlinType extensionReceiverKotlinType;
ReceiverParameterDescriptor receiverParameter = functionDescriptor.getOriginal().getExtensionReceiverParameter();
if (receiverParameter != null) {
receiverParameterType = mapType(receiverParameter.getType());
extensionReceiverKotlinType = receiverParameter.getType();
receiverParameterType = mapType(extensionReceiverKotlinType);
}
else {
extensionReceiverKotlinType = null;
receiverParameterType = null;
}
@@ -876,8 +895,9 @@ public class KotlinTypeMapper {
return new CallableMethod(
owner, ownerForDefaultImpl, defaultImplDesc, signature, invokeOpcode,
thisClass, receiverParameterType, calleeType,
isJvm8Target ? isInterfaceMember : invokeOpcode == INVOKEINTERFACE );
thisClass, dispatchReceiverKotlinType, receiverParameterType, extensionReceiverKotlinType, calleeType, returnKotlinType,
isJvm8Target ? isInterfaceMember : invokeOpcode == INVOKEINTERFACE
);
}
private boolean isJvm8InterfaceWithDefaults(@NotNull ClassDescriptor ownerForDefault) {