PrivateMembersLowering

This commit is contained in:
Anton Bannykh
2019-12-25 14:02:02 +03:00
committed by Anton Bannykh
parent f6d4ea469c
commit 3165556c6b
4 changed files with 132 additions and 123 deletions
@@ -50,8 +50,6 @@ class JsIrBackendContext(
override val lateinitNullableFields override val lateinitNullableFields
get() = error("Use Mapping.lateInitFieldToNullableField instead") get() = error("Use Mapping.lateInitFieldToNullableField instead")
val memberMap = mutableMapOf<IrSimpleFunctionSymbol, IrSimpleFunction>()
override val builtIns = module.builtIns override val builtIns = module.builtIns
override var inVerbosePhase: Boolean = false override var inVerbosePhase: Boolean = false
@@ -247,6 +247,12 @@ private val privateMembersLoweringPhase = makeJsModulePhase(
description = "Extract private members from classes" description = "Extract private members from classes"
) )
private val privateMemberUsagesLoweringPhase = makeJsModulePhase(
::PrivateMemberBodiesLowering,
name = "PrivateMemberUsagesLowering",
description = "Rewrite the private member usages"
)
private val callableReferenceLoweringPhase = makeJsModulePhase( private val callableReferenceLoweringPhase = makeJsModulePhase(
::CallableReferenceLowering, ::CallableReferenceLowering,
name = "CallableReferenceLowering", name = "CallableReferenceLowering",
@@ -486,6 +492,7 @@ val jsPhases = namedIrModulePhase(
propertyAccessorInlinerLoweringPhase then propertyAccessorInlinerLoweringPhase then
foldConstantLoweringPhase then foldConstantLoweringPhase then
privateMembersLoweringPhase then privateMembersLoweringPhase then
privateMemberUsagesLoweringPhase then
callableReferenceLoweringPhase then callableReferenceLoweringPhase then
defaultArgumentStubGeneratorPhase then defaultArgumentStubGeneratorPhase then
defaultArgumentPatchOverridesPhase then defaultArgumentPatchOverridesPhase then
@@ -18,4 +18,5 @@ class JsMapping : DefaultMapping() {
val objectToGetInstanceFunction = newMapping<IrClass, IrSimpleFunction>() val objectToGetInstanceFunction = newMapping<IrClass, IrSimpleFunction>()
val objectToInstanceField = newMapping<IrClass, IrField>() val objectToInstanceField = newMapping<IrClass, IrField>()
val classToSyntheticPrimaryConstructor = newMapping<IrClass, IrConstructor>() val classToSyntheticPrimaryConstructor = newMapping<IrClass, IrConstructor>()
val privateMemberToCorrespondingStatic = newMapping<IrFunction, IrSimpleFunction>()
} }
@@ -5,10 +5,10 @@
package org.jetbrains.kotlin.ir.backend.js.lower package org.jetbrains.kotlin.ir.backend.js.lower
import org.jetbrains.kotlin.backend.common.FileLoweringPass import org.jetbrains.kotlin.backend.common.BodyLoweringPass
import org.jetbrains.kotlin.backend.common.DeclarationTransformer
import org.jetbrains.kotlin.backend.common.ir.copyTo import org.jetbrains.kotlin.backend.common.ir.copyTo
import org.jetbrains.kotlin.descriptors.Visibilities import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.declarations.*
@@ -17,56 +17,143 @@ import org.jetbrains.kotlin.ir.declarations.impl.IrValueParameterImpl
import org.jetbrains.kotlin.ir.descriptors.WrappedSimpleFunctionDescriptor import org.jetbrains.kotlin.ir.descriptors.WrappedSimpleFunctionDescriptor
import org.jetbrains.kotlin.ir.descriptors.WrappedValueParameterDescriptor import org.jetbrains.kotlin.ir.descriptors.WrappedValueParameterDescriptor
import org.jetbrains.kotlin.ir.expressions.* import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl import org.jetbrains.kotlin.ir.expressions.impl.*
import org.jetbrains.kotlin.ir.expressions.impl.IrFunctionReferenceImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrPropertyReferenceImpl
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
import org.jetbrains.kotlin.ir.symbols.impl.IrSimpleFunctionSymbolImpl import org.jetbrains.kotlin.ir.symbols.impl.IrSimpleFunctionSymbolImpl
import org.jetbrains.kotlin.ir.symbols.impl.IrValueParameterSymbolImpl import org.jetbrains.kotlin.ir.symbols.impl.IrValueParameterSymbolImpl
import org.jetbrains.kotlin.ir.util.deepCopyWithSymbols import org.jetbrains.kotlin.ir.util.deepCopyWithSymbols
import org.jetbrains.kotlin.ir.util.transformFlat
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.name.Name import org.jetbrains.kotlin.name.Name
private val STATIC_THIS_PARAMETER = object : IrDeclarationOriginImpl("STATIC_THIS_PARAMETER") {} private val STATIC_THIS_PARAMETER = object : IrDeclarationOriginImpl("STATIC_THIS_PARAMETER") {}
class PrivateMembersLowering(val context: JsIrBackendContext) : FileLoweringPass { class PrivateMembersLowering(val context: JsIrBackendContext) : DeclarationTransformer {
private val memberMap = context.memberMap
override fun lower(irFile: IrFile) { private var IrFunction.correspondingStatic by context.mapping.privateMemberToCorrespondingStatic
transformPrivateDeclarations(irFile)
transformPrivateUseSites(irFile) override fun transformFlat(declaration: IrDeclaration): List<IrDeclaration>? {
return when (declaration) {
is IrSimpleFunction -> transformMemberToStaticFunction(declaration)?.let { staticFunction ->
declaration.correspondingStatic = staticFunction
listOf(staticFunction)
}
is IrProperty -> listOf(declaration.apply {
// Detach old function from corresponding property
this.getter = this.getter?.let { g -> transformAccessor(g) }
this.setter = this.setter?.let { s -> transformAccessor(s) }
})
else -> null
}
} }
private fun transformPrivateDeclarations(irFile: IrFile) { private fun transformAccessor(accessor: IrSimpleFunction) = transformMemberToStaticFunction(accessor) ?: accessor
irFile.transformChildrenVoid(object : IrElementTransformerVoid() {
override fun visitClass(declaration: IrClass): IrStatement { private fun transformMemberToStaticFunction(function: IrSimpleFunction): IrSimpleFunction? {
declaration.transformChildrenVoid(this)
declaration.declarations.transformFlat { if (function.visibility != Visibilities.PRIVATE || function.dispatchReceiverParameter == null) return null
when (it) {
is IrSimpleFunction -> transformMemberToStaticFunction(it)?.let { staticFunction -> val descriptor = WrappedSimpleFunctionDescriptor()
listOf(staticFunction) val symbol = IrSimpleFunctionSymbolImpl(descriptor)
} val staticFunction = function.run {
is IrProperty -> listOf(it.apply { IrFunctionImpl(
this.getter = this.getter?.let { g -> transformAccessor(g) } startOffset, endOffset, origin,
this.setter = this.setter?.let { s -> transformAccessor(s) } symbol, name, visibility, modality,
}) returnType,
else -> null isInline = isInline, isExternal = isExternal, isTailrec = isTailrec, isSuspend = isSuspend, isExpect = isExpect,
isFakeOverride = origin == IrDeclarationOrigin.FAKE_OVERRIDE,
isOperator = isOperator
).also {
descriptor.bind(it)
it.parent = parent
it.correspondingPropertySymbol = correspondingPropertySymbol
}
}
staticFunction.typeParameters += function.typeParameters.map { it.deepCopyWithSymbols(staticFunction) }
staticFunction.extensionReceiverParameter = function.extensionReceiverParameter?.copyTo(staticFunction)
val thisDesc = WrappedValueParameterDescriptor()
val thisSymbol = IrValueParameterSymbolImpl(thisDesc)
staticFunction.valueParameters += IrValueParameterImpl(
UNDEFINED_OFFSET,
UNDEFINED_OFFSET,
STATIC_THIS_PARAMETER,
thisSymbol,
Name.identifier("\$this"),
0,
function.dispatchReceiverParameter!!.type,
null,
isCrossinline = false,
isNoinline = false
).also {
thisDesc.bind(it)
it.parent = staticFunction
}
function.correspondingStatic = staticFunction
staticFunction.valueParameters += function.valueParameters.map {
// TODO better way to avoid copying default value
it.copyTo(staticFunction, index = it.index + 1, defaultValue = null)
}
val oldParameters =
listOfNotNull(function.extensionReceiverParameter, function.dispatchReceiverParameter) + function.valueParameters
val newParameters = listOfNotNull(staticFunction.extensionReceiverParameter) + staticFunction.valueParameters
assert(oldParameters.size == newParameters.size)
val parameterMapping = oldParameters.zip(newParameters).toMap()
val parameterTransformer = object : IrElementTransformerVoid() {
override fun visitGetValue(expression: IrGetValue) = parameterMapping[expression.symbol.owner]?.let {
expression.run { IrGetValueImpl(startOffset, endOffset, type, it.symbol, origin) }
} ?: expression
}
fun IrBody.copyWithParameters(): IrBody {
return deepCopyWithSymbols(staticFunction).also {
it.transform(parameterTransformer, null)
}
}
function.valueParameters.forEach {
// TODO better way to avoid copying default value
parameterMapping[it]?.apply {
it.defaultValue?.let { originalDefault ->
defaultValue = IrExpressionBodyImpl(it.startOffset, it.endOffset) {
expression = (originalDefault.copyWithParameters() as IrExpressionBody).expression
} }
} }
return declaration
} }
}) }
}
private fun transformPrivateUseSites(irFile: IrFile) { function.body?.let {
irFile.transform(object : IrElementTransformerVoid() { staticFunction.body = when (it) {
is IrBlockBody -> IrBlockBodyImpl(it.startOffset, it.endOffset) {
statements += (it.copyWithParameters() as IrBlockBody).statements
}
is IrExpressionBody -> IrExpressionBodyImpl(it.startOffset, it.endOffset) {
expression = (it.copyWithParameters() as IrExpressionBody).expression
}
is IrSyntheticBody -> it
else -> error("Unexpected body kind: ${it.javaClass}")
}
}
return staticFunction
}
}
class PrivateMemberBodiesLowering(val context: JsIrBackendContext) : BodyLoweringPass {
private var IrFunction.correspondingStatic by context.mapping.privateMemberToCorrespondingStatic
override fun lower(irBody: IrBody, container: IrDeclaration) {
irBody.transform(object : IrElementTransformerVoid() {
override fun visitCall(expression: IrCall): IrExpression { override fun visitCall(expression: IrCall): IrExpression {
super.visitCall(expression) super.visitCall(expression)
return getOrPutStaticFunction(expression.symbol)?.let { return expression.symbol.owner.correspondingStatic?.let {
transformPrivateToStaticCall(expression, it) transformPrivateToStaticCall(expression, it)
} ?: expression } ?: expression
} }
@@ -74,7 +161,7 @@ class PrivateMembersLowering(val context: JsIrBackendContext) : FileLoweringPass
override fun visitFunctionReference(expression: IrFunctionReference): IrExpression { override fun visitFunctionReference(expression: IrFunctionReference): IrExpression {
super.visitFunctionReference(expression) super.visitFunctionReference(expression)
return getOrPutStaticFunction(expression.symbol)?.let { return expression.symbol.owner.correspondingStatic?.let {
transformPrivateToStaticReference(expression) { transformPrivateToStaticReference(expression) {
IrFunctionReferenceImpl( IrFunctionReferenceImpl(
expression.startOffset, expression.endOffset, expression.startOffset, expression.endOffset,
@@ -89,8 +176,8 @@ class PrivateMembersLowering(val context: JsIrBackendContext) : FileLoweringPass
override fun visitPropertyReference(expression: IrPropertyReference): IrExpression { override fun visitPropertyReference(expression: IrPropertyReference): IrExpression {
super.visitPropertyReference(expression) super.visitPropertyReference(expression)
val staticGetter = expression.getter?.let { getOrPutStaticFunction(it) } val staticGetter = expression.getter?.owner?.correspondingStatic
val staticSetter = expression.setter?.let { getOrPutStaticFunction(it) } val staticSetter = expression.setter?.owner?.correspondingStatic
return if (staticGetter != null || staticSetter != null) { return if (staticGetter != null || staticSetter != null) {
transformPrivateToStaticReference(expression) { transformPrivateToStaticReference(expression) {
@@ -147,88 +234,4 @@ class PrivateMembersLowering(val context: JsIrBackendContext) : FileLoweringPass
} }
}, null) }, null)
} }
private fun transformAccessor(accessor: IrSimpleFunction) = transformMemberToStaticFunction(accessor) ?: accessor
private fun transformMemberToStaticFunction(function: IrSimpleFunction): IrSimpleFunction? {
val staticFunction = getOrPutStaticFunction(function.symbol) ?: return null
// Detach old function from corresponding property
val correspondingProperty = function.correspondingPropertySymbol?.owner
if (correspondingProperty != null) {
when (function) {
correspondingProperty.getter -> correspondingProperty.getter = staticFunction
correspondingProperty.setter -> correspondingProperty.setter = staticFunction
}
}
val oldParameters =
listOfNotNull(function.extensionReceiverParameter, function.dispatchReceiverParameter) + function.valueParameters
val newParameters = listOfNotNull(staticFunction.extensionReceiverParameter) + staticFunction.valueParameters
assert(oldParameters.size == newParameters.size)
val parameterMapping = oldParameters.zip(newParameters).toMap()
staticFunction.body = function.body?.deepCopyWithSymbols(staticFunction)
staticFunction.transform(object : IrElementTransformerVoid() {
override fun visitGetValue(expression: IrGetValue) = parameterMapping[expression.symbol.owner]?.let {
expression.run { IrGetValueImpl(startOffset, endOffset, type, it.symbol, origin) }
} ?: expression
}, null)
return staticFunction
}
private fun getOrPutStaticFunction(functionSymbol: IrFunctionSymbol): IrSimpleFunction? {
val function = functionSymbol.owner
if (function !is IrSimpleFunction) return null
if (function.visibility != Visibilities.PRIVATE || function.dispatchReceiverParameter == null) return null
return memberMap.getOrPut(function.symbol) {
val descriptor = WrappedSimpleFunctionDescriptor()
val symbol = IrSimpleFunctionSymbolImpl(descriptor)
val staticFunction = function.run {
IrFunctionImpl(
startOffset, endOffset, origin,
symbol, name, visibility, modality,
returnType,
isInline = isInline, isExternal = isExternal, isTailrec = isTailrec, isSuspend = isSuspend, isExpect = isExpect,
isFakeOverride = origin == IrDeclarationOrigin.FAKE_OVERRIDE,
isOperator = isOperator
).also {
descriptor.bind(it)
it.parent = parent
it.correspondingPropertySymbol = correspondingPropertySymbol
}
}
staticFunction.typeParameters += function.typeParameters.map { it.deepCopyWithSymbols(staticFunction) }
staticFunction.extensionReceiverParameter = function.extensionReceiverParameter?.copyTo(staticFunction)
val thisDesc = WrappedValueParameterDescriptor()
val thisSymbol = IrValueParameterSymbolImpl(thisDesc)
staticFunction.valueParameters += IrValueParameterImpl(
UNDEFINED_OFFSET,
UNDEFINED_OFFSET,
STATIC_THIS_PARAMETER,
thisSymbol,
Name.identifier("\$this"),
0,
function.dispatchReceiverParameter!!.type,
null,
isCrossinline = false,
isNoinline = false
).also {
thisDesc.bind(it)
it.parent = staticFunction
}
staticFunction.valueParameters += function.valueParameters.map { it.copyTo(staticFunction, index = it.index + 1) }
staticFunction
}
}
} }