Introduce BaseExpressionCodegen and SourceCompilerForInline,
switch CallGenerator and InlineCodegen to them ~base
This commit is contained in:
@@ -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()
|
||||
}
|
||||
@@ -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<StackValue, StackValue> implements LocalLookup {
|
||||
public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> implements LocalLookup, BaseExpressionCodegen {
|
||||
private final GenerationState state;
|
||||
final KotlinTypeMapper typeMapper;
|
||||
private final BindingContext bindingContext;
|
||||
@@ -1352,6 +1352,7 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> 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<StackValue, StackValue> impleme
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLastLineNumber() {
|
||||
return myLastLineNumber;
|
||||
}
|
||||
@@ -2286,10 +2288,10 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> 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<TypeParameterDescriptor, ReificationArgument> 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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<Unit>? = 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<KtPureElement>(delegate as MemberCodegen<KtPureElement>, 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<MethodInliner.PointForExternalFinallyBlocks>,
|
||||
offsetForFinallyLocalVar: Int
|
||||
) {
|
||||
if (!codegen.hasFinallyBlocks()) return
|
||||
|
||||
val extensionPoints = HashMap<AbstractInsnNode, MethodInliner.PointForExternalFinallyBlocks>()
|
||||
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<ArgumentAndDeclIndex>, valueParameterTypes: List<Type>
|
||||
) {
|
||||
@@ -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<FileMapping>
|
||||
): 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
|
||||
+13
-10
@@ -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) {
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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<CodegenContext<*>>()
|
||||
|
||||
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<FileMapping>
|
||||
): 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<KtPureElement>(delegate as MemberCodegen<KtPureElement>, 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<MethodInliner.PointForExternalFinallyBlocks>,
|
||||
offsetForFinallyLocalVar: Int
|
||||
) {
|
||||
if (!codegen.hasFinallyBlocks()) return
|
||||
|
||||
val extensionPoints = HashMap<AbstractInsnNode, MethodInliner.PointForExternalFinallyBlocks>()
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
|
||||
|
||||
Reference in New Issue
Block a user