From 8dc1b8f95f3109ed01c09363d0de929e09b77143 Mon Sep 17 00:00:00 2001 From: Mikhael Bogdanov Date: Mon, 12 Jun 2017 15:20:20 +0200 Subject: [PATCH] Introduce BaseExpressionCodegen and SourceCompilerForInline, switch CallGenerator and InlineCodegen to them ~base --- .../kotlin/codegen/BaseExpressionCodegen.kt | 48 +++ .../kotlin/codegen/ExpressionCodegen.java | 37 +- .../kotlin/codegen/inline/InlineCodegen.kt | 348 ++--------------- .../inline/InlineCodegenForDefaultBody.kt | 23 +- .../kotlin/codegen/inline/LambdaInfo.kt | 23 +- .../codegen/inline/SourceCompilerForInline.kt | 365 ++++++++++++++++++ .../codegen/inline/inlineCodegenUtils.kt | 7 +- 7 files changed, 501 insertions(+), 350 deletions(-) create mode 100644 compiler/backend/src/org/jetbrains/kotlin/codegen/BaseExpressionCodegen.kt create mode 100644 compiler/backend/src/org/jetbrains/kotlin/codegen/inline/SourceCompilerForInline.kt diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/BaseExpressionCodegen.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/BaseExpressionCodegen.kt new file mode 100644 index 00000000000..2257b7bb0d1 --- /dev/null +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/BaseExpressionCodegen.kt @@ -0,0 +1,48 @@ +/* + * Copyright 2010-2017 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.kotlin.codegen + +import org.jetbrains.kotlin.codegen.inline.NameGenerator +import org.jetbrains.kotlin.codegen.inline.ReifiedTypeParametersUsages +import org.jetbrains.kotlin.descriptors.ClassDescriptor +import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor +import org.jetbrains.kotlin.psi.KtElement +import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter + +interface BaseExpressionCodegen { + + val frameMap: FrameMap + + val visitor: InstructionAdapter + + val inlineNameGenerator: NameGenerator + + val lastLineNumber: Int + + fun consumeReifiedOperationMarker(typeParameterDescriptor: TypeParameterDescriptor) + + fun propagateChildReifiedTypeParametersUsages(reifiedTypeParametersUsages: ReifiedTypeParametersUsages) + + fun pushClosureOnStack( + classDescriptor: ClassDescriptor, + putThis: Boolean, + callGenerator: CallGenerator, + functionReferenceReceiver: StackValue? + ) + + fun markLineNumberAfterInlineIfNeeded() +} diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java index 0089381a2ad..fe30e0eff23 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java @@ -118,7 +118,7 @@ import static org.jetbrains.kotlin.types.expressions.ExpressionTypingUtils.isFun import static org.jetbrains.kotlin.types.expressions.ExpressionTypingUtils.isFunctionLiteral; import static org.jetbrains.org.objectweb.asm.Opcodes.*; -public class ExpressionCodegen extends KtVisitor implements LocalLookup { +public class ExpressionCodegen extends KtVisitor implements LocalLookup, BaseExpressionCodegen { private final GenerationState state; final KotlinTypeMapper typeMapper; private final BindingContext bindingContext; @@ -1352,6 +1352,7 @@ public class ExpressionCodegen extends KtVisitor impleme } //we should generate additional linenumber info after inline call only if it used as argument + @Override public void markLineNumberAfterInlineIfNeeded() { if (!shouldMarkLineNumbers) { //if it used as general argument @@ -1366,6 +1367,7 @@ public class ExpressionCodegen extends KtVisitor impleme } } + @Override public int getLastLineNumber() { return myLastLineNumber; } @@ -2286,10 +2288,10 @@ public class ExpressionCodegen extends KtVisitor impleme FunctionDescriptor original = unwrapInitialSignatureDescriptor(DescriptorUtils.unwrapFakeOverride((FunctionDescriptor) descriptor.getOriginal())); if (isDefaultCompilation) { - return new InlineCodegenForDefaultBody(original, this, state); + return new InlineCodegenForDefaultBody(original, this, state, new SourceCompilerForInline(this)); } else { - return new InlineCodegen(this, state, original, callElement, typeParameterMappings); + return new InlineCodegen(this, state, original, callElement, typeParameterMappings, new SourceCompilerForInline(this)); } } @@ -4060,19 +4062,17 @@ The "returned" value of try expression with no finally is either the last expres public void putReifiedOperationMarkerIfTypeIsReifiedParameter( @NotNull KotlinType type, @NotNull ReifiedTypeInliner.OperationKind operationKind ) { - putReifiedOperationMarkerIfTypeIsReifiedParameter(type, operationKind, v); + putReifiedOperationMarkerIfTypeIsReifiedParameter(type, operationKind, v, this); } - public void putReifiedOperationMarkerIfTypeIsReifiedParameter( - @NotNull KotlinType type, @NotNull ReifiedTypeInliner.OperationKind operationKind, @NotNull InstructionAdapter v + public static void putReifiedOperationMarkerIfTypeIsReifiedParameter( + @NotNull KotlinType type, @NotNull ReifiedTypeInliner.OperationKind operationKind, @NotNull InstructionAdapter v, + @NotNull BaseExpressionCodegen codegen ) { Pair typeParameterAndReificationArgument = extractReificationArgument(type); if (typeParameterAndReificationArgument != null && typeParameterAndReificationArgument.getFirst().isReified()) { TypeParameterDescriptor typeParameterDescriptor = typeParameterAndReificationArgument.getFirst(); - if (typeParameterDescriptor.getContainingDeclaration() != context.getContextDescriptor()) { - parentCodegen.getReifiedTypeParametersUsages(). - addUsedReifiedParameter(typeParameterDescriptor.getName().asString()); - } + codegen.consumeReifiedOperationMarker(typeParameterDescriptor); v.iconst(operationKind.getId()); v.visitLdcInsn(typeParameterAndReificationArgument.getSecond().asString()); v.invokestatic( @@ -4082,6 +4082,7 @@ The "returned" value of try expression with no finally is either the last expres } } + @Override public void propagateChildReifiedTypeParametersUsages(@NotNull ReifiedTypeParametersUsages usages) { parentCodegen.getReifiedTypeParametersUsages().propagateChildUsagesWithinContext(usages, context); } @@ -4203,6 +4204,7 @@ The "returned" value of try expression with no finally is either the last expres return context.getContextDescriptor().toString(); } + @Override @NotNull public FrameMap getFrameMap() { return myFrameMap; @@ -4213,6 +4215,7 @@ The "returned" value of try expression with no finally is either the last expres return context; } + @Override @NotNull public NameGenerator getInlineNameGenerator() { NameGenerator nameGenerator = getParentCodegen().getInlineNameGenerator(); @@ -4255,4 +4258,18 @@ The "returned" value of try expression with no finally is either the last expres ) { return StackValue.delegate(typeMapper.mapType(variableDescriptor.getType()), delegateValue, metadataValue, variableDescriptor, this); } + + @NotNull + @Override + public InstructionAdapter getVisitor() { + return v; + } + + @Override + public void consumeReifiedOperationMarker(@NotNull TypeParameterDescriptor typeParameterDescriptor) { + if (typeParameterDescriptor.getContainingDeclaration() != context.getContextDescriptor()) { + parentCodegen.getReifiedTypeParametersUsages(). + addUsedReifiedParameter(typeParameterDescriptor.getName().asString()); + } + } } 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 09684e00884..a8da31c11b3 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegen.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegen.kt @@ -18,12 +18,10 @@ package org.jetbrains.kotlin.codegen.inline import com.intellij.psi.PsiElement import com.intellij.util.ArrayUtil -import org.jetbrains.kotlin.backend.common.CodegenUtil import org.jetbrains.kotlin.builtins.BuiltInsPackageFragment import org.jetbrains.kotlin.codegen.* import org.jetbrains.kotlin.codegen.AsmUtil.getMethodAsmFlags import org.jetbrains.kotlin.codegen.AsmUtil.isPrimitive -import org.jetbrains.kotlin.codegen.context.* import org.jetbrains.kotlin.codegen.coroutines.createMethodNodeForSuspendCoroutineOrReturn import org.jetbrains.kotlin.codegen.coroutines.isBuiltInSuspendCoroutineOrReturnInJvm import org.jetbrains.kotlin.codegen.intrinsics.bytecode @@ -39,11 +37,11 @@ import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils import org.jetbrains.kotlin.resolve.DescriptorUtils import org.jetbrains.kotlin.resolve.ImportedFromObjectCallableDescriptor -import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCallWithAssert import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall import org.jetbrains.kotlin.resolve.inline.InlineUtil import org.jetbrains.kotlin.resolve.inline.InlineUtil.isInlinableParameterExpression import org.jetbrains.kotlin.resolve.jvm.AsmTypes +import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodGenericSignature import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodParameterKind import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature import org.jetbrains.kotlin.resolve.scopes.MemberScope @@ -51,22 +49,21 @@ import org.jetbrains.kotlin.serialization.deserialization.descriptors.Deserializ import org.jetbrains.kotlin.types.expressions.DoubleColonLHS import org.jetbrains.kotlin.types.expressions.ExpressionTypingUtils.isFunctionLiteral import org.jetbrains.kotlin.types.expressions.LabelResolver -import org.jetbrains.org.objectweb.asm.Label -import org.jetbrains.org.objectweb.asm.MethodVisitor import org.jetbrains.org.objectweb.asm.Opcodes import org.jetbrains.org.objectweb.asm.Type +import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter import org.jetbrains.org.objectweb.asm.commons.Method import org.jetbrains.org.objectweb.asm.tree.AbstractInsnNode -import org.jetbrains.org.objectweb.asm.tree.LabelNode import org.jetbrains.org.objectweb.asm.tree.MethodNode import java.util.* class InlineCodegen( - private val codegen: ExpressionCodegen, + private val codegen: BaseExpressionCodegen, private val state: GenerationState, function: FunctionDescriptor, private val callElement: KtElement, - private val typeParameterMappings: TypeParameterMappings + private val typeParameterMappings: TypeParameterMappings, + private val sourceCompiler: SourceCompilerForInline ) : CallGenerator() { init { assert(InlineUtil.isInline(function) || InlineUtil.isArrayConstructorWithLambda(function)) { @@ -89,15 +86,9 @@ class InlineCodegen( else function.original - private val context = - getContext( - functionDescriptor, state, - DescriptorToSourceUtils.descriptorToDeclaration(functionDescriptor)?.containingFile as? KtFile - ) as MethodContext + private val jvmSignature: JvmMethodGenericSignature - private val jvmSignature = typeMapper.mapSignatureWithGeneric(functionDescriptor, context.contextKind) - - private val isSameModule = JvmCodegenUtil.isCallInsideSameModuleAsDeclared(functionDescriptor, codegen.getContext(), state.outDirectory) + private val isSameModule: Boolean private val invocationParamBuilder = ParametersBuilder.newBuilder() @@ -105,7 +96,7 @@ class InlineCodegen( private var activeLambda: LambdaInfo? = null - private val sourceMapper = codegen.parentCodegen.orCreateSourceMapper + private val sourceMapper = sourceCompiler.lazySourceMapper private var delayedHiddenWriting: Function0? = null @@ -114,8 +105,12 @@ class InlineCodegen( private var methodHandleInDefaultMethodIndex = -1 init { + sourceCompiler.initializeInlineFunctionContext(functionDescriptor) + jvmSignature = typeMapper.mapSignatureWithGeneric(functionDescriptor, sourceCompiler.contextKind) + isSameModule = sourceCompiler.isCallInsideSameModuleAsDeclared(functionDescriptor) + if (functionDescriptor !is FictitiousArrayConstructor) { - reportIncrementalInfo(functionDescriptor, codegen.getContext().functionDescriptor.original, jvmSignature, state) + reportIncrementalInfo(functionDescriptor, sourceCompiler.compilationContextFunctionDescriptor.original, jvmSignature, state) val functionOrAccessorName = typeMapper.mapAsmMethod(function).name //track changes for property accessor and @JvmName inline functions/property accessors if (functionOrAccessorName != functionDescriptor.name.asString()) { @@ -130,7 +125,7 @@ class InlineCodegen( callableMethod: Callable, resolvedCall: ResolvedCall<*>?, callDefault: Boolean, - codegen: ExpressionCodegen + codegen: BaseExpressionCodegen ) { if (!state.inlineCycleReporter.enterIntoInlining(resolvedCall)) { generateStub(resolvedCall, codegen) @@ -139,7 +134,7 @@ class InlineCodegen( var nodeAndSmap: SMAPAndMethodNode? = null try { - nodeAndSmap = createMethodNode(functionDescriptor, jvmSignature, codegen, context, callDefault, resolvedCall) + nodeAndSmap = createInlineMethodNode(functionDescriptor, jvmSignature, codegen, callDefault, resolvedCall, state, sourceCompiler) endCall(inlineCall(nodeAndSmap, callDefault)) } catch (e: CompilationException) { @@ -159,7 +154,7 @@ class InlineCodegen( private fun throwCompilationException( nodeAndSmap: SMAPAndMethodNode?, e: Exception, generateNodeText: Boolean ): CompilationException { - val contextDescriptor = codegen.getContext().contextDescriptor + val contextDescriptor = sourceCompiler.compilationContextDescriptor val element = DescriptorToSourceUtils.descriptorToDeclaration(contextDescriptor) val node = nodeAndSmap?.node throw CompilationException( @@ -171,7 +166,7 @@ class InlineCodegen( ) } - private fun generateStub(resolvedCall: ResolvedCall<*>?, codegen: ExpressionCodegen) { + private fun generateStub(resolvedCall: ResolvedCall<*>?, codegen: BaseExpressionCodegen) { leaveTemps() assert(resolvedCall != null) val message = "Call is part of inline cycle: " + resolvedCall!!.call.callElement.text @@ -190,7 +185,7 @@ class InlineCodegen( private fun inlineCall(nodeAndSmap: SMAPAndMethodNode, callDefault: Boolean): InlineResult { assert(delayedHiddenWriting == null) { "'putHiddenParamsIntoLocals' should be called after 'processAndPutHiddenParameters(true)'" } - val defaultSourceMapper = codegen.parentCodegen.orCreateSourceMapper + val defaultSourceMapper = sourceMapper defaultSourceMapper.callSiteMarker = CallSiteMarker(codegen.lastLineNumber) val node = nodeAndSmap.node if (callDefault) { @@ -216,7 +211,7 @@ class InlineCodegen( val info = RootInliningContext( expressionMap, state, codegen.inlineNameGenerator.subGenerator(jvmSignature.asmMethod.name), - callElement, inlineCallSiteInfo, reifiedTypeInliner, typeParameterMappings + callElement, sourceCompiler.inlineCallSiteInfo, reifiedTypeInliner, typeParameterMappings ) val inliner = MethodInliner( @@ -235,15 +230,15 @@ class InlineCodegen( val result = inliner.doInline(adapter, remapper, true, LabelOwner.SKIP_ALL) result.reifiedTypeParametersUsages.mergeAll(reificationResult) - val descriptor = getLabelOwnerDescriptor(codegen.getContext()) + val descriptor = sourceCompiler.getLabelOwnerDescriptor() val labels = getDeclarationLabels(DescriptorToSourceUtils.descriptorToDeclaration(descriptor), descriptor) val infos = MethodInliner.processReturns(adapter, LabelOwner { labels.contains(it) }, true, null) - generateAndInsertFinallyBlocks( + sourceCompiler.generateAndInsertFinallyBlocks( adapter, infos, (remapper.remap(parameters.argsSizeOnStack + 1).value as StackValue.Local).index ) removeStaticInitializationTrigger(adapter) - if (!isFinallyMarkerRequired(codegen.getContext())) { + if (!sourceCompiler.isFinallyMarkerRequired()) { removeFinallyMarkers(adapter) } @@ -256,57 +251,9 @@ class InlineCodegen( return result } - private val inlineCallSiteInfo: InlineCallSiteInfo - get() { - var context = codegen.getContext() - var parentCodegen = codegen.parentCodegen - while (context is InlineLambdaContext) { - val closureContext = context.getParentContext() - assert(closureContext is ClosureContext) { "Parent context of inline lambda should be closure context" } - assert(closureContext.parentContext is MethodContext) { "Closure context should appear in method context" } - context = closureContext.parentContext as MethodContext - assert(parentCodegen is FakeMemberCodegen) { "Parent codegen of inlined lambda should be FakeMemberCodegen" } - parentCodegen = (parentCodegen as FakeMemberCodegen).delegate - } - - val signature = typeMapper.mapSignatureSkipGeneric(context.functionDescriptor, context.contextKind) - return InlineCallSiteInfo( - parentCodegen.className, signature.asmMethod.name, signature.asmMethod.descriptor - ) - } - private fun generateClosuresBodies() { for (info in expressionMap.values) { - info.generateLambdaBody(codegen, reifiedTypeInliner) - } - } - - private class FakeMemberCodegen( - internal val delegate: MemberCodegen<*>, - declaration: KtElement, - codegenContext: FieldOwnerContext<*>, - private val className: String - ) : MemberCodegen(delegate as MemberCodegen, declaration, codegenContext) { - - override fun generateDeclaration() { - throw IllegalStateException() - } - - override fun generateBody() { - throw IllegalStateException() - } - - override fun generateKotlinMetadataAnnotation() { - throw IllegalStateException() - } - - override fun getInlineNameGenerator(): NameGenerator { - return delegate.inlineNameGenerator - } - - override //TODO: obtain name from context - fun getClassName(): String { - return className + info.generateLambdaBody(sourceCompiler, reifiedTypeInliner) } } @@ -376,7 +323,7 @@ class InlineCodegen( } override fun processAndPutHiddenParameters(justProcess: Boolean) { - if (getMethodAsmFlags(functionDescriptor, context.contextKind, state) and Opcodes.ACC_STATIC == 0) { + if (getMethodAsmFlags(functionDescriptor, sourceCompiler.contextKind, state) and Opcodes.ACC_STATIC == 0) { invocationParamBuilder.addNextParameter(AsmTypes.OBJECT_TYPE, false) } @@ -519,69 +466,6 @@ class InlineCodegen( putArgumentOrCapturedToLocalVal(stackValue.type, stackValue, paramIndex, paramIndex, ValueKind.CAPTURED) } - private fun generateAndInsertFinallyBlocks( - intoNode: MethodNode, - insertPoints: List, - offsetForFinallyLocalVar: Int - ) { - if (!codegen.hasFinallyBlocks()) return - - val extensionPoints = HashMap() - for (insertPoint in insertPoints) { - extensionPoints.put(insertPoint.beforeIns, insertPoint) - } - - val processor = DefaultProcessor(intoNode, offsetForFinallyLocalVar) - - var curFinallyDepth = 0 - var curInstr: AbstractInsnNode? = intoNode.instructions.first - while (curInstr != null) { - processor.processInstruction(curInstr, true) - if (isFinallyStart(curInstr)) { - //TODO depth index calc could be more precise - curFinallyDepth = getConstant(curInstr.previous) - } - - val extension = extensionPoints[curInstr] - if (extension != null) { - val start = Label() - - val finallyNode = createEmptyMethodNode() - finallyNode.visitLabel(start) - - val finallyCodegen = ExpressionCodegen(finallyNode, codegen.frameMap, codegen.returnType, - codegen.getContext(), codegen.state, codegen.parentCodegen) - finallyCodegen.addBlockStackElementsForNonLocalReturns(codegen.blockStackElements, curFinallyDepth) - - val frameMap = finallyCodegen.frameMap - val mark = frameMap.mark() - val marker = processor.localVarsMetaInfo.currentIntervals.maxBy { it.node.index }?.node?.index?.plus(1) ?: -1 - - while (frameMap.currentSize < Math.max(processor.nextFreeLocalIndex, offsetForFinallyLocalVar + marker)) { - frameMap.enterTemp(Type.INT_TYPE) - } - - finallyCodegen.generateFinallyBlocksIfNeeded(extension.returnType, extension.finallyIntervalEnd.label) - - //Exception table for external try/catch/finally blocks will be generated in original codegen after exiting this method - insertNodeBefore(finallyNode, intoNode, curInstr) - - val splitBy = SimpleInterval(start.info as LabelNode, extension.finallyIntervalEnd) - processor.tryBlocksMetaInfo.splitCurrentIntervals(splitBy, true) - - //processor.getLocalVarsMetaInfo().splitAndRemoveIntervalsFromCurrents(splitBy); - - mark.dropTo() - } - - curInstr = curInstr.next - } - - processor.substituteTryBlockNodes(intoNode) - - //processor.substituteLocalVarTable(intoNode); - } - override fun reorderArgumentsIfNeeded( actualArgsWithDeclIndex: List, valueParameterTypes: List ) { @@ -605,13 +489,14 @@ class InlineCodegen( } } - internal fun createMethodNode( + internal fun createInlineMethodNode( functionDescriptor: FunctionDescriptor, jvmSignature: JvmMethodSignature, - codegen: ExpressionCodegen, - context: CodegenContext<*>, + codegen: BaseExpressionCodegen, callDefault: Boolean, - resolvedCall: ResolvedCall<*>? + resolvedCall: ResolvedCall<*>?, + state: GenerationState, + sourceCompilerForInline: SourceCompilerForInline ): SMAPAndMethodNode { if (isSpecialEnumMethod(functionDescriptor)) { val arguments = resolvedCall!!.typeArguments @@ -620,29 +505,28 @@ class InlineCodegen( codegen, functionDescriptor.name.asString(), arguments.keys.single().defaultType, - codegen.state.typeMapper + state.typeMapper ) return SMAPAndMethodNode(node, SMAPParser.parseOrCreateDefault(null, null, "fake", -1, -1)) } else if (functionDescriptor.isBuiltInSuspendCoroutineOrReturnInJvm()) { return SMAPAndMethodNode( createMethodNodeForSuspendCoroutineOrReturn( - functionDescriptor, codegen.state.typeMapper + functionDescriptor, state.typeMapper ), SMAPParser.parseOrCreateDefault(null, null, "fake", -1, -1) ) } - val state = codegen.state val asmMethod = if (callDefault) - state.typeMapper.mapDefaultMethod(functionDescriptor, context.contextKind) + state.typeMapper.mapDefaultMethod(functionDescriptor, sourceCompilerForInline.contextKind) else jvmSignature.asmMethod val methodId = MethodId(DescriptorUtils.getFqNameSafe(functionDescriptor.containingDeclaration), asmMethod) val directMember = getDirectMemberAndCallableFromObject(functionDescriptor) if (!isBuiltInArrayIntrinsic(functionDescriptor) && directMember !is DeserializedCallableMemberDescriptor) { - return doCreateMethodNodeFromSource(functionDescriptor, jvmSignature, codegen, context, callDefault, state, asmMethod) + return sourceCompilerForInline.doCreateMethodNodeFromSource(functionDescriptor, jvmSignature, callDefault, asmMethod) } val resultInCache = state.inlineCache.methodNodeById.getOrPut(methodId @@ -692,58 +576,7 @@ class InlineCodegen( return getMethodNode(bytes, asmMethod.name, asmMethod.descriptor, containerId.asString()) } - private fun doCreateMethodNodeFromSource( - callableDescriptor: FunctionDescriptor, - jvmSignature: JvmMethodSignature, - codegen: ExpressionCodegen, - context: CodegenContext<*>, - callDefault: Boolean, - state: GenerationState, - asmMethod: Method - ): SMAPAndMethodNode { - val element = DescriptorToSourceUtils.descriptorToDeclaration(callableDescriptor) - if (!(element is KtNamedFunction || element is KtPropertyAccessor)) { - throw IllegalStateException("Couldn't find declaration for function " + callableDescriptor) - } - val inliningFunction = element as KtDeclarationWithBody? - - val node = MethodNode( - API, - getMethodAsmFlags(callableDescriptor, context.contextKind, state) or if (callDefault) Opcodes.ACC_STATIC else 0, - asmMethod.name, - asmMethod.descriptor, null, null - ) - - //for maxLocals calculation - val maxCalcAdapter = wrapWithMaxLocalCalc(node) - val parentContext = context.parentContext ?: error("Context has no parent: " + context) - val methodContext = parentContext.intoFunction(callableDescriptor) - - val smap: SMAP - if (callDefault) { - val implementationOwner = state.typeMapper.mapImplementationOwner(callableDescriptor) - val parentCodegen = FakeMemberCodegen( - codegen.parentCodegen, inliningFunction!!, methodContext.parentContext as FieldOwnerContext<*>, - implementationOwner.internalName - ) - if (element !is KtNamedFunction) { - throw IllegalStateException("Property accessors with default parameters not supported " + callableDescriptor) - } - FunctionCodegen.generateDefaultImplBody( - methodContext, callableDescriptor, maxCalcAdapter, DefaultParameterValueLoader.DEFAULT, - inliningFunction as KtNamedFunction?, parentCodegen, asmMethod - ) - smap = createSMAPWithDefaultMapping(inliningFunction, parentCodegen.orCreateSourceMapper.resultMappings) - } - else { - smap = generateMethodBody(maxCalcAdapter, callableDescriptor, methodContext, inliningFunction!!, jvmSignature, codegen, null) - } - maxCalcAdapter.visitMaxs(-1, -1) - maxCalcAdapter.visitEnd() - - return SMAPAndMethodNode(node, smap) - } private fun isBuiltInArrayIntrinsic(callableDescriptor: CallableMemberDescriptor): Boolean { if (callableDescriptor is FictitiousArrayConstructor) return true @@ -751,14 +584,6 @@ class InlineCodegen( return (name == "arrayOf" || name == "emptyArray") && callableDescriptor.containingDeclaration is BuiltInsPackageFragment } - private fun getLabelOwnerDescriptor(context: MethodContext): CallableMemberDescriptor { - val parentContext = context.parentContext - if (parentContext is ClosureContext && parentContext.originalSuspendLambdaDescriptor != null) { - return parentContext.originalSuspendLambdaDescriptor!! - } - return context.contextDescriptor - } - private fun removeStaticInitializationTrigger(methodNode: MethodNode) { val insnList = methodNode.instructions var insn: AbstractInsnNode? = insnList.first @@ -774,79 +599,6 @@ class InlineCodegen( } } - fun generateMethodBody( - adapter: MethodVisitor, - descriptor: FunctionDescriptor, - context: MethodContext, - expression: KtExpression, - jvmMethodSignature: JvmMethodSignature, - codegen: ExpressionCodegen, - lambdaInfo: ExpressionLambda? - ): SMAP { - val isLambda = lambdaInfo != null - val state = codegen.state - - // Wrapping for preventing marking actual parent codegen as containing reified markers - val parentCodegen = FakeMemberCodegen( - codegen.parentCodegen, expression, context.parentContext as FieldOwnerContext<*>, - if (isLambda) - codegen.parentCodegen.className - else - state.typeMapper.mapImplementationOwner(descriptor).internalName - ) - - val strategy: FunctionGenerationStrategy - if (expression is KtCallableReferenceExpression) { - val callableReferenceExpression = expression - val receiverExpression = callableReferenceExpression.receiverExpression - val receiverType = if (receiverExpression != null && codegen.bindingContext.getType(receiverExpression) != null) - codegen.state.typeMapper.mapType(codegen.bindingContext.getType(receiverExpression)!!) - else - null - - if (isLambda && lambdaInfo!!.isPropertyReference) { - val asmType = state.typeMapper.mapClass(lambdaInfo.classDescriptor) - val info = lambdaInfo.propertyReferenceInfo - strategy = PropertyReferenceCodegen.PropertyReferenceGenerationStrategy( - true, info!!.getFunction, info.target, asmType, receiverType, - lambdaInfo.functionWithBodyOrCallableReference, state, true) - } - else { - strategy = FunctionReferenceGenerationStrategy( - state, - descriptor, - callableReferenceExpression.callableReference - .getResolvedCallWithAssert(codegen.bindingContext), - receiverType, null, - true - ) - } - } - else if (expression is KtFunctionLiteral) { - strategy = ClosureGenerationStrategy(state, expression as KtDeclarationWithBody) - } - else { - strategy = FunctionGenerationStrategy.FunctionDefault(state, expression as KtDeclarationWithBody) - } - - FunctionCodegen.generateMethodBody(adapter, descriptor, context, jvmMethodSignature, strategy, parentCodegen) - - if (isLambda) { - codegen.propagateChildReifiedTypeParametersUsages(parentCodegen.reifiedTypeParametersUsages) - } - - return createSMAPWithDefaultMapping(expression, parentCodegen.orCreateSourceMapper.resultMappings) - } - - private fun createSMAPWithDefaultMapping( - declaration: KtExpression, - mappings: List - ): SMAP { - val containingFile = declaration.containingFile - CodegenUtil.getLineNumberForElement(containingFile, true) ?: error("Couldn't extract line count in " + containingFile) - - return SMAP(mappings) - } /*descriptor is null for captured vars*/ private fun shouldPutGeneralValue(type: Type, stackValue: StackValue): Boolean { @@ -905,38 +657,7 @@ class InlineCodegen( return result } - fun getContext( - descriptor: DeclarationDescriptor, state: GenerationState, sourceFile: KtFile? - ): CodegenContext<*> { - if (descriptor is PackageFragmentDescriptor) { - return PackageContext(descriptor, state.rootContext, null, sourceFile) - } - val container = descriptor.containingDeclaration ?: error("No container for descriptor: " + descriptor) - val parent = getContext( - container, - state, - sourceFile - ) - - if (descriptor is ScriptDescriptor) { - val earlierScripts = state.replSpecific.earlierScriptsForReplInterpreter - return parent.intoScript( - descriptor, - earlierScripts ?: emptyList(), - descriptor as ClassDescriptor, state.typeMapper - ) - } - else if (descriptor is ClassDescriptor) { - val kind = if (DescriptorUtils.isInterface(descriptor)) OwnerKind.DEFAULT_IMPLS else OwnerKind.IMPLEMENTATION - return parent.intoClass(descriptor, kind, state) - } - else if (descriptor is FunctionDescriptor) { - return parent.intoFunction(descriptor) - } - - throw IllegalStateException("Couldn't build context for " + descriptor) - } fun createNestedSourceMapper(nodeAndSmap: SMAPAndMethodNode, parent: SourceMapper): SourceMapper { return NestedSourceMapper(parent, nodeAndSmap.sortedRanges, nodeAndSmap.classSMAP.sourceInfo) @@ -956,3 +677,6 @@ class InlineCodegen( } } } + +val BaseExpressionCodegen.v: InstructionAdapter + get() = visitor \ 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 dd4f9e09007..dfdba745615 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegenForDefaultBody.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegenForDefaultBody.kt @@ -22,10 +22,9 @@ import org.jetbrains.kotlin.descriptors.ConstructorDescriptor import org.jetbrains.kotlin.descriptors.FunctionDescriptor import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor import org.jetbrains.kotlin.psi.KtExpression -import org.jetbrains.kotlin.psi.KtFile -import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall import org.jetbrains.kotlin.resolve.inline.InlineUtil +import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodGenericSignature import org.jetbrains.org.objectweb.asm.Label import org.jetbrains.org.objectweb.asm.Type import org.jetbrains.org.objectweb.asm.tree.MethodNode @@ -33,7 +32,8 @@ import org.jetbrains.org.objectweb.asm.tree.MethodNode class InlineCodegenForDefaultBody( function: FunctionDescriptor, codegen: ExpressionCodegen, - val state: GenerationState + val state: GenerationState, + private val sourceCompilerForInline: SourceCompilerForInline ) : CallGenerator() { private val sourceMapper: SourceMapper = codegen.parentCodegen.orCreateSourceMapper @@ -45,12 +45,12 @@ class InlineCodegenForDefaultBody( function.original - private val context = InlineCodegen.getContext( - functionDescriptor, state, - DescriptorToSourceUtils.descriptorToDeclaration(functionDescriptor)?.containingFile as? KtFile - ) + init { + sourceCompilerForInline.initializeInlineFunctionContext(functionDescriptor) + } - private val jvmSignature = state.typeMapper.mapSignatureWithGeneric(functionDescriptor, context.contextKind) + + private val jvmSignature: JvmMethodGenericSignature private val methodStartLabel = Label() @@ -58,6 +58,9 @@ class InlineCodegenForDefaultBody( assert(InlineUtil.isInline(function)) { "InlineCodegen can inline only inline functions and array constructors: " + function } + sourceCompilerForInline.initializeInlineFunctionContext(functionDescriptor) + jvmSignature = state.typeMapper.mapSignatureWithGeneric(functionDescriptor, sourceCompilerForInline.contextKind) + InlineCodegen.reportIncrementalInfo(functionDescriptor, codegen.context.functionDescriptor.original, jvmSignature, state) //InlineCodegenForDefaultBody created just after visitCode call @@ -65,7 +68,7 @@ class InlineCodegenForDefaultBody( } override fun genCallInner(callableMethod: Callable, resolvedCall: ResolvedCall<*>?, callDefault: Boolean, codegen: ExpressionCodegen) { - val nodeAndSmap = InlineCodegen.createMethodNode(functionDescriptor, jvmSignature, codegen, context, callDefault, null) + val nodeAndSmap = InlineCodegen.createInlineMethodNode(functionDescriptor, jvmSignature, codegen, callDefault, null, state, sourceCompilerForInline) val childSourceMapper = InlineCodegen.createNestedSourceMapper(nodeAndSmap, sourceMapper) val node = nodeAndSmap.node @@ -84,7 +87,7 @@ class InlineCodegenForDefaultBody( } }) - transformedMethod.accept(MethodBodyVisitor(codegen.v)) + transformedMethod.accept(MethodBodyVisitor(codegen.visitor)) } override fun genValueAndPut(valueParameterDescriptor: ValueParameterDescriptor, argumentExpression: KtExpression, parameterType: Type, parameterIndex: Int) { diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/LambdaInfo.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/LambdaInfo.kt index 117bbf6bef4..ad117582109 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/LambdaInfo.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/LambdaInfo.kt @@ -55,7 +55,7 @@ abstract class LambdaInfo(@JvmField val isCrossInline: Boolean) : LabelOwner { lateinit var node: SMAPAndMethodNode - abstract fun generateLambdaBody(codegen: ExpressionCodegen, reifiedTypeInliner: ReifiedTypeInliner) + abstract fun generateLambdaBody(sourceCompiler: SourceCompilerForInline, reifiedTypeInliner: ReifiedTypeInliner) fun addAllParameters(remapper: FieldRemapper): Parameters { val builder = ParametersBuilder.initializeBuilderFrom(AsmTypes.OBJECT_TYPE, invokeMethod.descriptor, this) @@ -105,8 +105,8 @@ class DefaultLambda( override fun isMyLabel(name: String): Boolean = false - override fun generateLambdaBody(codegen: ExpressionCodegen, reifiedTypeInliner: ReifiedTypeInliner) { - val classReader = buildClassReaderByInternalName(codegen.state, lambdaClassType.internalName) + override fun generateLambdaBody(sourceCompiler: SourceCompilerForInline, reifiedTypeInliner: ReifiedTypeInliner) { + val classReader = buildClassReaderByInternalName(sourceCompiler.state, lambdaClassType.internalName) var isPropertyReference = false var isFunctionReference = false classReader.accept(object: ClassVisitor(API){ @@ -153,7 +153,7 @@ class DefaultLambda( invokeMethod = Method( (if (isPropertyReference) OperatorNameConventions.GET else OperatorNameConventions.INVOKE).asString(), - codegen.state.typeMapper.mapSignatureSkipGeneric(invokeMethodDescriptor).asmMethod.descriptor + sourceCompiler.state.typeMapper.mapSignatureSkipGeneric(invokeMethodDescriptor).asmMethod.descriptor ) node = getMethodNode( @@ -260,24 +260,17 @@ class ExpressionLambda( val isPropertyReference: Boolean get() = propertyReferenceInfo != null - override fun generateLambdaBody(codegen: ExpressionCodegen, reifiedTypeInliner: ReifiedTypeInliner) { - val closureContext = - if (isPropertyReference) - codegen.getContext().intoAnonymousClass(classDescriptor, codegen, OwnerKind.IMPLEMENTATION) - else - codegen.getContext().intoClosure(invokeMethodDescriptor, codegen, typeMapper) - val context = closureContext.intoInlinedLambda(invokeMethodDescriptor, isCrossInline, isPropertyReference) - + override fun generateLambdaBody(sourceCompiler: SourceCompilerForInline, reifiedTypeInliner: ReifiedTypeInliner) { val jvmMethodSignature = typeMapper.mapSignatureSkipGeneric(invokeMethodDescriptor) val asmMethod = jvmMethodSignature.asmMethod val methodNode = MethodNode( - API, AsmUtil.getMethodAsmFlags(invokeMethodDescriptor, context.contextKind, codegen.state), + API, AsmUtil.getMethodAsmFlags(invokeMethodDescriptor, OwnerKind.IMPLEMENTATION, sourceCompiler.state), asmMethod.name, asmMethod.descriptor, null, null ) node = wrapWithMaxLocalCalc(methodNode).let { adapter -> - val smap = InlineCodegen.generateMethodBody( - adapter, invokeMethodDescriptor, context, functionWithBodyOrCallableReference, jvmMethodSignature, codegen, this + val smap = sourceCompiler.generateLambdaBody( + adapter, jvmMethodSignature, this ) adapter.visitMaxs(-1, -1) SMAPAndMethodNode(methodNode, smap) diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/SourceCompilerForInline.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/SourceCompilerForInline.kt new file mode 100644 index 00000000000..218bc428ef8 --- /dev/null +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/SourceCompilerForInline.kt @@ -0,0 +1,365 @@ +/* + * Copyright 2010-2017 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.kotlin.codegen.inline + +import org.jetbrains.kotlin.backend.common.CodegenUtil +import org.jetbrains.kotlin.codegen.* +import org.jetbrains.kotlin.codegen.context.* +import org.jetbrains.kotlin.codegen.state.GenerationState +import org.jetbrains.kotlin.descriptors.* +import org.jetbrains.kotlin.psi.* +import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils +import org.jetbrains.kotlin.resolve.DescriptorUtils +import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCallWithAssert +import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature +import org.jetbrains.org.objectweb.asm.Label +import org.jetbrains.org.objectweb.asm.MethodVisitor +import org.jetbrains.org.objectweb.asm.Opcodes +import org.jetbrains.org.objectweb.asm.Type +import org.jetbrains.org.objectweb.asm.commons.Method +import org.jetbrains.org.objectweb.asm.tree.AbstractInsnNode +import org.jetbrains.org.objectweb.asm.tree.LabelNode +import org.jetbrains.org.objectweb.asm.tree.MethodNode +import java.util.HashMap +import kotlin.properties.Delegates + +class SourceCompilerForInline(private val codegen: ExpressionCodegen) { + + val state = codegen.state + + private var context by Delegates.notNull>() + + val contextKind + get () = context.contextKind + + val inlineCallSiteInfo: InlineCallSiteInfo + get() { + var context = codegen.getContext() + var parentCodegen = codegen.parentCodegen + while (context is InlineLambdaContext) { + val closureContext = context.getParentContext() + assert(closureContext is ClosureContext) { "Parent context of inline lambda should be closure context" } + assert(closureContext.parentContext is MethodContext) { "Closure context should appear in method context" } + context = closureContext.parentContext as MethodContext + assert(parentCodegen is FakeMemberCodegen) { "Parent codegen of inlined lambda should be FakeMemberCodegen" } + parentCodegen = (parentCodegen as FakeMemberCodegen).delegate + } + + val signature = codegen.state.typeMapper.mapSignatureSkipGeneric(context.functionDescriptor, context.contextKind) + return InlineCallSiteInfo( + parentCodegen.className, signature.asmMethod.name, signature.asmMethod.descriptor + ) + } + + val lazySourceMapper + get() = codegen.parentCodegen.orCreateSourceMapper + + fun generateLambdaBody(adapter: MethodVisitor, + jvmMethodSignature: JvmMethodSignature, + lambdaInfo: ExpressionLambda): SMAP { + val invokeMethodDescriptor = lambdaInfo.invokeMethodDescriptor + val closureContext = + if (lambdaInfo.isPropertyReference) + codegen.getContext().intoAnonymousClass(lambdaInfo.classDescriptor, codegen, OwnerKind.IMPLEMENTATION) + else + codegen.getContext().intoClosure(invokeMethodDescriptor, codegen, state.typeMapper) + val context = closureContext.intoInlinedLambda(invokeMethodDescriptor, lambdaInfo.isCrossInline, lambdaInfo.isPropertyReference) + + return generateMethodBody( + adapter, invokeMethodDescriptor, context, + lambdaInfo.functionWithBodyOrCallableReference, + jvmMethodSignature, lambdaInfo + ) + } + + private fun generateMethodBody( + adapter: MethodVisitor, + descriptor: FunctionDescriptor, + context: MethodContext, + expression: KtExpression, + jvmMethodSignature: JvmMethodSignature, + lambdaInfo: ExpressionLambda? + ): SMAP { + val isLambda = lambdaInfo != null + + // Wrapping for preventing marking actual parent codegen as containing reified markers + val parentCodegen = FakeMemberCodegen( + codegen.parentCodegen, expression, context.parentContext as FieldOwnerContext<*>, + if (isLambda) + codegen.parentCodegen.className + else + state.typeMapper.mapImplementationOwner(descriptor).internalName + ) + + val strategy = when (expression) { + is KtCallableReferenceExpression -> { + val callableReferenceExpression = expression + val receiverExpression = callableReferenceExpression.receiverExpression + val receiverType = if (receiverExpression != null && state.bindingContext.getType(receiverExpression) != null) + state.typeMapper.mapType(state.bindingContext.getType(receiverExpression)!!) + else + null + + if (isLambda && lambdaInfo!!.isPropertyReference) { + val asmType = state.typeMapper.mapClass(lambdaInfo.classDescriptor) + val info = lambdaInfo.propertyReferenceInfo + PropertyReferenceCodegen.PropertyReferenceGenerationStrategy( + true, info!!.getFunction, info.target, asmType, receiverType, + lambdaInfo.functionWithBodyOrCallableReference, state, true) + } + else { + FunctionReferenceGenerationStrategy( + state, + descriptor, + callableReferenceExpression.callableReference + .getResolvedCallWithAssert(state.bindingContext), + receiverType, null, + true + ) + } + } + is KtFunctionLiteral -> ClosureGenerationStrategy(state, expression as KtDeclarationWithBody) + else -> FunctionGenerationStrategy.FunctionDefault(state, expression as KtDeclarationWithBody) + } + + FunctionCodegen.generateMethodBody(adapter, descriptor, context, jvmMethodSignature, strategy, parentCodegen) + + if (isLambda) { + codegen.propagateChildReifiedTypeParametersUsages(parentCodegen.reifiedTypeParametersUsages) + } + + return createSMAPWithDefaultMapping(expression, parentCodegen.orCreateSourceMapper.resultMappings) + } + + + private fun createSMAPWithDefaultMapping( + declaration: KtExpression, + mappings: List + ): SMAP { + val containingFile = declaration.containingFile + CodegenUtil.getLineNumberForElement(containingFile, true) ?: error("Couldn't extract line count in " + containingFile) + + return SMAP(mappings) + } + + @Suppress("UNCHECKED_CAST") + private class FakeMemberCodegen( + internal val delegate: MemberCodegen<*>, + declaration: KtElement, + codegenContext: FieldOwnerContext<*>, + private val className: String + ) : MemberCodegen(delegate as MemberCodegen, declaration, codegenContext) { + + override fun generateDeclaration() { + throw IllegalStateException() + } + + override fun generateBody() { + throw IllegalStateException() + } + + override fun generateKotlinMetadataAnnotation() { + throw IllegalStateException() + } + + override fun getInlineNameGenerator(): NameGenerator { + return delegate.inlineNameGenerator + } + override //TODO: obtain name from context + fun getClassName(): String { + return className + } + + } + + fun doCreateMethodNodeFromSource( + callableDescriptor: FunctionDescriptor, + jvmSignature: JvmMethodSignature, + callDefault: Boolean, + asmMethod: Method + ): SMAPAndMethodNode { + val element = DescriptorToSourceUtils.descriptorToDeclaration(callableDescriptor) + + if (!(element is KtNamedFunction || element is KtPropertyAccessor)) { + throw IllegalStateException("Couldn't find declaration for function " + callableDescriptor) + } + val inliningFunction = element as KtDeclarationWithBody? + + val node = MethodNode( + API, + AsmUtil.getMethodAsmFlags(callableDescriptor, context.contextKind, state) or if (callDefault) Opcodes.ACC_STATIC else 0, + asmMethod.name, + asmMethod.descriptor, null, null + ) + + //for maxLocals calculation + val maxCalcAdapter = wrapWithMaxLocalCalc(node) + val parentContext = context.parentContext ?: error("Context has no parent: " + context) + val methodContext = parentContext.intoFunction(callableDescriptor) + + val smap: SMAP + if (callDefault) { + val implementationOwner = state.typeMapper.mapImplementationOwner(callableDescriptor) + val parentCodegen = FakeMemberCodegen( + codegen.parentCodegen, inliningFunction!!, methodContext.parentContext as FieldOwnerContext<*>, + implementationOwner.internalName + ) + if (element !is KtNamedFunction) { + throw IllegalStateException("Property accessors with default parameters not supported " + callableDescriptor) + } + FunctionCodegen.generateDefaultImplBody( + methodContext, callableDescriptor, maxCalcAdapter, DefaultParameterValueLoader.DEFAULT, + inliningFunction as KtNamedFunction?, parentCodegen, asmMethod + ) + smap = createSMAPWithDefaultMapping(inliningFunction, parentCodegen.orCreateSourceMapper.resultMappings) + } + else { + smap = generateMethodBody(maxCalcAdapter, callableDescriptor, methodContext, inliningFunction!!, jvmSignature, null) + } + maxCalcAdapter.visitMaxs(-1, -1) + maxCalcAdapter.visitEnd() + + return SMAPAndMethodNode(node, smap) + } + + fun generateAndInsertFinallyBlocks( + intoNode: MethodNode, + insertPoints: List, + offsetForFinallyLocalVar: Int + ) { + if (!codegen.hasFinallyBlocks()) return + + val extensionPoints = HashMap() + for (insertPoint in insertPoints) { + extensionPoints.put(insertPoint.beforeIns, insertPoint) + } + + val processor = DefaultProcessor(intoNode, offsetForFinallyLocalVar) + + var curFinallyDepth = 0 + var curInstr: AbstractInsnNode? = intoNode.instructions.first + while (curInstr != null) { + processor.processInstruction(curInstr, true) + if (isFinallyStart(curInstr)) { + //TODO depth index calc could be more precise + curFinallyDepth = getConstant(curInstr.previous) + } + + val extension = extensionPoints[curInstr] + if (extension != null) { + val start = Label() + + val finallyNode = createEmptyMethodNode() + finallyNode.visitLabel(start) + + val finallyCodegen = ExpressionCodegen(finallyNode, codegen.frameMap, codegen.returnType, + codegen.getContext(), codegen.state, codegen.parentCodegen) + finallyCodegen.addBlockStackElementsForNonLocalReturns(codegen.blockStackElements, curFinallyDepth) + + val frameMap = finallyCodegen.frameMap + val mark = frameMap.mark() + var marker = -1 + val intervals = processor.localVarsMetaInfo.currentIntervals + for (interval in intervals) { + marker = Math.max(interval.node.index + 1, marker) + } + while (frameMap.currentSize < Math.max(processor.nextFreeLocalIndex, offsetForFinallyLocalVar + marker)) { + frameMap.enterTemp(Type.INT_TYPE) + } + + finallyCodegen.generateFinallyBlocksIfNeeded(extension.returnType, extension.finallyIntervalEnd.label) + + //Exception table for external try/catch/finally blocks will be generated in original codegen after exiting this method + insertNodeBefore(finallyNode, intoNode, curInstr) + + val splitBy = SimpleInterval(start.info as LabelNode, extension.finallyIntervalEnd) + processor.tryBlocksMetaInfo.splitCurrentIntervals(splitBy, true) + + //processor.getLocalVarsMetaInfo().splitAndRemoveIntervalsFromCurrents(splitBy); + + mark.dropTo() + } + + curInstr = curInstr.next + } + + processor.substituteTryBlockNodes(intoNode) + + //processor.substituteLocalVarTable(intoNode); + } + + fun isCallInsideSameModuleAsDeclared(functionDescriptor: FunctionDescriptor) : Boolean { + return JvmCodegenUtil.isCallInsideSameModuleAsDeclared(functionDescriptor, codegen.getContext(), codegen.state.outDirectory) + } + + fun isFinallyMarkerRequired(): Boolean = isFinallyMarkerRequired(codegen.getContext()) + + + val compilationContextDescriptor + get() = codegen.getContext().contextDescriptor + + val compilationContextFunctionDescriptor + get() = codegen.getContext().functionDescriptor + + fun getLabelOwnerDescriptor(): CallableMemberDescriptor { + val context = codegen.getContext() + val parentContext = context.parentContext + if (parentContext is ClosureContext && parentContext.originalSuspendLambdaDescriptor != null) { + return parentContext.originalSuspendLambdaDescriptor!! + } + return context.contextDescriptor + } + + fun initializeInlineFunctionContext(functionDescriptor: FunctionDescriptor) { + context = getContext(functionDescriptor, state, DescriptorToSourceUtils.descriptorToDeclaration(functionDescriptor)?.containingFile as? KtFile) + } + + companion object { + fun getContext( + descriptor: DeclarationDescriptor, state: GenerationState, sourceFile: KtFile? + ): CodegenContext<*> { + if (descriptor is PackageFragmentDescriptor) { + return PackageContext(descriptor, state.rootContext, null, sourceFile) + } + + val container = descriptor.containingDeclaration ?: error("No container for descriptor: " + descriptor) + val parent = getContext( + container, + state, + sourceFile + ) + + if (descriptor is ScriptDescriptor) { + val earlierScripts = state.replSpecific.earlierScriptsForReplInterpreter + return parent.intoScript( + descriptor, + earlierScripts ?: emptyList(), + descriptor as ClassDescriptor, state.typeMapper + ) + } + else if (descriptor is ClassDescriptor) { + val kind = if (DescriptorUtils.isInterface(descriptor)) OwnerKind.DEFAULT_IMPLS else OwnerKind.IMPLEMENTATION + return parent.intoClass(descriptor, kind, state) + } + else if (descriptor is FunctionDescriptor) { + return parent.intoFunction(descriptor) + } + + throw IllegalStateException("Couldn't build context for " + descriptor) + } + } +} \ No newline at end of file diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/inlineCodegenUtils.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/inlineCodegenUtils.kt index 57e838e27cd..31e2a03ac4c 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/inlineCodegenUtils.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/inlineCodegenUtils.kt @@ -19,6 +19,7 @@ package org.jetbrains.kotlin.codegen.inline import com.intellij.openapi.vfs.VirtualFile import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.codegen.AsmUtil +import org.jetbrains.kotlin.codegen.BaseExpressionCodegen import org.jetbrains.kotlin.codegen.ExpressionCodegen import org.jetbrains.kotlin.codegen.JvmCodegenUtil import org.jetbrains.kotlin.codegen.binding.CodegenBinding @@ -502,7 +503,7 @@ internal fun isSpecialEnumMethod(functionDescriptor: FunctionDescriptor): Boolea } internal fun createSpecialEnumMethodBody( - codegen: ExpressionCodegen, + codegen: BaseExpressionCodegen, name: String, type: KotlinType, typeMapper: KotlinTypeMapper @@ -511,7 +512,7 @@ internal fun createSpecialEnumMethodBody( val invokeType = typeMapper.mapType(type) val desc = getSpecialEnumFunDescriptor(invokeType, isValueOf) val node = MethodNode(API, Opcodes.ACC_STATIC, "fake", desc, null, null) - codegen.putReifiedOperationMarkerIfTypeIsReifiedParameter(type, ReifiedTypeInliner.OperationKind.ENUM_REIFIED, InstructionAdapter(node)) + ExpressionCodegen.putReifiedOperationMarkerIfTypeIsReifiedParameter(type, ReifiedTypeInliner.OperationKind.ENUM_REIFIED, InstructionAdapter(node), codegen) if (isValueOf) { node.visitInsn(Opcodes.ACONST_NULL) node.visitVarInsn(Opcodes.ALOAD, 0) @@ -569,7 +570,7 @@ fun FunctionDescriptor.getClassFilePath(typeMapper: KotlinTypeMapper, cache: Inc } } -class InlineOnlySmapSkipper(codegen: ExpressionCodegen) { +class InlineOnlySmapSkipper(codegen: BaseExpressionCodegen) { private val callLineNumber = codegen.lastLineNumber