Access this through the dispatch parameter when available

This commit is contained in:
Steven Schäfer
2019-04-30 13:15:12 +02:00
committed by Georgy Bronnikov
parent 9b9236efcb
commit b04dc69157
4 changed files with 51 additions and 48 deletions
@@ -8,12 +8,14 @@ package org.jetbrains.kotlin.backend.common.lower
import org.jetbrains.kotlin.backend.common.BackendContext import org.jetbrains.kotlin.backend.common.BackendContext
import org.jetbrains.kotlin.backend.common.BodyLoweringPass import org.jetbrains.kotlin.backend.common.BodyLoweringPass
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.phaser.makeIrFilePhase import org.jetbrains.kotlin.backend.common.phaser.makeIrFilePhase
import org.jetbrains.kotlin.ir.IrStatement import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.builders.irGet import org.jetbrains.kotlin.ir.builders.irGet
import org.jetbrains.kotlin.ir.builders.irSetField import org.jetbrains.kotlin.ir.builders.irSetField
import org.jetbrains.kotlin.ir.declarations.IrClass import org.jetbrains.kotlin.ir.declarations.IrClass
import org.jetbrains.kotlin.ir.declarations.IrConstructor import org.jetbrains.kotlin.ir.declarations.IrConstructor
import org.jetbrains.kotlin.ir.declarations.IrFunction
import org.jetbrains.kotlin.ir.declarations.IrValueParameter import org.jetbrains.kotlin.ir.declarations.IrValueParameter
import org.jetbrains.kotlin.ir.expressions.* import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.* import org.jetbrains.kotlin.ir.expressions.impl.*
@@ -28,6 +30,7 @@ import org.jetbrains.kotlin.ir.util.transformDeclarationsFlat
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
// This pass has to run after LocalDeclarationsLowering, since we don't handle nested functions.
val innerClassesPhase = makeIrFilePhase( val innerClassesPhase = makeIrFilePhase(
::InnerClassesLowering, ::InnerClassesLowering,
name = "InnerClasses", name = "InnerClasses",
@@ -76,21 +79,10 @@ class InnerClassesLowering(val context: BackendContext) : ClassLoweringPass {
irClass.transformDeclarationsFlat { irMember -> (irMember as? IrConstructor)?.let { listOf(lowerConstructor(it)) } } irClass.transformDeclarationsFlat { irMember -> (irMember as? IrConstructor)?.let { listOf(lowerConstructor(it)) } }
irClass.transformChildrenVoid(VariableRemapper(oldConstructorParameterToNew)) irClass.transformChildrenVoid(VariableRemapper(oldConstructorParameterToNew))
irClass.transformChildrenVoid(object : IrElementTransformerVoid() { irClass.transformChildrenVoid(object : IrElementTransformerVoidWithContext() {
private var enclosingConstructor: IrConstructor? = null override fun visitClassNew(declaration: IrClass): IrStatement =
// TODO: maybe add another transformer that skips specified elements
override fun visitClass(declaration: IrClass): IrStatement =
declaration declaration
override fun visitConstructor(declaration: IrConstructor): IrStatement =
try {
enclosingConstructor = declaration
super.visitConstructor(declaration)
} finally {
enclosingConstructor = null
}
override fun visitGetValue(expression: IrGetValue): IrExpression { override fun visitGetValue(expression: IrGetValue): IrExpression {
expression.transformChildrenVoid(this) expression.transformChildrenVoid(this)
@@ -100,8 +92,10 @@ class InnerClassesLowering(val context: BackendContext) : ClassLoweringPass {
val startOffset = expression.startOffset val startOffset = expression.startOffset
val endOffset = expression.endOffset val endOffset = expression.endOffset
val origin = expression.origin val origin = expression.origin
val function = currentFunction?.irElement as? IrFunction
val enclosingThisReceiver = function?.dispatchReceiverParameter ?: irClass.thisReceiver!!
var irThis: IrExpression = IrGetValueImpl(startOffset, endOffset, irClass.thisReceiver!!.symbol, origin) var irThis: IrExpression = IrGetValueImpl(startOffset, endOffset, enclosingThisReceiver.symbol, origin)
var innerClass = irClass var innerClass = irClass
while (innerClass != implicitThisClass) { while (innerClass != implicitThisClass) {
if (!innerClass.isInner) { if (!innerClass.isInner) {
@@ -110,10 +104,10 @@ class InnerClassesLowering(val context: BackendContext) : ClassLoweringPass {
return expression return expression
} }
irThis = if (enclosingConstructor != null && irClass == innerClass) { irThis = if (function is IrConstructor && irClass == innerClass) {
// Might be before a super() call (e.g. an argument to one), in which case the JVM bytecode verifier will reject // Might be before a super() call (e.g. an argument to one), in which case the JVM bytecode verifier will reject
// an attempt to access the field. Good thing we have a local variable as well. // an attempt to access the field. Good thing we have a local variable as well.
IrGetValueImpl(startOffset, endOffset, enclosingConstructor!!.valueParameters[0].symbol, origin) IrGetValueImpl(startOffset, endOffset, function.valueParameters[0].symbol, origin)
} else { } else {
val outerThisField = context.declarationFactory.getOuterThisField(innerClass) val outerThisField = context.declarationFactory.getOuterThisField(innerClass)
IrGetFieldImpl(startOffset, endOffset, outerThisField.symbol, outerThisField.type, irThis, origin) IrGetFieldImpl(startOffset, endOffset, outerThisField.symbol, outerThisField.type, irThis, origin)
@@ -234,7 +234,7 @@ internal class CallableReferenceLowering(val context: JvmBackendContext) : FileL
functionReferenceClass = buildClass { functionReferenceClass = buildClass {
setSourceRange(irFunctionReference) setSourceRange(irFunctionReference)
origin = JvmLoweredDeclarationOrigin.FUNCTION_REFERENCE_IMPL origin = JvmLoweredDeclarationOrigin.FUNCTION_REFERENCE_IMPL
name = "${callee.name}\$${functionReferenceCount++}".synthesizedName name = "${callee.name.safeName()}\$${functionReferenceCount++}".synthesizedName
kind = ClassKind.CLASS kind = ClassKind.CLASS
visibility = Visibilities.PUBLIC visibility = Visibilities.PUBLIC
modality = Modality.FINAL modality = Modality.FINAL
@@ -403,7 +403,7 @@ internal class CallableReferenceLowering(val context: JvmBackendContext) : FileL
val argument = when { val argument = when {
!unboundArgsSet.contains(parameter) -> !unboundArgsSet.contains(parameter) ->
// Bound parameter - read from field. // Bound parameter - read from field.
irGetField(irGet(functionReferenceThis.owner), argumentToFieldMap[parameter]!!) irGetField(irGet(dispatchReceiverParameter!!), argumentToFieldMap[parameter]!!)
function.isSuspend && unboundIndex == valueParameters.size -> function.isSuspend && unboundIndex == valueParameters.size ->
// For suspend functions the last argument is continuation and it is implicit. // For suspend functions the last argument is continuation and it is implicit.
TODO() TODO()
@@ -111,7 +111,7 @@ private class FunctionNVarargInvokeLowering(var context: JvmBackendContext) : Cl
target.returnType, target.returnType,
target.returnType.classifierOrFail, target.returnType.classifierOrFail,
irCall(target).apply { irCall(target).apply {
dispatchReceiver = irGet(irClass.thisReceiver!!) dispatchReceiver = irGet(dispatchReceiverParameter!!)
target.valueParameters.forEachIndexed { i, irValueParameter -> target.valueParameters.forEachIndexed { i, irValueParameter ->
val type = irValueParameter.type val type = irValueParameter.type
putValueArgument( putValueArgument(
@@ -292,70 +292,79 @@ internal class PropertyReferenceLowering(val context: JvmBackendContext) : Class
} }
} }
fun buildOverride(method: IrSimpleFunction, build: IrBlockBodyBuilder.(List<IrValueParameter>) -> IrExpression) = fun buildOverride(
buildFun { method: IrSimpleFunction,
setSourceRange(expression) build: IrBlockBodyBuilder.(IrValueParameter, List<IrValueParameter>) -> IrExpression
name = method.name ) = referenceClass.addFunction {
returnType = method.returnType setSourceRange(expression)
visibility = method.visibility name = method.name
origin = referenceClass.origin returnType = method.returnType
}.apply { visibility = method.visibility
parent = referenceClass origin = referenceClass.origin
referenceClass.declarations.add(this) }.apply {
overriddenSymbols.add(method.symbol)
overriddenSymbols.add(method.symbol) val thisParameter = referenceThis.copyTo(this)
dispatchReceiverParameter = referenceThis.copyTo(this) dispatchReceiverParameter = thisParameter
for (parameter in method.valueParameters) for (parameter in method.valueParameters)
valueParameters.add(parameter.copyTo(this)) valueParameters.add(parameter.copyTo(this))
body = context.createIrBuilder(symbol).irBlockBody(startOffset, endOffset) { body = context.createIrBuilder(symbol).irBlockBody(startOffset, endOffset) {
+irReturn(build(valueParameters)) +irReturn(build(thisParameter, valueParameters))
}
} }
}
val receiverField = superClass.properties.single { it.name.asString() == "receiver" }.backingField!! val receiverField = superClass.properties.single { it.name.asString() == "receiver" }.backingField!!
fun IrBuilderWithScope.setReceiversOn(call: IrCall, valueParameters: List<IrValueParameter>) { fun IrBuilderWithScope.setReceiversOn(
call: IrCall,
dispatchReceiverParameter: IrValueParameter,
valueParameters: List<IrValueParameter>
) {
var index = 0 var index = 0
call.dispatchReceiver = call.symbol.owner.dispatchReceiverParameter?.let { call.dispatchReceiver = call.symbol.owner.dispatchReceiverParameter?.let {
if (expression.dispatchReceiver != null) if (expression.dispatchReceiver != null)
irGetField(irGet(referenceThis), receiverField) irGetField(irGet(dispatchReceiverParameter), receiverField)
else else
irImplicitCast(irGet(valueParameters[index++]), it.type) irImplicitCast(irGet(valueParameters[index++]), it.type)
} }
call.extensionReceiver = call.symbol.owner.extensionReceiverParameter?.let { call.extensionReceiver = call.symbol.owner.extensionReceiverParameter?.let {
if (expression.extensionReceiver != null) if (expression.extensionReceiver != null)
irGetField(irGet(referenceThis), receiverField) irGetField(irGet(dispatchReceiverParameter), receiverField)
else else
irImplicitCast(irGet(valueParameters[index++]), it.type) irImplicitCast(irGet(valueParameters[index++]), it.type)
} }
} }
buildOverride(superClass.functions.single { it.name.asString() == "getName" }) { buildOverride(superClass.functions.single { it.name.asString() == "getName" }) { _, _ ->
irString(expression.descriptor.name.asString()) irString(expression.descriptor.name.asString())
} }
buildOverride(superClass.functions.single { it.name.asString() == "getOwner" }) { buildOverride(superClass.functions.single { it.name.asString() == "getOwner" }) { _, _ ->
buildReflectedContainerReference(expression) buildReflectedContainerReference(expression)
} }
buildOverride(superClass.functions.single { it.name.asString() == "getSignature" }) { buildOverride(superClass.functions.single { it.name.asString() == "getSignature" }) { _, _ ->
irString(expression.signature) irString(expression.signature)
} }
expression.getter?.owner?.let { getter -> expression.getter?.owner?.let { getter ->
buildOverride(superClass.functions.single { it.name.asString() == "get" }) { valueParameters -> buildOverride(superClass.functions.single { it.name.asString() == "get" }) { dispatchReceiverParameter, valueParameters ->
irGet(getter.returnType, null, getter.symbol).apply { irGet(getter.returnType, null, getter.symbol).apply {
copyTypeArgumentsFrom(expression) copyTypeArgumentsFrom(expression)
setReceiversOn(this, valueParameters) setReceiversOn(
this,
dispatchReceiverParameter,
valueParameters
)
} }
} }
} }
expression.setter?.owner?.let { setter -> expression.setter?.owner?.let { setter ->
buildOverride(superClass.functions.single { it.name.asString() == "set" }) { valueParameters -> buildOverride(superClass.functions.single { it.name.asString() == "set" }) { dispatchReceiverParameter, valueParameters ->
val value = irGet(valueParameters.last()) val type = setter.valueParameters.last().type
val value = irImplicitCast(irGet(valueParameters.last()), type)
irSet(setter.returnType, null, setter.symbol, value).apply { irSet(setter.returnType, null, setter.symbol, value).apply {
copyTypeArgumentsFrom(expression) copyTypeArgumentsFrom(expression)
setReceiversOn(this, valueParameters) setReceiversOn(this, dispatchReceiverParameter, valueParameters)
} }
} }
} }