From e6dbe87ee2d12832e4092ba2ce527555a2c8ad8a Mon Sep 17 00:00:00 2001 From: Mikhael Bogdanov Date: Fri, 9 Jun 2017 14:52:38 +0200 Subject: [PATCH] Convert InlineCodegen to Kotlin --- .../kotlin/codegen/inline/InlineCodegen.kt | 1597 ++++++++--------- 1 file changed, 763 insertions(+), 834 deletions(-) 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 73ab803852d..ce072005262 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegen.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegen.kt @@ -14,1046 +14,975 @@ * limitations under the License. */ -package org.jetbrains.kotlin.codegen.inline; +package org.jetbrains.kotlin.codegen.inline -import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.psi.PsiElement; -import com.intellij.psi.PsiFile; -import com.intellij.util.ArrayUtil; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import org.jetbrains.kotlin.backend.common.CodegenUtil; -import org.jetbrains.kotlin.builtins.BuiltInsPackageFragment; -import org.jetbrains.kotlin.codegen.*; -import org.jetbrains.kotlin.codegen.context.*; -import org.jetbrains.kotlin.codegen.coroutines.CoroutineCodegenUtilKt; -import org.jetbrains.kotlin.codegen.intrinsics.IntrinsicArrayConstructorsKt; -import org.jetbrains.kotlin.codegen.state.GenerationState; -import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper; -import org.jetbrains.kotlin.descriptors.*; -import org.jetbrains.kotlin.incremental.KotlinLookupLocation; -import org.jetbrains.kotlin.load.kotlin.incremental.components.IncrementalCache; -import org.jetbrains.kotlin.name.ClassId; -import org.jetbrains.kotlin.name.Name; -import org.jetbrains.kotlin.psi.*; -import org.jetbrains.kotlin.renderer.DescriptorRenderer; -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.CallUtilKt; -import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall; -import org.jetbrains.kotlin.resolve.inline.InlineUtil; -import org.jetbrains.kotlin.resolve.jvm.AsmTypes; -import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodParameterKind; -import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodParameterSignature; -import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature; -import org.jetbrains.kotlin.resolve.scopes.MemberScope; -import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedCallableMemberDescriptor; -import org.jetbrains.kotlin.types.KotlinType; -import org.jetbrains.kotlin.types.expressions.DoubleColonLHS; -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.Method; -import org.jetbrains.org.objectweb.asm.tree.AbstractInsnNode; -import org.jetbrains.org.objectweb.asm.tree.InsnList; -import org.jetbrains.org.objectweb.asm.tree.LabelNode; -import org.jetbrains.org.objectweb.asm.tree.MethodNode; +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.inline.InlineCodegenUtil.* +import org.jetbrains.kotlin.codegen.intrinsics.bytecode +import org.jetbrains.kotlin.codegen.intrinsics.classId +import org.jetbrains.kotlin.codegen.state.GenerationState +import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper +import org.jetbrains.kotlin.descriptors.* +import org.jetbrains.kotlin.descriptors.annotations.isInlineOnly +import org.jetbrains.kotlin.incremental.KotlinLookupLocation +import org.jetbrains.kotlin.name.Name +import org.jetbrains.kotlin.psi.* +import org.jetbrains.kotlin.renderer.DescriptorRenderer +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.JvmMethodParameterKind +import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature +import org.jetbrains.kotlin.resolve.scopes.MemberScope +import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedCallableMemberDescriptor +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.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.io.IOException +import java.util.* -import java.io.IOException; -import java.util.*; +class InlineCodegen( + private val codegen: ExpressionCodegen, + private val state: GenerationState, + function: FunctionDescriptor, + private val callElement: KtElement, + private val typeParameterMappings: TypeParameterMappings +) : CallGenerator() { + private val typeMapper: KotlinTypeMapper -import static org.jetbrains.kotlin.codegen.AsmUtil.getMethodAsmFlags; -import static org.jetbrains.kotlin.codegen.AsmUtil.isPrimitive; -import static org.jetbrains.kotlin.codegen.inline.InlineCodegenUtil.*; -import static org.jetbrains.kotlin.descriptors.annotations.AnnotationUtilKt.isInlineOnly; -import static org.jetbrains.kotlin.resolve.inline.InlineUtil.isInlinableParameterExpression; -import static org.jetbrains.kotlin.types.expressions.ExpressionTypingUtils.isFunctionLiteral; + private val functionDescriptor: FunctionDescriptor + private val jvmSignature: JvmMethodSignature + private val context: MethodContext -public class InlineCodegen extends CallGenerator { - private final GenerationState state; - private final KotlinTypeMapper typeMapper; + private val asFunctionInline: Boolean + private val initialFrameSize: Int + private val isSameModule: Boolean - private final FunctionDescriptor functionDescriptor; - private final JvmMethodSignature jvmSignature; - private final KtElement callElement; - private final MethodContext context; - private final ExpressionCodegen codegen; + private val invocationParamBuilder = ParametersBuilder.newBuilder() + private val expressionMap = LinkedHashMap() - private final boolean asFunctionInline; - private final int initialFrameSize; - private final boolean isSameModule; + private val reifiedTypeInliner: ReifiedTypeInliner - private final ParametersBuilder invocationParamBuilder = ParametersBuilder.newBuilder(); - private final Map expressionMap = new LinkedHashMap<>(); + private var activeLambda: LambdaInfo? = null - private final ReifiedTypeInliner reifiedTypeInliner; + private val sourceMapper: SourceMapper - @NotNull - private final TypeParameterMappings typeParameterMappings; + private var delayedHiddenWriting: Function0? = null - private LambdaInfo activeLambda; + private val maskValues = ArrayList() + private var maskStartIndex = -1 + private var methodHandleInDefaultMethodIndex = -1 - private final SourceMapper sourceMapper; + init { + assert(InlineUtil.isInline(function) || InlineUtil.isArrayConstructorWithLambda(function)) { "InlineCodegen can inline only inline functions and array constructors: " + function } + this.typeMapper = state.typeMapper + this.functionDescriptor = if (InlineUtil.isArrayConstructorWithLambda(function)) + FictitiousArrayConstructor.create(function as ConstructorDescriptor) + else + function.original - private Runnable delayedHiddenWriting; + reifiedTypeInliner = ReifiedTypeInliner(typeParameterMappings) - private List maskValues = new ArrayList<>(); - private int maskStartIndex = -1; - private int methodHandleInDefaultMethodIndex = -1; + initialFrameSize = codegen.frameMap.currentSize - public InlineCodegen( - @NotNull ExpressionCodegen codegen, - @NotNull GenerationState state, - @NotNull FunctionDescriptor function, - @NotNull KtElement callElement, - @NotNull TypeParameterMappings typeParameterMappings - ) { - assert InlineUtil.isInline(function) || InlineUtil.isArrayConstructorWithLambda(function) : - "InlineCodegen can inline only inline functions and array constructors: " + function; - this.state = state; - this.typeMapper = state.getTypeMapper(); - this.codegen = codegen; - this.callElement = callElement; - this.functionDescriptor = - InlineUtil.isArrayConstructorWithLambda(function) - ? FictitiousArrayConstructor.create((ConstructorDescriptor) function) - : function.getOriginal(); - this.typeParameterMappings = typeParameterMappings; - - reifiedTypeInliner = new ReifiedTypeInliner(typeParameterMappings); - - initialFrameSize = codegen.getFrameMap().getCurrentSize(); - - PsiElement element = DescriptorToSourceUtils.descriptorToDeclaration(functionDescriptor); - context = (MethodContext) getContext(functionDescriptor, state, element != null ? (KtFile) element.getContainingFile() : null); - jvmSignature = typeMapper.mapSignatureWithGeneric(functionDescriptor, context.getContextKind()); + val element = DescriptorToSourceUtils.descriptorToDeclaration(functionDescriptor) + context = getContext(functionDescriptor, state, element?.containingFile as? KtFile) as MethodContext + jvmSignature = typeMapper.mapSignatureWithGeneric(functionDescriptor, context.contextKind) // TODO: implement AS_FUNCTION inline strategy - this.asFunctionInline = false; + this.asFunctionInline = false - isSameModule = JvmCodegenUtil.isCallInsideSameModuleAsDeclared(functionDescriptor, codegen.getContext(), state.getOutDirectory()); + isSameModule = JvmCodegenUtil.isCallInsideSameModuleAsDeclared(functionDescriptor, codegen.getContext(), state.outDirectory) - sourceMapper = codegen.getParentCodegen().getOrCreateSourceMapper(); + sourceMapper = codegen.parentCodegen.orCreateSourceMapper - if (!(functionDescriptor instanceof FictitiousArrayConstructor)) { - reportIncrementalInfo(functionDescriptor, codegen.getContext().getFunctionDescriptor().getOriginal(), jvmSignature, state); - String functionOrAccessorName = typeMapper.mapAsmMethod(function).getName(); + if (functionDescriptor !is FictitiousArrayConstructor) { + reportIncrementalInfo(functionDescriptor, codegen.getContext().functionDescriptor.original, jvmSignature, state) + val functionOrAccessorName = typeMapper.mapAsmMethod(function).name //track changes for property accessor and @JvmName inline functions/property accessors - if(!functionOrAccessorName.equals(functionDescriptor.getName().asString())) { - MemberScope scope = getMemberScope(functionDescriptor); - if (scope != null) { - //Fake lookup to track track changes for property accessors and @JvmName functions/property accessors - scope.getContributedFunctions(Name.identifier(functionOrAccessorName), new KotlinLookupLocation(callElement)); - } + if (functionOrAccessorName != functionDescriptor.name.asString()) { + val scope = getMemberScope(functionDescriptor) + //Fake lookup to track track changes for property accessors and @JvmName functions/property accessors + scope?.getContributedFunctions(Name.identifier(functionOrAccessorName), KotlinLookupLocation(callElement)) } } } - @Nullable - private static MemberScope getMemberScope(@NotNull FunctionDescriptor functionOrAccessor) { - CallableMemberDescriptor callableMemberDescriptor = JvmCodegenUtil.getDirectMember(functionOrAccessor); - DeclarationDescriptor classOrPackageFragment = callableMemberDescriptor.getContainingDeclaration(); - if (classOrPackageFragment instanceof ClassDescriptor) { - return ((ClassDescriptor) classOrPackageFragment).getUnsubstitutedMemberScope(); - } - else if (classOrPackageFragment instanceof PackageFragmentDescriptor) { - return ((PackageFragmentDescriptor) classOrPackageFragment).getMemberScope(); - } - return null; - } - - @Override - public void genCallInner( - @NotNull Callable callableMethod, - @Nullable ResolvedCall resolvedCall, - boolean callDefault, - @NotNull ExpressionCodegen codegen + override fun genCallInner( + callableMethod: Callable, + resolvedCall: ResolvedCall<*>?, + callDefault: Boolean, + codegen: ExpressionCodegen ) { - if (!state.getInlineCycleReporter().enterIntoInlining(resolvedCall)) { - generateStub(resolvedCall, codegen); - return; + if (!state.inlineCycleReporter.enterIntoInlining(resolvedCall)) { + generateStub(resolvedCall, codegen) + return } - SMAPAndMethodNode nodeAndSmap = null; + var nodeAndSmap: SMAPAndMethodNode? = null try { - nodeAndSmap = createMethodNode(functionDescriptor, jvmSignature, codegen, context, callDefault, resolvedCall); - endCall(inlineCall(nodeAndSmap, callDefault)); + nodeAndSmap = createMethodNode(functionDescriptor, jvmSignature, codegen, context, callDefault, resolvedCall) + endCall(inlineCall(nodeAndSmap, callDefault)) } - catch (CompilationException e) { - throw e; + catch (e: CompilationException) { + throw e } - catch (InlineException e) { - throw throwCompilationException(nodeAndSmap, e, false); + catch (e: InlineException) { + throw throwCompilationException(nodeAndSmap, e, false) } - catch (Exception e) { - throw throwCompilationException(nodeAndSmap, e, true); + catch (e: Exception) { + throw throwCompilationException(nodeAndSmap, e, true) } finally { - state.getInlineCycleReporter().exitFromInliningOf(resolvedCall); + state.inlineCycleReporter.exitFromInliningOf(resolvedCall) } } - @NotNull - private CompilationException throwCompilationException( - @Nullable SMAPAndMethodNode nodeAndSmap, @NotNull Exception e, boolean generateNodeText - ) { - CallableMemberDescriptor contextDescriptor = codegen.getContext().getContextDescriptor(); - PsiElement element = DescriptorToSourceUtils.descriptorToDeclaration(contextDescriptor); - MethodNode node = nodeAndSmap != null ? nodeAndSmap.getNode() : null; - throw new CompilationException( - "Couldn't inline method call '" + functionDescriptor.getName() + "' into\n" + + private fun throwCompilationException( + nodeAndSmap: SMAPAndMethodNode?, e: Exception, generateNodeText: Boolean + ): CompilationException { + val contextDescriptor = codegen.getContext().contextDescriptor + 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 != null ? element.getText() : "") + - (generateNodeText ? ("\nCause: " + InlineCodegenUtil.getNodeText(node)) : ""), + (element?.text ?: "") + + if (generateNodeText) "\nCause: " + InlineCodegenUtil.getNodeText(node) else "", e, callElement - ); + ) } - private void generateStub(@Nullable ResolvedCall resolvedCall, @NotNull ExpressionCodegen codegen) { - leaveTemps(); - assert resolvedCall != null; - String message = "Call is part of inline cycle: " + resolvedCall.getCall().getCallElement().getText(); - AsmUtil.genThrow(codegen.v, "java/lang/UnsupportedOperationException", message); + private fun generateStub(resolvedCall: ResolvedCall<*>?, codegen: ExpressionCodegen) { + 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 void endCall(@NotNull InlineResult result) { - leaveTemps(); + private fun endCall(result: InlineResult) { + leaveTemps() - codegen.propagateChildReifiedTypeParametersUsages(result.getReifiedTypeParametersUsages()); + codegen.propagateChildReifiedTypeParametersUsages(result.reifiedTypeParametersUsages) - state.getFactory().removeClasses(result.calcClassesToRemove()); + state.factory.removeClasses(result.calcClassesToRemove()) - codegen.markLineNumberAfterInlineIfNeeded(); + codegen.markLineNumberAfterInlineIfNeeded() } - @NotNull - static SMAPAndMethodNode createMethodNode( - @NotNull FunctionDescriptor functionDescriptor, - @NotNull JvmMethodSignature jvmSignature, - @NotNull ExpressionCodegen codegen, - @NotNull CodegenContext context, - boolean callDefault, - @Nullable ResolvedCall resolvedCall - ) { - if (InlineCodegenUtil.isSpecialEnumMethod(functionDescriptor)) { - assert resolvedCall != null : "Resolved call for " + functionDescriptor + " should be not null"; - Map arguments = resolvedCall.getTypeArguments(); - assert arguments.size() == 1 : "Resolved call for " + functionDescriptor + " should have 1 type argument"; - - MethodNode node = - InlineCodegenUtil.createSpecialEnumMethodBody( - codegen, - functionDescriptor.getName().asString(), - arguments.keySet().iterator().next().getDefaultType(), - codegen.getState().getTypeMapper() - ); - return new SMAPAndMethodNode(node, SMAPParser.parseOrCreateDefault(null, null, "fake", -1, -1)); - } - else if (CoroutineCodegenUtilKt.isBuiltInSuspendCoroutineOrReturnInJvm(functionDescriptor)) { - return new SMAPAndMethodNode( - CoroutineCodegenUtilKt.createMethodNodeForSuspendCoroutineOrReturn( - functionDescriptor, codegen.getState().getTypeMapper() - ), - SMAPParser.parseOrCreateDefault(null, null, "fake", -1, -1) - ); - } - - GenerationState state = codegen.getState(); - Method asmMethod = - callDefault - ? state.getTypeMapper().mapDefaultMethod(functionDescriptor, context.getContextKind()) - : jvmSignature.getAsmMethod(); - - MethodId methodId = new MethodId(DescriptorUtils.getFqNameSafe(functionDescriptor.getContainingDeclaration()), asmMethod); - CallableMemberDescriptor directMember = getDirectMemberAndCallableFromObject(functionDescriptor); - if (!isBuiltInArrayIntrinsic(functionDescriptor) && !(directMember instanceof DeserializedCallableMemberDescriptor)) { - return doCreateMethodNodeFromSource(functionDescriptor, jvmSignature, codegen, context, callDefault, state, asmMethod); - } - - SMAPAndMethodNode resultInCache = InlineCacheKt.getOrPut( - state.getInlineCache().getMethodNodeById(), methodId, () -> { - SMAPAndMethodNode result = doCreateMethodNodeFromCompiled(directMember, state, asmMethod); - if (result == null) { - throw new IllegalStateException("Couldn't obtain compiled function body for " + functionDescriptor); - } - return result; - } - ); - - return resultInCache.copyWithNewNode(cloneMethodNode(resultInCache.getNode())); - } - - @NotNull - private static CallableMemberDescriptor getDirectMemberAndCallableFromObject(@NotNull FunctionDescriptor functionDescriptor) { - CallableMemberDescriptor directMember = JvmCodegenUtil.getDirectMember(functionDescriptor); - if (directMember instanceof ImportedFromObjectCallableDescriptor) { - return ((ImportedFromObjectCallableDescriptor) directMember).getCallableFromObject(); - } - return directMember; - } - - @NotNull - private static MethodNode cloneMethodNode(@NotNull MethodNode methodNode) { - methodNode.instructions.resetLabels(); - MethodNode result = new MethodNode( - API, methodNode.access, methodNode.name, methodNode.desc, methodNode.signature, - ArrayUtil.toStringArray(methodNode.exceptions) - ); - methodNode.accept(result); - return result; - } - - @Nullable - private static SMAPAndMethodNode doCreateMethodNodeFromCompiled( - @NotNull CallableMemberDescriptor callableDescriptor, - @NotNull GenerationState state, - @NotNull Method asmMethod - ) { - if (isBuiltInArrayIntrinsic(callableDescriptor)) { - ClassId classId = IntrinsicArrayConstructorsKt.getClassId(); - byte[] bytes = - InlineCacheKt.getOrPut(state.getInlineCache().getClassBytes(), classId, IntrinsicArrayConstructorsKt::getBytecode); - return InlineCodegenUtil.getMethodNode(bytes, asmMethod.getName(), asmMethod.getDescriptor(), classId.asString()); - } - - assert callableDescriptor instanceof DeserializedCallableMemberDescriptor : "Not a deserialized function or proper: " + callableDescriptor; - - KotlinTypeMapper.ContainingClassesInfo containingClasses = - state.getTypeMapper().getContainingClassesForDeserializedCallable((DeserializedCallableMemberDescriptor) callableDescriptor); - - ClassId containerId = containingClasses.getImplClassId(); - - byte[] bytes = InlineCacheKt.getOrPut(state.getInlineCache().getClassBytes(), containerId, () -> { - VirtualFile file = InlineCodegenUtil.findVirtualFile(state, containerId); - if (file == null) { - throw new IllegalStateException("Couldn't find declaration file for " + containerId); - } - try { - return file.contentsToByteArray(); - } - catch (IOException e) { - throw new RuntimeException(e); - } - }); - - return InlineCodegenUtil.getMethodNode(bytes, asmMethod.getName(), asmMethod.getDescriptor(), containerId.asString()); - } - - @NotNull - private static SMAPAndMethodNode doCreateMethodNodeFromSource( - @NotNull FunctionDescriptor callableDescriptor, - @NotNull JvmMethodSignature jvmSignature, - @NotNull ExpressionCodegen codegen, - @NotNull CodegenContext context, - boolean callDefault, - @NotNull GenerationState state, - @NotNull Method asmMethod - ) { - PsiElement element = DescriptorToSourceUtils.descriptorToDeclaration(callableDescriptor); - - if (!(element instanceof KtNamedFunction || element instanceof KtPropertyAccessor)) { - throw new IllegalStateException("Couldn't find declaration for function " + callableDescriptor); - } - KtDeclarationWithBody inliningFunction = (KtDeclarationWithBody) element; - - MethodNode node = new MethodNode( - InlineCodegenUtil.API, - getMethodAsmFlags(callableDescriptor, context.getContextKind(), state) | (callDefault ? Opcodes.ACC_STATIC : 0), - asmMethod.getName(), - asmMethod.getDescriptor(), - null, null - ); - - //for maxLocals calculation - MethodVisitor maxCalcAdapter = InlineCodegenUtil.wrapWithMaxLocalCalc(node); - CodegenContext parentContext = context.getParentContext(); - assert parentContext != null : "Context has no parent: " + context; - MethodContext methodContext = parentContext.intoFunction(callableDescriptor); - - SMAP smap; + private fun inlineCall(nodeAndSmap: SMAPAndMethodNode, callDefault: Boolean): InlineResult { + assert(delayedHiddenWriting == null) { "'putHiddenParamsIntoLocals' should be called after 'processAndPutHiddenParameters(true)'" } + val defaultSourceMapper = codegen.parentCodegen.orCreateSourceMapper + defaultSourceMapper.callSiteMarker = CallSiteMarker(codegen.lastLineNumber) + val node = nodeAndSmap.node if (callDefault) { - Type implementationOwner = state.getTypeMapper().mapImplementationOwner(callableDescriptor); - FakeMemberCodegen parentCodegen = new FakeMemberCodegen( - codegen.getParentCodegen(), inliningFunction, (FieldOwnerContext) methodContext.getParentContext(), - implementationOwner.getInternalName() - ); - if (!(element instanceof KtNamedFunction)) { - throw new IllegalStateException("Property accessors with default parameters not supported " + callableDescriptor); - } - FunctionCodegen.generateDefaultImplBody( - methodContext, callableDescriptor, maxCalcAdapter, DefaultParameterValueLoader.DEFAULT, - (KtNamedFunction) inliningFunction, parentCodegen, asmMethod - ); - smap = createSMAPWithDefaultMapping(inliningFunction, parentCodegen.getOrCreateSourceMapper().getResultMappings()); - } - else { - smap = generateMethodBody(maxCalcAdapter, callableDescriptor, methodContext, inliningFunction, jvmSignature, codegen, - null); - } - maxCalcAdapter.visitMaxs(-1, -1); - maxCalcAdapter.visitEnd(); - - return new SMAPAndMethodNode(node, smap); - } - - private static boolean isBuiltInArrayIntrinsic(@NotNull CallableMemberDescriptor callableDescriptor) { - if (callableDescriptor instanceof FictitiousArrayConstructor) return true; - String name = callableDescriptor.getName().asString(); - return (name.equals("arrayOf") || name.equals("emptyArray")) && - callableDescriptor.getContainingDeclaration() instanceof BuiltInsPackageFragment; - } - - @NotNull - private InlineResult inlineCall(@NotNull SMAPAndMethodNode nodeAndSmap, boolean callDefault) { - assert delayedHiddenWriting == null : "'putHiddenParamsIntoLocals' should be called after 'processAndPutHiddenParameters(true)'"; - DefaultSourceMapper defaultSourceMapper = codegen.getParentCodegen().getOrCreateSourceMapper(); - defaultSourceMapper.setCallSiteMarker(new CallSiteMarker(codegen.getLastLineNumber())); - MethodNode node = nodeAndSmap.getNode(); - if (callDefault) { - List defaultLambdas = DefaultMethodUtilKt.expandMaskConditionsAndUpdateVariableNodes( + val defaultLambdas = expandMaskConditionsAndUpdateVariableNodes( node, maskStartIndex, maskValues, methodHandleInDefaultMethodIndex, - DefaultMethodUtilKt.extractDefaultLambdaOffsetAndDescriptor(jvmSignature, functionDescriptor) - ); - for (DefaultLambda lambda : defaultLambdas) { - invocationParamBuilder.buildParameters().getParameterByDeclarationSlot(lambda.getOffset()).setLambda(lambda); - LambdaInfo prev = expressionMap.put(lambda.getOffset(), lambda); - assert prev == null : "Lambda with offset " + lambda.getOffset() + " already exists: " + prev; + extractDefaultLambdaOffsetAndDescriptor(jvmSignature, functionDescriptor) + ) + for (lambda in defaultLambdas) { + invocationParamBuilder.buildParameters().getParameterByDeclarationSlot(lambda.offset).lambda = lambda + val prev = expressionMap.put(lambda.offset, lambda) + assert(prev == null) { "Lambda with offset " + lambda.offset + " already exists: " + prev } } } - ReifiedTypeParametersUsages reificationResult = reifiedTypeInliner.reifyInstructions(node); - generateClosuresBodies(); + val reificationResult = reifiedTypeInliner.reifyInstructions(node) + generateClosuresBodies() //through generation captured parameters will be added to invocationParamBuilder - putClosureParametersOnStack(); + putClosureParametersOnStack() - addInlineMarker(codegen.v, true); + addInlineMarker(codegen.v, true) - Parameters parameters = invocationParamBuilder.buildParameters(); + val parameters = invocationParamBuilder.buildParameters() - InliningContext info = new RootInliningContext( - expressionMap, state, codegen.getInlineNameGenerator().subGenerator(jvmSignature.getAsmMethod().getName()), - callElement, getInlineCallSiteInfo(), reifiedTypeInliner, typeParameterMappings - ); + val info = RootInliningContext( + expressionMap, state, codegen.inlineNameGenerator.subGenerator(jvmSignature.asmMethod.name), + callElement, inlineCallSiteInfo, reifiedTypeInliner, typeParameterMappings + ) - MethodInliner inliner = new MethodInliner( - node, parameters, info, new FieldRemapper(null, null, parameters), isSameModule, - "Method inlining " + callElement.getText(), - createNestedSourceMapper(nodeAndSmap, sourceMapper), info.getCallSiteInfo(), - isInlineOnly(functionDescriptor) ? new InlineOnlySmapSkipper(codegen) : null - ); //with captured + val inliner = MethodInliner( + node, parameters, info, FieldRemapper(null, null, parameters), isSameModule, + "Method inlining " + callElement.text, + createNestedSourceMapper(nodeAndSmap, sourceMapper), info.callSiteInfo, + if (functionDescriptor.isInlineOnly()) InlineOnlySmapSkipper(codegen) else null + ) //with captured - LocalVarRemapper remapper = new LocalVarRemapper(parameters, initialFrameSize); + val remapper = LocalVarRemapper(parameters, initialFrameSize) - MethodNode adapter = InlineCodegenUtil.createEmptyMethodNode(); + val adapter = InlineCodegenUtil.createEmptyMethodNode() //hack to keep linenumber info, otherwise jdi will skip begin of linenumber chain - adapter.visitInsn(Opcodes.NOP); + adapter.visitInsn(Opcodes.NOP) - InlineResult result = inliner.doInline(adapter, remapper, true, LabelOwner.SKIP_ALL); - result.getReifiedTypeParametersUsages().mergeAll(reificationResult); + val result = inliner.doInline(adapter, remapper, true, LabelOwner.SKIP_ALL) + result.reifiedTypeParametersUsages.mergeAll(reificationResult) - CallableMemberDescriptor descriptor = getLabelOwnerDescriptor(codegen.getContext()); - Set labels = getDeclarationLabels(DescriptorToSourceUtils.descriptorToDeclaration(descriptor), descriptor); + val descriptor = getLabelOwnerDescriptor(codegen.getContext()) + val labels = getDeclarationLabels(DescriptorToSourceUtils.descriptorToDeclaration(descriptor), descriptor) - List infos = MethodInliner.processReturns(adapter, labels::contains, true, null); + val infos = MethodInliner.processReturns(adapter, LabelOwner { labels.contains(it) }, true, null) generateAndInsertFinallyBlocks( - adapter, infos, ((StackValue.Local) remapper.remap(parameters.getArgsSizeOnStack() + 1).value).index - ); - removeStaticInitializationTrigger(adapter); + adapter, infos, (remapper.remap(parameters.argsSizeOnStack + 1).value as StackValue.Local).index + ) + removeStaticInitializationTrigger(adapter) if (!InlineCodegenUtil.isFinallyMarkerRequired(codegen.getContext())) { - InlineCodegenUtil.removeFinallyMarkers(adapter); + InlineCodegenUtil.removeFinallyMarkers(adapter) } - adapter.accept(new MethodBodyVisitor(codegen.v)); + adapter.accept(MethodBodyVisitor(codegen.v)) - addInlineMarker(codegen.v, false); + addInlineMarker(codegen.v, false) - defaultSourceMapper.setCallSiteMarker(null); + defaultSourceMapper.callSiteMarker = null - return result; + return result } - @NotNull - private static CallableMemberDescriptor getLabelOwnerDescriptor(@NotNull MethodContext context) { - if (context.getParentContext() instanceof ClosureContext && - ((ClosureContext) context.getParentContext()).getOriginalSuspendLambdaDescriptor() != null) { - //noinspection ConstantConditions - return ((ClosureContext) context.getParentContext()).getOriginalSuspendLambdaDescriptor(); - } - - return context.getContextDescriptor(); - } - - private static void removeStaticInitializationTrigger(@NotNull MethodNode methodNode) { - InsnList insnList = methodNode.instructions; - AbstractInsnNode insn = insnList.getFirst(); - while (insn != null) { - if (MultifileClassPartCodegen.isStaticInitTrigger(insn)) { - AbstractInsnNode clinitTriggerCall = insn; - insn = insn.getNext(); - insnList.remove(clinitTriggerCall); - } - else { - insn = insn.getNext(); + 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) } } - @NotNull - private InlineCallSiteInfo getInlineCallSiteInfo() { - MethodContext context = codegen.getContext(); - MemberCodegen parentCodegen = codegen.getParentCodegen(); - while (context instanceof InlineLambdaContext) { - CodegenContext closureContext = context.getParentContext(); - assert closureContext instanceof ClosureContext : "Parent context of inline lambda should be closure context"; - assert closureContext.getParentContext() instanceof MethodContext : "Closure context should appear in method context"; - context = (MethodContext) closureContext.getParentContext(); - assert parentCodegen instanceof FakeMemberCodegen : "Parent codegen of inlined lambda should be FakeMemberCodegen"; - parentCodegen = ((FakeMemberCodegen) parentCodegen).delegate; + 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() } - JvmMethodSignature signature = typeMapper.mapSignatureSkipGeneric(context.getFunctionDescriptor(), context.getContextKind()); - return new InlineCallSiteInfo( - parentCodegen.getClassName(), signature.getAsmMethod().getName(), signature.getAsmMethod().getDescriptor() - ); - } + override fun generateBody() { + throw IllegalStateException() + } - private void generateClosuresBodies() { - for (LambdaInfo info : expressionMap.values()) { - info.generateLambdaBody(codegen, reifiedTypeInliner); + override fun generateKotlinMetadataAnnotation() { + throw IllegalStateException() + } + + override fun getInlineNameGenerator(): NameGenerator { + return delegate.inlineNameGenerator + } + + override //TODO: obtain name from context + fun getClassName(): String { + return className } } - @NotNull - public static SMAP generateMethodBody( - @NotNull MethodVisitor adapter, - @NotNull FunctionDescriptor descriptor, - @NotNull MethodContext context, - @NotNull KtExpression expression, - @NotNull JvmMethodSignature jvmMethodSignature, - @NotNull ExpressionCodegen codegen, - @Nullable ExpressionLambda lambdaInfo + private fun putArgumentOrCapturedToLocalVal( + type: Type, + stackValue: StackValue, + capturedParamIndex: Int, + parameterIndex: Int, + kind: ValueKind ) { - boolean isLambda = lambdaInfo != null; - GenerationState state = codegen.getState(); - - // Wrapping for preventing marking actual parent codegen as containing reified markers - FakeMemberCodegen parentCodegen = new FakeMemberCodegen( - codegen.getParentCodegen(), expression, (FieldOwnerContext) context.getParentContext(), - isLambda ? codegen.getParentCodegen().getClassName() - : state.getTypeMapper().mapImplementationOwner(descriptor).getInternalName() - ); - - FunctionGenerationStrategy strategy; - if (expression instanceof KtCallableReferenceExpression) { - KtCallableReferenceExpression callableReferenceExpression = (KtCallableReferenceExpression) expression; - KtExpression receiverExpression = callableReferenceExpression.getReceiverExpression(); - Type receiverType = - receiverExpression != null && codegen.getBindingContext().getType(receiverExpression) != null - ? codegen.getState().getTypeMapper().mapType(codegen.getBindingContext().getType(receiverExpression)) - : null; - - if (isLambda && lambdaInfo.isPropertyReference()) { - Type asmType = state.getTypeMapper().mapClass(lambdaInfo.getClassDescriptor()); - PropertyReferenceInfo info = lambdaInfo.getPropertyReferenceInfo(); - strategy = new PropertyReferenceCodegen.PropertyReferenceGenerationStrategy( - true, info.getGetFunction(), info.getTarget(), asmType, receiverType, - lambdaInfo.getFunctionWithBodyOrCallableReference(), state, true); - } - else { - strategy = new FunctionReferenceGenerationStrategy( - state, - descriptor, - CallUtilKt - .getResolvedCallWithAssert(callableReferenceExpression.getCallableReference(), codegen.getBindingContext()), - receiverType, - null, - true - ); - } - } - else if (expression instanceof KtFunctionLiteral) { - strategy = new ClosureGenerationStrategy(state, (KtDeclarationWithBody) expression); - } - else { - strategy = new FunctionGenerationStrategy.FunctionDefault(state, (KtDeclarationWithBody) expression); - } - - FunctionCodegen.generateMethodBody(adapter, descriptor, context, jvmMethodSignature, strategy, parentCodegen); - - if (isLambda) { - codegen.propagateChildReifiedTypeParametersUsages(parentCodegen.getReifiedTypeParametersUsages()); - } - - return createSMAPWithDefaultMapping(expression, parentCodegen.getOrCreateSourceMapper().getResultMappings()); - } - - private static SMAP createSMAPWithDefaultMapping( - @NotNull KtExpression declaration, - @NotNull List mappings - ) { - PsiFile containingFile = declaration.getContainingFile(); - Integer lineNumbers = CodegenUtil.getLineNumberForElement(containingFile, true); - assert lineNumbers != null : "Couldn't extract line count in " + containingFile; - - return new SMAP(mappings); - } - - private static class FakeMemberCodegen extends MemberCodegen { - private final MemberCodegen delegate; - private final String className; - - @SuppressWarnings("unchecked") - public FakeMemberCodegen( - @NotNull MemberCodegen wrapped, - @NotNull KtElement declaration, - @NotNull FieldOwnerContext codegenContext, - @NotNull String className - ) { - super(wrapped, declaration, codegenContext); - this.delegate = wrapped; - this.className = className; - } - - @Override - protected void generateDeclaration() { - throw new IllegalStateException(); - } - - @Override - protected void generateBody() { - throw new IllegalStateException(); - } - - @Override - protected void generateKotlinMetadataAnnotation() { - throw new IllegalStateException(); - } - - @NotNull - @Override - public NameGenerator getInlineNameGenerator() { - return delegate.getInlineNameGenerator(); - } - - @NotNull - @Override - //TODO: obtain name from context - public String getClassName() { - return className; - } - } - - private void putArgumentOrCapturedToLocalVal( - @NotNull Type type, - @NotNull StackValue stackValue, - int capturedParamIndex, - int parameterIndex, - @NotNull ValueKind kind - ) { - boolean isDefaultParameter = kind == ValueKind.DEFAULT_PARAMETER; + val isDefaultParameter = kind === ValueKind.DEFAULT_PARAMETER if (!isDefaultParameter && shouldPutGeneralValue(type, stackValue)) { - stackValue.put(type, codegen.v); + stackValue.put(type, codegen.v) } - if (!asFunctionInline && Type.VOID_TYPE != type) { + if (!asFunctionInline && Type.VOID_TYPE !== type) { //TODO remap only inlinable closure => otherwise we could get a lot of problem - boolean couldBeRemapped = !shouldPutGeneralValue(type, stackValue) && kind != ValueKind.DEFAULT_PARAMETER; - StackValue remappedValue = couldBeRemapped ? stackValue : null; + val couldBeRemapped = !shouldPutGeneralValue(type, stackValue) && kind !== ValueKind.DEFAULT_PARAMETER + val remappedValue = if (couldBeRemapped) stackValue else null - ParameterInfo info; + val info: ParameterInfo if (capturedParamIndex >= 0) { - CapturedParamDesc capturedParamInfoInLambda = activeLambda.getCapturedVars().get(capturedParamIndex); - info = invocationParamBuilder.addCapturedParam(capturedParamInfoInLambda, capturedParamInfoInLambda.getFieldName(), false); - info.setRemapValue(remappedValue); + val capturedParamInfoInLambda = activeLambda!!.capturedVars[capturedParamIndex] + info = invocationParamBuilder.addCapturedParam(capturedParamInfoInLambda, capturedParamInfoInLambda.fieldName, false) + info.setRemapValue(remappedValue) } else { - info = invocationParamBuilder.addNextValueParameter(type, false, remappedValue, parameterIndex); + info = invocationParamBuilder.addNextValueParameter(type, false, remappedValue, parameterIndex) } recordParameterValueInLocalVal( false, - isDefaultParameter || kind == ValueKind.DEFAULT_LAMBDA_CAPTURED_PARAMETER, + isDefaultParameter || kind === ValueKind.DEFAULT_LAMBDA_CAPTURED_PARAMETER, info - ); + ) } } - /*descriptor is null for captured vars*/ - private static boolean shouldPutGeneralValue(@NotNull Type type, @NotNull StackValue stackValue) { - //remap only inline functions (and maybe non primitives) - //TODO - clean asserion and remapping logic - if (isPrimitive(type) != isPrimitive(stackValue.type)) { - //don't remap boxing/unboxing primitives - lost identity and perfomance - return true; - } - - if (stackValue instanceof StackValue.Local) { - return false; - } - - StackValue field = stackValue; - if (stackValue instanceof StackValue.FieldForSharedVar) { - field = ((StackValue.FieldForSharedVar) stackValue).receiver; - } - - //check that value corresponds to captured inlining parameter - if (field instanceof StackValue.Field) { - DeclarationDescriptor varDescriptor = ((StackValue.Field) field).descriptor; - //check that variable is inline function parameter - return !(varDescriptor instanceof ParameterDescriptor && - InlineUtil.isInlineLambdaParameter((ParameterDescriptor) varDescriptor) && - InlineUtil.isInline(varDescriptor.getContainingDeclaration())); - } - - return true; - } - - private Runnable recordParameterValueInLocalVal(boolean delayedWritingToLocals, boolean skipStore, @NotNull ParameterInfo... infos) { - int[] index = new int[infos.length]; - for (int i = 0; i < infos.length; i++) { - ParameterInfo info = infos[i]; - if (!info.isSkippedOrRemapped()) { - index[i] = codegen.getFrameMap().enterTemp(info.getType()); + private fun recordParameterValueInLocalVal(delayedWritingToLocals: Boolean, skipStore: Boolean, vararg infos: ParameterInfo): Function0? { + val index = IntArray(infos.size) + for (i in infos.indices) { + val info = infos[i] + if (!info.isSkippedOrRemapped) { + index[i] = codegen.frameMap.enterTemp(info.getType()) } else { - index[i] = -1; + index[i] = -1 } } - Runnable runnable = () -> { - for (int i = infos.length - 1; i >= 0; i--) { - ParameterInfo info = infos[i]; - if (!info.isSkippedOrRemapped()) { - Type type = info.type; - StackValue.Local local = StackValue.local(index[i], type); + val runnable = { + for (i in infos.indices.reversed()) { + val info = infos[i] + if (!info.isSkippedOrRemapped) { + val type = info.type + val local = StackValue.local(index[i], type) if (!skipStore) { - local.store(StackValue.onStack(type), codegen.v); + local.store(StackValue.onStack(type), codegen.v) } - if (info instanceof CapturedParamInfo) { - info.setRemapValue(local); - ((CapturedParamInfo) info).setSynthetic(true); + if (info is CapturedParamInfo) { + info.setRemapValue(local) + info.isSynthetic = true } } } - }; - - if (delayedWritingToLocals) return runnable; - runnable.run(); - return null; - } - - @Override - public void processAndPutHiddenParameters(boolean justProcess) { - if ((getMethodAsmFlags(functionDescriptor, context.getContextKind(), state) & Opcodes.ACC_STATIC) == 0) { - invocationParamBuilder.addNextParameter(AsmTypes.OBJECT_TYPE, false); } - for (JvmMethodParameterSignature param : jvmSignature.getValueParameters()) { - if (param.getKind() == JvmMethodParameterKind.VALUE) { - break; + if (delayedWritingToLocals) return runnable + runnable() + return null + } + + override fun processAndPutHiddenParameters(justProcess: Boolean) { + if (getMethodAsmFlags(functionDescriptor, context.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.getAsmType(), false); + invocationParamBuilder.addNextParameter(param.asmType, false) } - invocationParamBuilder.markValueParametersStart(); - List hiddenParameters = invocationParamBuilder.buildParameters().getParameters(); + invocationParamBuilder.markValueParametersStart() + val hiddenParameters = invocationParamBuilder.buildParameters().parameters - delayedHiddenWriting = recordParameterValueInLocalVal(justProcess, false, hiddenParameters.toArray(new ParameterInfo[hiddenParameters.size()])); + delayedHiddenWriting = recordParameterValueInLocalVal(justProcess, false, *hiddenParameters.toTypedArray()) } - private void leaveTemps() { - List infos = invocationParamBuilder.listAllParams(); - for (ListIterator iterator = infos.listIterator(infos.size()); iterator.hasPrevious(); ) { - ParameterInfo param = iterator.previous(); - if (!param.isSkippedOrRemapped() || CapturedParamInfo.isSynthetic(param)) { - codegen.getFrameMap().leaveTemp(param.type); + private fun leaveTemps() { + val infos = invocationParamBuilder.listAllParams() + val iterator = infos.listIterator(infos.size) + while (iterator.hasPrevious()) { + val param = iterator.previous() + if (!param.isSkippedOrRemapped || CapturedParamInfo.isSynthetic(param)) { + codegen.frameMap.leaveTemp(param.type) } } } - /*lambda or callable reference*/ - private static boolean isInliningParameter(@NotNull KtExpression expression, @NotNull ValueParameterDescriptor valueParameterDescriptor) { - //TODO deparenthisise typed - KtExpression deparenthesized = KtPsiUtil.deparenthesize(expression); + private fun rememberClosure(expression: KtExpression, type: Type, parameter: ValueParameterDescriptor): LambdaInfo { + val lambda = KtPsiUtil.deparenthesize(expression) + assert(isInlinableParameterExpression(lambda)) { "Couldn't find inline expression in " + expression.text } - return InlineUtil.isInlineLambdaParameter(valueParameterDescriptor) && - isInlinableParameterExpression(deparenthesized); + val info = ExpressionLambda(lambda!!, typeMapper, parameter.isCrossinline, getBoundCallableReferenceReceiver(expression) != null) + + val closureInfo = invocationParamBuilder.addNextValueParameter(type, true, null, parameter.index) + closureInfo.lambda = info + expressionMap.put(closureInfo.index, info) + return info } - private LambdaInfo rememberClosure(@NotNull KtExpression expression, @NotNull Type type, @NotNull ValueParameterDescriptor parameter) { - KtExpression lambda = KtPsiUtil.deparenthesize(expression); - assert isInlinableParameterExpression(lambda) : "Couldn't find inline expression in " + expression.getText(); - - LambdaInfo info = - new ExpressionLambda(lambda, typeMapper, parameter.isCrossinline(), getBoundCallableReferenceReceiver(expression) != null); - - ParameterInfo closureInfo = invocationParamBuilder.addNextValueParameter(type, true, null, parameter.getIndex()); - closureInfo.setLambda(info); - expressionMap.put(closureInfo.getIndex(), info); - return info; - } - - @NotNull - public static Set getDeclarationLabels(@Nullable PsiElement lambdaOrFun, @NotNull DeclarationDescriptor descriptor) { - Set result = new HashSet<>(); - - if (lambdaOrFun != null) { - Name label = LabelResolver.INSTANCE.getLabelNameIfAny(lambdaOrFun); - if (label != null) { - result.add(label.asString()); - } - } - - if (!isFunctionLiteral(descriptor)) { - if (!descriptor.getName().isSpecial()) { - result.add(descriptor.getName().asString()); - } - result.add(InlineCodegenUtil.FIRST_FUN_LABEL); - } - return result; - } - - private void putClosureParametersOnStack() { - for (LambdaInfo next : expressionMap.values()) { + private fun putClosureParametersOnStack() { + for (next in expressionMap.values) { //closure parameters for bounded callable references are generated inplace - if (next instanceof ExpressionLambda && next.isBoundCallableReference()) continue; - putClosureParametersOnStack(next, null); + if (next is ExpressionLambda && next.isBoundCallableReference) continue + putClosureParametersOnStack(next, null) } } - private void putClosureParametersOnStack(@NotNull LambdaInfo next, @Nullable StackValue functionReferenceReceiver) { - activeLambda = next; - if (next instanceof ExpressionLambda) { - codegen.pushClosureOnStack(((ExpressionLambda) next).getClassDescriptor(), true, this, functionReferenceReceiver); + private fun putClosureParametersOnStack(next: LambdaInfo, functionReferenceReceiver: StackValue?) { + activeLambda = next + if (next is ExpressionLambda) { + codegen.pushClosureOnStack(next.classDescriptor, true, this, functionReferenceReceiver) } - else if (next instanceof DefaultLambda) { - rememberCapturedForDefaultLambda((DefaultLambda) next); + else if (next is DefaultLambda) { + rememberCapturedForDefaultLambda(next) } else { - throw new RuntimeException("Unknown lambda: " + next); + throw RuntimeException("Unknown lambda: " + next) } - activeLambda = null; + activeLambda = null } - private void rememberCapturedForDefaultLambda(@NotNull DefaultLambda defaultLambda) { - List vars = defaultLambda.getCapturedVars(); - int paramIndex = 0; - for (CapturedParamDesc captured : vars) { + private fun rememberCapturedForDefaultLambda(defaultLambda: DefaultLambda) { + val vars = defaultLambda.capturedVars + var paramIndex = 0 + for (captured in vars) { putArgumentOrCapturedToLocalVal( - captured.getType(), + captured.type, //HACK: actually parameter would be placed on stack in default function // also see ValueKind.DEFAULT_LAMBDA_CAPTURED_PARAMETER check - StackValue.onStack(captured.getType()), + StackValue.onStack(captured.type), paramIndex, paramIndex, ValueKind.DEFAULT_LAMBDA_CAPTURED_PARAMETER - ); + ) - paramIndex++; - defaultLambda.getParameterOffsetsInDefault().add(invocationParamBuilder.getNextParameterOffset()); + paramIndex++ + defaultLambda.parameterOffsetsInDefault.add(invocationParamBuilder.nextParameterOffset) } } - @NotNull - public static CodegenContext getContext( - @NotNull DeclarationDescriptor descriptor, @NotNull GenerationState state, @Nullable KtFile sourceFile - ) { - if (descriptor instanceof PackageFragmentDescriptor) { - return new PackageContext((PackageFragmentDescriptor) descriptor, state.getRootContext(), null, sourceFile); - } - - DeclarationDescriptor container = descriptor.getContainingDeclaration(); - assert container != null : "No container for descriptor: " + descriptor; - CodegenContext parent = getContext(container, state, sourceFile); - - if (descriptor instanceof ScriptDescriptor) { - List earlierScripts = state.getReplSpecific().getEarlierScriptsForReplInterpreter(); - return parent.intoScript( - (ScriptDescriptor) descriptor, - earlierScripts == null ? Collections.emptyList() : earlierScripts, - (ClassDescriptor) descriptor, state.getTypeMapper() - ); - } - else if (descriptor instanceof ClassDescriptor) { - OwnerKind kind = DescriptorUtils.isInterface(descriptor) ? OwnerKind.DEFAULT_IMPLS : OwnerKind.IMPLEMENTATION; - return parent.intoClass((ClassDescriptor) descriptor, kind, state); - } - else if (descriptor instanceof FunctionDescriptor) { - return parent.intoFunction((FunctionDescriptor) descriptor); - } - - throw new IllegalStateException("Couldn't build context for " + descriptor); - } - - @Override - public void genValueAndPut( - @NotNull ValueParameterDescriptor valueParameterDescriptor, - @NotNull KtExpression argumentExpression, - @NotNull Type parameterType, - int parameterIndex + override fun genValueAndPut( + valueParameterDescriptor: ValueParameterDescriptor, + argumentExpression: KtExpression, + parameterType: Type, + parameterIndex: Int ) { if (isInliningParameter(argumentExpression, valueParameterDescriptor)) { - LambdaInfo lambdaInfo = rememberClosure(argumentExpression, parameterType, valueParameterDescriptor); + val lambdaInfo = rememberClosure(argumentExpression, parameterType, valueParameterDescriptor) - KtExpression receiver = getBoundCallableReferenceReceiver(argumentExpression); + val receiver = getBoundCallableReferenceReceiver(argumentExpression) if (receiver != null) { - putClosureParametersOnStack(lambdaInfo, codegen.gen(receiver)); + putClosureParametersOnStack(lambdaInfo, codegen.gen(receiver)) } } else { - StackValue value = codegen.gen(argumentExpression); - putValueIfNeeded(parameterType, value, ValueKind.GENERAL, valueParameterDescriptor.getIndex()); + val value = codegen.gen(argumentExpression) + putValueIfNeeded(parameterType, value, ValueKind.GENERAL, valueParameterDescriptor.index) } } - private KtExpression getBoundCallableReferenceReceiver( - @NotNull KtExpression argumentExpression - ) { - KtExpression deparenthesized = KtPsiUtil.deparenthesize(argumentExpression); - if (deparenthesized instanceof KtCallableReferenceExpression) { - KtExpression receiverExpression = ((KtCallableReferenceExpression) deparenthesized).getReceiverExpression(); + private fun getBoundCallableReferenceReceiver( + argumentExpression: KtExpression + ): KtExpression? { + val deparenthesized = KtPsiUtil.deparenthesize(argumentExpression) + if (deparenthesized is KtCallableReferenceExpression) { + val receiverExpression = deparenthesized.receiverExpression if (receiverExpression != null) { - DoubleColonLHS lhs = state.getBindingContext().get(BindingContext.DOUBLE_COLON_LHS, receiverExpression); - if (lhs instanceof DoubleColonLHS.Expression) return receiverExpression; + val lhs = state.bindingContext.get(BindingContext.DOUBLE_COLON_LHS, receiverExpression) + if (lhs is DoubleColonLHS.Expression) return receiverExpression } } - return null; + return null } - @Override - public void putValueIfNeeded(@NotNull Type parameterType, @NotNull StackValue value, @NotNull ValueKind kind, int parameterIndex) { - if (processDefaultMaskOrMethodHandler(value, kind)) return; + 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; + assert(maskValues.isEmpty()) { "Additional default call arguments should be last ones, but " + value } - putArgumentOrCapturedToLocalVal(parameterType, value, -1, parameterIndex, kind); + putArgumentOrCapturedToLocalVal(parameterType, value, -1, parameterIndex, kind) } - private boolean processDefaultMaskOrMethodHandler(@NotNull StackValue value, @NotNull ValueKind kind) { - if (kind != ValueKind.DEFAULT_MASK && kind != ValueKind.METHOD_HANDLE_IN_DEFAULT) { - return false; + private fun processDefaultMaskOrMethodHandler(value: StackValue, kind: ValueKind): Boolean { + if (kind !== ValueKind.DEFAULT_MASK && kind !== ValueKind.METHOD_HANDLE_IN_DEFAULT) { + return false } - assert value instanceof StackValue.Constant : "Additional default method argument should be constant, but " + value; - Object constantValue = ((StackValue.Constant) value).value; - if (kind == ValueKind.DEFAULT_MASK) { - assert constantValue instanceof Integer : "Mask should be of Integer type, but " + constantValue; - maskValues.add((Integer) constantValue); + assert(value is StackValue.Constant) { "Additional default method argument should be constant, but " + value } + val constantValue = (value as StackValue.Constant).value + if (kind === ValueKind.DEFAULT_MASK) { + assert(constantValue is Int) { "Mask should be of Integer type, but " + constantValue!! } + maskValues.add(constantValue as Int) if (maskStartIndex == -1) { - maskStartIndex = invocationParamBuilder.getNextParameterOffset(); + maskStartIndex = invocationParamBuilder.nextParameterOffset } } else { - assert constantValue == null : "Additional method handle for default argument should be null, but " + constantValue; - methodHandleInDefaultMethodIndex = maskStartIndex + maskValues.size(); + assert(constantValue == null) { "Additional method handle for default argument should be null, but " + constantValue!! } + methodHandleInDefaultMethodIndex = maskStartIndex + maskValues.size } - return true; + return true } - @Override - public void putCapturedValueOnStack(@NotNull StackValue stackValue, @NotNull Type valueType, int paramIndex) { - putArgumentOrCapturedToLocalVal(stackValue.type, stackValue, paramIndex, paramIndex, ValueKind.CAPTURED); + override fun putCapturedValueOnStack(stackValue: StackValue, valueType: Type, paramIndex: Int) { + putArgumentOrCapturedToLocalVal(stackValue.type, stackValue, paramIndex, paramIndex, ValueKind.CAPTURED) } - private void generateAndInsertFinallyBlocks( - @NotNull MethodNode intoNode, - @NotNull List insertPoints, - int offsetForFinallyLocalVar + private fun generateAndInsertFinallyBlocks( + intoNode: MethodNode, + insertPoints: List, + offsetForFinallyLocalVar: Int ) { - if (!codegen.hasFinallyBlocks()) return; + if (!codegen.hasFinallyBlocks()) return - Map extensionPoints = new HashMap<>(); - for (MethodInliner.PointForExternalFinallyBlocks insertPoint : insertPoints) { - extensionPoints.put(insertPoint.beforeIns, insertPoint); + val extensionPoints = HashMap() + for (insertPoint in insertPoints) { + extensionPoints.put(insertPoint.beforeIns, insertPoint) } - DefaultProcessor processor = new DefaultProcessor(intoNode, offsetForFinallyLocalVar); + val processor = DefaultProcessor(intoNode, offsetForFinallyLocalVar) - int curFinallyDepth = 0; - AbstractInsnNode curInstr = intoNode.instructions.getFirst(); + var curFinallyDepth = 0 + var curInstr: AbstractInsnNode? = intoNode.instructions.first while (curInstr != null) { - processor.processInstruction(curInstr, true); + processor.processInstruction(curInstr, true) if (InlineCodegenUtil.isFinallyStart(curInstr)) { //TODO depth index calc could be more precise - curFinallyDepth = getConstant(curInstr.getPrevious()); + curFinallyDepth = getConstant(curInstr.previous) } - MethodInliner.PointForExternalFinallyBlocks extension = extensionPoints.get(curInstr); + val extension = extensionPoints[curInstr] if (extension != null) { - Label start = new Label(); + val start = Label() - MethodNode finallyNode = InlineCodegenUtil.createEmptyMethodNode(); - finallyNode.visitLabel(start); + val finallyNode = InlineCodegenUtil.createEmptyMethodNode() + finallyNode.visitLabel(start) - ExpressionCodegen finallyCodegen = - new ExpressionCodegen(finallyNode, codegen.getFrameMap(), codegen.getReturnType(), - codegen.getContext(), codegen.getState(), codegen.getParentCodegen()); - finallyCodegen.addBlockStackElementsForNonLocalReturns(codegen.getBlockStackElements(), curFinallyDepth); + val finallyCodegen = ExpressionCodegen(finallyNode, codegen.frameMap, codegen.returnType, + codegen.getContext(), codegen.state, codegen.parentCodegen) + finallyCodegen.addBlockStackElementsForNonLocalReturns(codegen.blockStackElements, curFinallyDepth) - FrameMap frameMap = finallyCodegen.getFrameMap(); - FrameMap.Mark mark = frameMap.mark(); - int marker = -1; - Set intervals = processor.getLocalVarsMetaInfo().getCurrentIntervals(); - for (LocalVarNodeWrapper interval : intervals) { - marker = Math.max(interval.getNode().index + 1, marker); + 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.getCurrentSize() < Math.max(processor.getNextFreeLocalIndex(), offsetForFinallyLocalVar + marker)) { - frameMap.enterTemp(Type.INT_TYPE); + while (frameMap.currentSize < Math.max(processor.nextFreeLocalIndex, offsetForFinallyLocalVar + marker)) { + frameMap.enterTemp(Type.INT_TYPE) } - finallyCodegen.generateFinallyBlocksIfNeeded(extension.returnType, extension.finallyIntervalEnd.getLabel()); + 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 - InlineCodegenUtil.insertNodeBefore(finallyNode, intoNode, curInstr); + InlineCodegenUtil.insertNodeBefore(finallyNode, intoNode, curInstr) - SimpleInterval splitBy = new SimpleInterval((LabelNode) start.info, extension.finallyIntervalEnd); - processor.getTryBlocksMetaInfo().splitCurrentIntervals(splitBy, true); + val splitBy = SimpleInterval(start.info as LabelNode, extension.finallyIntervalEnd) + processor.tryBlocksMetaInfo.splitCurrentIntervals(splitBy, true) //processor.getLocalVarsMetaInfo().splitAndRemoveIntervalsFromCurrents(splitBy); - mark.dropTo(); + mark.dropTo() } - curInstr = curInstr.getNext(); + curInstr = curInstr.next } - processor.substituteTryBlockNodes(intoNode); + processor.substituteTryBlockNodes(intoNode) //processor.substituteLocalVarTable(intoNode); } - @NotNull - public static SourceMapper createNestedSourceMapper(@NotNull SMAPAndMethodNode nodeAndSmap, @NotNull SourceMapper parent) { - return new NestedSourceMapper(parent, nodeAndSmap.getSortedRanges(), nodeAndSmap.getClassSMAP().getSourceInfo()); - } - - static void reportIncrementalInfo( - @NotNull FunctionDescriptor sourceDescriptor, - @NotNull FunctionDescriptor targetDescriptor, - @NotNull JvmMethodSignature jvmSignature, - @NotNull GenerationState state - ) { - IncrementalCache incrementalCache = state.getIncrementalCacheForThisTarget(); - if (incrementalCache == null) return; - String classFilePath = InlineCodegenUtilsKt.getClassFilePath(sourceDescriptor, state.getTypeMapper(), incrementalCache); - String sourceFilePath = InlineCodegenUtilsKt.getSourceFilePath(targetDescriptor); - Method method = jvmSignature.getAsmMethod(); - incrementalCache.registerInline(classFilePath, method.getName() + method.getDescriptor(), sourceFilePath); - } - - @Override - public void reorderArgumentsIfNeeded( - @NotNull List actualArgsWithDeclIndex, @NotNull List valueParameterTypes + override fun reorderArgumentsIfNeeded( + actualArgsWithDeclIndex: List, valueParameterTypes: List ) { } - @Override - public void putHiddenParamsIntoLocals() { - assert delayedHiddenWriting != null : "processAndPutHiddenParameters(true) should be called before putHiddenParamsIntoLocals"; - delayedHiddenWriting.run(); - delayedHiddenWriting = null; + override fun putHiddenParamsIntoLocals() { + assert(delayedHiddenWriting != null) { "processAndPutHiddenParameters(true) should be called before putHiddenParamsIntoLocals" } + delayedHiddenWriting!!.invoke() + delayedHiddenWriting = null + } + + companion object { + + private fun getMemberScope(functionOrAccessor: FunctionDescriptor): MemberScope? { + val callableMemberDescriptor = JvmCodegenUtil.getDirectMember(functionOrAccessor) + val classOrPackageFragment = callableMemberDescriptor.containingDeclaration + if (classOrPackageFragment is ClassDescriptor) { + return classOrPackageFragment.unsubstitutedMemberScope + } + else if (classOrPackageFragment is PackageFragmentDescriptor) { + return classOrPackageFragment.getMemberScope() + } + return null + } + + internal fun createMethodNode( + functionDescriptor: FunctionDescriptor, + jvmSignature: JvmMethodSignature, + codegen: ExpressionCodegen, + context: CodegenContext<*>, + callDefault: Boolean, + resolvedCall: ResolvedCall<*>? + ): SMAPAndMethodNode { + if (InlineCodegenUtil.isSpecialEnumMethod(functionDescriptor)) { + assert(resolvedCall != null) { "Resolved call for $functionDescriptor should be not null" } + val arguments = resolvedCall!!.typeArguments + assert(arguments.size == 1) { "Resolved call for $functionDescriptor should have 1 type argument" } + + val node = InlineCodegenUtil.createSpecialEnumMethodBody( + codegen, + functionDescriptor.name.asString(), + arguments.keys.iterator().next().defaultType, + codegen.state.typeMapper + ) + return SMAPAndMethodNode(node, SMAPParser.parseOrCreateDefault(null, null, "fake", -1, -1)) + } + else if (functionDescriptor.isBuiltInSuspendCoroutineOrReturnInJvm()) { + return SMAPAndMethodNode( + createMethodNodeForSuspendCoroutineOrReturn( + functionDescriptor, codegen.state.typeMapper + ), + SMAPParser.parseOrCreateDefault(null, null, "fake", -1, -1) + ) + } + + val state = codegen.state + val asmMethod = if (callDefault) + state.typeMapper.mapDefaultMethod(functionDescriptor, context.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) + } + + val resultInCache = state.inlineCache.methodNodeById.getOrPut(methodId + ) { + val result = doCreateMethodNodeFromCompiled(directMember, state, asmMethod) ?: throw IllegalStateException("Couldn't obtain compiled function body for " + functionDescriptor) + result + } + + return resultInCache.copyWithNewNode(cloneMethodNode(resultInCache.node)) + } + + private fun getDirectMemberAndCallableFromObject(functionDescriptor: FunctionDescriptor): CallableMemberDescriptor { + val directMember = JvmCodegenUtil.getDirectMember(functionDescriptor) + if (directMember is ImportedFromObjectCallableDescriptor<*>) { + return (directMember as ImportedFromObjectCallableDescriptor<*>).callableFromObject + } + return directMember + } + + private fun cloneMethodNode(methodNode: MethodNode): MethodNode { + methodNode.instructions.resetLabels() + val result = MethodNode( + API, methodNode.access, methodNode.name, methodNode.desc, methodNode.signature, + ArrayUtil.toStringArray(methodNode.exceptions) + ) + methodNode.accept(result) + return result + } + + private fun doCreateMethodNodeFromCompiled( + callableDescriptor: CallableMemberDescriptor, + state: GenerationState, + asmMethod: Method + ): SMAPAndMethodNode? { + if (isBuiltInArrayIntrinsic(callableDescriptor)) { + val classId = classId + val bytes = state.inlineCache.classBytes.getOrPut(classId) { bytecode } + return InlineCodegenUtil.getMethodNode(bytes, asmMethod.name, asmMethod.descriptor, classId.asString()) + } + + assert(callableDescriptor is DeserializedCallableMemberDescriptor) { "Not a deserialized function or proper: " + callableDescriptor } + + val containingClasses = state.typeMapper.getContainingClassesForDeserializedCallable(callableDescriptor as DeserializedCallableMemberDescriptor) + + val containerId = containingClasses.implClassId + + val bytes = state.inlineCache.classBytes.getOrPut(containerId) { + val file = InlineCodegenUtil.findVirtualFile(state, containerId) ?: throw IllegalStateException("Couldn't find declaration file for " + containerId) + try { + file.contentsToByteArray() + } + catch (e: IOException) { + throw RuntimeException(e) + } + } + + return InlineCodegenUtil.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( + InlineCodegenUtil.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 = InlineCodegenUtil.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 + val name = callableDescriptor.name.asString() + 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 + while (insn != null) { + if (MultifileClassPartCodegen.isStaticInitTrigger(insn)) { + val clinitTriggerCall = insn + insn = insn.next + insnList.remove(clinitTriggerCall) + } + else { + insn = insn.next + } + } + } + + 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 { + //remap only inline functions (and maybe non primitives) + //TODO - clean asserion and remapping logic + if (isPrimitive(type) != isPrimitive(stackValue.type)) { + //don't remap boxing/unboxing primitives - lost identity and perfomance + return true + } + + if (stackValue is StackValue.Local) { + return false + } + + var field = stackValue + if (stackValue is StackValue.FieldForSharedVar) { + field = stackValue.receiver + } + + //check that value corresponds to captured inlining parameter + if (field is StackValue.Field) { + val varDescriptor = field.descriptor + //check that variable is inline function parameter + return !(varDescriptor is ParameterDescriptor && + InlineUtil.isInlineLambdaParameter(varDescriptor) && + InlineUtil.isInline(varDescriptor.containingDeclaration)) + } + + 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() + + if (lambdaOrFun != null) { + val label = LabelResolver.getLabelNameIfAny(lambdaOrFun) + if (label != null) { + result.add(label.asString()) + } + } + + if (!isFunctionLiteral(descriptor)) { + if (!descriptor.name.isSpecial) { + result.add(descriptor.name.asString()) + } + result.add(InlineCodegenUtil.FIRST_FUN_LABEL) + } + 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) + } + + internal fun reportIncrementalInfo( + sourceDescriptor: FunctionDescriptor, + targetDescriptor: FunctionDescriptor, + jvmSignature: JvmMethodSignature, + state: GenerationState + ) { + val incrementalCache = state.incrementalCacheForThisTarget ?: return + val classFilePath = sourceDescriptor.getClassFilePath(state.typeMapper, incrementalCache) + val sourceFilePath = targetDescriptor.sourceFilePath + val method = jvmSignature.asmMethod + incrementalCache.registerInline(classFilePath, method.name + method.descriptor, sourceFilePath) + } } }