Wrap property reference instance before storing to static field
This commit is contained in:
@@ -37,6 +37,7 @@ import org.jetbrains.kotlin.resolve.BindingContext;
|
|||||||
import org.jetbrains.kotlin.resolve.DescriptorUtils;
|
import org.jetbrains.kotlin.resolve.DescriptorUtils;
|
||||||
import org.jetbrains.kotlin.types.JetType;
|
import org.jetbrains.kotlin.types.JetType;
|
||||||
import org.jetbrains.kotlin.types.expressions.OperatorConventions;
|
import org.jetbrains.kotlin.types.expressions.OperatorConventions;
|
||||||
|
import org.jetbrains.kotlin.utils.UtilsPackage;
|
||||||
import org.jetbrains.org.objectweb.asm.MethodVisitor;
|
import org.jetbrains.org.objectweb.asm.MethodVisitor;
|
||||||
import org.jetbrains.org.objectweb.asm.Type;
|
import org.jetbrains.org.objectweb.asm.Type;
|
||||||
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter;
|
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter;
|
||||||
@@ -202,7 +203,7 @@ public class ClosureCodegen extends MemberCodegen<JetElement> {
|
|||||||
this.constructor = generateConstructor();
|
this.constructor = generateConstructor();
|
||||||
|
|
||||||
if (isConst(closure)) {
|
if (isConst(closure)) {
|
||||||
generateConstInstance(asmType);
|
generateConstInstance(asmType, asmType, UtilsPackage.<InstructionAdapter>doNothing());
|
||||||
}
|
}
|
||||||
|
|
||||||
genClosureFields(closure, v, typeMapper);
|
genClosureFields(closure, v, typeMapper);
|
||||||
|
|||||||
@@ -17,7 +17,9 @@
|
|||||||
package org.jetbrains.kotlin.codegen;
|
package org.jetbrains.kotlin.codegen;
|
||||||
|
|
||||||
import com.intellij.openapi.progress.ProcessCanceledException;
|
import com.intellij.openapi.progress.ProcessCanceledException;
|
||||||
|
import kotlin.Unit;
|
||||||
import kotlin.jvm.functions.Function0;
|
import kotlin.jvm.functions.Function0;
|
||||||
|
import kotlin.jvm.functions.Function1;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
import org.jetbrains.kotlin.codegen.context.*;
|
import org.jetbrains.kotlin.codegen.context.*;
|
||||||
@@ -533,15 +535,21 @@ public abstract class MemberCodegen<T extends JetElement/* TODO: & JetDeclaratio
|
|||||||
return sourceMapper;
|
return sourceMapper;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void generateConstInstance(@NotNull Type asmType) {
|
protected void generateConstInstance(
|
||||||
v.newField(OtherOrigin(element), ACC_STATIC | ACC_FINAL | ACC_PUBLIC, JvmAbi.INSTANCE_FIELD, asmType.getDescriptor(), null, null);
|
@NotNull Type thisAsmType,
|
||||||
|
@NotNull Type fieldAsmType,
|
||||||
|
@NotNull Function1<InstructionAdapter, Unit> initialization
|
||||||
|
) {
|
||||||
|
v.newField(OtherOrigin(element), ACC_STATIC | ACC_FINAL | ACC_PUBLIC, JvmAbi.INSTANCE_FIELD, fieldAsmType.getDescriptor(),
|
||||||
|
null, null);
|
||||||
|
|
||||||
if (state.getClassBuilderMode() == ClassBuilderMode.FULL) {
|
if (state.getClassBuilderMode() == ClassBuilderMode.FULL) {
|
||||||
InstructionAdapter iv = createOrGetClInitCodegen().v;
|
InstructionAdapter iv = createOrGetClInitCodegen().v;
|
||||||
iv.anew(asmType);
|
iv.anew(thisAsmType);
|
||||||
iv.dup();
|
iv.dup();
|
||||||
iv.invokespecial(asmType.getInternalName(), "<init>", "()V", false);
|
iv.invokespecial(thisAsmType.getInternalName(), "<init>", "()V", false);
|
||||||
iv.putstatic(asmType.getInternalName(), JvmAbi.INSTANCE_FIELD, asmType.getDescriptor());
|
initialization.invoke(iv);
|
||||||
|
iv.putstatic(thisAsmType.getInternalName(), JvmAbi.INSTANCE_FIELD, fieldAsmType.getDescriptor());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -54,11 +54,27 @@ public class PropertyReferenceCodegen(
|
|||||||
) : MemberCodegen<JetCallableReferenceExpression>(state, parentCodegen, context, expression, classBuilder) {
|
) : MemberCodegen<JetCallableReferenceExpression>(state, parentCodegen, context, expression, classBuilder) {
|
||||||
private val target = resolvedCall.getResultingDescriptor()
|
private val target = resolvedCall.getResultingDescriptor()
|
||||||
private val asmType = typeMapper.mapClass(classDescriptor)
|
private val asmType = typeMapper.mapClass(classDescriptor)
|
||||||
private val superAsmType: Type
|
|
||||||
|
// e.g. MutablePropertyReference0
|
||||||
|
private val superAsmType = typeMapper.mapClass(classDescriptor.getSuperClassNotAny().sure { "No super class for $classDescriptor" })
|
||||||
|
|
||||||
|
// e.g. mutableProperty0(Lkotlin/jvm/internal/MutablePropertyReference0;)Lkotlin/reflect/KMutableProperty0;
|
||||||
|
private val wrapperMethod: Method
|
||||||
|
|
||||||
init {
|
init {
|
||||||
val superClass = classDescriptor.getSuperClassNotAny().sure { "No super class for $classDescriptor" }
|
val hasReceiver = target.getDispatchReceiverParameter() != null || target.getExtensionReceiverParameter() != null
|
||||||
superAsmType = typeMapper.mapClass(superClass)
|
val isMutable = target.isVar()
|
||||||
|
|
||||||
|
wrapperMethod = when {
|
||||||
|
hasReceiver -> when {
|
||||||
|
isMutable -> method("mutableProperty1", K_MUTABLE_PROPERTY1_TYPE, MUTABLE_PROPERTY_REFERENCE1)
|
||||||
|
else -> method("property1", K_PROPERTY1_TYPE, PROPERTY_REFERENCE1)
|
||||||
|
}
|
||||||
|
else -> when {
|
||||||
|
isMutable -> method("mutableProperty0", K_MUTABLE_PROPERTY0_TYPE, MUTABLE_PROPERTY_REFERENCE0)
|
||||||
|
else -> method("property0", K_PROPERTY0_TYPE, PROPERTY_REFERENCE0)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun generateDeclaration() {
|
override fun generateDeclaration() {
|
||||||
@@ -77,8 +93,9 @@ public class PropertyReferenceCodegen(
|
|||||||
|
|
||||||
// TODO: ImplementationBodyCodegen.markLineNumberForSyntheticFunction?
|
// TODO: ImplementationBodyCodegen.markLineNumberForSyntheticFunction?
|
||||||
override fun generateBody() {
|
override fun generateBody() {
|
||||||
// TODO: instance should be already wrapped by Reflection
|
generateConstInstance(asmType, wrapperMethod.getReturnType()) { iv ->
|
||||||
generateConstInstance(asmType)
|
iv.invokestatic(REFLECTION, wrapperMethod.getName(), wrapperMethod.getDescriptor(), false)
|
||||||
|
}
|
||||||
|
|
||||||
generateMethod("property reference init", 0, method("<init>", Type.VOID_TYPE)) {
|
generateMethod("property reference init", 0, method("<init>", Type.VOID_TYPE)) {
|
||||||
load(0, OBJECT_TYPE)
|
load(0, OBJECT_TYPE)
|
||||||
@@ -102,7 +119,7 @@ public class PropertyReferenceCodegen(
|
|||||||
defaultGetter
|
defaultGetter
|
||||||
}
|
}
|
||||||
|
|
||||||
val method = typeMapper.mapSignature(getter.sure { "No getter: $target" }).getAsmMethod()
|
val method = typeMapper.mapSignature(getter).getAsmMethod()
|
||||||
aconst(method.getName() + method.getDescriptor())
|
aconst(method.getName() + method.getDescriptor())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -178,24 +195,8 @@ public class PropertyReferenceCodegen(
|
|||||||
writeKotlinSyntheticClassAnnotation(v, KotlinSyntheticClass.Kind.CALLABLE_REFERENCE_WRAPPER)
|
writeKotlinSyntheticClassAnnotation(v, KotlinSyntheticClass.Kind.CALLABLE_REFERENCE_WRAPPER)
|
||||||
}
|
}
|
||||||
|
|
||||||
public fun putInstanceOnStack(): StackValue {
|
public fun putInstanceOnStack(): StackValue =
|
||||||
val hasReceiver = target.getDispatchReceiverParameter() != null || target.getExtensionReceiverParameter() != null
|
StackValue.operation(wrapperMethod.getReturnType()) { iv ->
|
||||||
|
iv.getstatic(asmType.getInternalName(), JvmAbi.INSTANCE_FIELD, wrapperMethod.getReturnType().getDescriptor())
|
||||||
val method =
|
}
|
||||||
when {
|
|
||||||
hasReceiver -> when {
|
|
||||||
target.isVar() -> method("mutableProperty1", K_MUTABLE_PROPERTY1_TYPE, MUTABLE_PROPERTY_REFERENCE1)
|
|
||||||
else -> method("property1", K_PROPERTY1_TYPE, PROPERTY_REFERENCE1)
|
|
||||||
}
|
|
||||||
else -> when {
|
|
||||||
target.isVar() -> method("mutableProperty0", K_MUTABLE_PROPERTY0_TYPE, MUTABLE_PROPERTY_REFERENCE0)
|
|
||||||
else -> method("property0", K_PROPERTY0_TYPE, PROPERTY_REFERENCE0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return StackValue.operation(method.getReturnType()) { iv ->
|
|
||||||
iv.getstatic(asmType.getInternalName(), JvmAbi.INSTANCE_FIELD, asmType.getDescriptor())
|
|
||||||
iv.invokestatic(REFLECTION, method.getName(), method.getDescriptor(), false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,12 +16,17 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.utils
|
package org.jetbrains.kotlin.utils
|
||||||
|
|
||||||
private val IDENTITY: Function1<Any?, Any?> = { it }
|
private val IDENTITY: (Any?) -> Any? = { it }
|
||||||
|
|
||||||
suppress("UNCHECKED_CAST")
|
suppress("UNCHECKED_CAST")
|
||||||
public fun <T> identity(): Function1<T, T> = IDENTITY as Function1<T, T>
|
public fun <T> identity(): (T) -> T = IDENTITY as (T) -> T
|
||||||
|
|
||||||
|
|
||||||
private val ALWAYS_TRUE: Function1<Any?, Boolean> = { true }
|
private val ALWAYS_TRUE: (Any?) -> Boolean = { true }
|
||||||
|
|
||||||
public fun <T> alwaysTrue(): Function1<T, Boolean> = ALWAYS_TRUE
|
public fun <T> alwaysTrue(): (T) -> Boolean = ALWAYS_TRUE
|
||||||
|
|
||||||
|
|
||||||
|
public val DO_NOTHING: (Any?) -> Unit = { }
|
||||||
|
|
||||||
|
public fun <T> doNothing(): (T) -> Unit = DO_NOTHING
|
||||||
|
|||||||
Reference in New Issue
Block a user