JVM_IR: support references to Java fields
This commit is contained in:
+89
-119
@@ -7,9 +7,9 @@ package org.jetbrains.kotlin.backend.jvm.lower
|
|||||||
|
|
||||||
import org.jetbrains.kotlin.backend.common.ClassLoweringPass
|
import org.jetbrains.kotlin.backend.common.ClassLoweringPass
|
||||||
import org.jetbrains.kotlin.backend.common.IrElementTransformerVoidWithContext
|
import org.jetbrains.kotlin.backend.common.IrElementTransformerVoidWithContext
|
||||||
|
import org.jetbrains.kotlin.backend.common.ir.addSimpleDelegatingConstructor
|
||||||
import org.jetbrains.kotlin.backend.common.ir.copyTo
|
import org.jetbrains.kotlin.backend.common.ir.copyTo
|
||||||
import org.jetbrains.kotlin.backend.common.ir.createImplicitParameterDeclarationWithWrappedDescriptor
|
import org.jetbrains.kotlin.backend.common.ir.createImplicitParameterDeclarationWithWrappedDescriptor
|
||||||
import org.jetbrains.kotlin.backend.common.ir.passTypeArgumentsFrom
|
|
||||||
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
|
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
|
||||||
import org.jetbrains.kotlin.backend.common.phaser.makeIrFilePhase
|
import org.jetbrains.kotlin.backend.common.phaser.makeIrFilePhase
|
||||||
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
|
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
|
||||||
@@ -20,12 +20,8 @@ import org.jetbrains.kotlin.ir.builders.declarations.*
|
|||||||
import org.jetbrains.kotlin.ir.declarations.*
|
import org.jetbrains.kotlin.ir.declarations.*
|
||||||
import org.jetbrains.kotlin.ir.expressions.*
|
import org.jetbrains.kotlin.ir.expressions.*
|
||||||
import org.jetbrains.kotlin.ir.expressions.impl.IrClassReferenceImpl
|
import org.jetbrains.kotlin.ir.expressions.impl.IrClassReferenceImpl
|
||||||
import org.jetbrains.kotlin.ir.expressions.impl.IrInstanceInitializerCallImpl
|
|
||||||
import org.jetbrains.kotlin.ir.expressions.impl.IrVarargImpl
|
import org.jetbrains.kotlin.ir.expressions.impl.IrVarargImpl
|
||||||
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
|
import org.jetbrains.kotlin.ir.symbols.*
|
||||||
import org.jetbrains.kotlin.ir.symbols.IrFieldSymbol
|
|
||||||
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
|
|
||||||
import org.jetbrains.kotlin.ir.symbols.IrSymbol
|
|
||||||
import org.jetbrains.kotlin.ir.types.createType
|
import org.jetbrains.kotlin.ir.types.createType
|
||||||
import org.jetbrains.kotlin.ir.types.impl.IrSimpleTypeImpl
|
import org.jetbrains.kotlin.ir.types.impl.IrSimpleTypeImpl
|
||||||
import org.jetbrains.kotlin.ir.types.impl.makeTypeProjection
|
import org.jetbrains.kotlin.ir.types.impl.makeTypeProjection
|
||||||
@@ -48,10 +44,10 @@ internal class PropertyReferenceLowering(val context: JvmBackendContext) : Class
|
|||||||
private val localPropertyIndices = mutableMapOf<IrSymbol, Int>()
|
private val localPropertyIndices = mutableMapOf<IrSymbol, Int>()
|
||||||
|
|
||||||
// TODO: join IrLocalDelegatedPropertyReference and IrPropertyReference via the class hierarchy?
|
// TODO: join IrLocalDelegatedPropertyReference and IrPropertyReference via the class hierarchy?
|
||||||
private val IrMemberAccessExpression.getter: IrFunctionSymbol?
|
private val IrMemberAccessExpression.getter: IrSimpleFunctionSymbol?
|
||||||
get() = (this as? IrPropertyReference)?.getter ?: (this as? IrLocalDelegatedPropertyReference)?.getter
|
get() = (this as? IrPropertyReference)?.getter ?: (this as? IrLocalDelegatedPropertyReference)?.getter
|
||||||
|
|
||||||
private val IrMemberAccessExpression.setter: IrFunctionSymbol?
|
private val IrMemberAccessExpression.setter: IrSimpleFunctionSymbol?
|
||||||
get() = (this as? IrPropertyReference)?.setter ?: (this as? IrLocalDelegatedPropertyReference)?.setter
|
get() = (this as? IrPropertyReference)?.setter ?: (this as? IrLocalDelegatedPropertyReference)?.setter
|
||||||
|
|
||||||
private val IrMemberAccessExpression.field: IrFieldSymbol?
|
private val IrMemberAccessExpression.field: IrFieldSymbol?
|
||||||
@@ -60,12 +56,13 @@ internal class PropertyReferenceLowering(val context: JvmBackendContext) : Class
|
|||||||
private val IrSimpleFunction.signature: String
|
private val IrSimpleFunction.signature: String
|
||||||
get() = context.state.typeMapper.mapSignatureSkipGeneric(collectRealOverrides().first().descriptor).toString()
|
get() = context.state.typeMapper.mapSignatureSkipGeneric(collectRealOverrides().first().descriptor).toString()
|
||||||
|
|
||||||
|
// Plain Java fields do not have a getter, but can be referenced nonetheless. The signature should be the one
|
||||||
|
// that a getter would have, if it existed.
|
||||||
|
private val IrField.signature: String
|
||||||
|
get() = "${JvmAbi.getterName(name.asString())}()${context.state.typeMapper.mapReturnType(descriptor)}"
|
||||||
|
|
||||||
private val IrMemberAccessExpression.signature: String
|
private val IrMemberAccessExpression.signature: String
|
||||||
get() = localPropertyIndices[getter]?.let { "<v#$it>" }
|
get() = localPropertyIndices[getter]?.let { "<v#$it>" } ?: getter?.owner?.signature ?: field!!.owner.signature
|
||||||
?: (getter?.owner as? IrSimpleFunction)?.signature
|
|
||||||
// Plain Java fields do not have a getter, but can be referenced nonetheless. The signature should be
|
|
||||||
// the one that a getter would have, if it existed.
|
|
||||||
?: TODO("plain Java field signature")
|
|
||||||
|
|
||||||
private val IrMemberAccessExpression.symbol: IrSymbol
|
private val IrMemberAccessExpression.symbol: IrSymbol
|
||||||
get() = getter?.owner?.symbol ?: field!!.owner.symbol
|
get() = getter?.owner?.symbol ?: field!!.owner.symbol
|
||||||
@@ -85,8 +82,8 @@ internal class PropertyReferenceLowering(val context: JvmBackendContext) : Class
|
|||||||
|
|
||||||
// Return some declaration the parent of which is the containing class/package for the referenced property. This is
|
// Return some declaration the parent of which is the containing class/package for the referenced property. This is
|
||||||
// a bit of a hack, as the reason for not returning the container itself is the `mapImplementationOwner` call below.
|
// a bit of a hack, as the reason for not returning the container itself is the `mapImplementationOwner` call below.
|
||||||
// TODO: move after LocalDeclarationsLowering and always use the getter/field? (not possible right now:
|
// TODO: move after LocalDeclarationsLowering and always use the getter/field? Can't move below ConstLowering
|
||||||
// need Java field support to move below PropertiesToFieldsLowering)
|
// right now -- get() would not be optimized.
|
||||||
private val IrMemberAccessExpression.propertyContainerChild: IrDeclaration?
|
private val IrMemberAccessExpression.propertyContainerChild: IrDeclaration?
|
||||||
get() {
|
get() {
|
||||||
var current: IrDeclaration? = getter?.owner ?: field?.owner
|
var current: IrDeclaration? = getter?.owner ?: field?.owner
|
||||||
@@ -102,7 +99,7 @@ internal class PropertyReferenceLowering(val context: JvmBackendContext) : Class
|
|||||||
context.ir.symbols.javaLangClass.typeWith(),
|
context.ir.symbols.javaLangClass.typeWith(),
|
||||||
context.ir.symbols.javaLangClass,
|
context.ir.symbols.javaLangClass,
|
||||||
// TODO: when the parent is an interface, this should map to DefaultImpls. However, that requires
|
// TODO: when the parent is an interface, this should map to DefaultImpls. However, that requires
|
||||||
// moving this lowering below InterfaceLowering; see another TODO above.
|
// moving this lowering below InterfaceLowering; see comment about the ordering above, though.
|
||||||
CrIrType(context.state.typeMapper.mapImplementationOwner(propertyContainerChild!!.descriptor))
|
CrIrType(context.state.typeMapper.mapImplementationOwner(propertyContainerChild!!.descriptor))
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -126,6 +123,23 @@ internal class PropertyReferenceLowering(val context: JvmBackendContext) : Class
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun IrClass.addOverride(method: IrSimpleFunction, buildBody: IrBuilderWithScope.(List<IrValueParameter>) -> IrExpression) =
|
||||||
|
addFunction {
|
||||||
|
setSourceRange(this@addOverride)
|
||||||
|
name = method.name
|
||||||
|
returnType = method.returnType
|
||||||
|
visibility = method.visibility
|
||||||
|
origin = this@addOverride.origin
|
||||||
|
}.apply {
|
||||||
|
overriddenSymbols.add(method.symbol)
|
||||||
|
dispatchReceiverParameter = thisReceiver!!.copyTo(this)
|
||||||
|
for (parameter in method.valueParameters)
|
||||||
|
valueParameters.add(parameter.copyTo(this))
|
||||||
|
body = context.createIrBuilder(symbol, startOffset, endOffset).run {
|
||||||
|
irExprBody(buildBody(listOf(dispatchReceiverParameter!!) + valueParameters))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private class PropertyReferenceKind(
|
private class PropertyReferenceKind(
|
||||||
val interfaceSymbol: IrClassSymbol,
|
val interfaceSymbol: IrClassSymbol,
|
||||||
val reflectedSymbol: IrClassSymbol,
|
val reflectedSymbol: IrClassSymbol,
|
||||||
@@ -258,119 +272,75 @@ internal class PropertyReferenceLowering(val context: JvmBackendContext) : Class
|
|||||||
superTypes += IrSimpleTypeImpl(superClass.symbol, false, listOf(), listOf())
|
superTypes += IrSimpleTypeImpl(superClass.symbol, false, listOf(), listOf())
|
||||||
createImplicitParameterDeclarationWithWrappedDescriptor()
|
createImplicitParameterDeclarationWithWrappedDescriptor()
|
||||||
}
|
}
|
||||||
val referenceThis = referenceClass.thisReceiver!!
|
|
||||||
|
|
||||||
buildConstructor {
|
|
||||||
setSourceRange(expression)
|
|
||||||
returnType = referenceClass.defaultType
|
|
||||||
origin = referenceClass.origin
|
|
||||||
isPrimary = true
|
|
||||||
}.apply {
|
|
||||||
parent = referenceClass
|
|
||||||
referenceClass.declarations.add(this)
|
|
||||||
|
|
||||||
val constructor = this
|
|
||||||
// See propertyReferenceKindFor -- only one of them could ever be present.
|
|
||||||
val parameter = (expression.dispatchReceiver ?: expression.extensionReceiver)?.let {
|
|
||||||
buildValueParameter {
|
|
||||||
setSourceRange(expression)
|
|
||||||
name = Name.identifier("receiver")
|
|
||||||
type = it.type
|
|
||||||
index = valueParameters.size
|
|
||||||
origin = referenceClass.origin
|
|
||||||
}.apply {
|
|
||||||
parent = constructor
|
|
||||||
valueParameters.add(this)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
body = context.createIrBuilder(symbol).irBlockBody(startOffset, endOffset) {
|
|
||||||
val superArgs = if (parameter == null) 0 else 1
|
|
||||||
+irDelegatingConstructorCall(superClass.constructors.single { it.valueParameters.size == superArgs }).apply {
|
|
||||||
parameter?.let { putValueArgument(0, irGet(parameter)) }
|
|
||||||
}
|
|
||||||
+IrInstanceInitializerCallImpl(startOffset, endOffset, referenceClass.symbol, context.irBuiltIns.unitType)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun buildOverride(
|
|
||||||
method: IrSimpleFunction,
|
|
||||||
build: IrBlockBodyBuilder.(IrValueParameter, List<IrValueParameter>) -> IrExpression
|
|
||||||
) = referenceClass.addFunction {
|
|
||||||
setSourceRange(expression)
|
|
||||||
name = method.name
|
|
||||||
returnType = method.returnType
|
|
||||||
visibility = method.visibility
|
|
||||||
origin = referenceClass.origin
|
|
||||||
}.apply {
|
|
||||||
overriddenSymbols.add(method.symbol)
|
|
||||||
val thisParameter = referenceThis.copyTo(this)
|
|
||||||
dispatchReceiverParameter = thisParameter
|
|
||||||
for (parameter in method.valueParameters)
|
|
||||||
valueParameters.add(parameter.copyTo(this))
|
|
||||||
body = context.createIrBuilder(symbol).irBlockBody(startOffset, endOffset) {
|
|
||||||
+irReturn(build(thisParameter, valueParameters))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
// See propertyReferenceKindFor -- only one of them could ever be present.
|
||||||
|
val numOfSuperArgs = if (expression.dispatchReceiver != null || expression.extensionReceiver != null) 1 else 0
|
||||||
|
val superConstructor = superClass.constructors.single { it.valueParameters.size == numOfSuperArgs }
|
||||||
val receiverField = superClass.properties.single { it.name.asString() == "receiver" }.backingField!!
|
val receiverField = superClass.properties.single { it.name.asString() == "receiver" }.backingField!!
|
||||||
fun IrBuilderWithScope.setReceiversOn(
|
val getName = superClass.functions.single { it.name.asString() == "getName" }
|
||||||
call: IrCall,
|
val getOwner = superClass.functions.single { it.name.asString() == "getOwner" }
|
||||||
dispatchReceiverParameter: IrValueParameter,
|
val getSignature = superClass.functions.single { it.name.asString() == "getSignature" }
|
||||||
valueParameters: List<IrValueParameter>
|
val get = superClass.functions.find { it.name.asString() == "get" }
|
||||||
) {
|
val set = superClass.functions.find { it.name.asString() == "set" }
|
||||||
var index = 0
|
|
||||||
call.dispatchReceiver = call.symbol.owner.dispatchReceiverParameter?.let {
|
|
||||||
if (expression.dispatchReceiver != null)
|
|
||||||
irGetField(irGet(dispatchReceiverParameter), receiverField)
|
|
||||||
else
|
|
||||||
irImplicitCast(irGet(valueParameters[index++]), it.type)
|
|
||||||
}
|
|
||||||
call.extensionReceiver = call.symbol.owner.extensionReceiverParameter?.let {
|
|
||||||
if (expression.extensionReceiver != null)
|
|
||||||
irGetField(irGet(dispatchReceiverParameter), receiverField)
|
|
||||||
else
|
|
||||||
irImplicitCast(irGet(valueParameters[index++]), it.type)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
buildOverride(superClass.functions.single { it.name.asString() == "getName" }) { _, _ ->
|
referenceClass.addSimpleDelegatingConstructor(superConstructor, context.irBuiltIns, isPrimary = true)
|
||||||
irString(expression.descriptor.name.asString())
|
referenceClass.addOverride(getName) { irString(expression.descriptor.name.asString()) }
|
||||||
}
|
referenceClass.addOverride(getOwner) { buildReflectedContainerReference(expression) }
|
||||||
|
referenceClass.addOverride(getSignature) { irString(expression.signature) }
|
||||||
|
|
||||||
buildOverride(superClass.functions.single { it.name.asString() == "getOwner" }) { _, _ ->
|
val field = expression.field?.owner
|
||||||
buildReflectedContainerReference(expression)
|
if (field == null) {
|
||||||
}
|
fun IrBuilderWithScope.setCallArguments(call: IrCall, arguments: List<IrValueParameter>) {
|
||||||
|
var index = 1
|
||||||
buildOverride(superClass.functions.single { it.name.asString() == "getSignature" }) { _, _ ->
|
call.copyTypeArgumentsFrom(expression)
|
||||||
irString(expression.signature)
|
call.dispatchReceiver = call.symbol.owner.dispatchReceiverParameter?.let {
|
||||||
}
|
if (expression.dispatchReceiver != null)
|
||||||
|
irImplicitCast(irGetField(irGet(arguments[0]), receiverField), it.type)
|
||||||
expression.getter?.owner?.let { getter ->
|
else
|
||||||
buildOverride(superClass.functions.single { it.name.asString() == "get" }) { dispatchReceiverParameter, valueParameters ->
|
irImplicitCast(irGet(arguments[index++]), it.type)
|
||||||
irGet(getter.returnType, null, getter.symbol).apply {
|
}
|
||||||
copyTypeArgumentsFrom(expression)
|
call.extensionReceiver = call.symbol.owner.extensionReceiverParameter?.let {
|
||||||
setReceiversOn(
|
if (expression.extensionReceiver != null)
|
||||||
this,
|
irImplicitCast(irGetField(irGet(arguments[0]), receiverField), it.type)
|
||||||
dispatchReceiverParameter,
|
else
|
||||||
valueParameters
|
irImplicitCast(irGet(arguments[index++]), it.type)
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
expression.setter?.owner?.let { setter ->
|
expression.getter?.owner?.let { getter ->
|
||||||
buildOverride(superClass.functions.single { it.name.asString() == "set" }) { dispatchReceiverParameter, valueParameters ->
|
referenceClass.addOverride(get!!) { arguments ->
|
||||||
val type = setter.valueParameters.last().type
|
irGet(getter.returnType, null, getter.symbol).apply {
|
||||||
val value = irImplicitCast(irGet(valueParameters.last()), type)
|
setCallArguments(this, arguments)
|
||||||
irSet(setter.returnType, null, setter.symbol, value).apply {
|
}
|
||||||
copyTypeArgumentsFrom(expression)
|
|
||||||
setReceiversOn(this, dispatchReceiverParameter, valueParameters)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
expression.field?.owner?.let {
|
expression.setter?.owner?.let { setter ->
|
||||||
TODO("plain Java property reference") // no accessors, should generate direct field read/write instead
|
referenceClass.addOverride(set!!) { arguments ->
|
||||||
|
irSet(setter.returnType, null, setter.symbol, irGet(arguments.last())).apply {
|
||||||
|
setCallArguments(this, arguments)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
fun IrBuilderWithScope.fieldReceiver(arguments: List<IrValueParameter>) = when {
|
||||||
|
field.isStatic ->
|
||||||
|
null
|
||||||
|
expression.dispatchReceiver != null ->
|
||||||
|
irImplicitCast(irGetField(irGet(arguments[0]), receiverField), field.parentAsClass.defaultType)
|
||||||
|
else ->
|
||||||
|
irImplicitCast(irGet(arguments[1]), field.parentAsClass.defaultType)
|
||||||
|
}
|
||||||
|
|
||||||
|
referenceClass.addOverride(get!!) { arguments ->
|
||||||
|
irGetField(fieldReceiver(arguments), field)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!field.isFinal) {
|
||||||
|
referenceClass.addOverride(set!!) { arguments ->
|
||||||
|
irSetField(fieldReceiver(arguments), field, irGet(arguments.last()))
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return referenceClass
|
return referenceClass
|
||||||
}
|
}
|
||||||
|
|||||||
-1
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JVM_IR
|
|
||||||
// TARGET_BACKEND: JVM
|
// TARGET_BACKEND: JVM
|
||||||
|
|
||||||
// WITH_REFLECT
|
// WITH_REFLECT
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JVM_IR
|
|
||||||
// TARGET_BACKEND: JVM
|
// TARGET_BACKEND: JVM
|
||||||
|
|
||||||
// WITH_REFLECT
|
// WITH_REFLECT
|
||||||
|
|||||||
-1
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JVM_IR
|
|
||||||
// TARGET_BACKEND: JVM
|
// TARGET_BACKEND: JVM
|
||||||
|
|
||||||
// FILE: J.java
|
// FILE: J.java
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JVM_IR
|
|
||||||
// TARGET_BACKEND: JVM
|
// TARGET_BACKEND: JVM
|
||||||
|
|
||||||
// WITH_REFLECT
|
// WITH_REFLECT
|
||||||
|
|||||||
Vendored
-1
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JVM_IR
|
|
||||||
// TARGET_BACKEND: JVM
|
// TARGET_BACKEND: JVM
|
||||||
|
|
||||||
// WITH_REFLECT
|
// WITH_REFLECT
|
||||||
|
|||||||
Vendored
-1
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JVM_IR
|
|
||||||
// TARGET_BACKEND: JVM
|
// TARGET_BACKEND: JVM
|
||||||
|
|
||||||
// FILE: J.java
|
// FILE: J.java
|
||||||
|
|||||||
-1
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JVM_IR
|
|
||||||
// FILE: A.java
|
// FILE: A.java
|
||||||
|
|
||||||
public class A {
|
public class A {
|
||||||
|
|||||||
-1
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JVM_IR
|
|
||||||
// FILE: A.java
|
// FILE: A.java
|
||||||
|
|
||||||
public class A {
|
public class A {
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JVM_IR
|
|
||||||
// WITH_REFLECT
|
// WITH_REFLECT
|
||||||
// FULL_JDK
|
// FULL_JDK
|
||||||
// FILE: J.java
|
// FILE: J.java
|
||||||
|
|||||||
-1
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND: JVM_IR
|
|
||||||
// WITH_REFLECT
|
// WITH_REFLECT
|
||||||
// FILE: test/J.java
|
// FILE: test/J.java
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user