Revert "Revert commits: (#1162)

This commit is contained in:
KonstantinAnisimov
2017-12-18 15:03:55 +03:00
committed by Nikolay Igotti
parent 5d856665c8
commit d237afdea5
@@ -26,7 +26,10 @@ import org.jetbrains.kotlin.backend.konan.descriptors.isFunctionInvoke
import org.jetbrains.kotlin.backend.konan.descriptors.needsInlining
import org.jetbrains.kotlin.backend.konan.descriptors.resolveFakeOverride
import org.jetbrains.kotlin.backend.konan.ir.DeserializerDriver
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.descriptors.ValueDescriptor
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.declarations.IrFunction
@@ -44,7 +47,6 @@ import org.jetbrains.kotlin.resolve.descriptorUtil.hasDefaultValue
import org.jetbrains.kotlin.types.TypeProjectionImpl
import org.jetbrains.kotlin.types.TypeSubstitutor
//-----------------------------------------------------------------------------//
internal class FunctionInlining(val context: Context): IrElementTransformerVoidWithContext() {
@@ -66,31 +68,21 @@ internal class FunctionInlining(val context: Context): IrElementTransformerVoidW
override fun visitCall(expression: IrCall): IrExpression {
val functionDescriptor = expression.descriptor
if (!functionDescriptor.needsInlining) return super.visitCall(expression) // This call does not need inlining.
if (isInlineFunctionScope()) return super.visitCall(expression) // Ignore inlining in functions declared as "inline"
val irCall = super.visitCall(expression) as IrCall
val functionDescriptor = irCall.descriptor
if (!functionDescriptor.needsInlining) return irCall // This call does not need inlining.
val functionDeclaration = getFunctionDeclaration(expression) // Get declaration of the function to be inlined.
val functionDeclaration = getFunctionDeclaration(irCall) // Get declaration of the function to be inlined.
if (functionDeclaration == null) { // We failed to get the declaration.
val message = "Inliner failed to obtain function declaration: " +
functionDescriptor.fqNameSafe.toString()
context.reportWarning(message, currentFile, expression) // Report warning.
return super.visitCall(expression)
context.reportWarning(message, currentFile, irCall) // Report warning.
return irCall
}
functionDeclaration.transformChildrenVoid(this) // Process recursive inline.
val inliner = Inliner(globalSubstituteMap, functionDeclaration, currentScope!!, context) // Create inliner for this scope.
val inlinedFunctionBody = inliner.inline(expression) // Return newly created IrInlineBody instead of IrCall.
inlinedFunctionBody.transformChildrenVoid(this)
return inlinedFunctionBody
}
//-------------------------------------------------------------------------//
private fun isInlineFunctionScope(): Boolean {
if (currentFunction == null) return false
val scopeOwner = currentFunction!!.scope.scopeOwner
if (scopeOwner !is FunctionDescriptor) return false
return scopeOwner.isInline
return inliner.inline(irCall ) // Return newly created IrInlineBody instead of IrCall.
}
//-------------------------------------------------------------------------//
@@ -234,35 +226,21 @@ private class Inliner(val globalSubstituteMap: MutableMap<DeclarationDescriptor,
private class ParameterToArgument(val parameterDescriptor: ValueDescriptor,
val argumentExpression : IrExpression) {
val needsEvaluation : Boolean
val isInlinableLambda : Boolean
get() {
if (parameterDescriptor.isNoinline()) return true
if (argumentExpression.isInlinableBody()) return false
return true // The expression must be evaluated.
if (argumentExpression !is IrBlock) return false // Lambda must be represented with IrBlock.
if (argumentExpression.origin != IrStatementOrigin.LAMBDA && // Origin must be LAMBDA or ANONYMOUS.
argumentExpression.origin != IrStatementOrigin.ANONYMOUS_FUNCTION) return false
val statements = argumentExpression.statements
val irFunction = statements[0] // Lambda function declaration.
val irCallableReference = statements[1] // Lambda callable reference.
if (irFunction !is IrFunction) return false // First statement of the block must be lambda declaration.
if (irCallableReference !is IrCallableReference) return false // Second statement of the block must be CallableReference.
if (parameterDescriptor is ValueParameterDescriptor &&
parameterDescriptor.isNoinline) return false // If parameter marked as "noinline" - do not inline.
return true // The expression represents lambda.
}
//-------------------------------------------------------------------------//
fun ValueDescriptor.isNoinline(): Boolean {
if (this !is ValueParameterDescriptor) return false
if (this.isNoinline) return true // If parameter marked as "noinline" - do not inline.
return false
}
//-------------------------------------------------------------------------//
private fun isAnonymousFunction(descriptor: DeclarationDescriptor): Boolean {
return descriptor is SimpleFunctionDescriptor && descriptor.name.asString().contains("<anonymous>")
}
//-------------------------------------------------------------------------//
fun IrExpression.isInlinableBody(): Boolean {
if (this !is IrBlock) return false // Lambda must be represented with IrBlock.
val lastStatement = statements.last()
if (lastStatement !is IrCallableReference) return false // Second statement of the lambda block must be CallableReference.
return isAnonymousFunction(lastStatement.descriptor)
}
}
//-------------------------------------------------------------------------//
@@ -353,7 +331,7 @@ private class Inliner(val globalSubstituteMap: MutableMap<DeclarationDescriptor,
parameterToArgumentOld.forEach {
val parameterDescriptor = it.parameterDescriptor
if (!it.needsEvaluation) { // If parameter has functional type - it can not be evaluated.
if (it.isInlinableLambda) { // If argument is inlinable lambda.
substituteMap[parameterDescriptor] = it.argumentExpression // Associate parameter with lambda argument.
return@forEach
}