Introduce kotlin.Cloneable
- Cloneable is a trait with a single protected member 'clone', which is mapped to java.lang.Cloneable on JVM - 'clone' is non-abstract to be able to call 'super.clone()' in the implementations. Also if you need your class to be Cloneable, most of the time inheriting from Cloneable and calling 'super.clone()' will work - hack 'super.clone()' in JVM intrinsics and TImpl delegation generation - make arrays Cloneable, handle 'clone()' calls in the intrinsic #KT-4890 Fixed
This commit is contained in:
@@ -1505,7 +1505,8 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
|
||||
public void doGenerateBody(@NotNull ExpressionCodegen codegen, @NotNull JvmMethodSignature signature) {
|
||||
DeclarationDescriptor containingDeclaration = traitFun.getContainingDeclaration();
|
||||
if (!DescriptorUtils.isTrait(containingDeclaration)) return;
|
||||
Type traitImplType = typeMapper.mapTraitImpl((ClassDescriptor) containingDeclaration);
|
||||
ClassDescriptor containingTrait = (ClassDescriptor) containingDeclaration;
|
||||
Type traitImplType = typeMapper.mapTraitImpl(containingTrait);
|
||||
|
||||
Method traitMethod = typeMapper.mapSignature(traitFun.getOriginal(), OwnerKind.TRAIT_IMPL).getAsmMethod();
|
||||
|
||||
@@ -1522,7 +1523,14 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
|
||||
reg += argTypes[i].getSize();
|
||||
}
|
||||
|
||||
iv.invokestatic(traitImplType.getInternalName(), traitMethod.getName(), traitMethod.getDescriptor());
|
||||
if (KotlinBuiltIns.getInstance().isCloneable(containingTrait) && traitMethod.getName().equals("clone")) {
|
||||
// A special hack for Cloneable: there's no kotlin/Cloneable$$TImpl class at runtime,
|
||||
// and its 'clone' method is actually located in java/lang/Object
|
||||
iv.invokespecial("java/lang/Object", "clone", "()Ljava/lang/Object;", false);
|
||||
}
|
||||
else {
|
||||
iv.invokestatic(traitImplType.getInternalName(), traitMethod.getName(), traitMethod.getDescriptor());
|
||||
}
|
||||
|
||||
Type returnType = signature.getReturnType();
|
||||
StackValue.onStack(traitMethod.getReturnType()).put(returnType, iv);
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Copyright 2010-2014 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.jet.codegen.intrinsics;
|
||||
|
||||
import com.intellij.psi.PsiElement;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jet.codegen.ExpressionCodegen;
|
||||
import org.jetbrains.jet.codegen.StackValue;
|
||||
import org.jetbrains.jet.lang.psi.JetElement;
|
||||
import org.jetbrains.jet.lang.psi.JetExpression;
|
||||
import org.jetbrains.jet.lang.psi.JetSuperExpression;
|
||||
import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall;
|
||||
import org.jetbrains.jet.lang.resolve.scopes.receivers.ExpressionReceiver;
|
||||
import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverValue;
|
||||
import org.jetbrains.org.objectweb.asm.Type;
|
||||
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static org.jetbrains.jet.lang.resolve.bindingContextUtil.BindingContextUtilPackage.getResolvedCallWithAssert;
|
||||
import static org.jetbrains.jet.lang.resolve.java.AsmTypeConstants.OBJECT_TYPE;
|
||||
|
||||
public class Clone extends IntrinsicMethod {
|
||||
@NotNull
|
||||
@Override
|
||||
protected Type generateImpl(
|
||||
@NotNull ExpressionCodegen codegen,
|
||||
@NotNull InstructionAdapter v,
|
||||
@NotNull Type returnType,
|
||||
@Nullable PsiElement element,
|
||||
@Nullable List<JetExpression> arguments,
|
||||
@Nullable StackValue receiver
|
||||
) {
|
||||
ResolvedCall<?> resolvedCall = getResolvedCallWithAssert(((JetElement) element), codegen.getBindingContext());
|
||||
StackValue.receiver(resolvedCall, receiver, codegen, null).put(OBJECT_TYPE, v);
|
||||
if (isSuperCall(resolvedCall)) {
|
||||
v.invokespecial("java/lang/Object", "clone", "()Ljava/lang/Object;", false);
|
||||
}
|
||||
else {
|
||||
v.invokevirtual("java/lang/Object", "clone", "()Ljava/lang/Object;", false);
|
||||
}
|
||||
return OBJECT_TYPE;
|
||||
}
|
||||
|
||||
private static boolean isSuperCall(@NotNull ResolvedCall<?> resolvedCall) {
|
||||
ReceiverValue thisObject = resolvedCall.getThisObject();
|
||||
return thisObject instanceof ExpressionReceiver &&
|
||||
((ExpressionReceiver) thisObject).getExpression() instanceof JetSuperExpression;
|
||||
}
|
||||
}
|
||||
@@ -61,6 +61,7 @@ public class IntrinsicMethods {
|
||||
private static final EnumValues ENUM_VALUES = new EnumValues();
|
||||
private static final EnumValueOf ENUM_VALUE_OF = new EnumValueOf();
|
||||
private static final ToString TO_STRING = new ToString();
|
||||
private static final Clone CLONE = new Clone();
|
||||
|
||||
private static final FqNameUnsafe KOTLIN_ANY_FQ_NAME = DescriptorUtils.getFqName(KotlinBuiltIns.getInstance().getAny());
|
||||
private static final FqNameUnsafe KOTLIN_STRING_FQ_NAME = DescriptorUtils.getFqName(KotlinBuiltIns.getInstance().getString());
|
||||
@@ -121,6 +122,8 @@ public class IntrinsicMethods {
|
||||
declareIntrinsicFunction("CharSequence", "get", 1, new StringGetChar());
|
||||
declareIntrinsicFunction("String", "get", 1, new StringGetChar());
|
||||
|
||||
declareIntrinsicFunction("Cloneable", "clone", 0, CLONE);
|
||||
|
||||
intrinsicsMap.registerIntrinsic(BUILT_INS_PACKAGE_FQ_NAME, KOTLIN_ANY_FQ_NAME, "toString", 0, TO_STRING);
|
||||
intrinsicsMap.registerIntrinsic(BUILT_INS_PACKAGE_FQ_NAME, KOTLIN_ANY_FQ_NAME, "equals", 1, EQUALS);
|
||||
intrinsicsMap.registerIntrinsic(BUILT_INS_PACKAGE_FQ_NAME, KOTLIN_ANY_FQ_NAME, "identityEquals", 1, IDENTITY_EQUALS);
|
||||
@@ -148,6 +151,7 @@ public class IntrinsicMethods {
|
||||
declareIntrinsicProperty("Array", "indices", ARRAY_INDICES);
|
||||
declareIntrinsicFunction("Array", "set", 2, ARRAY_SET);
|
||||
declareIntrinsicFunction("Array", "get", 1, ARRAY_GET);
|
||||
declareIntrinsicFunction("Array", "clone", 0, CLONE);
|
||||
declareIterator("Array");
|
||||
}
|
||||
|
||||
@@ -157,6 +161,7 @@ public class IntrinsicMethods {
|
||||
declareIntrinsicProperty(arrayTypeName, "indices", ARRAY_INDICES);
|
||||
declareIntrinsicFunction(arrayTypeName, "set", 2, ARRAY_SET);
|
||||
declareIntrinsicFunction(arrayTypeName, "get", 1, ARRAY_GET);
|
||||
declareIntrinsicFunction(arrayTypeName, "clone", 0, CLONE);
|
||||
declareIterator(arrayTypeName);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user