JVM_IR: support references to Java fields

This commit is contained in:
pyos
2019-05-13 12:02:31 +02:00
committed by max-kammerer
parent e191eef10a
commit f392b027fa
11 changed files with 89 additions and 129 deletions
@@ -7,9 +7,9 @@ package org.jetbrains.kotlin.backend.jvm.lower
import org.jetbrains.kotlin.backend.common.ClassLoweringPass
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.createImplicitParameterDeclarationWithWrappedDescriptor
import org.jetbrains.kotlin.backend.common.ir.passTypeArgumentsFrom
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
import org.jetbrains.kotlin.backend.common.phaser.makeIrFilePhase
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.expressions.*
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.symbols.IrClassSymbol
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.symbols.*
import org.jetbrains.kotlin.ir.types.createType
import org.jetbrains.kotlin.ir.types.impl.IrSimpleTypeImpl
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>()
// 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
private val IrMemberAccessExpression.setter: IrFunctionSymbol?
private val IrMemberAccessExpression.setter: IrSimpleFunctionSymbol?
get() = (this as? IrPropertyReference)?.setter ?: (this as? IrLocalDelegatedPropertyReference)?.setter
private val IrMemberAccessExpression.field: IrFieldSymbol?
@@ -60,12 +56,13 @@ internal class PropertyReferenceLowering(val context: JvmBackendContext) : Class
private val IrSimpleFunction.signature: String
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
get() = localPropertyIndices[getter]?.let { "<v#$it>" }
?: (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")
get() = localPropertyIndices[getter]?.let { "<v#$it>" } ?: getter?.owner?.signature ?: field!!.owner.signature
private val IrMemberAccessExpression.symbol: IrSymbol
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
// 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:
// need Java field support to move below PropertiesToFieldsLowering)
// TODO: move after LocalDeclarationsLowering and always use the getter/field? Can't move below ConstLowering
// right now -- get() would not be optimized.
private val IrMemberAccessExpression.propertyContainerChild: IrDeclaration?
get() {
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,
// 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))
)
@@ -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(
val interfaceSymbol: IrClassSymbol,
val reflectedSymbol: IrClassSymbol,
@@ -258,119 +272,75 @@ internal class PropertyReferenceLowering(val context: JvmBackendContext) : Class
superTypes += IrSimpleTypeImpl(superClass.symbol, false, listOf(), listOf())
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!!
fun IrBuilderWithScope.setReceiversOn(
call: IrCall,
dispatchReceiverParameter: IrValueParameter,
valueParameters: List<IrValueParameter>
) {
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)
}
}
val getName = superClass.functions.single { it.name.asString() == "getName" }
val getOwner = superClass.functions.single { it.name.asString() == "getOwner" }
val getSignature = superClass.functions.single { it.name.asString() == "getSignature" }
val get = superClass.functions.find { it.name.asString() == "get" }
val set = superClass.functions.find { it.name.asString() == "set" }
buildOverride(superClass.functions.single { it.name.asString() == "getName" }) { _, _ ->
irString(expression.descriptor.name.asString())
}
referenceClass.addSimpleDelegatingConstructor(superConstructor, context.irBuiltIns, isPrimary = true)
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" }) { _, _ ->
buildReflectedContainerReference(expression)
}
buildOverride(superClass.functions.single { it.name.asString() == "getSignature" }) { _, _ ->
irString(expression.signature)
}
expression.getter?.owner?.let { getter ->
buildOverride(superClass.functions.single { it.name.asString() == "get" }) { dispatchReceiverParameter, valueParameters ->
irGet(getter.returnType, null, getter.symbol).apply {
copyTypeArgumentsFrom(expression)
setReceiversOn(
this,
dispatchReceiverParameter,
valueParameters
)
val field = expression.field?.owner
if (field == null) {
fun IrBuilderWithScope.setCallArguments(call: IrCall, arguments: List<IrValueParameter>) {
var index = 1
call.copyTypeArgumentsFrom(expression)
call.dispatchReceiver = call.symbol.owner.dispatchReceiverParameter?.let {
if (expression.dispatchReceiver != null)
irImplicitCast(irGetField(irGet(arguments[0]), receiverField), it.type)
else
irImplicitCast(irGet(arguments[index++]), it.type)
}
call.extensionReceiver = call.symbol.owner.extensionReceiverParameter?.let {
if (expression.extensionReceiver != null)
irImplicitCast(irGetField(irGet(arguments[0]), receiverField), it.type)
else
irImplicitCast(irGet(arguments[index++]), it.type)
}
}
}
expression.setter?.owner?.let { setter ->
buildOverride(superClass.functions.single { it.name.asString() == "set" }) { dispatchReceiverParameter, valueParameters ->
val type = setter.valueParameters.last().type
val value = irImplicitCast(irGet(valueParameters.last()), type)
irSet(setter.returnType, null, setter.symbol, value).apply {
copyTypeArgumentsFrom(expression)
setReceiversOn(this, dispatchReceiverParameter, valueParameters)
expression.getter?.owner?.let { getter ->
referenceClass.addOverride(get!!) { arguments ->
irGet(getter.returnType, null, getter.symbol).apply {
setCallArguments(this, arguments)
}
}
}
}
expression.field?.owner?.let {
TODO("plain Java property reference") // no accessors, should generate direct field read/write instead
expression.setter?.owner?.let { setter ->
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
}
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JVM_IR
// TARGET_BACKEND: JVM
// WITH_REFLECT
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JVM_IR
// TARGET_BACKEND: JVM
// WITH_REFLECT
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JVM_IR
// TARGET_BACKEND: JVM
// FILE: J.java
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JVM_IR
// TARGET_BACKEND: JVM
// WITH_REFLECT
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JVM_IR
// TARGET_BACKEND: JVM
// WITH_REFLECT
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JVM_IR
// TARGET_BACKEND: JVM
// FILE: J.java
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JVM_IR
// FILE: A.java
public class A {
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JVM_IR
// FILE: A.java
public class A {
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JVM_IR
// WITH_REFLECT
// FULL_JDK
// FILE: J.java
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JVM_IR
// WITH_REFLECT
// FILE: test/J.java