From 2507780e1965f6894f8508a3916b2792c9625e36 Mon Sep 17 00:00:00 2001 From: Mikhael Bogdanov Date: Wed, 14 Jun 2017 13:45:30 +0200 Subject: [PATCH] Extract PsiInlineCodegen --- .../jetbrains/kotlin/codegen/CallGenerator.kt | 18 +- .../kotlin/codegen/ExpressionCodegen.java | 2 +- .../kotlin/codegen/inline/InlineCodegen.kt | 344 ++++++++++-------- .../inline/InlineCodegenForDefaultBody.kt | 2 +- .../codegen/inline/ParametersBuilder.kt | 2 +- 5 files changed, 195 insertions(+), 173 deletions(-) diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/CallGenerator.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/CallGenerator.kt index bb55c092f31..08c7f474445 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/CallGenerator.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/CallGenerator.kt @@ -31,9 +31,9 @@ enum class ValueKind { DEFAULT_LAMBDA_CAPTURED_PARAMETER } -abstract class CallGenerator { +interface CallGenerator { - internal class DefaultCallGenerator(private val codegen: ExpressionCodegen) : CallGenerator() { + class DefaultCallGenerator(private val codegen: ExpressionCodegen) : CallGenerator { override fun genCallInner( callableMethod: Callable, @@ -106,9 +106,9 @@ abstract class CallGenerator { genCallInner(callableMethod, resolvedCall, callDefault, codegen) } - abstract fun genCallInner(callableMethod: Callable, resolvedCall: ResolvedCall<*>?, callDefault: Boolean, codegen: ExpressionCodegen) + fun genCallInner(callableMethod: Callable, resolvedCall: ResolvedCall<*>?, callDefault: Boolean, codegen: ExpressionCodegen) - abstract fun genValueAndPut( + fun genValueAndPut( valueParameterDescriptor: ValueParameterDescriptor, argumentExpression: KtExpression, parameterType: Type, @@ -120,20 +120,20 @@ abstract class CallGenerator { putValueIfNeeded(parameterType, value, ValueKind.GENERAL) } - abstract fun putValueIfNeeded( + fun putValueIfNeeded( parameterType: Type, value: StackValue, kind: ValueKind = ValueKind.GENERAL, parameterIndex: Int = -1) - abstract fun putCapturedValueOnStack( + fun putCapturedValueOnStack( stackValue: StackValue, valueType: Type, paramIndex: Int) - abstract fun processAndPutHiddenParameters(justProcess: Boolean) + fun processAndPutHiddenParameters(justProcess: Boolean) /*should be called if justProcess = true in processAndPutHiddenParameters*/ - abstract fun putHiddenParamsIntoLocals() + fun putHiddenParamsIntoLocals() - abstract fun reorderArgumentsIfNeeded(actualArgsWithDeclIndex: List, valueParameterTypes: List) + fun reorderArgumentsIfNeeded(actualArgsWithDeclIndex: List, valueParameterTypes: List) } diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java index fe30e0eff23..db4db2d93ab 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java @@ -2291,7 +2291,7 @@ public class ExpressionCodegen extends KtVisitor impleme return new InlineCodegenForDefaultBody(original, this, state, new SourceCompilerForInline(this)); } else { - return new InlineCodegen(this, state, original, callElement, typeParameterMappings, new SourceCompilerForInline(this)); + return new PsiInlineCodegen(this, state, original, callElement, typeParameterMappings, new SourceCompilerForInline(this)); } } diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegen.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegen.kt index a8da31c11b3..cbb6fa66a1b 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegen.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegen.kt @@ -57,14 +57,14 @@ import org.jetbrains.org.objectweb.asm.tree.AbstractInsnNode import org.jetbrains.org.objectweb.asm.tree.MethodNode import java.util.* -class InlineCodegen( - private val codegen: BaseExpressionCodegen, - private val state: GenerationState, +abstract class InlineCodegen( + protected val codegen: BaseExpressionCodegen, + protected val state: GenerationState, function: FunctionDescriptor, private val callElement: KtElement, private val typeParameterMappings: TypeParameterMappings, - private val sourceCompiler: SourceCompilerForInline -) : CallGenerator() { + protected val sourceCompiler: SourceCompilerForInline +) { init { assert(InlineUtil.isInline(function) || InlineUtil.isArrayConstructorWithLambda(function)) { "InlineCodegen can inline only inline functions and array constructors: " + function @@ -74,35 +74,35 @@ class InlineCodegen( // TODO: implement AS_FUNCTION inline strategy private val asFunctionInline = false - private val typeMapper = state.typeMapper + protected val typeMapper = state.typeMapper private val initialFrameSize = codegen.frameMap.currentSize private val reifiedTypeInliner = ReifiedTypeInliner(typeParameterMappings) - private val functionDescriptor: FunctionDescriptor = + protected val functionDescriptor: FunctionDescriptor = if (InlineUtil.isArrayConstructorWithLambda(function)) FictitiousArrayConstructor.create(function as ConstructorDescriptor) else function.original - private val jvmSignature: JvmMethodGenericSignature + protected val jvmSignature: JvmMethodGenericSignature private val isSameModule: Boolean - private val invocationParamBuilder = ParametersBuilder.newBuilder() + protected val invocationParamBuilder = ParametersBuilder.newBuilder() - private val expressionMap = linkedMapOf() + protected val expressionMap = linkedMapOf() - private var activeLambda: LambdaInfo? = null + protected var activeLambda: LambdaInfo? = null private val sourceMapper = sourceCompiler.lazySourceMapper - private var delayedHiddenWriting: Function0? = null + protected var delayedHiddenWriting: Function0? = null - private val maskValues = ArrayList() - private var maskStartIndex = -1 - private var methodHandleInDefaultMethodIndex = -1 + protected val maskValues = ArrayList() + protected var maskStartIndex = -1 + protected var methodHandleInDefaultMethodIndex = -1 init { sourceCompiler.initializeInlineFunctionContext(functionDescriptor) @@ -121,8 +121,40 @@ class InlineCodegen( } } - override fun genCallInner( - callableMethod: Callable, + + protected fun throwCompilationException( + nodeAndSmap: SMAPAndMethodNode?, e: Exception, generateNodeText: Boolean + ): CompilationException { + val contextDescriptor = sourceCompiler.compilationContextDescriptor + val element = DescriptorToSourceUtils.descriptorToDeclaration(contextDescriptor) + val node = nodeAndSmap?.node + throw CompilationException( + "Couldn't inline method call '" + functionDescriptor.name + "' into\n" + + DescriptorRenderer.DEBUG_TEXT.render(contextDescriptor) + "\n" + + (element?.text ?: "") + + if (generateNodeText) "\nCause: " + node.nodeText else "", + e, callElement + ) + } + + protected fun generateStub(resolvedCall: ResolvedCall<*>?, codegen: BaseExpressionCodegen) { + leaveTemps() + assert(resolvedCall != null) + val message = "Call is part of inline cycle: " + resolvedCall!!.call.callElement.text + AsmUtil.genThrow(codegen.v, "java/lang/UnsupportedOperationException", message) + } + + protected fun endCall(result: InlineResult) { + leaveTemps() + + codegen.propagateChildReifiedTypeParametersUsages(result.reifiedTypeParametersUsages) + + state.factory.removeClasses(result.calcClassesToRemove()) + + codegen.markLineNumberAfterInlineIfNeeded() + } + + fun performInline( resolvedCall: ResolvedCall<*>?, callDefault: Boolean, codegen: BaseExpressionCodegen @@ -151,39 +183,8 @@ class InlineCodegen( } } - private fun throwCompilationException( - nodeAndSmap: SMAPAndMethodNode?, e: Exception, generateNodeText: Boolean - ): CompilationException { - val contextDescriptor = sourceCompiler.compilationContextDescriptor - val element = DescriptorToSourceUtils.descriptorToDeclaration(contextDescriptor) - val node = nodeAndSmap?.node - throw CompilationException( - "Couldn't inline method call '" + functionDescriptor.name + "' into\n" + - DescriptorRenderer.DEBUG_TEXT.render(contextDescriptor) + "\n" + - (element?.text ?: "") + - if (generateNodeText) "\nCause: " + node.nodeText else "", - e, callElement - ) - } - private fun generateStub(resolvedCall: ResolvedCall<*>?, codegen: BaseExpressionCodegen) { - leaveTemps() - assert(resolvedCall != null) - val message = "Call is part of inline cycle: " + resolvedCall!!.call.callElement.text - AsmUtil.genThrow(codegen.v, "java/lang/UnsupportedOperationException", message) - } - - private fun endCall(result: InlineResult) { - leaveTemps() - - codegen.propagateChildReifiedTypeParametersUsages(result.reifiedTypeParametersUsages) - - state.factory.removeClasses(result.calcClassesToRemove()) - - codegen.markLineNumberAfterInlineIfNeeded() - } - - private fun inlineCall(nodeAndSmap: SMAPAndMethodNode, callDefault: Boolean): InlineResult { + protected fun inlineCall(nodeAndSmap: SMAPAndMethodNode, callDefault: Boolean): InlineResult { assert(delayedHiddenWriting == null) { "'putHiddenParamsIntoLocals' should be called after 'processAndPutHiddenParameters(true)'" } val defaultSourceMapper = sourceMapper defaultSourceMapper.callSiteMarker = CallSiteMarker(codegen.lastLineNumber) @@ -257,7 +258,7 @@ class InlineCodegen( } } - private fun putArgumentOrCapturedToLocalVal( + protected fun putArgumentOrCapturedToLocalVal( type: Type, stackValue: StackValue, capturedParamIndex: Int, @@ -292,7 +293,7 @@ class InlineCodegen( } } - private fun recordParameterValueInLocalVal(delayedWritingToLocals: Boolean, skipStore: Boolean, vararg infos: ParameterInfo): Function0? { + protected fun recordParameterValueInLocalVal(delayedWritingToLocals: Boolean, skipStore: Boolean, vararg infos: ParameterInfo): Function0? { val index = IntArray(infos.size) { i -> if (!infos[i].isSkippedOrRemapped) { codegen.frameMap.enterTemp(infos[i].getType()) @@ -322,23 +323,6 @@ class InlineCodegen( return null } - override fun processAndPutHiddenParameters(justProcess: Boolean) { - if (getMethodAsmFlags(functionDescriptor, sourceCompiler.contextKind, state) and Opcodes.ACC_STATIC == 0) { - invocationParamBuilder.addNextParameter(AsmTypes.OBJECT_TYPE, false) - } - - for (param in jvmSignature.valueParameters) { - if (param.kind == JvmMethodParameterKind.VALUE) { - break - } - invocationParamBuilder.addNextParameter(param.asmType, false) - } - - invocationParamBuilder.markValueParametersStart() - val hiddenParameters = invocationParamBuilder.buildParameters().parameters - - delayedHiddenWriting = recordParameterValueInLocalVal(justProcess, false, *hiddenParameters.toTypedArray()) - } private fun leaveTemps() { invocationParamBuilder.listAllParams().asReversed().forEach { @@ -349,19 +333,6 @@ class InlineCodegen( } } - private fun rememberClosure(expression: KtExpression, type: Type, parameter: ValueParameterDescriptor): LambdaInfo { - val ktLambda = KtPsiUtil.deparenthesize(expression) - assert(isInlinableParameterExpression(ktLambda)) { "Couldn't find inline expression in ${expression.text}" } - - return ExpressionLambda( - ktLambda!!, typeMapper, parameter.isCrossinline, getBoundCallableReferenceReceiver(expression) != null - ).also { lambda -> - val closureInfo = invocationParamBuilder.addNextValueParameter(type, true, null, parameter.index) - closureInfo.lambda = lambda - expressionMap.put(closureInfo.index, lambda) - } - } - private fun putClosureParametersOnStack() { for (next in expressionMap.values) { //closure parameters for bounded callable references are generated inplace @@ -370,21 +341,9 @@ class InlineCodegen( } } - private fun putClosureParametersOnStack(next: LambdaInfo, functionReferenceReceiver: StackValue?) { - activeLambda = next - if (next is ExpressionLambda) { - codegen.pushClosureOnStack(next.classDescriptor, true, this, functionReferenceReceiver) - } - else if (next is DefaultLambda) { - rememberCapturedForDefaultLambda(next) - } - else { - throw RuntimeException("Unknown lambda: $next") - } - activeLambda = null - } + abstract protected fun putClosureParametersOnStack(next: LambdaInfo, functionReferenceReceiver: StackValue?) - private fun rememberCapturedForDefaultLambda(defaultLambda: DefaultLambda) { + protected fun rememberCapturedForDefaultLambda(defaultLambda: DefaultLambda) { for ((paramIndex, captured) in defaultLambda.capturedVars.withIndex()) { putArgumentOrCapturedToLocalVal( captured.type, @@ -400,49 +359,8 @@ class InlineCodegen( } } - override fun genValueAndPut( - valueParameterDescriptor: ValueParameterDescriptor, - argumentExpression: KtExpression, - parameterType: Type, - parameterIndex: Int - ) { - if (isInliningParameter(argumentExpression, valueParameterDescriptor)) { - val lambdaInfo = rememberClosure(argumentExpression, parameterType, valueParameterDescriptor) - val receiver = getBoundCallableReferenceReceiver(argumentExpression) - if (receiver != null) { - putClosureParametersOnStack(lambdaInfo, codegen.gen(receiver)) - } - } - else { - val value = codegen.gen(argumentExpression) - putValueIfNeeded(parameterType, value, ValueKind.GENERAL, valueParameterDescriptor.index) - } - } - - private fun getBoundCallableReferenceReceiver( - argumentExpression: KtExpression - ): KtExpression? { - val deparenthesized = KtPsiUtil.deparenthesize(argumentExpression) - if (deparenthesized is KtCallableReferenceExpression) { - val receiverExpression = deparenthesized.receiverExpression - if (receiverExpression != null) { - val lhs = state.bindingContext.get(BindingContext.DOUBLE_COLON_LHS, receiverExpression) - if (lhs is DoubleColonLHS.Expression) return receiverExpression - } - } - return null - } - - override fun putValueIfNeeded(parameterType: Type, value: StackValue, kind: ValueKind, parameterIndex: Int) { - if (processDefaultMaskOrMethodHandler(value, kind)) return - - assert(maskValues.isEmpty()) { "Additional default call arguments should be last ones, but " + value } - - putArgumentOrCapturedToLocalVal(parameterType, value, -1, parameterIndex, kind) - } - - private fun processDefaultMaskOrMethodHandler(value: StackValue, kind: ValueKind): Boolean { + protected fun processDefaultMaskOrMethodHandler(value: StackValue, kind: ValueKind): Boolean { if (kind !== ValueKind.DEFAULT_MASK && kind !== ValueKind.METHOD_HANDLE_IN_DEFAULT) { return false } @@ -462,20 +380,6 @@ class InlineCodegen( return true } - override fun putCapturedValueOnStack(stackValue: StackValue, valueType: Type, paramIndex: Int) { - putArgumentOrCapturedToLocalVal(stackValue.type, stackValue, paramIndex, paramIndex, ValueKind.CAPTURED) - } - - override fun reorderArgumentsIfNeeded( - actualArgsWithDeclIndex: List, valueParameterTypes: List - ) { - } - - override fun putHiddenParamsIntoLocals() { - assert(delayedHiddenWriting != null) { "processAndPutHiddenParameters(true) should be called before putHiddenParamsIntoLocals" } - delayedHiddenWriting!!.invoke() - delayedHiddenWriting = null - } companion object { @@ -577,7 +481,6 @@ class InlineCodegen( } - private fun isBuiltInArrayIntrinsic(callableDescriptor: CallableMemberDescriptor): Boolean { if (callableDescriptor is FictitiousArrayConstructor) return true val name = callableDescriptor.name.asString() @@ -630,13 +533,6 @@ class InlineCodegen( return true } - /*lambda or callable reference*/ - private fun isInliningParameter(expression: KtExpression, valueParameterDescriptor: ValueParameterDescriptor): Boolean { - //TODO deparenthisise typed - val deparenthesized = KtPsiUtil.deparenthesize(expression) - - return InlineUtil.isInlineLambdaParameter(valueParameterDescriptor) && isInlinableParameterExpression(deparenthesized) - } fun getDeclarationLabels(lambdaOrFun: PsiElement?, descriptor: DeclarationDescriptor): Set { val result = HashSet() @@ -658,7 +554,6 @@ class InlineCodegen( } - fun createNestedSourceMapper(nodeAndSmap: SMAPAndMethodNode, parent: SourceMapper): SourceMapper { return NestedSourceMapper(parent, nodeAndSmap.sortedRanges, nodeAndSmap.classSMAP.sourceInfo) } @@ -679,4 +574,131 @@ class InlineCodegen( } val BaseExpressionCodegen.v: InstructionAdapter - get() = visitor \ No newline at end of file + get() = visitor + +class PsiInlineCodegen( + codegen: ExpressionCodegen, + state: GenerationState, + function: FunctionDescriptor, + callElement: KtElement, + typeParameterMappings: TypeParameterMappings, + sourceCompiler: SourceCompilerForInline +) : InlineCodegen(codegen, state, function, callElement, typeParameterMappings, sourceCompiler), CallGenerator { + + override fun genCallInner( + callableMethod: Callable, + resolvedCall: ResolvedCall<*>?, + callDefault: Boolean, + codegen: ExpressionCodegen + ) { + performInline(resolvedCall, callDefault, codegen) + } + + override fun processAndPutHiddenParameters(justProcess: Boolean) { + if (getMethodAsmFlags(functionDescriptor, sourceCompiler.contextKind, state) and Opcodes.ACC_STATIC == 0) { + invocationParamBuilder.addNextParameter(AsmTypes.OBJECT_TYPE, false) + } + + for (param in jvmSignature.valueParameters) { + if (param.kind == JvmMethodParameterKind.VALUE) { + break + } + invocationParamBuilder.addNextParameter(param.asmType, false) + } + + invocationParamBuilder.markValueParametersStart() + val hiddenParameters = invocationParamBuilder.buildParameters().parameters + + delayedHiddenWriting = recordParameterValueInLocalVal(justProcess, false, *hiddenParameters.toTypedArray()) + } + + override fun putClosureParametersOnStack(next: LambdaInfo, functionReferenceReceiver: StackValue?) { + activeLambda = next + if (next is ExpressionLambda) { + codegen.pushClosureOnStack(next.classDescriptor, true, this, functionReferenceReceiver) + } + else if (next is DefaultLambda) { + rememberCapturedForDefaultLambda(next) + } + else { + throw RuntimeException("Unknown lambda: $next") + } + activeLambda = null + } + + + private fun getBoundCallableReferenceReceiver( + argumentExpression: KtExpression + ): KtExpression? { + val deparenthesized = KtPsiUtil.deparenthesize(argumentExpression) + if (deparenthesized is KtCallableReferenceExpression) { + val receiverExpression = deparenthesized.receiverExpression + if (receiverExpression != null) { + val lhs = state.bindingContext.get(BindingContext.DOUBLE_COLON_LHS, receiverExpression) + if (lhs is DoubleColonLHS.Expression) return receiverExpression + } + } + return null + } + + /*lambda or callable reference*/ + private fun isInliningParameter(expression: KtExpression, valueParameterDescriptor: ValueParameterDescriptor): Boolean { + //TODO deparenthisise typed + val deparenthesized = KtPsiUtil.deparenthesize(expression) + + return InlineUtil.isInlineLambdaParameter(valueParameterDescriptor) && isInlinableParameterExpression(deparenthesized) + } + + override fun genValueAndPut( + valueParameterDescriptor: ValueParameterDescriptor, + argumentExpression: KtExpression, + parameterType: Type, + parameterIndex: Int + ) { + if (isInliningParameter(argumentExpression, valueParameterDescriptor)) { + val lambdaInfo = rememberClosure(argumentExpression, parameterType, valueParameterDescriptor) + + val receiver = getBoundCallableReferenceReceiver(argumentExpression) + if (receiver != null) { + putClosureParametersOnStack(lambdaInfo, codegen.gen(receiver)) + } + } + else { + val value = codegen.gen(argumentExpression) + putValueIfNeeded(parameterType, value, ValueKind.GENERAL, valueParameterDescriptor.index) + } + } + + private fun rememberClosure(expression: KtExpression, type: Type, parameter: ValueParameterDescriptor): LambdaInfo { + val ktLambda = KtPsiUtil.deparenthesize(expression) + assert(isInlinableParameterExpression(ktLambda)) { "Couldn't find inline expression in ${expression.text}" } + + return ExpressionLambda( + ktLambda!!, typeMapper, parameter.isCrossinline, getBoundCallableReferenceReceiver(expression) != null + ).also { lambda -> + val closureInfo = invocationParamBuilder.addNextValueParameter(type, true, null, parameter.index) + closureInfo.lambda = lambda + expressionMap.put(closureInfo.index, lambda) + } + } + + override fun putValueIfNeeded(parameterType: Type, value: StackValue, kind: ValueKind, parameterIndex: Int) { + if (processDefaultMaskOrMethodHandler(value, kind)) return + + assert(maskValues.isEmpty()) { "Additional default call arguments should be last ones, but " + value } + + putArgumentOrCapturedToLocalVal(parameterType, value, -1, parameterIndex, kind) + } + + override fun putCapturedValueOnStack(stackValue: StackValue, valueType: Type, paramIndex: Int) { + putArgumentOrCapturedToLocalVal(stackValue.type, stackValue, paramIndex, paramIndex, ValueKind.CAPTURED) + } + + override fun reorderArgumentsIfNeeded(actualArgsWithDeclIndex: List, valueParameterTypes: List) = Unit + + override fun putHiddenParamsIntoLocals() { + assert(delayedHiddenWriting != null) { "processAndPutHiddenParameters(true) should be called before putHiddenParamsIntoLocals" } + delayedHiddenWriting!!.invoke() + delayedHiddenWriting = null + } +} \ No newline at end of file diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegenForDefaultBody.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegenForDefaultBody.kt index dfdba745615..341304b1df2 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegenForDefaultBody.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegenForDefaultBody.kt @@ -34,7 +34,7 @@ class InlineCodegenForDefaultBody( codegen: ExpressionCodegen, val state: GenerationState, private val sourceCompilerForInline: SourceCompilerForInline -) : CallGenerator() { +) : CallGenerator { private val sourceMapper: SourceMapper = codegen.parentCodegen.orCreateSourceMapper diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/ParametersBuilder.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/ParametersBuilder.kt index 2f31013843b..12f614f38cd 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/ParametersBuilder.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/ParametersBuilder.kt @@ -19,7 +19,7 @@ package org.jetbrains.kotlin.codegen.inline import org.jetbrains.kotlin.codegen.StackValue import org.jetbrains.org.objectweb.asm.Type -internal class ParametersBuilder private constructor() { +class ParametersBuilder private constructor() { private val params = arrayListOf()