JVM_IR: buffer method bytecode in FunctionCodegen

This commit is contained in:
pyos
2020-03-20 16:19:36 +01:00
committed by max-kammerer
parent f6e7d7f7f1
commit b317187f20
3 changed files with 27 additions and 45 deletions
@@ -45,6 +45,7 @@ import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmClassSignature
import org.jetbrains.kotlin.serialization.DescriptorSerializer
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
import org.jetbrains.org.objectweb.asm.*
import org.jetbrains.org.objectweb.asm.commons.Method
import java.io.File
open class ClassCodegen protected constructor(
@@ -352,8 +353,11 @@ open class ClassCodegen protected constructor(
return
}
val signature = FunctionCodegen(method, this).generate().asmMethod
jvmSignatureClashDetector.trackMethod(method, RawSignature(signature.name, signature.descriptor, MemberKind.METHOD))
val node = FunctionCodegen(method, this).generate()
node.accept(with(node) { visitor.newMethod(method.OtherOrigin, access, name, desc, signature, exceptions.toTypedArray()) })
jvmSignatureClashDetector.trackMethod(method, RawSignature(node.name, node.desc, MemberKind.METHOD))
val signature = Method(node.name, node.desc)
when (val metadata = method.metadata) {
is MetadataSource.Property -> {
// We can't check for JvmLoweredDeclarationOrigin.SYNTHETIC_METHOD_FOR_PROPERTY_ANNOTATIONS because for interface methods
@@ -13,6 +13,7 @@ import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin
import org.jetbrains.kotlin.backend.jvm.lower.suspendFunctionOriginal
import org.jetbrains.kotlin.codegen.AsmUtil
import org.jetbrains.kotlin.codegen.inline.DefaultSourceMapper
import org.jetbrains.kotlin.codegen.inline.wrapWithMaxLocalCalc
import org.jetbrains.kotlin.codegen.mangleNameIfNeeded
import org.jetbrains.kotlin.codegen.state.GenerationState
import org.jetbrains.kotlin.codegen.visitAnnotableParameterCount
@@ -28,31 +29,39 @@ import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.jvm.annotations.JVM_SYNTHETIC_ANNOTATION_FQ_NAME
import org.jetbrains.kotlin.resolve.jvm.annotations.STRICTFP_ANNOTATION_FQ_NAME
import org.jetbrains.kotlin.resolve.jvm.annotations.SYNCHRONIZED_ANNOTATION_FQ_NAME
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.utils.addToStdlib.safeAs
import org.jetbrains.org.objectweb.asm.*
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
import org.jetbrains.org.objectweb.asm.tree.MethodNode
open class FunctionCodegen(
class FunctionCodegen(
private val irFunction: IrFunction,
private val classCodegen: ClassCodegen,
private val inlinedInto: ExpressionCodegen? = null
) {
private val context = classCodegen.context
fun generate(smapOverride: DefaultSourceMapper? = null): JvmMethodGenericSignature =
fun generate(smapOverride: DefaultSourceMapper? = null): MethodNode =
try {
doGenerate(smapOverride)
} catch (e: Throwable) {
throw RuntimeException("Exception while generating code for:\n${irFunction.dump()}", e)
}
private fun doGenerate(smapOverride: DefaultSourceMapper?): JvmMethodGenericSignature {
private fun doGenerate(smapOverride: DefaultSourceMapper?): MethodNode {
val signature = context.methodSignatureMapper.mapSignatureWithGeneric(irFunction)
val flags = irFunction.calculateMethodFlags()
var methodVisitor = createMethod(flags, signature)
val methodNode = MethodNode(
Opcodes.API_VERSION,
flags,
signature.asmMethod.name,
signature.asmMethod.descriptor,
signature.genericsSignature.takeIf { flags.and(Opcodes.ACC_SYNTHETIC) == 0 },
getThrownExceptions(irFunction)?.toTypedArray()
)
var methodVisitor: MethodVisitor = wrapWithMaxLocalCalc(methodNode)
if (context.state.generateParametersMetadata && flags.and(Opcodes.ACC_SYNTHETIC) == 0) {
generateParameterNames(irFunction, methodVisitor, signature, context.state)
@@ -103,7 +112,7 @@ open class FunctionCodegen(
if (continuationClassCodegen.isInitialized() || irFunction.alwaysNeedsContinuation()) {
continuationClassCodegen.value.done()
}
return signature
return methodNode
}
// Since the only arguments to anonymous object constructors are captured variables and complex
@@ -156,16 +165,6 @@ open class FunctionCodegen(
(if (isSynchronized) Opcodes.ACC_SYNCHRONIZED else 0)
}
protected open fun createMethod(flags: Int, signature: JvmMethodGenericSignature): MethodVisitor =
classCodegen.visitor.newMethod(
irFunction.OtherOrigin,
flags,
signature.asmMethod.name,
signature.asmMethod.descriptor,
signature.genericsSignature.takeIf { flags.and(Opcodes.ACC_SYNTHETIC) == 0 },
getThrownExceptions(irFunction)?.toTypedArray()
)
private fun getThrownExceptions(function: IrFunction): List<String>? {
if (context.state.languageVersionSettings.supportsFeature(LanguageFeature.DoNotGenerateThrowsForDelegatedKotlinMembers) &&
function.origin == IrDeclarationOrigin.DELEGATED_MEMBER
@@ -37,7 +37,6 @@ import org.jetbrains.kotlin.psi.doNotAnalyze
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.jvm.diagnostics.ErrorsJvm.SUSPENSION_POINT_INSIDE_MONITOR
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodGenericSignature
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature
import org.jetbrains.kotlin.resolve.source.getPsi
import org.jetbrains.org.objectweb.asm.*
@@ -97,32 +96,10 @@ class IrSourceCompilerForInline(
override val lazySourceMapper: DefaultSourceMapper
get() = codegen.smapOverride ?: codegen.classCodegen.getOrCreateSourceMapper()
private fun makeInlineNode(function: IrFunction, classCodegen: ClassCodegen, isLambda: Boolean): SMAPAndMethodNode {
var node: MethodNode? = null
val smap = if (isLambda)
codegen.context.getSourceMapper(codegen.classCodegen.irClass)
else
classCodegen.getOrCreateSourceMapper()
val functionCodegen = object : FunctionCodegen(function, classCodegen, codegen.takeIf { isLambda }) {
override fun createMethod(flags: Int, signature: JvmMethodGenericSignature): MethodVisitor {
val asmMethod = signature.asmMethod
node = MethodNode(
Opcodes.API_VERSION,
flags,
asmMethod.name.removeSuffix(FOR_INLINE_SUFFIX),
asmMethod.descriptor,
signature.genericsSignature,
null
)
return wrapWithMaxLocalCalc(node!!)
}
}
functionCodegen.generate(smap)
return SMAPAndMethodNode(node!!, SMAP(smap.resultMappings))
}
override fun generateLambdaBody(lambdaInfo: ExpressionLambda): SMAPAndMethodNode {
return makeInlineNode((lambdaInfo as IrExpressionLambdaImpl).function, codegen.classCodegen, true)
val smap = codegen.context.getSourceMapper(codegen.classCodegen.irClass)
val node = FunctionCodegen((lambdaInfo as IrExpressionLambdaImpl).function, codegen.classCodegen, codegen).generate(smap)
return SMAPAndMethodNode(node, SMAP(smap.resultMappings))
}
override fun doCreateMethodNodeFromSource(
@@ -141,7 +118,9 @@ class IrSourceCompilerForInline(
} ?: callee
else
callee
return makeInlineNode(forInlineFunction, FakeClassCodegen(forInlineFunction, codegen.classCodegen), false)
val fakeCodegen = FakeClassCodegen(forInlineFunction, codegen.classCodegen)
val node = FunctionCodegen(forInlineFunction, fakeCodegen).generate()
return SMAPAndMethodNode(node, SMAP(fakeCodegen.getOrCreateSourceMapper().resultMappings))
}
override fun hasFinallyBlocks() = data.hasFinallyBlocks()