All arguments evaluated before inlining procedure

Type of "substituteMap" changed to "MutableMap"
Code improved according with Slava's comments
This commit is contained in:
Konstantin Anisimov
2017-03-15 17:00:26 +07:00
committed by KonstantinAnisimov
parent 22b74c0a3a
commit 98322d6f55
@@ -71,13 +71,55 @@ internal class FunctionInlining(val context: Context): IrElementTransformerVoid(
val functionDescriptor = expression.descriptor as FunctionDescriptor
if (functionDescriptor.isInline) {
val inlineFunctionBody = inlineFunction(expression)
// inlineFunctionBody.transformChildrenVoid(this) // TODO
inlineFunctionBody.transformChildrenVoid(this) // TODO
return inlineFunctionBody // Return newly created IrInlineBody instead of IrCall.
}
return super.visitCall(expression)
}
//---------------------------------------------------------------------//
fun isLambdaExpression(expression: IrExpression) : Boolean {
if (expression !is IrContainerExpressionBase) return false
if (expression.origin != IrStatementOrigin.LAMBDA) return false
return true
}
//---------------------------------------------------------------------//
fun needsEvaluation(expression: IrExpression): Boolean {
if (expression is IrGetValue) return false // Parameter is already GetValue - nothing to evaluate.
if (expression is IrConst<*>) return false // Parameter is constant - nothing to evaluate.
if (isLambdaExpression(expression)) return false // Parameter is lambda - will be inlined.
return true
}
//-------------------------------------------------------------------------//
fun evaluateParameters(irCall: IrCall, statements: MutableList<IrStatement>): MutableMap<ValueDescriptor, IrExpression> {
val parametersOld = irCall.getArguments() // Create map call_site_argument -> inline_function_parameter.
val parametersNew = mutableMapOf<ValueDescriptor, IrExpression> ()
parametersOld.forEach {
val parameter = it.first.original
val argument = it.second
if (!needsEvaluation(argument)) {
parametersNew[parameter] = argument
return@forEach
}
val newVar = functionScope!!.createTemporaryVariable(argument, "inline", false) // Create new variable and init it with the parameter expression.
statements.add(0, newVar) // Add initialization of the new variable in statement list.
val getVal = IrGetValueImpl(0, 0, newVar.descriptor) // Create new IR element representing access the new variable.
parametersNew[parameter] = getVal // Parameter will be replaced with the new variable.
}
return parametersNew
}
//-------------------------------------------------------------------------//
fun inlineFunction(irCall: IrCall): IrExpression {
@@ -103,22 +145,22 @@ internal class FunctionInlining(val context: Context): IrElementTransformerVoid(
val statements = blockBody.statements
val inlineBody = IrInlineFunctionBody(startOffset, endOffset, returnType, null, statements)
val parameterToArgument: MutableList <Pair <ValueDescriptor, IrExpression>> = irCall.getArguments().toMutableList()
val evaluationStatements = mutableListOf<IrStatement>()
val parameterToArgument = evaluateParameters(irCall, evaluationStatements)
val lambdaInliner = LambdaInliner(parameterToArgument)
inlineBody.transformChildrenVoid(lambdaInliner)
val typeArgsMap = (irCall as IrMemberAccessExpressionBase).typeArguments
val statementsBuf = mutableListOf<IrStatement>()
val transformer = ParametersTransformer(parameterToArgument, typeArgsMap, statementsBuf)
inlineBody.transformChildrenVoid(transformer) // Replace parameters with expression.
inlineBody.statements.addAll(0, statementsBuf)
val transformer = ParametersTransformer(parameterToArgument, typeArgsMap, evaluationStatements)
inlineBody.transformChildrenVoid(transformer) // Replace parameters with expression.
inlineBody.statements.addAll(0, evaluationStatements)
return inlineBody
}
//-------------------------------------------------------------------------//
inner class ParametersTransformer(val substituteMap: MutableList <Pair <ValueDescriptor, IrExpression>>,
inner class ParametersTransformer(val substituteMap: MutableMap <ValueDescriptor, IrExpression>,
val typeArgsMap: Map <TypeParameterDescriptor, KotlinType>?,
val statements: MutableList<IrStatement>): IrElementTransformerVoid() {
@@ -141,7 +183,7 @@ internal class FunctionInlining(val context: Context): IrElementTransformerVoid(
val typeNew = typeArgsMap[operandTypeDescriptor]!!
val startOffset = expression.startOffset
val endOffset = expression.endOffset
val type = expression.type // TODO
val type = expression.type // TODO
val operator = expression.operator
val argument = expression.argument
@@ -150,50 +192,12 @@ internal class FunctionInlining(val context: Context): IrElementTransformerVoid(
//---------------------------------------------------------------------//
fun isLambdaExpression(expression: IrExpression) : Boolean {
if (expression !is IrContainerExpressionBase) return false
if (expression.origin != IrStatementOrigin.LAMBDA) return false
return true
}
//---------------------------------------------------------------------//
fun needsEvaluation(expression: IrExpression): Boolean {
if (expression is IrGetValue) return false // Parameter is already GetValue - nothing to evaluate.
if (expression is IrConst<*>) return false // Parameter is constant - nothing to evaluate.
if (isLambdaExpression(expression)) return false // Parameter is lambda - will be inlined.
return true
}
//---------------------------------------------------------------------//
fun evaluateExpression(expression: IrExpression): IrGetValue {
// println(" evaluateExpression $expression")
val newVar = functionScope!!.createTemporaryVariable(expression, "inline", false) // Create new variable and init it with the parameter expression.
statements.add(0, newVar) // Add initialization of the new variable in statement list.
val getVal = IrGetValueImpl(0, 0, newVar.descriptor) // Create new IR element representing access the new variable.
return getVal // Parameter will be replaced with the new variable.
}
//---------------------------------------------------------------------//
override fun visitGetValue(expression: IrGetValue): IrExpression {
// println(" visitGetValue ${expression.descriptor.name}")
val newExpression = super.visitGetValue(expression) as IrGetValue
val descriptor = newExpression.descriptor
val substitute = substituteMap.find { it.first.original == descriptor } // Find expression to replace this parameter.
if (substitute == null) return newExpression // If there is no such expression - do nothing
val parameter = substitute.first
val argument = substitute.second
if (needsEvaluation(argument)) {
val newArgument = evaluateExpression(argument)
val index = substituteMap.indexOf(substitute)
val newSubstitute = parameter to newArgument
substituteMap[index] = newSubstitute
return newArgument
}
val argument = substituteMap[descriptor] // Find expression to replace this parameter.
if (argument == null) return newExpression // If there is no such expression - do nothing
return argument
}
@@ -213,14 +217,14 @@ internal class FunctionInlining(val context: Context): IrElementTransformerVoid(
val newDeclaration = super.visitVariable(declaration) as IrVariable // Process variable initializer.
val newVariable = newVariable(newDeclaration) // Create new local variable.
val getVal = IrGetValueImpl(0, 0, newVariable.descriptor) // Create new IR element representing access the new variable.
substituteMap.add(declaration.descriptor to getVal)
substituteMap[declaration.descriptor.original] to getVal
return newVariable
}
}
//-------------------------------------------------------------------------//
inner class LambdaInliner(val substituteMap: MutableList <Pair <ValueDescriptor, IrExpression>>): IrElementTransformerVoid() {
inner class LambdaInliner(val substituteMap: MutableMap <ValueDescriptor, IrExpression>): IrElementTransformerVoid() {
override fun visitElement(element: IrElement) = element.accept(this, null)
@@ -234,23 +238,6 @@ internal class FunctionInlining(val context: Context): IrElementTransformerVoid(
//---------------------------------------------------------------------//
fun getLambdaStatements(value: IrExpression) : MutableList<IrStatement> {
val statements = (value as IrContainerExpressionBase).statements
val lambdaFunction = statements[0] as IrFunction
val lambdaBody = lambdaFunction.body as IrBlockBody
return lambdaBody.statements
}
//---------------------------------------------------------------------//
fun getLambdaReturnType(value: IrExpression) : KotlinType {
val statements = (value as IrContainerExpressionBase).statements
val lambdaFunction = statements[0] as IrFunction
return lambdaFunction.descriptor.returnType!!
}
//---------------------------------------------------------------------//
fun getLambdaFunction(lambdaArgument: IrExpression): IrFunction? {
if (lambdaArgument !is IrBlock) return null
@@ -281,31 +268,35 @@ internal class FunctionInlining(val context: Context): IrElementTransformerVoid(
//---------------------------------------------------------------------//
fun buildParameterToArgument(lambdaFunction: IrFunction, irCall: IrCall): MutableMap<ValueDescriptor, IrExpression> {
val parameters = lambdaFunction.descriptor.valueParameters // Get lambda function parameters.
val parameterToArgument = mutableMapOf<ValueDescriptor, IrExpression>()
parameters.forEach { // Iterate parameters.
val parameter = it
val argument = irCall.getValueArgument(it.index) // Get corresponding argument.
parameterToArgument[parameter] = argument!! // Create (parameter -> argument) pair.
}
return parameterToArgument
}
//---------------------------------------------------------------------//
fun inlineLambda(irCall: IrCall): IrExpression {
val dispatchReceiver = irCall.dispatchReceiver as IrGetValue //
val substitute = substituteMap.find { // Find expression to replace this parameter.
it.first == dispatchReceiver.descriptor
}
if (substitute == null) return super.visitCall(irCall) // It is not function parameter - nothing to substitute.
val lambdaArgument = substituteMap[dispatchReceiver.descriptor] // Find expression to replace this parameter.
if (lambdaArgument == null) return super.visitCall(irCall) // It is not function parameter - nothing to substitute.
val lambdaArgument = substitute.second
val lambdaFunction = getLambdaFunction(lambdaArgument)
if (lambdaFunction == null) return super.visitCall(irCall) // TODO
val parameters = lambdaFunction.descriptor.valueParameters // Get lambda function parameters.
val substituteMap = parameters.map { // Iterate parameters.
val parameter = it as ValueDescriptor
val argument = irCall.getValueArgument(it.index) // Get corresponding argument.
parameter to argument!! // Create (parameter -> argument) pair.
}.toMutableList()
val parameterToArgument = buildParameterToArgument(lambdaFunction, irCall)
val lambdaStatements = getLambdaStatements(lambdaArgument)
val lambdaReturnType = getLambdaReturnType(lambdaArgument)
val lambdaStatements = (lambdaFunction.body as IrBlockBody).statements
val lambdaReturnType = lambdaFunction.descriptor.returnType!!
val inlineBody = IrInlineFunctionBody(0, 0, lambdaReturnType, null, lambdaStatements)
val transformer = ParametersTransformer(substituteMap, null, lambdaStatements)
val transformer = ParametersTransformer(parameterToArgument, null, lambdaStatements)
inlineBody.accept(transformer, null) // Replace parameters with expression.
return inlineBody // Replace call site with InlineFunctionBody.